Repository: li9chuan/BaseService Branch: master Commit: ad24dd61a3d7 Files: 1194 Total size: 8.3 MB Directory structure: gitextract_0_cdghvg/ ├── .github/ │ └── workflows/ │ └── ccpp.yml ├── LICENSE ├── README.md ├── code/ │ ├── CMakeLists.txt │ ├── CMakeModules/ │ │ ├── AndroidToolChain.cmake │ │ ├── CheckDepends.cmake │ │ ├── ConfigureChecks.cmake │ │ ├── Find3dsMaxSDK.cmake │ │ ├── FindCEGUI.cmake │ │ ├── FindCppTest.cmake │ │ ├── FindCrashRpt.cmake │ │ ├── FindCurl.cmake │ │ ├── FindCustomMFC.cmake │ │ ├── FindDInput.cmake │ │ ├── FindDSound.cmake │ │ ├── FindDirectXSDK.cmake │ │ ├── FindEFXUtil.cmake │ │ ├── FindExternal.cmake │ │ ├── FindFMOD.cmake │ │ ├── FindFreeType.cmake │ │ ├── FindGTK2.cmake │ │ ├── FindIconv.cmake │ │ ├── FindJpeg.cmake │ │ ├── FindLibEvent.cmake │ │ ├── FindLibOVR.cmake │ │ ├── FindLibVR.cmake │ │ ├── FindLibwww.cmake │ │ ├── FindLua51.cmake │ │ ├── FindLua52.cmake │ │ ├── FindLua53.cmake │ │ ├── FindLuabind.cmake │ │ ├── FindMSVC.cmake │ │ ├── FindMercurial.cmake │ │ ├── FindMySQL.cmake │ │ ├── FindMysqlConnector.cmake │ │ ├── FindOgg.cmake │ │ ├── FindOpenGLES.cmake │ │ ├── FindOpenSSL.cmake │ │ ├── FindPBC.cmake │ │ ├── FindProtoBuf.cmake │ │ ├── FindS3TC.cmake │ │ ├── FindSTLport.cmake │ │ ├── FindSquish.cmake │ │ ├── FindTinyXml.cmake │ │ ├── FindToLua.cmake │ │ ├── FindVorbis.cmake │ │ ├── FindWindowsSDK.cmake │ │ ├── FindXF86VidMode.cmake │ │ ├── GetRevision.cmake │ │ ├── PCHSupport.cmake │ │ ├── iOSToolChain.cmake │ │ └── nel.cmake │ ├── CMakePackaging.txt │ ├── COPYING │ ├── CTestConfig.cmake │ ├── EVA/ │ │ ├── CMakeLists.txt │ │ ├── server/ │ │ │ ├── CMakeLists.txt │ │ │ ├── _del_log.bat │ │ │ ├── _robot_start .bat │ │ │ ├── _robot_stop .bat │ │ │ ├── _shard_start.bat │ │ │ ├── _shard_stop.bat │ │ │ ├── admin_executor_service.cfg │ │ │ ├── admin_modules/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── admin_modules.cpp │ │ │ │ ├── admin_modules_itf.cpp │ │ │ │ ├── admin_modules_itf.h │ │ │ │ ├── admin_modules_itf.xml │ │ │ │ ├── aes_client_module.cpp │ │ │ │ ├── aes_module.cpp │ │ │ │ └── as_module.cpp │ │ │ ├── admin_service/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── admin_service.cpp │ │ │ ├── admin_service.cfg │ │ │ ├── client_robot/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── client_robot.cpp │ │ │ ├── client_robot.cfg │ │ │ ├── common.cfg │ │ │ ├── frontend_service/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── frontend_service.cpp │ │ │ │ ├── frontend_service.h │ │ │ │ ├── stdpch.cpp │ │ │ │ └── stdpch.h │ │ │ ├── frontend_service.cfg │ │ │ ├── msg.xml │ │ │ ├── naming_service/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── naming_service.cpp │ │ │ ├── naming_service.cfg │ │ │ ├── player_logic_service/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── player_logic_service.cpp │ │ │ │ ├── player_logic_service.h │ │ │ │ ├── stdpch.cpp │ │ │ │ └── stdpch.h │ │ │ ├── player_logic_service.cfg │ │ │ ├── save_shard/ │ │ │ │ └── rrd_graphs/ │ │ │ │ ├── aes.ProcessUsedMemory.rrd │ │ │ │ ├── egs.ProcessUsedMemory.rrd │ │ │ │ ├── fes.ProcessUsedMemory.rrd │ │ │ │ ├── fes_0.FPSProcessMsg.rrd │ │ │ │ ├── fes_0.ProcessUsedMemory.rrd │ │ │ │ ├── hold_dir │ │ │ │ ├── lgc.ProcessUsedMemory.rrd │ │ │ │ ├── lgc_0.ProcessUsedMemory.rrd │ │ │ │ ├── pds.ProcessUsedMemory.rrd │ │ │ │ ├── ras.ProcessUsedMemory.rrd │ │ │ │ └── rns.ProcessUsedMemory.rrd │ │ │ ├── schedule_service/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── schedule_service.cpp │ │ │ ├── schedule_service.cfg │ │ │ ├── script/ │ │ │ │ ├── .vs/ │ │ │ │ │ ├── ProjectSettings.json │ │ │ │ │ ├── VSWorkspaceState.json │ │ │ │ │ └── script/ │ │ │ │ │ └── v15/ │ │ │ │ │ └── .suo │ │ │ │ ├── BaseService.luaprj │ │ │ │ ├── DataTable/ │ │ │ │ │ ├── ProtoMsg.pb │ │ │ │ │ ├── RoomConfig.json │ │ │ │ │ ├── RoomCreateCost.json │ │ │ │ │ ├── SpecialConfig.json │ │ │ │ │ ├── proto/ │ │ │ │ │ │ ├── define_attrib.proto │ │ │ │ │ │ ├── define_pro.proto │ │ │ │ │ │ ├── msg_client.proto │ │ │ │ │ │ ├── msg_doudizhu.proto │ │ │ │ │ │ └── msg_service.proto │ │ │ │ │ └── ssl/ │ │ │ │ │ ├── 1_root_bundle.crt │ │ │ │ │ ├── 2_ssl.ranatune.com.crt │ │ │ │ │ └── 3_ssl.ranatune.com.key │ │ │ │ ├── Framework/ │ │ │ │ │ ├── CJsonUtil.lua │ │ │ │ │ ├── Class.lua │ │ │ │ │ ├── Event/ │ │ │ │ │ │ ├── EventController.lua │ │ │ │ │ │ ├── EventRegister.lua │ │ │ │ │ │ └── EventTrigger.lua │ │ │ │ │ ├── Hotfix/ │ │ │ │ │ │ ├── HotfixHelper.lua │ │ │ │ │ │ ├── hotfix.lua │ │ │ │ │ │ └── internal/ │ │ │ │ │ │ ├── functions_replacer.lua │ │ │ │ │ │ └── module_updater.lua │ │ │ │ │ ├── InitFramework.lua │ │ │ │ │ ├── List.lua │ │ │ │ │ ├── Map.lua │ │ │ │ │ ├── MapMap.lua │ │ │ │ │ ├── MemoryReferenceInfo.lua │ │ │ │ │ ├── MiddleClass.lua │ │ │ │ │ ├── Net/ │ │ │ │ │ │ ├── BaseService.lua │ │ │ │ │ │ ├── CallbackServer.lua │ │ │ │ │ │ ├── NetWorkHandler.lua │ │ │ │ │ │ └── protobuf.lua │ │ │ │ │ ├── Queue.lua │ │ │ │ │ ├── SimpleStateMachine.lua │ │ │ │ │ ├── Stack.lua │ │ │ │ │ ├── StateFul.lua │ │ │ │ │ ├── Test/ │ │ │ │ │ │ ├── FSMClass.lua │ │ │ │ │ │ ├── MainTest.lua │ │ │ │ │ │ └── TimerTest.lua │ │ │ │ │ ├── TimerMgr.lua │ │ │ │ │ ├── Utils.lua │ │ │ │ │ └── functions.lua │ │ │ │ ├── Robot.luaprj │ │ │ │ ├── SharedLib/ │ │ │ │ │ ├── Event/ │ │ │ │ │ │ └── EventType.lua │ │ │ │ │ ├── InitSharedLib.lua │ │ │ │ │ └── StaticTableMgr.lua │ │ │ │ ├── _FES/ │ │ │ │ │ ├── Client/ │ │ │ │ │ │ ├── Client.lua │ │ │ │ │ │ └── ClientMgr.lua │ │ │ │ │ ├── FrontEndService.lua │ │ │ │ │ ├── Msg/ │ │ │ │ │ │ └── MsgLogin.lua │ │ │ │ │ ├── Player/ │ │ │ │ │ │ ├── PlayerInfo.lua │ │ │ │ │ │ └── PlayerInfoMgr.lua │ │ │ │ │ └── _FESMain.lua │ │ │ │ ├── _FES.luaprj │ │ │ │ ├── _PLS/ │ │ │ │ │ ├── DB/ │ │ │ │ │ │ ├── DBMgr.lua │ │ │ │ │ │ ├── DBProc.lua │ │ │ │ │ │ ├── DBSubProc.lua │ │ │ │ │ │ └── DBSubStart.lua │ │ │ │ │ ├── Games/ │ │ │ │ │ │ ├── Common/ │ │ │ │ │ │ │ ├── CardsAnalyseRes.lua │ │ │ │ │ │ │ ├── CommonDef.lua │ │ │ │ │ │ │ └── PokerDef.lua │ │ │ │ │ │ └── PokerDdz/ │ │ │ │ │ │ ├── DDZOutCardData.lua │ │ │ │ │ │ ├── DdzCardTypes.lua │ │ │ │ │ │ ├── DdzFSM.lua │ │ │ │ │ │ ├── DdzPlayerInfo.lua │ │ │ │ │ │ ├── MsgRoomDdz.lua │ │ │ │ │ │ └── RoomDdz.lua │ │ │ │ │ ├── Msg/ │ │ │ │ │ │ ├── MsgLogin.lua │ │ │ │ │ │ └── MsgRoom.lua │ │ │ │ │ ├── Player/ │ │ │ │ │ │ ├── PlayerDataHelper.lua │ │ │ │ │ │ ├── PlayerHelper.lua │ │ │ │ │ │ └── PlayerMgr.lua │ │ │ │ │ ├── PlayerLogicService.lua │ │ │ │ │ ├── Room/ │ │ │ │ │ │ ├── RoomBase.lua │ │ │ │ │ │ ├── RoomFactory.lua │ │ │ │ │ │ ├── RoomMgr.lua │ │ │ │ │ │ └── RoomPlayerBase.lua │ │ │ │ │ ├── _PLSConfig.lua │ │ │ │ │ ├── _PLSMain.lua │ │ │ │ │ └── hotfix_module_names.lua │ │ │ │ ├── _PLS.luaprj │ │ │ │ ├── _SCH/ │ │ │ │ │ ├── Msg/ │ │ │ │ │ │ ├── MsgLogin.lua │ │ │ │ │ │ └── MsgRoom.lua │ │ │ │ │ ├── PLSInfo/ │ │ │ │ │ │ ├── PLSGameInfo.lua │ │ │ │ │ │ ├── PLSInfo.lua │ │ │ │ │ │ └── PLSInfoMgr.lua │ │ │ │ │ ├── Player/ │ │ │ │ │ │ ├── PlayerInfo.lua │ │ │ │ │ │ └── PlayerInfoMgr.lua │ │ │ │ │ ├── Room/ │ │ │ │ │ │ ├── RoomIDAlloter.lua │ │ │ │ │ │ ├── RoomInfo.lua │ │ │ │ │ │ └── RoomMgr.lua │ │ │ │ │ ├── ScheduleService.lua │ │ │ │ │ └── _SCHMain.lua │ │ │ │ ├── _SCH.luaprj │ │ │ │ └── __Robot/ │ │ │ │ ├── RobotSub/ │ │ │ │ │ ├── FSMRobot.lua │ │ │ │ │ ├── GameDdz/ │ │ │ │ │ │ ├── FSMDdz.lua │ │ │ │ │ │ └── RobotGameDdz.lua │ │ │ │ │ ├── PublicRoomInfo.lua │ │ │ │ │ ├── PublicRoomInfoMgr.lua │ │ │ │ │ ├── Robot.lua │ │ │ │ │ ├── RobotData.lua │ │ │ │ │ ├── RobotGameBase.lua │ │ │ │ │ ├── RobotMgr.lua │ │ │ │ │ └── RobotSubStart.lua │ │ │ │ ├── Test/ │ │ │ │ │ ├── CppTimerBase.lua │ │ │ │ │ └── CppTimerTest.lua │ │ │ │ ├── ThreadMgr.lua │ │ │ │ └── _ClientRobotMain.lua │ │ │ ├── server_share/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── base_object.h │ │ │ │ ├── bin_luabind/ │ │ │ │ │ ├── Public.h │ │ │ │ │ ├── Public.hpp │ │ │ │ │ ├── ScriptBase.cpp │ │ │ │ │ ├── ScriptBase.h │ │ │ │ │ ├── ScriptExporter.cpp │ │ │ │ │ ├── ScriptExporter.h │ │ │ │ │ ├── ScriptHandle.cpp │ │ │ │ │ ├── ScriptHandle.h │ │ │ │ │ ├── ScriptObject.h │ │ │ │ │ ├── ScriptProxy.cpp │ │ │ │ │ └── ScriptProxy.h │ │ │ │ ├── bit_set_ext2.h │ │ │ │ ├── buf_fifo2.h │ │ │ │ ├── buf_fifo_ring.h │ │ │ │ ├── callback_adaptor.h │ │ │ │ ├── cjson/ │ │ │ │ │ ├── dtoa.cpp │ │ │ │ │ ├── dtoa_config.h │ │ │ │ │ ├── fpconv.cpp │ │ │ │ │ ├── fpconv.h │ │ │ │ │ ├── g_fmt.cpp │ │ │ │ │ ├── lua_cjson.cpp │ │ │ │ │ ├── strbuf.cpp │ │ │ │ │ └── strbuf.h │ │ │ │ ├── client_msg_desc.cpp │ │ │ │ ├── client_msg_desc.h │ │ │ │ ├── game_def.h │ │ │ │ ├── i18n_def.cpp │ │ │ │ ├── i18n_def.h │ │ │ │ ├── id_generate.cpp │ │ │ │ ├── id_generate.h │ │ │ │ ├── lua/ │ │ │ │ │ ├── lua_base_function.cpp │ │ │ │ │ ├── lua_engine.cpp │ │ │ │ │ ├── lua_engine.h │ │ │ │ │ ├── lua_param.cpp │ │ │ │ │ ├── lua_param.h │ │ │ │ │ ├── lua_thread.cpp │ │ │ │ │ ├── lua_thread.h │ │ │ │ │ ├── script_mgr.cpp │ │ │ │ │ └── script_mgr.h │ │ │ │ ├── lua_mysql/ │ │ │ │ │ ├── mysql_conn.cpp │ │ │ │ │ ├── mysql_conn.h │ │ │ │ │ ├── mysql_result.cpp │ │ │ │ │ ├── mysql_result.h │ │ │ │ │ ├── mysql_stmt.cpp │ │ │ │ │ ├── mysql_stmt.h │ │ │ │ │ ├── mysql_string.cpp │ │ │ │ │ └── mysql_string.h │ │ │ │ ├── lua_net/ │ │ │ │ │ ├── lua_callback_client.cpp │ │ │ │ │ ├── lua_callback_client.h │ │ │ │ │ ├── lua_callback_server.cpp │ │ │ │ │ ├── lua_callback_server.h │ │ │ │ │ ├── lua_message.cpp │ │ │ │ │ ├── lua_message.h │ │ │ │ │ ├── lua_network.cpp │ │ │ │ │ └── lua_network.h │ │ │ │ ├── msg_leaf.cpp │ │ │ │ ├── msg_leaf.h │ │ │ │ ├── object_pool.h │ │ │ │ ├── pbc/ │ │ │ │ │ ├── alloc.cpp │ │ │ │ │ ├── alloc.h │ │ │ │ │ ├── array.cpp │ │ │ │ │ ├── array.h │ │ │ │ │ ├── bootstrap.cpp │ │ │ │ │ ├── bootstrap.h │ │ │ │ │ ├── context.cpp │ │ │ │ │ ├── context.h │ │ │ │ │ ├── decode.cpp │ │ │ │ │ ├── descriptor.pbc.h │ │ │ │ │ ├── map.cpp │ │ │ │ │ ├── map.h │ │ │ │ │ ├── pattern.cpp │ │ │ │ │ ├── pattern.h │ │ │ │ │ ├── pbc-lua53.cpp │ │ │ │ │ ├── pbc.h │ │ │ │ │ ├── proto.cpp │ │ │ │ │ ├── proto.h │ │ │ │ │ ├── register.cpp │ │ │ │ │ ├── rmessage.cpp │ │ │ │ │ ├── stringpool.cpp │ │ │ │ │ ├── stringpool.h │ │ │ │ │ ├── varint.cpp │ │ │ │ │ ├── varint.h │ │ │ │ │ └── wmessage.cpp │ │ │ │ ├── ranking_change_near.h │ │ │ │ ├── ranking_slot.h │ │ │ │ ├── server_def.cpp │ │ │ │ ├── server_def.h │ │ │ │ ├── sigslot.h │ │ │ │ ├── singleton_registry.h │ │ │ │ ├── stdpch.cpp │ │ │ │ ├── stdpch.h │ │ │ │ ├── timer.cpp │ │ │ │ ├── timer.h │ │ │ │ ├── tools.cpp │ │ │ │ ├── tools.h │ │ │ │ ├── utils.cpp │ │ │ │ └── utils.h │ │ │ └── shard.screen.rc │ │ └── tools/ │ │ └── scripts/ │ │ └── linux/ │ │ ├── clean_log.sh │ │ ├── generate_packed_sheets.sh │ │ ├── loop_aes.sh │ │ ├── mt_domain_screen_wrapper.sh │ │ ├── service_launcher.sh │ │ ├── shard │ │ └── utilities │ ├── README │ ├── changelog.template │ ├── config.h.cmake │ ├── nel/ │ │ ├── AUTHORS │ │ ├── CMakeLists.txt │ │ ├── COPYING │ │ ├── ChangeLog │ │ ├── INSTALL │ │ ├── NEWS │ │ ├── README │ │ ├── include/ │ │ │ ├── CMakeLists.txt │ │ │ └── nel/ │ │ │ ├── CMakeLists.txt │ │ │ ├── georges/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── form.h │ │ │ │ ├── form_dfn.h │ │ │ │ ├── form_elm.h │ │ │ │ ├── form_loader.h │ │ │ │ ├── header.h │ │ │ │ ├── load_form.h │ │ │ │ ├── type.h │ │ │ │ ├── u_form.h │ │ │ │ ├── u_form_dfn.h │ │ │ │ ├── u_form_elm.h │ │ │ │ ├── u_form_loader.h │ │ │ │ └── u_type.h │ │ │ ├── ligo/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── ligo_config.h │ │ │ │ ├── primitive.h │ │ │ │ ├── primitive_class.h │ │ │ │ ├── primitive_configuration.h │ │ │ │ ├── primitive_utils.h │ │ │ │ ├── zone_bank.h │ │ │ │ └── zone_region.h │ │ │ ├── logic/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── logic_condition.h │ │ │ │ ├── logic_event.h │ │ │ │ ├── logic_state.h │ │ │ │ ├── logic_state_machine.h │ │ │ │ └── logic_variable.h │ │ │ ├── misc/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── aabbox.h │ │ │ │ ├── algo.h │ │ │ │ ├── app_context.h │ │ │ │ ├── array_2d.h │ │ │ │ ├── async_file_manager.h │ │ │ │ ├── base64.h │ │ │ │ ├── big_file.h │ │ │ │ ├── bit_mem_stream.h │ │ │ │ ├── bit_set.h │ │ │ │ ├── bitmap.h │ │ │ │ ├── block_memory.h │ │ │ │ ├── bsphere.h │ │ │ │ ├── buf_fifo.h │ │ │ │ ├── callback.h │ │ │ │ ├── cdb.h │ │ │ │ ├── cdb_bank_handler.h │ │ │ │ ├── cdb_branch.h │ │ │ │ ├── cdb_branch_observing_handler.h │ │ │ │ ├── cdb_check_sum.h │ │ │ │ ├── cdb_leaf.h │ │ │ │ ├── cdb_manager.h │ │ │ │ ├── check_fpu.h │ │ │ │ ├── class_id.h │ │ │ │ ├── class_registry.h │ │ │ │ ├── cmd_args.h │ │ │ │ ├── co_task.h │ │ │ │ ├── command.h │ │ │ │ ├── common.h │ │ │ │ ├── config_file.h │ │ │ │ ├── contiguous_block_allocator.h │ │ │ │ ├── cpu_time_stat.h │ │ │ │ ├── debug.h │ │ │ │ ├── di_event_emitter.h │ │ │ │ ├── diff_tool.h │ │ │ │ ├── displayer.h │ │ │ │ ├── dummy_window.h │ │ │ │ ├── dynloadlib.h │ │ │ │ ├── eid_translator.h │ │ │ │ ├── entity_id.h │ │ │ │ ├── enum_bitset.h │ │ │ │ ├── eval_num_expr.h │ │ │ │ ├── event_emitter.h │ │ │ │ ├── event_emitter_multi.h │ │ │ │ ├── event_listener.h │ │ │ │ ├── event_server.h │ │ │ │ ├── events.h │ │ │ │ ├── factory.h │ │ │ │ ├── fast_floor.h │ │ │ │ ├── fast_id_map.h │ │ │ │ ├── fast_mem.h │ │ │ │ ├── file.h │ │ │ │ ├── fixed_size_allocator.h │ │ │ │ ├── game_device.h │ │ │ │ ├── game_device_events.h │ │ │ │ ├── geom_ext.h │ │ │ │ ├── grid_traversal.h │ │ │ │ ├── gtk_displayer.h │ │ │ │ ├── heap_memory.h │ │ │ │ ├── hierarchical_timer.h │ │ │ │ ├── historic.h │ │ │ │ ├── i18n.h │ │ │ │ ├── i_xml.h │ │ │ │ ├── input_device.h │ │ │ │ ├── input_device_manager.h │ │ │ │ ├── input_device_server.h │ │ │ │ ├── inter_window_msg_queue.h │ │ │ │ ├── keyboard_device.h │ │ │ │ ├── line.h │ │ │ │ ├── log.h │ │ │ │ ├── matrix.h │ │ │ │ ├── md5.h │ │ │ │ ├── mem_displayer.h │ │ │ │ ├── mem_stream.h │ │ │ │ ├── mouse_device.h │ │ │ │ ├── mouse_smoother.h │ │ │ │ ├── mutable_container.h │ │ │ │ ├── mutex.h │ │ │ │ ├── noise_value.h │ │ │ │ ├── o_xml.h │ │ │ │ ├── object_arena_allocator.h │ │ │ │ ├── object_vector.h │ │ │ │ ├── p_thread.h │ │ │ │ ├── path.h │ │ │ │ ├── plane.h │ │ │ │ ├── plane_inline.h │ │ │ │ ├── polygon.h │ │ │ │ ├── pool_memory.h │ │ │ │ ├── progress_callback.h │ │ │ │ ├── quad.h │ │ │ │ ├── quat.h │ │ │ │ ├── random.h │ │ │ │ ├── reader_writer.h │ │ │ │ ├── rect.h │ │ │ │ ├── report.h │ │ │ │ ├── resource_ptr.h │ │ │ │ ├── resource_ptr_inline.h │ │ │ │ ├── rgba.h │ │ │ │ ├── sha1.h │ │ │ │ ├── shared_memory.h │ │ │ │ ├── sheet_id.h │ │ │ │ ├── singleton.h │ │ │ │ ├── smart_ptr.h │ │ │ │ ├── smart_ptr_inline.h │ │ │ │ ├── speaker_listener.h │ │ │ │ ├── sstring.h │ │ │ │ ├── static_map.h │ │ │ │ ├── stl_block_allocator.h │ │ │ │ ├── stl_block_list.h │ │ │ │ ├── stop_watch.h │ │ │ │ ├── stream.h │ │ │ │ ├── stream_inline.h │ │ │ │ ├── string_common.h │ │ │ │ ├── string_conversion.h │ │ │ │ ├── string_id_array.h │ │ │ │ ├── string_mapper.h │ │ │ │ ├── string_stream.h │ │ │ │ ├── system_info.h │ │ │ │ ├── system_utils.h │ │ │ │ ├── task_manager.h │ │ │ │ ├── tds.h │ │ │ │ ├── thread.h │ │ │ │ ├── time_nl.h │ │ │ │ ├── timeout_assertion_thread.h │ │ │ │ ├── traits_nl.h │ │ │ │ ├── triangle.h │ │ │ │ ├── twin_map.h │ │ │ │ ├── types_nl.h │ │ │ │ ├── ucstring.h │ │ │ │ ├── uv.h │ │ │ │ ├── value_smoother.h │ │ │ │ ├── variable.h │ │ │ │ ├── vector.h │ │ │ │ ├── vector_2d.h │ │ │ │ ├── vector_2f.h │ │ │ │ ├── vector_h.h │ │ │ │ ├── vector_inline.h │ │ │ │ ├── vectord.h │ │ │ │ ├── vectord_inline.h │ │ │ │ ├── voter.h │ │ │ │ ├── win32_util.h │ │ │ │ ├── win_displayer.h │ │ │ │ ├── win_event_emitter.h │ │ │ │ ├── win_thread.h │ │ │ │ ├── win_tray.h │ │ │ │ ├── window_displayer.h │ │ │ │ ├── words_dictionary.h │ │ │ │ ├── xml_auto_ptr.h │ │ │ │ └── xml_pack.h │ │ │ └── net/ │ │ │ ├── CMakeLists.txt │ │ │ ├── admin.h │ │ │ ├── buf_client.h │ │ │ ├── buf_net_base.h │ │ │ ├── buf_server.h │ │ │ ├── buf_server_tcp.h │ │ │ ├── buf_server_tcp_func.h │ │ │ ├── buf_server_websocket.h │ │ │ ├── buf_server_websocket_func.h │ │ │ ├── buf_sock.h │ │ │ ├── callback_client.h │ │ │ ├── callback_net_base.h │ │ │ ├── callback_server.h │ │ │ ├── callback_server_tcp.h │ │ │ ├── callback_server_websocket.h │ │ │ ├── cvar_log_filter.h │ │ │ ├── dummy_tcp_sock.h │ │ │ ├── email.h │ │ │ ├── inet_address.h │ │ │ ├── listen_sock.h │ │ │ ├── login_client.h │ │ │ ├── login_cookie.h │ │ │ ├── login_server.h │ │ │ ├── message.h │ │ │ ├── message_recorder.h │ │ │ ├── module.h │ │ │ ├── module_builder_parts.h │ │ │ ├── module_common.h │ │ │ ├── module_gateway.h │ │ │ ├── module_manager.h │ │ │ ├── module_message.h │ │ │ ├── module_socket.h │ │ │ ├── naming_client.h │ │ │ ├── net_displayer.h │ │ │ ├── net_log.h │ │ │ ├── net_manager.h │ │ │ ├── pacs_client.h │ │ │ ├── service.h │ │ │ ├── sock.h │ │ │ ├── tcp_sock.h │ │ │ ├── transport_class.h │ │ │ ├── udp_sim_sock.h │ │ │ ├── udp_sock.h │ │ │ ├── unified_network.h │ │ │ ├── unitime.h │ │ │ └── varpath.h │ │ ├── nel-config.in │ │ ├── samples/ │ │ │ ├── CMakeLists.txt │ │ │ ├── georges/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── boolean.typ │ │ │ │ ├── coolfilesinfo.dfn │ │ │ │ ├── default.sample_config │ │ │ │ ├── int.typ │ │ │ │ ├── log.log │ │ │ │ ├── main.cpp │ │ │ │ ├── positiondata.dfn │ │ │ │ ├── sample_config.dfn │ │ │ │ ├── sample_configs_sheets.packed_sheets │ │ │ │ └── string.typ │ │ │ ├── misc/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── command/ │ │ │ │ │ ├── CMakeLists.txt │ │ │ │ │ └── main.cpp │ │ │ │ ├── configfile/ │ │ │ │ │ ├── CMakeLists.txt │ │ │ │ │ ├── main.cpp │ │ │ │ │ └── simpletest.txt │ │ │ │ ├── debug/ │ │ │ │ │ ├── CMakeLists.txt │ │ │ │ │ └── main.cpp │ │ │ │ ├── i18n/ │ │ │ │ │ ├── CMakeLists.txt │ │ │ │ │ ├── de.uxt │ │ │ │ │ ├── en.uxt │ │ │ │ │ ├── fr.uxt │ │ │ │ │ └── main.cpp │ │ │ │ ├── log/ │ │ │ │ │ ├── CMakeLists.txt │ │ │ │ │ └── main.cpp │ │ │ │ ├── strings/ │ │ │ │ │ ├── CMakeLists.txt │ │ │ │ │ └── main.cpp │ │ │ │ └── types_check/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── main.cpp │ │ │ └── net/ │ │ │ ├── CMakeLists.txt │ │ │ ├── chat/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── chat_service.cfg │ │ │ │ ├── client.cfg │ │ │ │ ├── client.cpp │ │ │ │ ├── kbhit.cpp │ │ │ │ ├── kbhit.h │ │ │ │ └── server.cpp │ │ │ ├── class_transport/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── ai_service.cfg │ │ │ │ ├── ai_service.cpp │ │ │ │ ├── gd_service.cfg │ │ │ │ └── gd_service.cpp │ │ │ ├── login_system/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── client.cfg │ │ │ │ ├── client.cpp │ │ │ │ ├── frontend_service.cfg │ │ │ │ └── frontend_service.cpp │ │ │ ├── multi_shards/ │ │ │ │ ├── client.cpp │ │ │ │ ├── frontend_service.cpp │ │ │ │ └── shard_config/ │ │ │ │ ├── 01_admin_executor_service.lnk │ │ │ │ ├── 02_login_service.lnk │ │ │ │ ├── 03_naming_service_shard1.lnk │ │ │ │ ├── 04_welcome_service_shard1.lnk │ │ │ │ ├── 05_frontend_service_shard1.lnk │ │ │ │ ├── 06_naming_service_shard2.lnk │ │ │ │ ├── 07_welcome_service_shard2.lnk │ │ │ │ ├── 08_frontend_service_shard2.lnk │ │ │ │ ├── 09_naming_service_shard3.lnk │ │ │ │ ├── 10_frontend_service_shard3.lnk │ │ │ │ ├── 11_welcome_service_shard3.lnk │ │ │ │ ├── 12_client.lnk │ │ │ │ ├── admin_executor_service.cfg │ │ │ │ ├── client.cfg │ │ │ │ ├── login_service.cfg │ │ │ │ ├── login_service_database.cfg │ │ │ │ ├── shard1_config/ │ │ │ │ │ ├── frontend_service.cfg │ │ │ │ │ ├── naming_service.cfg │ │ │ │ │ └── welcome_service.cfg │ │ │ │ ├── shard2_config/ │ │ │ │ │ ├── frontend_service.cfg │ │ │ │ │ ├── naming_service.cfg │ │ │ │ │ └── welcome_service.cfg │ │ │ │ └── shard3_config/ │ │ │ │ ├── frontend_service.cfg │ │ │ │ ├── naming_service.cfg │ │ │ │ └── welcome_service.cfg │ │ │ ├── net_layer3/ │ │ │ │ ├── client.cpp │ │ │ │ ├── frontend_service.cfg │ │ │ │ ├── frontend_service.cpp │ │ │ │ ├── ping_service.cfg │ │ │ │ └── ping_service.cpp │ │ │ ├── net_layer4/ │ │ │ │ ├── client.cpp │ │ │ │ ├── frontend_service.cfg │ │ │ │ ├── frontend_service.cpp │ │ │ │ ├── ping_service.cfg │ │ │ │ └── ping_service.cpp │ │ │ ├── net_layer5/ │ │ │ │ ├── flood_service.cfg │ │ │ │ ├── flood_service.cpp │ │ │ │ ├── frontend_service.cfg │ │ │ │ ├── frontend_service.cpp │ │ │ │ ├── gpm_service.cfg │ │ │ │ ├── gpm_service.cpp │ │ │ │ ├── ping_service.cfg │ │ │ │ ├── ping_service.cpp │ │ │ │ ├── player_service.cfg │ │ │ │ └── player_service.cpp │ │ │ ├── service/ │ │ │ │ ├── chat_service.cfg │ │ │ │ └── chat_service.cpp │ │ │ ├── udp/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── bench_service.cfg │ │ │ │ ├── bench_service.cpp │ │ │ │ ├── client.cfg │ │ │ │ ├── client.cpp │ │ │ │ ├── graph.cpp │ │ │ │ ├── graph.h │ │ │ │ ├── n019003l.pfb │ │ │ │ ├── readme.txt │ │ │ │ ├── receive_task.cpp │ │ │ │ ├── receive_task.h │ │ │ │ ├── simlag.cpp │ │ │ │ └── simlag.h │ │ │ └── udp_ping/ │ │ │ ├── client.cpp │ │ │ ├── udp_service.cfg │ │ │ └── udp_service.cpp │ │ ├── src/ │ │ │ ├── CMakeLists.txt │ │ │ ├── georges/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── form.cpp │ │ │ │ ├── form_dfn.cpp │ │ │ │ ├── form_elm.cpp │ │ │ │ ├── form_loader.cpp │ │ │ │ ├── georges_file_format.txt │ │ │ │ ├── header.cpp │ │ │ │ ├── load_form.cpp │ │ │ │ ├── nel-georges.pc.in │ │ │ │ ├── stdgeorges.cpp │ │ │ │ ├── stdgeorges.h │ │ │ │ └── type.cpp │ │ │ ├── ligo/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── ligo_config.cpp │ │ │ │ ├── ligo_error.cpp │ │ │ │ ├── ligo_error.h │ │ │ │ ├── ligo_material.cpp │ │ │ │ ├── ligo_material.h │ │ │ │ ├── nel-ligo.pc.in │ │ │ │ ├── primitive.cpp │ │ │ │ ├── primitive_class.cpp │ │ │ │ ├── primitive_configuration.cpp │ │ │ │ ├── primitive_utils.cpp │ │ │ │ ├── stdligo.cpp │ │ │ │ ├── stdligo.h │ │ │ │ ├── transition.cpp │ │ │ │ ├── transition.h │ │ │ │ ├── zone_bank.cpp │ │ │ │ ├── zone_edge.cpp │ │ │ │ ├── zone_edge.h │ │ │ │ ├── zone_region.cpp │ │ │ │ ├── zone_template.cpp │ │ │ │ └── zone_template.h │ │ │ ├── logic/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── logic_condition.cpp │ │ │ │ ├── logic_event.cpp │ │ │ │ ├── logic_state.cpp │ │ │ │ ├── logic_state_machine.cpp │ │ │ │ └── logic_variable.cpp │ │ │ ├── misc/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── aabbox.cpp │ │ │ │ ├── algo.cpp │ │ │ │ ├── app_context.cpp │ │ │ │ ├── async_file_manager.cpp │ │ │ │ ├── base64.cpp │ │ │ │ ├── big_file.cpp │ │ │ │ ├── bit_mem_stream.cpp │ │ │ │ ├── bit_set.cpp │ │ │ │ ├── bitmap.cpp │ │ │ │ ├── bitmap_jpeg.cpp │ │ │ │ ├── bitmap_png.cpp │ │ │ │ ├── block_memory.cpp │ │ │ │ ├── bsphere.cpp │ │ │ │ ├── buf_fifo.cpp │ │ │ │ ├── cdb.cpp │ │ │ │ ├── cdb_bank_handler.cpp │ │ │ │ ├── cdb_branch.cpp │ │ │ │ ├── cdb_branch_observing_handler.cpp │ │ │ │ ├── cdb_check_sum.cpp │ │ │ │ ├── cdb_leaf.cpp │ │ │ │ ├── cdb_manager.cpp │ │ │ │ ├── check_fpu.cpp │ │ │ │ ├── class_id.cpp │ │ │ │ ├── class_registry.cpp │ │ │ │ ├── cmd_args.cpp │ │ │ │ ├── co_task.cpp │ │ │ │ ├── command.cpp │ │ │ │ ├── common.cpp │ │ │ │ ├── config_file/ │ │ │ │ │ ├── cf_bison.simple │ │ │ │ │ ├── cf_flex.skl │ │ │ │ │ ├── cf_gramatical.cpp │ │ │ │ │ ├── cf_gramatical.h │ │ │ │ │ ├── cf_gramatical.ypp │ │ │ │ │ ├── cf_lexical.cpp │ │ │ │ │ ├── cf_lexical.lpp │ │ │ │ │ ├── config_file.cpp │ │ │ │ │ └── do.bat │ │ │ │ ├── contiguous_block_allocator.cpp │ │ │ │ ├── cpu_time_stat.cpp │ │ │ │ ├── debug.cpp │ │ │ │ ├── diff_tool.cpp │ │ │ │ ├── displayer.cpp │ │ │ │ ├── dummy_window.cpp │ │ │ │ ├── dynloadlib.cpp │ │ │ │ ├── eid_translator.cpp │ │ │ │ ├── entity_id.cpp │ │ │ │ ├── eval_num_expr.cpp │ │ │ │ ├── event_emitter.cpp │ │ │ │ ├── event_emitter_multi.cpp │ │ │ │ ├── event_listener.cpp │ │ │ │ ├── event_server.cpp │ │ │ │ ├── events.cpp │ │ │ │ ├── fast_floor.cpp │ │ │ │ ├── fast_id_map.cpp │ │ │ │ ├── fast_mem.cpp │ │ │ │ ├── file.cpp │ │ │ │ ├── fixed_size_allocator.cpp │ │ │ │ ├── game_device.cpp │ │ │ │ ├── game_device_events.cpp │ │ │ │ ├── geom_ext.cpp │ │ │ │ ├── grid_traversal.cpp │ │ │ │ ├── gtk_displayer.cpp │ │ │ │ ├── heap_memory.cpp │ │ │ │ ├── hierarchical_timer.cpp │ │ │ │ ├── i18n.cpp │ │ │ │ ├── i_xml.cpp │ │ │ │ ├── input_device.cpp │ │ │ │ ├── input_device_server.cpp │ │ │ │ ├── inter_window_msg_queue.cpp │ │ │ │ ├── keyboard_device.cpp │ │ │ │ ├── line.cpp │ │ │ │ ├── log.cpp │ │ │ │ ├── matrix.cpp │ │ │ │ ├── md5.cpp │ │ │ │ ├── mem_displayer.cpp │ │ │ │ ├── mem_stream.cpp │ │ │ │ ├── mouse_smoother.cpp │ │ │ │ ├── mutex.cpp │ │ │ │ ├── nel-misc.pc │ │ │ │ ├── nel-misc.pc.in │ │ │ │ ├── noise_value.cpp │ │ │ │ ├── o_xml.cpp │ │ │ │ ├── object_arena_allocator.cpp │ │ │ │ ├── object_vector.cpp │ │ │ │ ├── p_thread.cpp │ │ │ │ ├── path.cpp │ │ │ │ ├── plane.cpp │ │ │ │ ├── polygon.cpp │ │ │ │ ├── progress_callback.cpp │ │ │ │ ├── quad.cpp │ │ │ │ ├── quat.cpp │ │ │ │ ├── reader_writer.cpp │ │ │ │ ├── rect.cpp │ │ │ │ ├── report.cpp │ │ │ │ ├── rgba.cpp │ │ │ │ ├── sha1.cpp │ │ │ │ ├── shared_memory.cpp │ │ │ │ ├── sheet_id.cpp │ │ │ │ ├── smart_ptr.cpp │ │ │ │ ├── sstring.cpp │ │ │ │ ├── stdmisc.cpp │ │ │ │ ├── stdmisc.h │ │ │ │ ├── stl_block_allocator.cpp │ │ │ │ ├── stl_block_list.cpp │ │ │ │ ├── stop_watch.cpp │ │ │ │ ├── stream.cpp │ │ │ │ ├── string_common.cpp │ │ │ │ ├── string_id_array.cpp │ │ │ │ ├── string_mapper.cpp │ │ │ │ ├── system_info.cpp │ │ │ │ ├── system_utils.cpp │ │ │ │ ├── task_manager.cpp │ │ │ │ ├── tds.cpp │ │ │ │ ├── time_nl.cpp │ │ │ │ ├── triangle.cpp │ │ │ │ ├── unicode.cpp │ │ │ │ ├── uv.cpp │ │ │ │ ├── value_smoother.cpp │ │ │ │ ├── variable.cpp │ │ │ │ ├── vector.cpp │ │ │ │ ├── vector_2d.cpp │ │ │ │ ├── vector_2f.cpp │ │ │ │ ├── vector_h.cpp │ │ │ │ ├── vectord.cpp │ │ │ │ ├── win32_util.cpp │ │ │ │ ├── win_displayer.cpp │ │ │ │ ├── win_event_emitter.cpp │ │ │ │ ├── win_thread.cpp │ │ │ │ ├── win_tray.cpp │ │ │ │ ├── window_displayer.cpp │ │ │ │ ├── words_dictionary.cpp │ │ │ │ └── xml_pack.cpp │ │ │ └── net/ │ │ │ ├── CMakeLists.txt │ │ │ ├── admin.cpp │ │ │ ├── buf_client.cpp │ │ │ ├── buf_net_base.cpp │ │ │ ├── buf_server.cpp │ │ │ ├── buf_server_tcp.cpp │ │ │ ├── buf_server_tcp_func.cpp │ │ │ ├── buf_server_websocket.cpp │ │ │ ├── buf_server_websocket_func.cpp │ │ │ ├── buf_sock.cpp │ │ │ ├── callback_client.cpp │ │ │ ├── callback_net_base.cpp │ │ │ ├── callback_server.cpp │ │ │ ├── callback_server_tcp.cpp │ │ │ ├── callback_server_websocket.cpp │ │ │ ├── define_sys.pb.cc │ │ │ ├── dummy_tcp_sock.cpp │ │ │ ├── email.cpp │ │ │ ├── inet_address.cpp │ │ │ ├── listen_sock.cpp │ │ │ ├── login_client.cpp │ │ │ ├── login_cookie.cpp │ │ │ ├── login_server.cpp │ │ │ ├── message.cpp │ │ │ ├── message_recorder.cpp │ │ │ ├── module.cpp │ │ │ ├── module_common.cpp │ │ │ ├── module_gateway.cpp │ │ │ ├── module_gateway_transport.cpp │ │ │ ├── module_l5_transport.cpp │ │ │ ├── module_local_gateway.cpp │ │ │ ├── module_manager.cpp │ │ │ ├── module_message.cpp │ │ │ ├── module_socket.cpp │ │ │ ├── naming_client.cpp │ │ │ ├── nel-net.pc.in │ │ │ ├── net_displayer.cpp │ │ │ ├── net_log.cpp │ │ │ ├── net_manager.cpp │ │ │ ├── service.cpp │ │ │ ├── sock.cpp │ │ │ ├── stdin_monitor_thread.cpp │ │ │ ├── stdin_monitor_thread.h │ │ │ ├── stdnet.cpp │ │ │ ├── stdnet.h │ │ │ ├── tcp_sock.cpp │ │ │ ├── transport_class.cpp │ │ │ ├── udp_sim_sock.cpp │ │ │ ├── udp_sock.cpp │ │ │ ├── unified_network.cpp │ │ │ ├── unitime.cpp │ │ │ └── varpath.cpp │ │ └── tools/ │ │ ├── CMakeLists.txt │ │ └── nel_unit_test/ │ │ ├── CMakeLists.txt │ │ ├── __copy_file_dst.foo │ │ ├── __ligo_class.xml │ │ ├── __test_prim.primitive │ │ ├── debug_cfg_with_error_main.cfg │ │ ├── nel_unit_test.cpp │ │ ├── nel_unit_test.exp │ │ ├── result.html │ │ ├── run_test.bat │ │ ├── ut_ligo.h │ │ ├── ut_ligo_primitive.h │ │ ├── ut_misc.h │ │ ├── ut_misc_co_task.h │ │ ├── ut_misc_command.h │ │ ├── ut_misc_config_file.h │ │ ├── ut_misc_debug.h │ │ ├── ut_misc_dynlibload.h │ │ ├── ut_misc_file.h │ │ ├── ut_misc_files/ │ │ │ ├── cfg_with_bad_test.cfg │ │ │ ├── cfg_with_define.cfg │ │ │ ├── cfg_with_error.cfg │ │ │ ├── cfg_with_error_main.cfg │ │ │ ├── cfg_with_include.cfg │ │ │ ├── cfg_with_include_and_optional.cfg │ │ │ ├── cfg_with_optional.cfg │ │ │ ├── file1_in_bnp.txt │ │ │ ├── file2_in_bnp.txt │ │ │ ├── files.bnp │ │ │ ├── files.xml_pack │ │ │ ├── files_for_xml_subpack/ │ │ │ │ ├── same_subfolder_1/ │ │ │ │ │ └── samename/ │ │ │ │ │ ├── .xml_pack_index │ │ │ │ │ ├── file1_in_sub_1.xml │ │ │ │ │ ├── file2_in_sub_1.xml │ │ │ │ │ └── samename.xml_pack │ │ │ │ └── same_subfolder_2/ │ │ │ │ └── samename/ │ │ │ │ ├── .xml_pack_index │ │ │ │ ├── file1_in_sub_2.xml │ │ │ │ ├── file2_in_sub_2.xml │ │ │ │ └── samename.xml_pack │ │ │ ├── included_cfg.cfg │ │ │ └── xml_files/ │ │ │ ├── file1_in_xml_pack.xml │ │ │ ├── file2_in_xml_pack.xml │ │ │ ├── same_subfolder_1/ │ │ │ │ └── samename/ │ │ │ │ └── samename.xml_pack │ │ │ ├── same_subfolder_2/ │ │ │ │ └── samename/ │ │ │ │ └── samename.xml_pack │ │ │ └── xml_files.xml_pack │ │ ├── ut_misc_pack_file.h │ │ ├── ut_misc_singleton.h │ │ ├── ut_misc_sstring.h │ │ ├── ut_misc_stream.h │ │ ├── ut_misc_string_common.h │ │ ├── ut_misc_types.h │ │ ├── ut_misc_variable.h │ │ ├── ut_net.h │ │ ├── ut_net_layer3.h │ │ ├── ut_net_message.h │ │ └── ut_net_module.h │ ├── nelDashBuild.cmd │ ├── nelDashBuild.sh │ └── revision.h.in └── tools/ ├── protobuf/ │ ├── JS/ │ │ ├── README.md │ │ ├── protobuf/ │ │ │ └── protofile/ │ │ │ └── hold │ │ └── protobuf_gen_js.bat │ ├── define_attrib.proto │ ├── define_pro.proto │ ├── lua/ │ │ └── protobuf_gen_lua.bat │ ├── msg_client.proto │ ├── msg_doudizhu.proto │ └── msg_service.proto ├── server/ │ ├── admin/ │ │ ├── common.php │ │ ├── config.php │ │ ├── crons/ │ │ │ ├── cron_harddisk.php │ │ │ ├── cron_harddisk.sh │ │ │ └── index.html │ │ ├── docs/ │ │ │ └── shard_restart/ │ │ │ ├── Filelist.xml │ │ │ ├── H38.css │ │ │ ├── H70_2.htm │ │ │ ├── HOWTO_Restarting_Ryzom_Game_Shards.htm │ │ │ ├── Hd36.xml │ │ │ ├── Hf69.htm │ │ │ ├── Hg39_1.htm │ │ │ ├── Hg41_2.htm │ │ │ ├── Hg43_3.htm │ │ │ ├── Hg45_4.htm │ │ │ ├── Hg47_5.htm │ │ │ ├── Hg49_6.htm │ │ │ ├── Hg51_7.htm │ │ │ ├── Hg53_8.htm │ │ │ ├── Hg55_9.htm │ │ │ ├── Hg57_10.htm │ │ │ ├── Hg59_11.htm │ │ │ ├── Hg61_12.htm │ │ │ ├── Hn68.htm │ │ │ ├── Hu37.js │ │ │ └── Hz63.htm │ │ ├── functions_auth.php │ │ ├── functions_common.php │ │ ├── functions_mysql.php │ │ ├── functions_mysqli.php │ │ ├── functions_tool_administration.php │ │ ├── functions_tool_applications.php │ │ ├── functions_tool_event_entities.php │ │ ├── functions_tool_graphs.php │ │ ├── functions_tool_guild_locator.php │ │ ├── functions_tool_log_analyser.php │ │ ├── functions_tool_main.php │ │ ├── functions_tool_mfs.php │ │ ├── functions_tool_notes.php │ │ ├── functions_tool_player_locator.php │ │ ├── functions_tool_preferences.php │ │ ├── functions_tool_shop.php │ │ ├── graphs_output/ │ │ │ └── placeholder │ │ ├── index.php │ │ ├── jpgraph/ │ │ │ ├── imgdata_balls.inc │ │ │ ├── imgdata_bevels.inc │ │ │ ├── imgdata_diamonds.inc │ │ │ ├── imgdata_pushpins.inc │ │ │ ├── imgdata_squares.inc │ │ │ ├── imgdata_stars.inc │ │ │ ├── jpg-config.inc │ │ │ ├── jpgraph.php │ │ │ ├── jpgraph_antispam-digits.php │ │ │ ├── jpgraph_antispam.php │ │ │ ├── jpgraph_bar.php │ │ │ ├── jpgraph_canvas.php │ │ │ ├── jpgraph_canvtools.php │ │ │ ├── jpgraph_date.php │ │ │ ├── jpgraph_error.php │ │ │ ├── jpgraph_flags.php │ │ │ ├── jpgraph_gantt.php │ │ │ ├── jpgraph_gb2312.php │ │ │ ├── jpgraph_gradient.php │ │ │ ├── jpgraph_iconplot.php │ │ │ ├── jpgraph_imgtrans.php │ │ │ ├── jpgraph_line.php │ │ │ ├── jpgraph_log.php │ │ │ ├── jpgraph_pie.php │ │ │ ├── jpgraph_pie3d.php │ │ │ ├── jpgraph_plotband.php │ │ │ ├── jpgraph_plotmark.inc │ │ │ ├── jpgraph_polar.php │ │ │ ├── jpgraph_radar.php │ │ │ ├── jpgraph_regstat.php │ │ │ ├── jpgraph_scatter.php │ │ │ ├── jpgraph_stock.php │ │ │ ├── jpgraph_utils.inc │ │ │ └── lang/ │ │ │ └── en.inc.php │ │ ├── logs/ │ │ │ └── empty.txt │ │ ├── nel/ │ │ │ ├── admin_modules_itf.php │ │ │ └── nel_message.php │ │ ├── neltool.css │ │ ├── overlib/ │ │ │ ├── makemini.pl │ │ │ ├── overlib.js │ │ │ ├── overlib_anchor.js │ │ │ ├── overlib_anchor_mini.js │ │ │ ├── overlib_draggable.js │ │ │ ├── overlib_draggable_mini.js │ │ │ └── overlib_mini.js │ │ ├── scripts/ │ │ │ ├── index.html │ │ │ ├── restart_sequence.php │ │ │ └── run_script.sh │ │ ├── smarty/ │ │ │ ├── Config_File.class.php │ │ │ ├── Smarty.class.php │ │ │ ├── Smarty_Compiler.class.php │ │ │ ├── debug.tpl │ │ │ ├── internals/ │ │ │ │ ├── core.assemble_plugin_filepath.php │ │ │ │ ├── core.assign_smarty_interface.php │ │ │ │ ├── core.create_dir_structure.php │ │ │ │ ├── core.display_debug_console.php │ │ │ │ ├── core.get_include_path.php │ │ │ │ ├── core.get_microtime.php │ │ │ │ ├── core.get_php_resource.php │ │ │ │ ├── core.is_secure.php │ │ │ │ ├── core.is_trusted.php │ │ │ │ ├── core.load_plugins.php │ │ │ │ ├── core.load_resource_plugin.php │ │ │ │ ├── core.process_cached_inserts.php │ │ │ │ ├── core.process_compiled_include.php │ │ │ │ ├── core.read_cache_file.php │ │ │ │ ├── core.rm_auto.php │ │ │ │ ├── core.rmdir.php │ │ │ │ ├── core.run_insert_handler.php │ │ │ │ ├── core.smarty_include_php.php │ │ │ │ ├── core.write_cache_file.php │ │ │ │ ├── core.write_compiled_include.php │ │ │ │ ├── core.write_compiled_resource.php │ │ │ │ └── core.write_file.php │ │ │ └── plugins/ │ │ │ ├── block.textformat.php │ │ │ ├── compiler.assign.php │ │ │ ├── function.assign_debug_info.php │ │ │ ├── function.config_load.php │ │ │ ├── function.counter.php │ │ │ ├── function.cycle.php │ │ │ ├── function.debug.php │ │ │ ├── function.eval.php │ │ │ ├── function.fetch.php │ │ │ ├── function.html_checkboxes.php │ │ │ ├── function.html_image.php │ │ │ ├── function.html_options.php │ │ │ ├── function.html_radios.php │ │ │ ├── function.html_select_date.php │ │ │ ├── function.html_select_time.php │ │ │ ├── function.html_table.php │ │ │ ├── function.mailto.php │ │ │ ├── function.math.php │ │ │ ├── function.popup.php │ │ │ ├── function.popup_init.php │ │ │ ├── function.substr.php │ │ │ ├── modifier.capitalize.php │ │ │ ├── modifier.cat.php │ │ │ ├── modifier.count_characters.php │ │ │ ├── modifier.count_paragraphs.php │ │ │ ├── modifier.count_sentences.php │ │ │ ├── modifier.count_words.php │ │ │ ├── modifier.date_format.php │ │ │ ├── modifier.debug_print_var.php │ │ │ ├── modifier.default.php │ │ │ ├── modifier.escape.php │ │ │ ├── modifier.indent.php │ │ │ ├── modifier.lower.php │ │ │ ├── modifier.nl2br.php │ │ │ ├── modifier.regex_replace.php │ │ │ ├── modifier.replace.php │ │ │ ├── modifier.spacify.php │ │ │ ├── modifier.string_format.php │ │ │ ├── modifier.strip.php │ │ │ ├── modifier.strip_tags.php │ │ │ ├── modifier.truncate.php │ │ │ ├── modifier.upper.php │ │ │ ├── modifier.wordwrap.php │ │ │ ├── outputfilter.trimwhitespace.php │ │ │ ├── shared.escape_special_chars.php │ │ │ └── shared.make_timestamp.php │ │ ├── templates/ │ │ │ ├── default/ │ │ │ │ ├── _index.tpl │ │ │ │ ├── index.tpl │ │ │ │ ├── index_login.tpl │ │ │ │ ├── index_restart_sequence.tpl │ │ │ │ ├── page_footer.tpl │ │ │ │ ├── page_footer_light.tpl │ │ │ │ ├── page_header.tpl │ │ │ │ ├── page_header_light.tpl │ │ │ │ ├── tool_actions.tpl │ │ │ │ ├── tool_administration.tpl │ │ │ │ ├── tool_administration_applications.tpl │ │ │ │ ├── tool_administration_domains.tpl │ │ │ │ ├── tool_administration_groups.tpl │ │ │ │ ├── tool_administration_logs.tpl │ │ │ │ ├── tool_administration_restarts.tpl │ │ │ │ ├── tool_administration_shards.tpl │ │ │ │ ├── tool_administration_users.tpl │ │ │ │ ├── tool_administration_users.tpl.backup │ │ │ │ ├── tool_event_entities.tpl │ │ │ │ ├── tool_graphs.tpl │ │ │ │ ├── tool_graphs_ccu.tpl │ │ │ │ ├── tool_graphs_hires.tpl │ │ │ │ ├── tool_graphs_tech.tpl │ │ │ │ ├── tool_guild_locator.tpl │ │ │ │ ├── tool_log_analyser.tpl │ │ │ │ ├── tool_log_analyser_file_view.tpl │ │ │ │ ├── tool_mfs.tpl │ │ │ │ ├── tool_notes.tpl │ │ │ │ ├── tool_player_locator.tpl │ │ │ │ ├── tool_preferences.tpl │ │ │ │ └── tool_shop.tpl │ │ │ └── default_c/ │ │ │ └── placeholder │ │ ├── tool_actions.php │ │ ├── tool_administration.php │ │ ├── tool_event_entities.php │ │ ├── tool_graphs.php │ │ ├── tool_guild_locator.php │ │ ├── tool_log_analyser.php │ │ ├── tool_mfs.php │ │ ├── tool_notes.php │ │ ├── tool_player_locator.php │ │ ├── tool_preferences.php │ │ └── tool_shop.php │ ├── sql/ │ │ ├── d_mt_account.sql │ │ ├── d_mt_player_procedure.sql │ │ ├── d_mt_player_table.sql │ │ └── nel_tool.sql │ └── www/ │ ├── login/ │ │ ├── code2accesstoken.php │ │ ├── config.php │ │ ├── login_test.php │ │ ├── logs/ │ │ │ └── placeholder │ │ ├── pay_service_itf.php │ │ └── public_func.php │ └── tools/ │ └── nel_message.php └── xlsx2json/ ├── LICENSE ├── README.md ├── config.json ├── excel/ │ └── GameConfig.xlsx ├── export.bat ├── export.sh ├── index.js ├── lib/ │ └── xlsx-to-json.js └── package.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/ccpp.yml ================================================ name: C/C++ CI on: [push] jobs: build: runs-on: ubuntu-latest steps: - path: ./BaseService/build run: ./cmake ../code - name: make run: make ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: README.md ================================================ # BaseService 微信小游戏服务器,房间及卡牌类游戏服务器。支持websocket及tcp连接,lua编写游戏逻辑,运行于C++服务器,跨平台。C++底层已支持多款线上产品。 使用lua编写游戏逻辑,不需要编写C++代码。函数支持不停机热更新。 # 依赖库 https://gitee.com/li9chuan/ExternalLib # Wiki https://gitee.com/li9chuan/EQipaiServer/wikis # QQ: 9703021 ================================================ FILE: code/CMakeLists.txt ================================================ #----------------------------------------------------------------------------- # # NeL # Authors: Nevrax and the NeL Community # Version: 0.8.0 # # Notes: # * Changing install location: add -DCMAKE_INSTALL_PREFIX:PATH=/my/new/path # * Changing specific install location variables: # * NL_ETC_PREFIX (default: $CMAKE_INSTALL_PREFIX/etc) # * NL_SHARE_PREFIX (default: $CMAKE_INSTALL_PREFIX/share) # * NL_BIN_PREFIX (default: $CMAKE_INSTALL_PREFIX/bin) # * NL_SBIN_PREFIX (default: $CMAKE_INSTALL_PREFIX/sbin) # * NL_LIB_PREFIX (default: $CMAKE_INSTALL_PREFIX/lib) # * NL_DRIVER_PREFIX (default: $CMAKE_INSTALL_PREFIX/lib (windows) or $CMAKE_INSTALL_PREFIX/lib/nel) # * Enable building of documentation: add -DBUILD_DOCUMENTATION:BOOL=ON - new make target: DoxygenDoc # * Updating version: update header (above) but also update NL_VERSION below. # * To build binary archive, use the 'package' target. # To build source archive, use the 'package_source' target. #----------------------------------------------------------------------------- # Load some macros. SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules;${CMAKE_MODULE_PATH}") #----------------------------------------------------------------------------- # Set CMake 2.6 Policies. IF(COMMAND cmake_policy) # Works around warnings libraries linked against that don't # have absolute paths (e.g. -lpthread) cmake_policy(SET CMP0003 NEW) # Works around warnings about escaped quotes in ADD_DEFINITIONS # statements cmake_policy(SET CMP0005 OLD) ENDIF(COMMAND cmake_policy) INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/nel.cmake) INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/ConfigureChecks.cmake) INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/CheckDepends.cmake) INCLUDE(${CMAKE_ROOT}/Modules/Documentation.cmake OPTIONAL) # Force out of source builds. CHECK_OUT_OF_SOURCE() CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(BaseService CXX C) SET(NL_VERSION_MAJOR 0) SET(NL_VERSION_MINOR 8) SET(NL_VERSION_PATCH 0) SET(NL_VERSION "${NL_VERSION_MAJOR}.${NL_VERSION_MINOR}.${NL_VERSION_PATCH}") #----------------------------------------------------------------------------- # Redirect output files SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # DLL should be in the same directory as EXE under Windows IF(WIN32) SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) ELSE(WIN32) SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) ENDIF(WIN32) IF(WIN32) IF(WITH_MFC) FIND_PACKAGE(MFC QUIET) ENDIF(WITH_MFC) IF(NOT DEFINED ENV{QTDIR}) SET(ENV{QTDIR} "c:/qt/4.6.3") ENDIF(NOT DEFINED ENV{QTDIR}) ENDIF(WIN32) # set platfrom defind IF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") SET(FreeBSD ON) ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") #----------------------------------------------------------------------------- # Set default config options # NL_SETUP_DEFAULT_OPTIONS() NL_SETUP_NEL_DEFAULT_OPTIONS() NL_SETUP_NELNS_DEFAULT_OPTIONS() NL_SETUP_PREFIX_PATHS() EVA_SETUP_PREFIX_PATHS() NL_CONFIGURE_CHECKS() NL_SETUP_BUILD() NL_SETUP_BUILD_FLAGS() #----------------------------------------------------------------------------- #Platform specifics SETUP_EXTERNAL() NL_GEN_REVISION_H() IF(WIN32) SET(WINSOCK2_LIB ws2_32.lib) SET(WINLDAP_LIB wldap32.lib) IF(WITH_MFC) FIND_PACKAGE(CustomMFC REQUIRED) ENDIF(WITH_MFC) ENDIF(WIN32) FIND_PACKAGE(Threads REQUIRED) FIND_PACKAGE(LibXml2 REQUIRED) FIND_PACKAGE(ProtoBuf REQUIRED) FIND_PACKAGE(Lua53 REQUIRED) #FIND_PACKAGE(PBC REQUIRED) FIND_PACKAGE(LibEvent REQUIRED) FIND_PACKAGE(OpenSSL REQUIRED) #SET(OPENSSL_USE_STATIC_LIBS TRUE) # openssl使用静态库 FIND_PACKAGE(ZLIB REQUIRED) ADD_DEFINITIONS(-DLUA_COMPAT_MODULE) # for lua_bind #FIND_PACKAGE(TinyXml REQUIRED) #FIND_PACKAGE(PNG REQUIRED) #FIND_PACKAGE(Jpeg) IF(WITH_STATIC) # libxml2 could need winsock2 library SET(LIBXML2_DEFINITIONS ${LIBXML2_DEFINITIONS} -DLIBXML_STATIC) SET(LIBXML2_LIBRARIES ${LIBXML2_LIBRARIES} ${WINSOCK2_LIB} ${WINLDAP_LIB}) # on Mac OS X libxml2 requieres iconv IF(FREEBSD OR APPLE) FIND_PACKAGE(Iconv REQUIRED) SET(LIBXML2_LIBRARIES ${LIBXML2_LIBRARIES} ${ICONV_LIBRARIES}) INCLUDE_DIRECTORIES(${ICONV_INCLUDE_DIR}) MESSAGE(STATUS "ICONV: ${ICONV_INCLUDE_DIR} ${ICONV_LIBRARIES}") ENDIF(FREEBSD OR APPLE) ENDIF(WITH_STATIC) INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/PCHSupport.cmake) IF(FINAL_VERSION) ADD_DEFINITIONS(-DFINAL_VERSION=1) ENDIF(FINAL_VERSION) ADD_DEFINITIONS(-DNL_MAP_ASSERT) IF(WITH_SSE2) ADD_DEFINITIONS(-DNL_HAS_SSE2) IF(WITH_SSE3) ADD_DEFINITIONS(-DNL_HAS_SSE3) ENDIF(WITH_SSE3) ENDIF(WITH_SSE2) IF(WITH_EVA) ADD_DEFINITIONS(-DEVA) ENDIF(WITH_EVA) IF(WITH_NEL) IF(WITH_NEL_TESTS) FIND_PACKAGE(CppTest) ENDIF(WITH_NEL_TESTS) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/nel/include ${LIBXML2_INCLUDE_DIR}) ADD_DEFINITIONS(${LIBXML2_DEFINITIONS}) ADD_SUBDIRECTORY(nel) ENDIF(WITH_NEL) IF(WITH_NELNS) ADD_SUBDIRECTORY(nelns) ENDIF(WITH_NELNS) IF(WITH_EVA) ADD_SUBDIRECTORY(EVA) ENDIF(WITH_EVA) # To build the documention, you will have to enable it # and then do the equivalent of "make DoxygenDoc". IF(BUILD_DOCUMENTATION) IF(DOT) SET(HAVE_DOT YES) ELSE(DOT) SET(HAVE_DOT NO) ENDIF(DOT) # This processes our Doxyfile.in and substitutes paths to generate # a final Doxyfile CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/doc/Doxyfile.cmake.in ${CMAKE_BINARY_DIR}/doc/Doxyfile) ADD_CUSTOM_TARGET(DoxygenDoc ${DOXYGEN} ${CMAKE_BINARY_DIR}/doc/Doxyfile) ENDIF(BUILD_DOCUMENTATION) IF(WITH_NEL_TESTS) ENABLE_TESTING() ADD_TEST(nel_unit_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/nel_unit_test --html) IF(BUILD_DASHBOARD) INCLUDE(Dart) SET(SVNCOMMAND svn) SET(SVNSOURCEDIR http://dev.ryzom.com/svn/trunk/nel) SET(GENERATELOGS svn2cl) ENDIF(BUILD_DASHBOARD) ENDIF(WITH_NEL_TESTS) # packaging information SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "NeL MMORPG Framework") SET(CPACK_PACKAGE_VENDOR "NeL") SET(CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_SOURCE_DIR}/README) SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/COPYING) SET(CPACK_PACKAGE_VERSION_MAJOR "${NL_VERSION_MAJOR}") SET(CPACK_PACKAGE_VERSION_MINOR "${NL_VERSION_MINOR}") SET(CPACK_PACKAGE_VERSION_PATCH "${NL_VERSION_PATCH}") SET(CPACK_INSTALL_CMAKE_PROJECTS "${CMAKE_BINARY_DIR};NeL;ALL;/") SET(CPACK_PACKAGE_EXECUTABLES "nel${NL_VERSION}" "nel") # NSIS Specific Packing Setup SET(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "NeL") SET(CPACK_NSIS_MODIFY_PATH "ON") SET(CPACK_NSIS_MUI_ICON ${CMAKE_SOURCE_DIR}/resources/nevraxpill.ico) SET(CPACK_NSIS_MUI_UNIICON ${CMAKE_SOURCE_DIR}/resources/nevraxpill.ico) SET(CPACK_PACKAGE_ICON ${CMAKE_SOURCE_DIR}/resources\\\\nel.bmp) SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} NeL") SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\dev.ryzom.com") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\dev.ryzom.com\\\\projects\\\\nel\\\\wiki") SET(CPACK_NSIS_CONTACT "matt.raykowski@gmail.com") ## Source Packages SET(CPACK_PACKAGE_FILE_NAME "nel-${NL_VERSION}") SET(CPACK_SOURCE_PACKAGE_FILE_NAME "nel-${NL_VERSION}") IF(WIN32) #SET(CPACK_GENERATOR "NSIS") SET(CPACK_GENERATOR "NSIS;ZIP") SET(CPACK_SOURCE_GENERATOR "ZIP") ELSE(WIN32) SET(CPACK_GENERATOR "TGZ") SET(CPACK_SOURCE_GENERATOR "TGZ") ENDIF(WIN32) set(CPACK_SOURCE_IGNORE_FILES "~$" "\\\\.cvsignore$" "^${CMAKE_SOURCE_DIR}.*/CVS/" "^${CMAKE_SOURCE_DIR}.*/\\\\.svn/" "^${CMAKE_SOURCE_DIR}/debian/" "^${CMAKE_SOURCE_DIR}/old/") IF(WIN32) IF(NOT CMAKE_BUILD_TYPE STREQUAL "Release") SET(CMAKE_INSTALL_DEBUG_LIBRARIES TRUE) ELSE(NOT CMAKE_BUILD_TYPE STREQUAL "Release") ENDIF(NOT CMAKE_BUILD_TYPE STREQUAL "Release") # Only the tools require MFC. IF(WITH_TOOLS) SET(CMAKE_INSTALL_MFC_LIBRARIES TRUE) ENDIF(WITH_TOOLS) INCLUDE(InstallRequiredSystemLibraries) ENDIF(WIN32) INCLUDE(CPack) INCLUDE(CMakePackaging.txt) ## Debian Packages #INCLUDE(UseDebian) #IF(DEBIAN_FOUND) # ADD_DEBIAN_TARGETS(nel) #ENDIF(DEBIAN_FOUND) ================================================ FILE: code/CMakeModules/AndroidToolChain.cmake ================================================ IF(DEFINED CMAKE_CROSSCOMPILING) # subsequent toolchain loading is not really needed RETURN() ENDIF() # Standard settings SET(CMAKE_SYSTEM_NAME Linux) SET(CMAKE_SYSTEM_VERSION 1) # TODO: determine target Linux version SET(UNIX ON) SET(LINUX ON) SET(ANDROID ON) IF(NOT NDK_ROOT) SET(NDK_ROOT $ENV{NDK_ROOT}) IF(CMAKE_HOST_WIN32) FILE(TO_CMAKE_PATH ${NDK_ROOT} NDK_ROOT) ENDIF(CMAKE_HOST_WIN32) ENDIF(NOT NDK_ROOT) IF(NOT TARGET_CPU) SET(TARGET_CPU "armv7") ENDIF(NOT TARGET_CPU) IF(TARGET_CPU STREQUAL "armv7") SET(LIBRARY_ARCHITECTURE "armeabi-v7a") SET(CMAKE_SYSTEM_PROCESSOR "armv7") SET(TOOLCHAIN_ARCH "arm") SET(GCC_TOOLCHAIN_PREFIX "arm-linux-androideabi") SET(TOOLCHAIN_BIN_PREFIX "arm") SET(MINIMUM_NDK_TARGET 4) ELSEIF(TARGET_CPU STREQUAL "armv5") SET(LIBRARY_ARCHITECTURE "armeabi") SET(CMAKE_SYSTEM_PROCESSOR "armv5") SET(TOOLCHAIN_ARCH "arm") SET(GCC_TOOLCHAIN_PREFIX "arm-linux-androideabi") SET(TOOLCHAIN_BIN_PREFIX "arm") SET(MINIMUM_NDK_TARGET 4) ELSEIF(TARGET_CPU STREQUAL "x86") SET(LIBRARY_ARCHITECTURE "x86") SET(CMAKE_SYSTEM_PROCESSOR "x86") SET(TOOLCHAIN_ARCH "x86") SET(GCC_TOOLCHAIN_PREFIX "x86") SET(TOOLCHAIN_BIN_PREFIX "i686") SET(MINIMUM_NDK_TARGET 9) ELSEIF(TARGET_CPU STREQUAL "mips") SET(LIBRARY_ARCHITECTURE "mips") SET(CMAKE_SYSTEM_PROCESSOR "mips") SET(TOOLCHAIN_ARCH "mips") SET(GCC_TOOLCHAIN_PREFIX "mipsel-linux-android") SET(TOOLCHAIN_BIN_PREFIX "mipsel") SET(MINIMUM_NDK_TARGET 9) ENDIF(TARGET_CPU STREQUAL "armv7") SET(ANDROID_COMPILER "GCC") IF(NDK_TOOLCHAIN_VERSION STREQUAL "clang") SET(ANDROID_COMPILER "clang") SET(CLANG_TOOLCHAIN_PREFIX "llvm") SET(CLANG ON) ELSE() SET(GCC_TOOLCHAIN_VERSION ${NDK_TOOLCHAIN_VERSION}) ENDIF() IF(NOT NDK_TARGET) SET(NDK_TARGET ${MINIMUM_NDK_TARGET}) ENDIF(NOT NDK_TARGET) IF(CMAKE_HOST_WIN32) SET(TOOLCHAIN_HOST "windows") SET(TOOLCHAIN_BIN_SUFFIX ".exe") ELSEIF(CMAKE_HOST_APPLE) SET(TOOLCHAIN_HOST "apple") SET(TOOLCHAIN_BIN_SUFFIX "") ELSEIF(CMAKE_HOST_UNIX) SET(TOOLCHAIN_HOST "linux") SET(TOOLCHAIN_BIN_SUFFIX "") ENDIF(CMAKE_HOST_WIN32) MACRO(SEARCH_TOOLCHAIN _COMPILER) SET(${_COMPILER}_TOOLCHAIN_VERSIONS) FILE(GLOB _TOOLCHAIN_VERSIONS "${NDK_ROOT}/toolchains/${${_COMPILER}_TOOLCHAIN_PREFIX}-*") IF(_TOOLCHAIN_VERSIONS) LIST(SORT _TOOLCHAIN_VERSIONS) LIST(REVERSE _TOOLCHAIN_VERSIONS) FOREACH(_TOOLCHAIN_VERSION ${_TOOLCHAIN_VERSIONS}) STRING(REGEX REPLACE ".+${_PREFIX}-([0-9.]+)" "\\1" _TOOLCHAIN_VERSION "${_TOOLCHAIN_VERSION}") IF(_TOOLCHAIN_VERSION MATCHES "^([0-9.]+)$") LIST(APPEND ${_COMPILER}_TOOLCHAIN_VERSIONS ${_TOOLCHAIN_VERSION}) ENDIF() ENDFOREACH() ENDIF() IF(NOT ${_COMPILER}_TOOLCHAIN_VERSIONS) MESSAGE(FATAL_ERROR "No Android ${_COMPILER} toolchain found in default search path ${NDK_ROOT}/toolchains") ENDIF() IF(${_COMPILER}_TOOLCHAIN_VERSIONS) LIST(FIND ${_COMPILER}_TOOLCHAIN_VERSIONS "${${_COMPILER}_TOOLCHAIN_VERSION}" _INDEX) IF(_INDEX EQUAL -1) LIST(GET ${_COMPILER}_TOOLCHAIN_VERSIONS 0 ${_COMPILER}_TOOLCHAIN_VERSION) ENDIF() ELSE() LIST(GET ${_COMPILER}_TOOLCHAIN_VERSIONS 0 ${_COMPILER}_TOOLCHAIN_VERSION) ENDIF() SET(${_COMPILER}_TOOLCHAIN_ROOT "${NDK_ROOT}/toolchains/${${_COMPILER}_TOOLCHAIN_PREFIX}-${${_COMPILER}_TOOLCHAIN_VERSION}/prebuilt/${TOOLCHAIN_HOST}") IF(NOT EXISTS "${${_COMPILER}_TOOLCHAIN_ROOT}") FILE(GLOB _TOOLCHAIN_PREFIXES "${${_COMPILER}_TOOLCHAIN_ROOT}*") IF(_TOOLCHAIN_PREFIXES) LIST(GET _TOOLCHAIN_PREFIXES 0 ${_COMPILER}_TOOLCHAIN_ROOT) ENDIF(_TOOLCHAIN_PREFIXES) ENDIF() ENDMACRO() IF(CLANG) SEARCH_TOOLCHAIN(CLANG) MESSAGE(STATUS "Target Android NDK ${NDK_TARGET} and use clang ${CLANG_TOOLCHAIN_VERSION}") ENDIF() SEARCH_TOOLCHAIN(GCC) MESSAGE(STATUS "Target Android NDK ${NDK_TARGET} and use GCC ${GCC_TOOLCHAIN_VERSION}") MESSAGE(STATUS "Found Android LLVM toolchain in ${CLANG_TOOLCHAIN_ROOT}") MESSAGE(STATUS "Found Android GCC toolchain in ${GCC_TOOLCHAIN_ROOT}") SET(PLATFORM_ROOT "${NDK_ROOT}/platforms/android-${NDK_TARGET}/arch-${TOOLCHAIN_ARCH}") MESSAGE(STATUS "Found Android platform in ${PLATFORM_ROOT}") # include dirs SET(PLATFORM_INCLUDE_DIR "${PLATFORM_ROOT}/usr/include") SET(STL_DIR "${NDK_ROOT}/sources/cxx-stl/gnu-libstdc++") IF(EXISTS "${STL_DIR}/${GCC_TOOLCHAIN_VERSION}") # NDK version >= 8b SET(STL_DIR "${STL_DIR}/${GCC_TOOLCHAIN_VERSION}") ENDIF(EXISTS "${STL_DIR}/${GCC_TOOLCHAIN_VERSION}") # Determine bin prefix for toolchain FILE(GLOB _TOOLCHAIN_BIN_PREFIXES "${GCC_TOOLCHAIN_ROOT}/bin/${TOOLCHAIN_BIN_PREFIX}-*-gcc${TOOLCHAIN_BIN_SUFFIX}") IF(_TOOLCHAIN_BIN_PREFIXES) LIST(GET _TOOLCHAIN_BIN_PREFIXES 0 _TOOLCHAIN_BIN_PREFIX) STRING(REGEX REPLACE "${GCC_TOOLCHAIN_ROOT}/bin/([a-z0-9-]+)-gcc${TOOLCHAIN_BIN_SUFFIX}" "\\1" TOOLCHAIN_BIN_PREFIX "${_TOOLCHAIN_BIN_PREFIX}") ENDIF(_TOOLCHAIN_BIN_PREFIXES) SET(STL_INCLUDE_DIR "${STL_DIR}/include") SET(STL_LIBRARY_DIR "${STL_DIR}/libs/${LIBRARY_ARCHITECTURE}") SET(STL_INCLUDE_CPU_DIR "${STL_LIBRARY_DIR}/include") SET(STL_LIBRARY "${STL_LIBRARY_DIR}/libgnustl_static.a") MESSAGE(STATUS "STL include dir: ${STL_INCLUDE_DIR}") MESSAGE(STATUS "STL library dir: ${STL_LIBRARY_DIR}") SET(CMAKE_FIND_ROOT_PATH ${CLANG_TOOLCHAIN_ROOT} ${GCC_TOOLCHAIN_ROOT} ${PLATFORM_ROOT}/usr ${CMAKE_PREFIX_PATH} ${CMAKE_INSTALL_PREFIX} $ENV{EXTERNAL_ANDROID_PATH} CACHE string "Android find search path root") SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) MACRO(SET_TOOLCHAIN_BINARY _NAME _BINARY) IF("${_BINARY}" MATCHES "clang") SET(${_NAME} ${CLANG_TOOLCHAIN_ROOT}/bin/${_BINARY}${TOOLCHAIN_BIN_SUFFIX} CACHE PATH "" FORCE ) ELSE() SET(${_NAME} ${GCC_TOOLCHAIN_ROOT}/bin/${TOOLCHAIN_BIN_PREFIX}-${_BINARY}${TOOLCHAIN_BIN_SUFFIX} CACHE PATH "" FORCE) ENDIF() ENDMACRO(SET_TOOLCHAIN_BINARY) # Force the compilers to GCC for Android include (CMakeForceCompiler) IF(CLANG) SET_TOOLCHAIN_BINARY(CMAKE_C_COMPILER clang) SET_TOOLCHAIN_BINARY(CMAKE_CXX_COMPILER clang++) CMAKE_FORCE_C_COMPILER(${CMAKE_C_COMPILER} clang) CMAKE_FORCE_CXX_COMPILER(${CMAKE_CXX_COMPILER} clang) MESSAGE(STATUS "Using clang compiler") ELSE() SET_TOOLCHAIN_BINARY(CMAKE_C_COMPILER gcc) SET_TOOLCHAIN_BINARY(CMAKE_CXX_COMPILER g++) CMAKE_FORCE_C_COMPILER(${CMAKE_C_COMPILER} GNU) CMAKE_FORCE_CXX_COMPILER(${CMAKE_CXX_COMPILER} GNU) MESSAGE(STATUS "Using GCC compiler") ENDIF() SET_TOOLCHAIN_BINARY(CMAKE_STRIP strip) SET_TOOLCHAIN_BINARY(CMAKE_AR ar) SET_TOOLCHAIN_BINARY(CMAKE_LINKER ld) SET_TOOLCHAIN_BINARY(CMAKE_NM nm) SET_TOOLCHAIN_BINARY(CMAKE_OBJCOPY objcopy) SET_TOOLCHAIN_BINARY(CMAKE_OBJDUMP objdump) SET_TOOLCHAIN_BINARY(CMAKE_RANLIB ranlib) ================================================ FILE: code/CMakeModules/CheckDepends.cmake ================================================ # Macros to check if a library needs to be manually linked to another one # because it's using a symbol from it but it's not linked to # CHECK_UNDEFINED_SYMBOL # Macro to check if a library is calling an undefined symbol # # Syntax: # CHECK_UNDEFINED_SYMBOL(MYLIBRARY SYMBOL SYMBOL_FOUND) # SYMBOL_FOUND will be set to TRUE if UNDEFINED # # Example: # CHECK_UNDEFINED_SYMBOL(PNG_LIBRARY inflate INFLATE_FOUND) # MACRO(CHECK_UNDEFINED_SYMBOL MYLIBRARY SYMBOL SYMBOL_FOUND) SET(${SYMBOL_FOUND} TRUE) IF(WIN32) # Always TRUE under Windows because we are using static libraries ELSEIF(APPLE) SET(CMAKE_NM nm) IF(CMAKE_NM) # Use nm to check if a library is using an external symbol EXEC_PROGRAM(${CMAKE_NM} ARGS "-gu ${${MYLIBRARY}} | grep ${SYMBOL}" OUTPUT_VARIABLE NM_SYMBOL) # MESSAGE(STATUS "Checking for undefined symbol ${SYMBOL} in ${${MYLIBRARY}}") IF(NOT NM_SYMBOL MATCHES ${SYMBOL}) SET(${SYMBOL_FOUND} FALSE) # MESSAGE(STATUS "Defined symbol ${SYMBOL} detected in ${${MYLIBRARY}}") ENDIF(NOT NM_SYMBOL MATCHES ${SYMBOL}) ENDIF(CMAKE_NM) ELSEIF(UNIX) SET(CMAKE_OBJDUMP objdump) IF(CMAKE_OBJDUMP) # Use objdump to check if a library is using an external symbol #MESSAGE(STATUS "exec ${CMAKE_OBJDUMP} -T ${${MYLIBRARY}} | grep ${SYMBOL}") EXEC_PROGRAM(${CMAKE_OBJDUMP} ARGS "-T ${${MYLIBRARY}} | grep ${SYMBOL}" OUTPUT_VARIABLE OBJDUMP_SYMBOL) IF(NOT OBJDUMP_SYMBOL MATCHES "UND") #MESSAGE(STATUS "${${MYLIBRARY}} does not use symbol ${SYMBOL}") SET(${SYMBOL_FOUND} FALSE) ELSE(NOT OBJDUMP_SYMBOL MATCHES "UND") #MESSAGE(STATUS "${${MYLIBRARY}} uses symbol ${SYMBOL}") ENDIF(NOT OBJDUMP_SYMBOL MATCHES "UND") ENDIF(CMAKE_OBJDUMP) ENDIF(WIN32) ENDMACRO(CHECK_UNDEFINED_SYMBOL) # CHECK_LINKED_LIBRARY # Macro to check if a library is linked to another one # # Syntax: # CHECK_LINKED_LIBRARY(MYLIBRARY OTHERLIBRARY LIBRARY_FOUND) # LIBRARY_FOUND will be set to TRUE if LINKED # # Example: # CHECK_LINKED_LIBRARY(PNG_LIBRARY ZLIB_LIBRARY ZLIB_FOUND) # MACRO(CHECK_LINKED_LIBRARY MYLIBRARY OTHERLIBRARY LIBRARY_FOUND) SET(${LIBRARY_FOUND} FALSE) IF(WIN32) # Always FALSE under Windows because we are using static libraries ELSEIF(APPLE) SET(CMAKE_OTOOL otool) IF(CMAKE_OTOOL) # Use otool to check if a library is linked to another library GET_FILENAME_COMPONENT(LIBNAME "${${OTHERLIBRARY}}" NAME_WE) EXEC_PROGRAM(${CMAKE_OTOOL} ARGS "-L ${${MYLIBRARY}} | grep ${LIBNAME}" OUTPUT_VARIABLE OTOOL_LIBRARY) # MESSAGE(STATUS "Checking if ${LIBNAME} is linked to ${${MYLIBRARY}}") IF(OTOOL_LIBRARY MATCHES "${LIBNAME}") SET(${LIBRARY_FOUND} TRUE) # MESSAGE(STATUS "Library ${LIBNAME} already linked to ${${MYLIBRARY}}") ENDIF(OTOOL_LIBRARY MATCHES "${LIBNAME}") ENDIF(CMAKE_OTOOL) ELSEIF(UNIX) SET(CMAKE_OBJDUMP objdump) IF(CMAKE_OBJDUMP) GET_FILENAME_COMPONENT(LIBNAME "${${OTHERLIBRARY}}" NAME) # TODO: under Solaris use dump -Lv # Use objdump to check if a library is linked to another library #MESSAGE(STATUS "exec ${CMAKE_OBJDUMP} -p ${${MYLIBRARY}} | grep ${LIBNAME}") EXEC_PROGRAM(${CMAKE_OBJDUMP} ARGS "-p ${${MYLIBRARY}} | grep ${LIBNAME}" OUTPUT_VARIABLE OBJDUMP_LIBRARY) IF(OBJDUMP_LIBRARY MATCHES "NEEDED") #MESSAGE(STATUS "${${MYLIBRARY}} references to ${LIBNAME}.") SET(${LIBRARY_FOUND} TRUE) ELSE(OBJDUMP_LIBRARY MATCHES "NEEDED") #MESSAGE(STATUS "${${MYLIBRARY}} does not reference to ${LIBNAME}!") ENDIF(OBJDUMP_LIBRARY MATCHES "NEEDED") ENDIF(CMAKE_OBJDUMP) ENDIF(WIN32) ENDMACRO(CHECK_LINKED_LIBRARY) MACRO(CHECK_DEPENDS MYLIBRARY OTHERLIBRARY SYMBOL MUSTLINK) CHECK_UNDEFINED_SYMBOL(MYLIBRARY SYMBOL SYMBOL_FOUND) IF(SYMBOL_FOUND) CHECK_LINKED_LIBRARY(MYLIBRARY OTHERLIBRARY LIBRARY_FOUND) ENDIF(SYMBOL_FOUND) IF(SYMBOL_FOUND AND NOT LIBRARY_FOUND) SET(${MUSTLINK} YES) ELSE(SYMBOL_FOUND AND NOT LIBRARY_FOUND) SET(${MUSTLINK} NO) ENDIF(SYMBOL_FOUND AND NOT LIBRARY_FOUND) ENDMACRO(CHECK_DEPENDS) # LINK_DEPENDS # Macro to link a library if a symbol is used but is not already linked to it # # Syntax: # LINK_DEPENDS(LIBRARIES MYLIBRARY OTHERLIBRARY SYMBOL) # OTHERLIBRARY_LINKED will be set to TRUE or FALSE # # Example: # LINK_DEPENDS(PNG_LIBRARIES PNG_LIBRARY ZLIB_LIBRARY inflate) # MACRO(LINK_DEPENDS LIBRARIES MYLIBRARY OTHERLIBRARY SYMBOL) SET(MUST_LINK FALSE) IF(${MYLIBRARY} AND ${OTHERLIBRARY} AND NOT ${OTHERLIBRARY}_LINKED) IF(WIN32 OR WITH_STATIC) # In static, we link all libraries because it will keep only used symbols SET(MUST_LINK TRUE) ELSE(WIN32 OR WITH_STATIC) CHECK_UNDEFINED_SYMBOL(${MYLIBRARY} ${SYMBOL} SYMBOL_FOUND) IF(SYMBOL_FOUND) CHECK_LINKED_LIBRARY(${MYLIBRARY} ${OTHERLIBRARY} LIBRARY_FOUND) ENDIF(SYMBOL_FOUND) IF(SYMBOL_FOUND AND NOT LIBRARY_FOUND) MESSAGE(STATUS "Underlinking found: ${${MYLIBRARY}} needs ${${OTHERLIBRARY}} but is not linked to, manually linking...") SET(MUST_LINK TRUE) ENDIF(SYMBOL_FOUND AND NOT LIBRARY_FOUND) ENDIF(WIN32 OR WITH_STATIC) ENDIF(${MYLIBRARY} AND ${OTHERLIBRARY} AND NOT ${OTHERLIBRARY}_LINKED) IF(MUST_LINK) MESSAGE(STATUS "Linking with ${${OTHERLIBRARY}}") SET(${LIBRARIES} ${${LIBRARIES}} ${${OTHERLIBRARY}}) SET(${OTHERLIBRARY}_LINKED TRUE) ENDIF(MUST_LINK) ENDMACRO(LINK_DEPENDS) ================================================ FILE: code/CMakeModules/ConfigureChecks.cmake ================================================ MACRO(NL_CONFIGURE_CHECKS) INCLUDE(CheckIncludeFiles) INCLUDE(CheckFunctionExists) INCLUDE(CheckLibraryExists) INCLUDE(CheckTypeSize) CHECK_INCLUDE_FILES ("execinfo.h" HAVE_EXECINFO_H) CHECK_INCLUDE_FILES ("stdint.h" HAVE_STDINT_H) CHECK_INCLUDE_FILES ("sys/types.h" HAVE_SYS_TYPES_H) CHECK_INCLUDE_FILES ("inttypes.h" HAVE_INTTYPES_H) CHECK_INCLUDE_FILES ("unistd.h" HAVE_UNISTD_H) CHECK_INCLUDE_FILES ("utime.h" HAVE_UTIME_H) CHECK_INCLUDE_FILES ("dl.h" HAVE_DL_H) CHECK_INCLUDE_FILES ("limits.h" HAVE_LIMITS_H) CHECK_INCLUDE_FILES ("malloc.h" HAVE_MALLOC_H) CHECK_INCLUDE_FILES ("sys/param.h" HAVE_SYS_PARAM_H) CHECK_INCLUDE_FILES ("sys/param.h;sys/mount.h" HAVE_SYS_MOUNT_H) CHECK_INCLUDE_FILES ("sys/statvfs.h" HAVE_SYS_STATVFS_H) CHECK_INCLUDE_FILES ("pthread.h" HAVE_PTHREAD) CHECK_TYPE_SIZE("size_t" SIZEOF_SIZE_T) #if (NOT HAVE_SIZEOF_SIZE_T) # MESSAGE(FATAL_ERROR "size_t is not present on this architecture - aborting") #endif (NOT HAVE_SIZEOF_SIZE_T) MESSAGE(STATUS "DEBUG size_t is ${SIZEOF_SIZE_T}") CHECK_TYPE_SIZE("off_t" SIZEOF_OFF_T) MESSAGE(STATUS "DEBUG off_t is ${SIZEOF_OFF_T}") CHECK_FUNCTION_EXISTS("backtrace" HAVE_BACKTRACE) CHECK_FUNCTION_EXISTS("getsockname" HAVE_GETSOCKNAME) CHECK_FUNCTION_EXISTS("inet_ntoa" HAVE_INET_NTOA) CHECK_FUNCTION_EXISTS("inet_ntop" HAVE_INET_NTOP) CHECK_FUNCTION_EXISTS("inet_pton" HAVE_INET_PTON) CHECK_FUNCTION_EXISTS("regcomp" HAVE_REGCOMP) CHECK_FUNCTION_EXISTS("strerror" HAVE_STRERROR) CHECK_FUNCTION_EXISTS("strlcat" HAVE_STRLCAT) CHECK_FUNCTION_EXISTS("strptime" HAVE_STRPTIME) CHECK_FUNCTION_EXISTS("strtok_r" HAVE_STRTOK_R) CHECK_FUNCTION_EXISTS("strtoull" HAVE_STRTOULL) CHECK_FUNCTION_EXISTS("statvfs" HAVE_STATVFS) CHECK_FUNCTION_EXISTS("stat64" HAVE_STAT64) # 3D drivers IF(WITH_DRIVER_OPENGL) SET(NL_OPENGL_AVAILABLE 1) ENDIF(WITH_DRIVER_OPENGL) IF(WITH_DRIVER_OPENGLES) SET(NL_OPENGLES_AVAILABLE 1) ENDIF(WITH_DRIVER_OPENGLES) IF(WITH_DRIVER_DIRECT3D) SET(NL_DIRECT3D_AVAILABLE 1) ENDIF(WITH_DRIVER_DIRECT3D) # sound drivers IF(WITH_DRIVER_FMOD) SET(NL_FMOD_AVAILABLE 1) ENDIF(WITH_DRIVER_FMOD) IF(WITH_DRIVER_OPENAL) SET(NL_OPENAL_AVAILABLE 1) ENDIF(WITH_DRIVER_OPENAL) IF(WITH_DRIVER_DSOUND) SET(NL_DSOUND_AVAILABLE 1) ENDIF(WITH_DRIVER_DSOUND) IF(WITH_DRIVER_XAUDIO2) SET(NL_XAUDIO2_AVAILABLE 1) ENDIF(WITH_DRIVER_XAUDIO2) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) ADD_DEFINITIONS(-DHAVE_CONFIG_H) ENDMACRO(NL_CONFIGURE_CHECKS) ================================================ FILE: code/CMakeModules/Find3dsMaxSDK.cmake ================================================ # - Find DirectInput # Find the DirectSound includes and libraries # # MAXSDK_DIR - 3DSMAX SDK root directory # MAXSDK_INCLUDE_DIR - where to find baseinterface.h # MAXSDK_LIBRARIES - List of libraries when using 3DSMAX. # MAXSDK_FOUND - True if MAX SDK found. if(MAXSDK_INCLUDE_DIR) # Already in cache, be silent SET(MAXSDK_FIND_QUIETLY TRUE) endif(MAXSDK_INCLUDE_DIR) FIND_PATH(MAXSDK_DIR "include/maxversion.h" HINTS "$ENV{MAXSDK_DIR}" PATHS "$ENV{ADSK_3DSMAX_SDK_2012}/maxsdk" "$ENV{3DSMAX_2011_SDK_PATH}/maxsdk" "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2010 SDK/maxsdk" "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2009 SDK/maxsdk" "$ENV{PROGRAMFILES}/Autodesk/3ds Max 2008 SDK/maxsdk" "$ENV{PROGRAMFILES}/Autodesk/3ds Max 9 SDK/maxsdk" ) FIND_PATH(MAXSDK_INCLUDE_DIR max.h HINTS ${MAXSDK_DIR}/include ) FIND_PATH(MAXSDK_CS_INCLUDE_DIR bipexp.h HINTS ${MAXSDK_DIR}/include/CS ) IF(TARGET_X64) SET(MAXSDK_LIBRARY_DIRS ${MAXSDK_DIR}/x64/lib) ELSE(TARGET_X64) SET(MAXSDK_LIBRARY_DIRS ${MAXSDK_DIR}/lib) ENDIF(TARGET_X64) MACRO(FIND_3DS_LIBRARY MYLIBRARY MYLIBRARYNAME) FIND_LIBRARY(${MYLIBRARY} NAMES ${MYLIBRARYNAME} HINTS ${MAXSDK_LIBRARY_DIRS} ) ENDMACRO(FIND_3DS_LIBRARY MYLIBRARY MYLIBRARYNAME) FIND_3DS_LIBRARY(MAXSDK_CORE_LIBRARY core) FIND_3DS_LIBRARY(MAXSDK_GEOM_LIBRARY geom) FIND_3DS_LIBRARY(MAXSDK_GFX_LIBRARY gfx) FIND_3DS_LIBRARY(MAXSDK_MESH_LIBRARY mesh) FIND_3DS_LIBRARY(MAXSDK_MAXUTIL_LIBRARY maxutil) FIND_3DS_LIBRARY(MAXSDK_MAXSCRIPT_LIBRARY maxscrpt) FIND_3DS_LIBRARY(MAXSDK_PARAMBLK2_LIBRARY paramblk2) FIND_3DS_LIBRARY(MAXSDK_BMM_LIBRARY bmm) # Handle the QUIETLY and REQUIRED arguments and set MAXSDK_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) find_package_handle_standard_args(MAXSDK DEFAULT_MSG MAXSDK_INCLUDE_DIR MAXSDK_CORE_LIBRARY) if(MAXSDK_FOUND) SET(MAXSDK_LIBRARIES ${MAXSDK_CORE_LIBRARY} ${MAXSDK_GEOM_LIBRARY} ${MAXSDK_GFX_LIBRARY} ${MAXSDK_MESH_LIBRARY} ${MAXSDK_MAXUTIL_LIBRARY} ${MAXSDK_MAXSCRIPT_LIBRARY} ${MAXSDK_PARAMBLK2_LIBRARY} ${MAXSDK_BMM_LIBRARY} ) else(MAXSDK_FOUND) set(MAXSDK_LIBRARIES) endif(MAXSDK_FOUND) mark_as_advanced(MAXSDK_INCLUDE_DIR MAXSDK_LIBRARY) ================================================ FILE: code/CMakeModules/FindCEGUI.cmake ================================================ # - Locate CEGUI library # This module defines # CEGUI_LIBRARY, the library to link against # CEGUI_FOUND, if false, do not try to link to CEGUI # CEGUI_INCLUDE_DIRS, where to find headers. IF(CEGUI_LIBRARY AND CEGUI_INCLUDE_DIRS) # in cache already SET(CEGUI_FIND_QUIETLY TRUE) ENDIF(CEGUI_LIBRARY AND CEGUI_INCLUDE_DIRS) FIND_PATH(CEGUI_INCLUDE_DIRS CEGUI PATHS $ENV{CEGUI_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include PATH_SUFFIXES cegui CEGUI ) FIND_LIBRARY(CEGUI_LIBRARY NAMES CEGUIBase PATHS $ENV{CEGUI_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) GET_FILENAME_COMPONENT(CEGUI_LIB_DIR ${CEGUI_LIBRARY} PATH CACHE) IF(CEGUI_LIBRARY AND CEGUI_INCLUDE_DIRS) SET(CEGUI_FOUND "YES") SET(CEGUI_INCLUDE_DIRS "${CEGUI_INCLUDE_DIRS}/CEGUI") IF(NOT CEGUI_FIND_QUIETLY) MESSAGE(STATUS "Found CEGUI: ${CEGUI_LIBRARY}") ENDIF(NOT CEGUI_FIND_QUIETLY) ELSE(CEGUI_LIBRARY AND CEGUI_INCLUDE_DIRS) IF(NOT CEGUI_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find CEGUI!") ENDIF(NOT CEGUI_FIND_QUIETLY) ENDIF(CEGUI_LIBRARY AND CEGUI_INCLUDE_DIRS) ================================================ FILE: code/CMakeModules/FindCppTest.cmake ================================================ # # Find the CppTest includes and library # # This module defines # CPPTEST_INCLUDE_DIR, where to find tiff.h, etc. # CPPTEST_LIBRARIES, where to find the CppTest libraries. # CPPTEST_FOUND, If false, do not try to use CppTest. # also defined, but not for general use are IF(CPPTEST_LIBRARIES AND CPPTEST_INCLUDE_DIR) # in cache already SET(CPPTEST_FIND_QUIETLY TRUE) ENDIF(CPPTEST_LIBRARIES AND CPPTEST_INCLUDE_DIR) FIND_PATH(CPPTEST_INCLUDE_DIR cpptest.h PATHS /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include PATH_SUFFIXES cppunit cpptest ) SET(LIBRARY_NAME_RELEASE cpptest) SET(LIBRARY_NAME_DEBUG cpptestd) IF(WITH_STLPORT) SET(LIBRARY_NAME_RELEASE cpptest_stlport ${LIBRARY_NAME_RELEASE}) SET(LIBRARY_NAME_DEBUG cpptest_stlportd ${LIBRARY_NAME_DEBUG}) ENDIF(WITH_STLPORT) FIND_LIBRARY(CPPTEST_LIBRARY_RELEASE ${LIBRARY_NAME_RELEASE} PATHS /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) FIND_LIBRARY(CPPTEST_LIBRARY_DEBUG ${LIBRARY_NAME_DEBUG} PATHS /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(CPPTEST_INCLUDE_DIR) IF(CPPTEST_LIBRARY_RELEASE) SET(CPPTEST_FOUND TRUE) SET(CPPTEST_LIBRARIES "optimized;${CPPTEST_LIBRARY_RELEASE}") IF(CPPTEST_LIBRARY_DEBUG) SET(CPPTEST_LIBRARIES "${CPPTEST_LIBRARIES};debug;${CPPTEST_LIBRARY_DEBUG}") ENDIF(CPPTEST_LIBRARY_DEBUG) ENDIF(CPPTEST_LIBRARY_RELEASE) ENDIF(CPPTEST_INCLUDE_DIR) IF(CPPTEST_FOUND) IF(NOT CPPTEST_FIND_QUIETLY) MESSAGE(STATUS "Found CppTest: ${CPPTEST_LIBRARIES}") ENDIF(NOT CPPTEST_FIND_QUIETLY) ELSE(CPPTEST_FOUND) IF(NOT CPPTEST_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find CppTest!") ENDIF(NOT CPPTEST_FIND_QUIETLY) ENDIF(CPPTEST_FOUND) MARK_AS_ADVANCED(CPPTEST_LIBRARY_RELEASE CPPTEST_LIBRARY_DEBUG) ================================================ FILE: code/CMakeModules/FindCrashRpt.cmake ================================================ # - Locate CrashRpt library # This module defines # CrashRpt_LIBRARIES, the libraries to link against # CrashRpt_FOUND, if false, do not try to link to CrashRpt # CrashRpt_INCLUDE_DIR, where to find headers. IF(CrashRpt_LIBRARIES AND CrashRpt_INCLUDE_DIR) # in cache already SET(CrashRpt_FIND_QUIETLY TRUE) ENDIF(CrashRpt_LIBRARIES AND CrashRpt_INCLUDE_DIR) FIND_PATH(CrashRpt_INCLUDE_DIR CrashRpt.h PATH_SUFFIXES crashrpt CrashRpt $ENV{CrashRpt_DIR}/include ) FIND_LIBRARY(CrashRpt_LIBRARIES NAMES CrashRpt1402 PATHS $ENV{CrashRpt_DIR}/lib ) IF(CrashRpt_INCLUDE_DIR) IF(CrashRpt_LIBRARIES) SET(CrashRpt_FOUND TRUE) ENDIF(CrashRpt_LIBRARIES) ENDIF(CrashRpt_INCLUDE_DIR) IF(CrashRpt_FOUND) IF(NOT CrashRpt_FIND_QUIETLY) MESSAGE(STATUS "Found CrashRpt: ${CrashRpt_INCLUDE_DIR} ${CrashRpt_LIBRARIES}") ENDIF(NOT CrashRpt_FIND_QUIETLY) ELSE(CrashRpt_FOUND) IF(NOT CrashRpt_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find CrashRpt!") ENDIF(NOT CrashRpt_FIND_QUIETLY) ENDIF(CrashRpt_FOUND) MARK_AS_ADVANCED(CrashRpt_LIBRARIES) ================================================ FILE: code/CMakeModules/FindCurl.cmake ================================================ # - Locate Curl library # This module defines # CURL_INCLUDE_DIRS - where to find curl/curl.h, etc. # CURL_LIBRARIES - List of libraries when using curl. # CURL_FOUND - True if curl found. # CURL_VERSION_STRING - the version of curl found (since CMake 2.8.8) IF(CURL_LIBRARY AND CURL_INCLUDE_DIR) # in cache already SET(CURL_FIND_QUIETLY TRUE) ENDIF(CURL_LIBRARY AND CURL_INCLUDE_DIR) FIND_PATH(CURL_INCLUDE_DIR curl.h PATH_SUFFIXES curl $ENV{CURL_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include /usr/local/include/curl /mingw/include ) SET(LIBRARY_NAME_RELEASE curl libcurl) SET(LIBRARY_NAME_DEBUG curl libcurl) FIND_LIBRARY(CURL_LIBRARY_RELEASE NAMES ${LIBRARY_NAME_RELEASE} PATHS $ENV{CURL_DIR}/lib /usr/local/lib /usr/lib /usr/lib64 /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 /usr/local/lib/curl /mingw/lib ) FIND_LIBRARY(CURL_LIBRARY_DEBUG NAMES ${LIBRARY_NAME_DEBUG} PATHS $ENV{CURL_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 /usr/local/lib/curl /mingw/lib ) IF(CURL_INCLUDE_DIR) IF(CURL_LIBRARY_RELEASE AND CURL_LIBRARY_DEBUG) # Case where both Release and Debug versions are provided SET(CURL_FOUND TRUE) SET(CURL_LIBRARY optimized ${CURL_LIBRARY_RELEASE} debug ${CURL_LIBRARY_DEBUG}) ELSEIF(CURL_LIBRARY_RELEASE) # Normal case SET(CURL_FOUND TRUE) SET(CURL_LIBRARY ${CURL_LIBRARY_RELEASE}) ELSEIF(CURL_LIBRARY_DEBUG) # Case where Curl is compiled from sources (debug version is compiled by default) SET(CURL_FOUND TRUE) SET(CURL_LIBRARY ${CURL_LIBRARY_DEBUG}) ENDIF(CURL_LIBRARY_RELEASE AND CURL_LIBRARY_DEBUG) ENDIF(CURL_INCLUDE_DIR) IF(CURL_FOUND) IF(NOT CURL_FIND_QUIETLY) MESSAGE(STATUS "Found Curl: ${CURL_INCLUDE_DIR} ${CURL_LIBRARY}") ENDIF(NOT CURL_FIND_QUIETLY) ELSE(CURL_FOUND) IF(NOT CURL_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find Curl! INCLUDE: ${CURL_INCLUDE_DIR} LIB:${CURL_LIBRARY} ") ENDIF(NOT CURL_FIND_QUIETLY) ENDIF(CURL_FOUND) MARK_AS_ADVANCED(CURL_LIBRARY_RELEASE CURL_LIBRARY_DEBUG) IF(WIN32) ADD_DEFINITIONS(-DCURL_STATICLIB) ENDIF(WIN32) ================================================ FILE: code/CMakeModules/FindCustomMFC.cmake ================================================ # - Locate MFC libraries # This module defines # MFC_FOUND, if false, do not try to link to MFC # MFC_LIBRARY_DIR, where to find libraries # MFC_INCLUDE_DIR, where to find headers IF(CustomMFC_FIND_REQUIRED) SET(MFC_FIND_REQUIRED TRUE) ENDIF(CustomMFC_FIND_REQUIRED) IF(NOT MFC_DIR) # If MFC have been found, remember their directory IF(VC_DIR) SET(MFC_STANDARD_DIR "${VC_DIR}/atlmfc") ENDIF(VC_DIR) FIND_PATH(MFC_DIR include/afxwin.h HINTS ${MFC_STANDARD_DIR} ) ENDIF(NOT MFC_DIR) # Display an error message if MFC are not found, MFC_FOUND is updated # User will be able to update MFC_DIR to the correct directory INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(MFC DEFAULT_MSG MFC_DIR) IF(MFC_FOUND) SET(MFC_INCLUDE_DIR "${MFC_DIR}/include") INCLUDE_DIRECTORIES(${MFC_INCLUDE_DIR}) # Using 32 or 64 bits libraries IF(TARGET_X64) SET(MFC_LIBRARY_DIR "${MFC_DIR}/lib/amd64") ELSE(TARGET_X64) SET(MFC_LIBRARY_DIR "${MFC_DIR}/lib") ENDIF(TARGET_X64) # Add MFC libraries directory to default library path LINK_DIRECTORIES(${MFC_LIBRARY_DIR}) # Set definitions for using MFC in DLL SET(MFC_DEFINITIONS -D_AFXDLL) # Set CMake flag to use MFC DLL SET(CMAKE_MFC_FLAG 2) ENDIF(MFC_FOUND) # TODO: create a macro which set MFC_DEFINITIONS, MFC_LIBRARY_DIR and MFC_INCLUDE_DIR for a project ================================================ FILE: code/CMakeModules/FindDInput.cmake ================================================ # - Find DirectInput # Find the DirectSound includes and libraries # # DINPUT_INCLUDE_DIR - where to find dinput.h # DINPUT_LIBRARIES - List of libraries when using DirectInput. # DINPUT_FOUND - True if DirectInput found. if(DINPUT_INCLUDE_DIR) # Already in cache, be silent set(DINPUT_FIND_QUIETLY TRUE) endif(DINPUT_INCLUDE_DIR) find_path(DINPUT_INCLUDE_DIR dinput.h "$ENV{DXSDK_DIR}" "$ENV{DXSDK_DIR}/Include" ) find_library(DINPUT_LIBRARY NAMES dinput dinput8 PATHS "$ENV{DXSDK_DIR}" "$ENV{DXSDK_DIR}/Lib" "$ENV{DXSDK_DIR}/Lib/x86" ) # Handle the QUIETLY and REQUIRED arguments and set DINPUT_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) find_package_handle_standard_args(DINPUT DEFAULT_MSG DINPUT_INCLUDE_DIR DINPUT_LIBRARY) if(DINPUT_FOUND) set(DINPUT_LIBRARIES ${DINPUT_LIBRARY}) else(DINPUT_FOUND) set(DINPUT_LIBRARIES) endif(DINPUT_FOUND) mark_as_advanced(DINPUT_INCLUDE_DIR DINPUT_LIBRARY) ================================================ FILE: code/CMakeModules/FindDSound.cmake ================================================ # - Find DirectSound # Find the DirectSound includes and libraries # # DSOUND_INCLUDE_DIR - where to find dsound.h # DSOUND_LIBRARIES - List of libraries when using dsound. # DSOUND_FOUND - True if dsound found. if(DSOUND_INCLUDE_DIR) # Already in cache, be silent set(DSOUND_FIND_QUIETLY TRUE) endif(DSOUND_INCLUDE_DIR) find_path(DSOUND_INCLUDE_DIR dsound.h "$ENV{DXSDK_DIR}" "$ENV{DXSDK_DIR}/Include" ) find_library(DSOUND_LIBRARY dsound "$ENV{DXSDK_DIR}" "$ENV{DXSDK_DIR}/Lib" "$ENV{DXSDK_DIR}/Lib/x86" ) # Handle the QUIETLY and REQUIRED arguments and set DSOUND_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) find_package_handle_standard_args(DSOUND DEFAULT_MSG DSOUND_INCLUDE_DIR DSOUND_LIBRARY) if(DSOUND_FOUND) set(DSOUND_LIBRARIES ${DSOUND_LIBRARY}) else(DSOUND_FOUND) set(DSOUND_LIBRARIES) endif(DSOUND_FOUND) mark_as_advanced(DSOUND_INCLUDE_DIR DSOUND_LIBRARY) ================================================ FILE: code/CMakeModules/FindDirectXSDK.cmake ================================================ # - Find DirectX # Find the DirectX includes and libraries # # DXSDK_INCLUDE_DIR - where to find baseinterface.h # DXSDK_LIBRARIES - List of libraries when using 3DSMAX. # DXSDK_FOUND - True if MAX SDK found. IF(DXSDK_DIR) # Already in cache, be silent SET(DXSDK_FIND_QUIETLY TRUE) ENDIF(DXSDK_DIR) FIND_PATH(DXSDK_DIR "Include/dxsdkver.h" PATHS "$ENV{DXSDK_DIR}" "C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)" "C:/Program Files/Microsoft DirectX SDK (June 2010)" "C:/Program Files (x86)/Microsoft DirectX SDK (February 2010)" "C:/Program Files/Microsoft DirectX SDK (February 2010)" "C:/Program Files (x86)/Microsoft DirectX SDK (November 2007)" "C:/Program Files/Microsoft DirectX SDK (November 2007)" "C:/Program Files (x86)/Microsoft DirectX SDK" "C:/Program Files/Microsoft DirectX SDK" ) MACRO(FIND_DXSDK_LIBRARY MYLIBRARY MYLIBRARYNAME) FIND_LIBRARY(${MYLIBRARY} NAMES ${MYLIBRARYNAME} HINTS "${DXSDK_LIBRARY_DIR}" ) ENDMACRO(FIND_DXSDK_LIBRARY MYLIBRARY MYLIBRARYNAME) IF(DXSDK_DIR) SET(DXSDK_INCLUDE_DIR "${DXSDK_DIR}/Include") IF(TARGET_X64) SET(DXSDK_LIBRARY_DIRS ${DXSDK_DIR}/Lib/x64 ${DXSDK_DIR}/lib/amd64) ELSE(TARGET_X64) SET(DXSDK_LIBRARY_DIRS ${DXSDK_DIR}/Lib/x86 ${DXSDK_DIR}/lib) ENDIF(TARGET_X64) FIND_PATH(DXSDK_LIBRARY_DIR dxguid.lib PATHS ${DXSDK_LIBRARY_DIRS}) FIND_DXSDK_LIBRARY(DXSDK_GUID_LIBRARY dxguid) FIND_DXSDK_LIBRARY(DXSDK_DINPUT_LIBRARY dinput8) FIND_DXSDK_LIBRARY(DXSDK_DSOUND_LIBRARY dsound) FIND_DXSDK_LIBRARY(DXSDK_XAUDIO_LIBRARY x3daudio) FIND_DXSDK_LIBRARY(DXSDK_D3DX9_LIBRARY d3dx9) FIND_DXSDK_LIBRARY(DXSDK_D3D9_LIBRARY d3d9) ENDIF(DXSDK_DIR) # Handle the QUIETLY and REQUIRED arguments and set DXSDK_FOUND to TRUE if # all listed variables are TRUE. INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(DirectXSDK DEFAULT_MSG DXSDK_DIR DXSDK_GUID_LIBRARY DXSDK_DINPUT_LIBRARY) MARK_AS_ADVANCED(DXSDK_INCLUDE_DIR DXSDK_GUID_LIBRARY DXSDK_DINPUT_LIBRARY DXSDK_DSOUND_LIBRARY DXSDK_XAUDIO_LIBRARY DXSDK_D3DX9_LIBRARY DXSDK_D3D9_LIBRARY) ================================================ FILE: code/CMakeModules/FindEFXUtil.cmake ================================================ # - Locate EFX-Util library # This module defines # EFXUTIL_LIBRARY, the library to link against # EFXUTIL_FOUND, if false, do not try to link to EFX-Util # EFXUTIL_INCLUDE_DIR, where to find headers. IF(EFXUTIL_LIBRARY AND EFXUTIL_INCLUDE_DIR) # in cache already SET(EFXUTIL_FIND_QUIETLY TRUE) ENDIF(EFXUTIL_LIBRARY AND EFXUTIL_INCLUDE_DIR) FIND_PATH(EFXUTIL_INCLUDE_DIR EFX-Util.h PATHS $ENV{EFXUTIL_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include PATH_SUFFIXES AL ) FIND_LIBRARY(EFXUTIL_LIBRARY NAMES EFX-Util efxutil libefxutil PATHS $ENV{EFXUTIL_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(EFXUTIL_LIBRARY AND EFXUTIL_INCLUDE_DIR) SET(EFXUTIL_FOUND "YES") IF(NOT EFXUTIL_FIND_QUIETLY) MESSAGE(STATUS "Found EFX-Util: ${EFXUTIL_LIBRARY}") ENDIF(NOT EFXUTIL_FIND_QUIETLY) ELSE(EFXUTIL_LIBRARY AND EFXUTIL_INCLUDE_DIR) IF(NOT EFXUTIL_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find EFX-Util!") ENDIF(NOT EFXUTIL_FIND_QUIETLY) ENDIF(EFXUTIL_LIBRARY AND EFXUTIL_INCLUDE_DIR) ================================================ FILE: code/CMakeModules/FindExternal.cmake ================================================ # Look for a directory containing external libraries. # # The following values are defined # EXTERNAL_PATH - where to find external # EXTERNAL_INCLUDE_PATH - where to find external includes # EXTERNAL_BINARY_PATH - where to find external binaries # EXTERNAL_LIBRARY_PATH - where to find external libraries # EXTERNAL_FOUND - True if the external libraries are available SET(EXTERNAL_TEMP_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external ${CMAKE_CURRENT_SOURCE_DIR}/../external ${CMAKE_CURRENT_SOURCE_DIR}/3rdParty ${CMAKE_CURRENT_SOURCE_DIR}/../3rdParty ${EXTERNAL_PATH}) SET(EXTERNAL_TEMP_FILE "include/libwww/wwwconf.h") SET(EXTERNAL_NAME "external") # If using STLport preprend external_stlport IF(WITH_STLPORT) SET(EXTERNAL_TEMP_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external_stlport ${CMAKE_CURRENT_SOURCE_DIR}/../external_stlport ${EXTERNAL_TEMP_PATH}) SET(EXTERNAL_TEMP_FILE "include/stlport/string") SET(EXTERNAL_NAME "external with STLport") ENDIF(WITH_STLPORT) FIND_PATH(EXTERNAL_PATH ${EXTERNAL_TEMP_FILE} PATHS $ENV{EXTERNAL_PATH} ${EXTERNAL_TEMP_PATH} /usr/local /usr /sw /opt/local /opt/csw /opt ) IF(EXTERNAL_PATH) SET(EXTERNAL_FOUND TRUE) SET(EXTERNAL_INCLUDE_PATH "${EXTERNAL_PATH}/include") # Using 32 or 64 bits binaries IF(TARGET_X64 AND WIN32) SET(EXTERNAL_BINARY_PATH "${EXTERNAL_PATH}/bin64") ELSE(TARGET_X64 AND WIN32) SET(EXTERNAL_BINARY_PATH "${EXTERNAL_PATH}/bin") ENDIF(TARGET_X64 AND WIN32) # Using 32 or 64 bits libraries IF(TARGET_X64 AND WIN32) SET(EXTERNAL_LIBRARY_PATH "${EXTERNAL_PATH}/lib64") ELSE(TARGET_X64 AND WIN32) SET(EXTERNAL_LIBRARY_PATH "${EXTERNAL_PATH}/lib") ENDIF(TARGET_X64 AND WIN32) SET(CMAKE_INCLUDE_PATH "${EXTERNAL_INCLUDE_PATH};${CMAKE_INCLUDE_PATH}") # Stupid hack for FindOpenAL.cmake SET(CMAKE_INCLUDE_PATH "${EXTERNAL_PATH};${CMAKE_INCLUDE_PATH}") SET(CMAKE_LIBRARY_PATH "${EXTERNAL_LIBRARY_PATH};${CMAKE_LIBRARY_PATH}") ENDIF(EXTERNAL_PATH) IF(EXTERNAL_FOUND) IF(NOT External_FIND_QUIETLY) MESSAGE(STATUS "Found ${EXTERNAL_NAME}: ${EXTERNAL_PATH}") ENDIF(NOT External_FIND_QUIETLY) ELSE(EXTERNAL_FOUND) IF(External_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Unable to find ${EXTERNAL_NAME}!") ELSE(External_FIND_REQUIRED) IF(NOT External_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find ${EXTERNAL_NAME}!") ENDIF(NOT External_FIND_QUIETLY) ENDIF(External_FIND_REQUIRED) ENDIF(EXTERNAL_FOUND) MARK_AS_ADVANCED(EXTERNAL_INCLUDE_PATH EXTERNAL_BINARY_PATH EXTERNAL_LIBRARY_PATH) ================================================ FILE: code/CMakeModules/FindFMOD.cmake ================================================ # - Locate FMOD library # This module defines # FMOD_LIBRARY, the library to link against # FMOD_FOUND, if false, do not try to link to FMOD # FMOD_INCLUDE_DIR, where to find headers. IF(FMOD_LIBRARY AND FMOD_INCLUDE_DIR) # in cache already SET(FMOD_FIND_QUIETLY TRUE) ENDIF(FMOD_LIBRARY AND FMOD_INCLUDE_DIR) FIND_PATH(FMOD_INCLUDE_DIR fmod.h PATHS $ENV{FMOD_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include PATH_SUFFIXES fmod fmod3 ) IF(TARGET_X64) SET(FMOD_LIBRARY_NAMES fmod64 fmod) ELSE(TARGET_X64) SET(FMOD_LIBRARY_NAMES fmodvc fmod) ENDIF(TARGET_X64) FIND_LIBRARY(FMOD_LIBRARY NAMES ${FMOD_LIBRARY_NAMES} PATHS $ENV{FMOD_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(FMOD_LIBRARY AND FMOD_INCLUDE_DIR) SET(FMOD_FOUND "YES") IF(NOT FMOD_FIND_QUIETLY) MESSAGE(STATUS "Found FMOD: ${FMOD_LIBRARY}") ENDIF(NOT FMOD_FIND_QUIETLY) ELSE(FMOD_LIBRARY AND FMOD_INCLUDE_DIR) IF(NOT FMOD_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find FMOD!") ENDIF(NOT FMOD_FIND_QUIETLY) ENDIF(FMOD_LIBRARY AND FMOD_INCLUDE_DIR) ================================================ FILE: code/CMakeModules/FindFreeType.cmake ================================================ # - Locate FreeType library # This module defines # FREETYPE_LIBRARIES, libraries to link against # FREETYPE_FOUND, if false, do not try to link to FREETYPE # FREETYPE_INCLUDE_DIRS, where to find headers. IF(FREETYPE_LIBRARIES AND FREETYPE_INCLUDE_DIRS) # in cache already SET(Freetype_FIND_QUIETLY TRUE) ENDIF(FREETYPE_LIBRARIES AND FREETYPE_INCLUDE_DIRS) FIND_PATH(FREETYPE_INCLUDE_DIRS freetype PATHS $ENV{FREETYPE_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include PATH_SUFFIXES freetype2 ) IF(NOT FREETYPE_INCLUDE_DIRS) SET(FREETYPE_INCLUDE_DIRS "") ENDIF(NOT FREETYPE_INCLUDE_DIRS) # ft2build.h does not reside in the freetype include dir FIND_PATH(FREETYPE_ADDITIONAL_INCLUDE_DIR ft2build.h PATHS /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include PATH_SUFFIXES freetype2 ) # combine both include directories into one variable IF(FREETYPE_ADDITIONAL_INCLUDE_DIR) SET(FREETYPE_INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS} ${FREETYPE_ADDITIONAL_INCLUDE_DIR}) ENDIF(FREETYPE_ADDITIONAL_INCLUDE_DIR) FIND_LIBRARY(FREETYPE_LIBRARY_RELEASE NAMES freetype libfreetype freetype219 freetype246 PATHS $ENV{FREETYPE_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 /usr/lib/x86_64-linux-gnu ) FIND_LIBRARY(FREETYPE_LIBRARY_DEBUG NAMES freetyped libfreetyped freetype219d freetype246d PATHS $ENV{FREETYPE_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 /usr/lib/x86_64-linux-gnu ) IF(FREETYPE_INCLUDE_DIRS) IF(FREETYPE_LIBRARY_RELEASE AND FREETYPE_LIBRARY_DEBUG) # Case where both Release and Debug versions are provided SET(FREETYPE_FOUND ON) SET(FREETYPE_LIBRARIES optimized ${FREETYPE_LIBRARY_RELEASE} debug ${FREETYPE_LIBRARY_DEBUG}) ELSEIF(FREETYPE_LIBRARY_RELEASE) # Normal case SET(FREETYPE_FOUND ON) SET(FREETYPE_LIBRARIES ${FREETYPE_LIBRARY_RELEASE}) ELSEIF(FREETYPE_LIBRARY_DEBUG) # Case where Freetype is compiled from sources (debug version is compiled by default) SET(FREETYPE_FOUND ON) SET(FREETYPE_LIBRARIES ${FREETYPE_LIBRARY_DEBUG}) ENDIF(FREETYPE_LIBRARY_RELEASE AND FREETYPE_LIBRARY_DEBUG) ENDIF(FREETYPE_INCLUDE_DIRS) IF(FREETYPE_FOUND) IF(WITH_STATIC_EXTERNAL AND APPLE) FIND_PACKAGE(BZip2) IF(BZIP2_FOUND) SET(FREETYPE_INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS} ${BZIP2_INCLUDE_DIR}) SET(FREETYPE_LIBRARIES ${FREETYPE_LIBRARIES} ${BZIP2_LIBRARIES}) ENDIF(BZIP2_FOUND) ENDIF(WITH_STATIC_EXTERNAL AND APPLE) IF(NOT Freetype_FIND_QUIETLY) MESSAGE(STATUS "Found FreeType: ${FREETYPE_LIBRARIES}") ENDIF(NOT Freetype_FIND_QUIETLY) ELSE(FREETYPE_LIBRARY AND FREETYPE_INCLUDE_DIRS) IF(NOT Freetype_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find FreeType!") ENDIF(NOT Freetype_FIND_QUIETLY) ENDIF(FREETYPE_FOUND) ================================================ FILE: code/CMakeModules/FindGTK2.cmake ================================================ # - Try to find GTK2 # Once done this will define # # GTK2_FOUND - System has GTK2 # GTK2_INCLUDE_DIRS - GTK2 include directory # GTK2_LIBRARIES - Link these to use GTK2 # GTK2_LIBRARY_DIRS - The path to where the GTK2 library files are. # GTK2_DEFINITIONS - Compiler switches required for using GTK2 # # Copyright (c) 2007 Andreas Schneider # # Redistribution and use is allowed according to the terms of the New # BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # set(GTK2_DEBUG ON) macro(GTK2_DEBUG_MESSAGE _message) if (GTK2_DEBUG) message(STATUS "(DEBUG) ${_message}") endif (GTK2_DEBUG) endmacro(GTK2_DEBUG_MESSAGE _message) if (GTK2_LIBRARIES AND GTK2_INCLUDE_DIRS) # in cache already set(GTK2_FOUND TRUE) else (GTK2_LIBRARIES AND GTK2_INCLUDE_DIRS) if (UNIX) # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls include(UsePkgConfig) pkgconfig(gtk+-2.0 _GTK2IncDir _GTK2LinkDir _GTK2LinkFlags _GTK2Cflags) find_path(GTK2_GTK_INCLUDE_DIR NAMES gtk/gtk.h PATHS $ENV{GTK2_HOME} ${_GTK2IncDir} /usr/include/gtk-2.0 /usr/local/include/gtk-2.0 /opt/include/gtk-2.0 /opt/gnome/include/gtk-2.0 /sw/include/gtk-2.0 ) gtk2_debug_message("GTK2_GTK_INCLUDE_DIR is ${GTK2_GTK_INCLUDE_DIR}") # Some Linux distributions (e.g. Red Hat) have glibconfig.h # and glib.h in different directories, so we need to look # for both. # - Atanas Georgiev pkgconfig(glib-2.0 _GLIB2IncDir _GLIB2LinkDir _GLIB2LinkFlags _GLIB2Cflags) pkgconfig(gmodule-2.0 _GMODULE2IncDir _GMODULE2LinkDir _GMODULE2LinkFlags _GMODULE2Cflags) find_path(GTK2_GLIBCONFIG_INCLUDE_DIR NAMES glibconfig.h PATHS ${_GLIB2IncDir} ${_GMODULE2IncDir} /opt/gnome/lib64/glib-2.0/include /opt/gnome/lib/glib-2.0/include /opt/lib/glib-2.0/include /usr/lib64/glib-2.0/include /usr/lib/glib-2.0/include /sw/lib/glib-2.0/include /usr/lib/x86_64-linux-gnu/glib-2.0/include /usr/lib/arm-linux-gnueabihf/glib-2.0/include ) gtk2_debug_message("GTK2_GLIBCONFIG_INCLUDE_DIR is ${GTK2_GLIBCONFIG_INCLUDE_DIR}") find_path(GTK2_GLIB_INCLUDE_DIR NAMES glib.h PATHS ${_GLIB2IncDir} ${_GMODULE2IncDir} /opt/include/glib-2.0 /opt/gnome/include/glib-2.0 /usr/include/glib-2.0 /sw/include/glib-2.0 ) gtk2_debug_message("GTK2_GLIB_INCLUDE_DIR is ${GTK2_GLIB_INCLUDE_DIR}") pkgconfig(gdk-2.0 _GDK2IncDir _GDK2LinkDir _GDK2LinkFlags _GDK2Cflags) find_path(GTK2_GDK_INCLUDE_DIR NAMES gdkconfig.h PATHS ${_GDK2IncDir} /opt/gnome/lib/gtk-2.0/include /opt/gnome/lib64/gtk-2.0/include /opt/lib/gtk-2.0/include /usr/lib/gtk-2.0/include /usr/lib64/gtk-2.0/include /sw/lib/gtk-2.0/include /usr/lib/x86_64-linux-gnu/gtk-2.0/include /usr/lib/arm-linux-gnueabihf/gtk-2.0/include ) gtk2_debug_message("GTK2_GDK_INCLUDE_DIR is ${GTK2_GDK_INCLUDE_DIR}") find_path(GTK2_GDK_PIXBUF_INCLUDE_DIR NAMES gdk-pixbuf/gdk-pixbuf.h PATHS ${_GDK2IncDir} /opt/gnome/lib/gtk-2.0/include /opt/gnome/lib64/gtk-2.0/include /opt/lib/gtk-2.0/include /usr/lib/gtk-2.0/include /usr/lib64/gtk-2.0/include /sw/lib/gtk-2.0/include /usr/include/gdk-pixbuf-2.0 ) gtk2_debug_message("GTK2_GDK_PIXBUF_INCLUDE_DIR is ${GTK2_GDK_PIXBUF_INCLUDE_DIR}") find_path(GTK2_GTKGL_INCLUDE_DIR NAMES gtkgl/gtkglarea.h PATHS ${_GLIB2IncDir} /usr/include /usr/include/gtkgl-2.0 /usr/local/include /usr/openwin/share/include /opt/gnome/include /opt/include /sw/include ) gtk2_debug_message("GTK2_GTKGL_INCLUDE_DIR is ${GTK2_GTKGL_INCLUDE_DIR}") pkgconfig(libglade-2.0 _GLADEIncDir _GLADELinkDir _GLADELinkFlags _GLADECflags) find_path(GTK2_GLADE_INCLUDE_DIR NAMES glade/glade.h PATHS ${_GLADEIncDir} /opt/gnome/include/libglade-2.0 /usr/include/libglade-2.0 /opt/include/libglade-2.0 /sw/include/libglade-2.0 ) gtk2_debug_message("GTK2_GLADE_INCLUDE_DIR is ${GTK2_GLADE_INCLUDE_DIR}") pkgconfig(pango _PANGOIncDir _PANGOLinkDir _PANGOLinkFlags _PANGOCflags) find_path(GTK2_PANGO_INCLUDE_DIR NAMES pango/pango.h PATHS ${_PANGOIncDir} /usr/include/pango-1.0 /opt/gnome/include/pango-1.0 /opt/include/pango-1.0 /sw/include/pango-1.0 ) gtk2_debug_message("GTK2_PANGO_INCLUDE_DIR is ${GTK2_PANGO_INCLUDE_DIR}") pkgconfig(cairo _CAIROIncDir _CAIROLinkDir _CAIROLinkFlags _CAIROCflags) find_path(GTK2_CAIRO_INCLUDE_DIR NAMES cairo.h PATHS ${_CAIROIncDir} /opt/gnome/include/cairo /usr/include /usr/include/cairo /opt/include /opt/include/cairo /sw/include /sw/include/cairo ) gtk2_debug_message("GTK2_CAIRO_INCLUDE_DIR is ${GTK2_CAIRO_INCLUDE_DIR}") pkgconfig(atk _ATKIncDir _ATKLinkDir _ATKLinkFlags _ATKCflags) find_path(GTK2_ATK_INCLUDE_DIR NAMES atk/atk.h PATHS ${_ATKIncDir} /opt/gnome/include/atk-1.0 /usr/include/atk-1.0 /opt/include/atk-1.0 /sw/include/atk-1.0 ) gtk2_debug_message("GTK2_ATK_INCLUDE_DIR is ${GTK2_ATK_INCLUDE_DIR}") find_library(GTK2_GTK_LIBRARY NAMES gtk-x11-2.0 PATHS ${_GTK2LinkDir} /usr/lib /usr/local/lib /usr/openwin/lib /usr/X11R6/lib /opt/gnome/lib /opt/lib /sw/lib ) gtk2_debug_message("GTK2_GTK_LIBRARY is ${GTK2_GTK_LIBRARY}") find_library(GTK2_GDK_LIBRARY NAMES gdk-x11-2.0 PATHS ${_GDK2LinkDir} /usr/lib /usr/local/lib /usr/openwin/lib /usr/X11R6/lib /opt/gnome/lib /opt/lib /sw/lib ) gtk2_debug_message("GTK2_GDK_LIBRARY is ${GTK2_GDK_LIBRARY}") find_library(GTK2_GDK_PIXBUF_LIBRARY NAMES gdk_pixbuf-2.0 PATHS ${_GDK2LinkDir} /usr/lib /usr/local/lib /usr/openwin/lib /usr/X11R6/lib /opt/gnome/lib /opt/lib /sw/lib ) gtk2_debug_message("GTK2_GDK_PIXBUF_LIBRARY is ${GTK2_GDK_PIXBUF_LIBRARY}") find_library(GTK2_GMODULE_LIBRARY NAMES gmodule-2.0 PATHS ${_GMODULE2LinkDir} /usr/lib /usr/local/lib /usr/openwin/lib /usr/X11R6/lib /opt/gnome/lib /opt/lib /sw/lib ) gtk2_debug_message("GTK2_GMODULE_LIBRARY is ${GTK2_GMODULE_LIBRARY}") find_library(GTK2_GTHREAD_LIBRARY NAMES gthread-2.0 PATHS ${_GTK2LinkDir} /usr/lib /usr/local/lib /usr/openwin/lib /usr/X11R6/lib /opt/gnome/lib /opt/lib /sw/lib ) gtk2_debug_message("GTK2_GTHREAD_LIBRARY is ${GTK2_GTHREAD_LIBRARY}") find_library(GTK2_GOBJECT_LIBRARY NAMES gobject-2.0 PATHS ${_GTK2LinkDir} /usr/lib /usr/local/lib /usr/openwin/lib /usr/X11R6/lib /opt/gnome/lib /opt/lib /sw/lib ) gtk2_debug_message("GTK2_GOBJECT_LIBRARY is ${GTK2_GOBJECT_LIBRARY}") find_library(GTK2_GLIB_LIBRARY NAMES glib-2.0 PATHS ${_GLIB2LinkDir} /usr/lib /usr/local/lib /usr/openwin/lib /usr/X11R6/lib /opt/gnome/lib /opt/lib /sw/lib ) gtk2_debug_message("GTK2_GLIB_LIBRARY is ${GTK2_GLIB_LIBRARY}") find_library(GTK2_GTKGL_LIBRARY NAMES gtkgl-2.0 PATHS ${_GTK2LinkDir} /usr/lib /usr/local/lib /usr/openwin/lib /usr/X11R6/lib /opt/gnome/lib /opt/lib /sw/lib ) gtk2_debug_message("GTK2_GTKGL_LIBRARY is ${GTK2_GTKGL_LIBRARY}") find_library(GTK2_GLADE_LIBRARY NAMES glade-2.0 PATHS ${_GLADELinkDir} /usr/lib /usr/local/lib /usr/openwin/lib /usr/X11R6/lib /opt/gnome/lib /opt/lib /sw/lib ) gtk2_debug_message("GTK2_GLADE_LIBRARY is ${GTK2_GLADE_LIBRARY}") find_library(GTK2_PANGO_LIBRARY NAMES pango-1.0 PATHS ${_PANGOLinkDir} /usr/lib /usr/local/lib /usr/openwin/lib /usr/X11R6/lib /opt/gnome/lib /opt/lib /sw/lib ) gtk2_debug_message("GTK2_PANGO_LIBRARY is ${GTK2_PANGO_LIBRARY}") find_library(GTK2_CAIRO_LIBRARY NAMES pangocairo-1.0 PATHS ${_CAIROLinkDir} /usr/lib /usr/local/lib /usr/openwin/lib /usr/X11R6/lib /opt/gnome/lib /opt/lib /sw/lib ) gtk2_debug_message("GTK2_PANGO_LIBRARY is ${GTK2_CAIRO_LIBRARY}") find_library(GTK2_ATK_LIBRARY NAMES atk-1.0 PATHS ${_ATKinkDir} /usr/lib /usr/local/lib /usr/openwin/lib /usr/X11R6/lib /opt/gnome/lib /opt/lib /sw/lib ) gtk2_debug_message("GTK2_ATK_LIBRARY is ${GTK2_ATK_LIBRARY}") set(GTK2_INCLUDE_DIRS ${GTK2_GTK_INCLUDE_DIR} ${GTK2_GLIBCONFIG_INCLUDE_DIR} ${GTK2_GLIB_INCLUDE_DIR} ${GTK2_GDK_INCLUDE_DIR} ${GTK2_GDK_PIXBUF_INCLUDE_DIR} ${GTK2_GLADE_INCLUDE_DIR} ${GTK2_PANGO_INCLUDE_DIR} ${GTK2_CAIRO_INCLUDE_DIR} ${GTK2_ATK_INCLUDE_DIR} ) if (GTK2_GTK_LIBRARY AND GTK2_GTK_INCLUDE_DIR) if (GTK2_GDK_LIBRARY AND GTK2_GDK_PIXBUF_LIBRARY AND GTK2_GDK_INCLUDE_DIR AND GTK2_GDK_PIXBUF_INCLUDE_DIR) if (GTK2_GMODULE_LIBRARY) if (GTK2_GTHREAD_LIBRARY) if (GTK2_GOBJECT_LIBRARY) if (GTK2_GLADE_LIBRARY AND GTK2_GLADE_INCLUDE_DIR) if (GTK2_PANGO_LIBRARY AND GTK2_PANGO_INCLUDE_DIR) if (GTK2_CAIRO_LIBRARY AND GTK2_CAIRO_INCLUDE_DIR) if (GTK2_ATK_LIBRARY AND GTK2_ATK_INCLUDE_DIR) # set GTK2 libraries set (GTK2_LIBRARIES ${GTK2_GTK_LIBRARY} ${GTK2_GDK_LIBRARY} ${GTK2_GDK_PIXBUF_LIBRARY} ${GTK2_GMODULE_LIBRARY} ${GTK2_GTHREAD_LIBRARY} ${GTK2_GOBJECT_LIBRARY} ${GTK2_GLADE_LIBRARY} ${GTK2_PANGO_LIBRARY} ${GTK2_CAIRO_LIBRARY} ${GTK2_ATK_LIBRARY} ) # check for gtkgl support if (GTK2_GTKGL_LIBRARY AND GTK2_GTKGL_INCLUDE_DIR) set(GTK2_GTKGL_FOUND TRUE) set(GTK2_INCLUDE_DIRS ${GTK2_INCLUDE_DIRS} ${GTK2_GTKGL_INCLUDE_DIR} ) set(GTK2_LIBRARIES ${GTK2_LIBRARIES} ${GTK2_GTKGL_LIBRARY} ) endif (GTK2_GTKGL_LIBRARY AND GTK2_GTKGL_INCLUDE_DIR) else (GTK2_ATK_LIBRARY AND GTK2_ATK_INCLUDE_DIR) message(SEND_ERROR "Could not find ATK") endif (GTK2_ATK_LIBRARY AND GTK2_ATK_INCLUDE_DIR) else (GTK2_CAIRO_LIBRARY AND GTK2_CAIRO_INCLUDE_DIR) message(SEND_ERROR "Could not find CAIRO") endif (GTK2_CAIRO_LIBRARY AND GTK2_CAIRO_INCLUDE_DIR) else (GTK2_PANGO_LIBRARY AND GTK2_PANGO_INCLUDE_DIR) message(SEND_ERROR "Could not find PANGO") endif (GTK2_PANGO_LIBRARY AND GTK2_PANGO_INCLUDE_DIR) else (GTK2_GLADE_LIBRARY AND GTK2_GLADE_INCLUDE_DIR) message(SEND_ERROR "Could not find GLADE") endif (GTK2_GLADE_LIBRARY AND GTK2_GLADE_INCLUDE_DIR) else (GTK2_GOBJECT_LIBRARY) message(SEND_ERROR "Could not find GOBJECT") endif (GTK2_GOBJECT_LIBRARY) else (GTK2_GTHREAD_LIBRARY) message(SEND_ERROR "Could not find GTHREAD") endif (GTK2_GTHREAD_LIBRARY) else (GTK2_GMODULE_LIBRARY) message(SEND_ERROR "Could not find GMODULE") endif (GTK2_GMODULE_LIBRARY) else (GTK2_GDK_LIBRARY AND GTK2_GDK_PIXBUF_LIBRARY AND GTK2_GDK_INCLUDE_DIR AND GTK2_GDK_PIXBUF_INCLUDE_DIR) message(SEND_ERROR "Could not find GDK (GDK_PIXBUF)") endif (GTK2_GDK_LIBRARY AND GTK2_GDK_PIXBUF_LIBRARY AND GTK2_GDK_INCLUDE_DIR AND GTK2_GDK_PIXBUF_INCLUDE_DIR) else (GTK2_GTK_LIBRARY AND GTK2_GTK_INCLUDE_DIR) message(SEND_ERROR "Could not find GTK2-X11") endif (GTK2_GTK_LIBRARY AND GTK2_GTK_INCLUDE_DIR) if (GTK2_INCLUDE_DIRS AND GTK2_LIBRARIES) set(GTK2_FOUND TRUE) endif (GTK2_INCLUDE_DIRS AND GTK2_LIBRARIES) if (GTK2_FOUND) if (NOT GTK2_FIND_QUIETLY) message(STATUS "Found GTK2: ${GTK2_LIBRARIES}") endif (NOT GTK2_FIND_QUIETLY) else (GTK2_FOUND) if (GTK2_FIND_REQUIRED) message(FATAL_ERROR "Could not find GTK2") endif (GTK2_FIND_REQUIRED) endif (GTK2_FOUND) # show the GTK2_INCLUDE_DIRS and GTK2_LIBRARIES variables only in the advanced view mark_as_advanced(GTK2_INCLUDE_DIRS GTK2_LIBRARIES) endif (UNIX) endif (GTK2_LIBRARIES AND GTK2_INCLUDE_DIRS) ================================================ FILE: code/CMakeModules/FindIconv.cmake ================================================ # - Try to find Iconv # Once done this will define # # ICONV_FOUND - system has Iconv # ICONV_INCLUDE_DIR - the Iconv include directory # ICONV_LIBRARIES - Link these to use Iconv # ICONV_SECOND_ARGUMENT_IS_CONST - the second argument for iconv() is const # include(CheckCCompilerFlag) include(CheckCSourceCompiles) IF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) # Already in cache, be silent SET(ICONV_FIND_QUIETLY TRUE) ENDIF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) FIND_PATH(ICONV_INCLUDE_DIR iconv.h HINTS /sw/include/ PATHS /opt/local) FIND_LIBRARY(ICONV_LIBRARIES NAMES iconv libiconv c PATHS /opt/local) IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) SET(ICONV_FOUND TRUE) ENDIF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES}) IF(ICONV_FOUND) check_c_compiler_flag("-Werror" ICONV_HAVE_WERROR) set (CMAKE_C_FLAGS_BACKUP "${CMAKE_C_FLAGS}") if(ICONV_HAVE_WERROR) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") endif(ICONV_HAVE_WERROR) check_c_source_compiles(" #include int main(){ iconv_t conv = 0; const char* in = 0; size_t ilen = 0; char* out = 0; size_t olen = 0; iconv(conv, &in, &ilen, &out, &olen); return 0; } " ICONV_SECOND_ARGUMENT_IS_CONST ) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS_BACKUP}") ENDIF(ICONV_FOUND) set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) IF(ICONV_FOUND) IF(NOT ICONV_FIND_QUIETLY) MESSAGE(STATUS "Found Iconv: ${ICONV_LIBRARIES}") ENDIF(NOT ICONV_FIND_QUIETLY) ELSE(ICONV_FOUND) IF(Iconv_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find Iconv") ENDIF(Iconv_FIND_REQUIRED) ENDIF(ICONV_FOUND) MARK_AS_ADVANCED( ICONV_INCLUDE_DIR ICONV_LIBRARIES ICONV_SECOND_ARGUMENT_IS_CONST ) ================================================ FILE: code/CMakeModules/FindJpeg.cmake ================================================ # - Locate Jpeg library # This module defines # JPEG_LIBRARY, the library to link against # JPEG_FOUND, if false, do not try to link to JPEG # JPEG_INCLUDE_DIR, where to find headers. IF(JPEG_LIBRARY AND JPEG_INCLUDE_DIR) # in cache already SET(JPEG_FIND_QUIETLY TRUE) ENDIF(JPEG_LIBRARY AND JPEG_INCLUDE_DIR) FIND_PATH(JPEG_INCLUDE_DIR jpeglib.h PATHS $ENV{JPEG_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include PATH_SUFFIXES jpeg ) FIND_LIBRARY(JPEG_LIBRARY NAMES jpeg libjpeg PATHS $ENV{JPEG_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(JPEG_LIBRARY AND JPEG_INCLUDE_DIR) SET(JPEG_FOUND "YES") IF(NOT JPEG_FIND_QUIETLY) MESSAGE(STATUS "Found Jpeg: ${JPEG_LIBRARY}") ENDIF(NOT JPEG_FIND_QUIETLY) ELSE(JPEG_LIBRARY AND JPEG_INCLUDE_DIR) IF(NOT JPEG_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find Jpeg!") ENDIF(NOT JPEG_FIND_QUIETLY) ENDIF(JPEG_LIBRARY AND JPEG_INCLUDE_DIR) ================================================ FILE: code/CMakeModules/FindLibEvent.cmake ================================================ # - Locate LibEvent library # This module defines # LIBEVENT_INCLUDE_DIRS - where to find libevent/libevent.h, etc. # LIBEVENT_LIBRARIES - List of libraries when using libevent. # LIBEVENT_FOUND - True if libevent found. # LIBEVENT_VERSION_STRING - the version of libevent found (since CMake 2.8.8) IF(LIBEVENT_LIBRARY AND LIBEVENT_INCLUDE_DIR) # in cache already SET(LIBEVENT_FIND_QUIETLY TRUE) ENDIF(LIBEVENT_LIBRARY AND LIBEVENT_INCLUDE_DIR) FIND_PATH(LIBEVENT_INCLUDE_DIR evutil.h PATH_SUFFIXES libevent $ENV{LIBEVENT_DIR}/include /usr/local/include /sw/include /opt/local/include /opt/csw/include /opt/include /usr/local/include/libevent /mingw/include ) SET(LIBRARY_NAME_RELEASE libevent libevent.a) SET(LIBRARY_NAME_DEBUG libevent libevent.a) FIND_LIBRARY(LIBEVENT_LIBRARY_RELEASE NAMES ${LIBRARY_NAME_RELEASE} PATHS $ENV{LIBEVENT_DIR}/lib /usr/local/lib /usr/lib /usr/lib64 /usr/local/X11R6/lib /usr/local/lib/libevent ) FIND_LIBRARY(LIBEVENT_LIBRARY_DEBUG NAMES ${LIBRARY_NAME_DEBUG} PATHS $ENV{LIBEVENT_DIR}/lib /usr/local/lib /usr/lib /usr/local/lib/libevent ) IF(NOT WIN32) SET(LIBRARY_NAME_PTHREADS libevent_pthreads libevent_pthreads.a) FIND_LIBRARY(PTHREADS_LIBRARIE_RELEASE NAMES ${LIBRARY_NAME_PTHREADS} PATHS $ENV{LIBEVENT_DIR}/lib /usr/local/lib ) ADD_DEFINITIONS(-DEVENT__HAVE_PTHREADS) ENDIF() IF(LIBEVENT_INCLUDE_DIR) IF(LIBEVENT_LIBRARY_RELEASE AND LIBEVENT_LIBRARY_DEBUG) # Case where both Release and Debug versions are provided SET(LIBEVENT_FOUND TRUE) IF(WIN32) SET(LIBEVENT_LIBRARY optimized ${LIBEVENT_LIBRARY_RELEASE} debug ${LIBEVENT_LIBRARY_DEBUG}) ELSE() #SET(LIBEVENT_LIBRARY "${LIBEVENT_LIBRARY_RELEASE};${PTHREADS_LIBRARIE_RELEASE}" CACHE STRING "LibEvent Libraries") SET(LIBEVENT_LIBRARY "${LIBEVENT_LIBRARY_RELEASE};${PTHREADS_LIBRARIE_RELEASE}") ENDIF() ELSEIF(LIBEVENT_LIBRARY_RELEASE) # Normal case SET(LIBEVENT_FOUND TRUE) SET(LIBEVENT_LIBRARY ${LIBEVENT_LIBRARY_RELEASE}) ELSEIF(LIBEVENT_LIBRARY_DEBUG) # Case where LibEvent is compiled from sources (debug version is compiled by default) SET(LIBEVENT_FOUND TRUE) SET(LIBEVENT_LIBRARY ${LIBEVENT_LIBRARY_DEBUG}) ENDIF(LIBEVENT_LIBRARY_RELEASE AND LIBEVENT_LIBRARY_DEBUG) ENDIF(LIBEVENT_INCLUDE_DIR) IF(LIBEVENT_FOUND) IF(NOT LIBEVENT_FIND_QUIETLY) MESSAGE(STATUS "Found LibEvent: ${LIBEVENT_INCLUDE_DIR} ${LIBEVENT_LIBRARY}") ENDIF(NOT LIBEVENT_FIND_QUIETLY) ELSE(LIBEVENT_FOUND) IF(NOT LIBEVENT_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find LibEvent! INCLUDE: ${LIBEVENT_INCLUDE_DIR} LIB:${LIBEVENT_LIBRARY} ") ENDIF(NOT LIBEVENT_FIND_QUIETLY) ENDIF(LIBEVENT_FOUND) MARK_AS_ADVANCED(LIBEVENT_LIBRARY_RELEASE LIBEVENT_LIBRARY_DEBUG) # libevent_openssl FIND_LIBRARY(LIBEVENT_OPENSSL_LIBRARY NAMES libevent_openssl libevent_openssl.a PATHS $ENV{LIBEVENT_DIR}/lib /usr/local/lib /usr/lib /usr/lib64 /usr/local/lib/libevent ) ADD_DEFINITIONS(-DEVENT__HAVE_OPENSSL) MESSAGE(STATUS "LIBEVENT_OPENSSL_LIBRARY: ${LIBEVENT_OPENSSL_LIBRARY}") ================================================ FILE: code/CMakeModules/FindLibOVR.cmake ================================================ # - Locate LibOVR library # This module defines # LIBOVR_LIBRARIES, the libraries to link against # LIBOVR_FOUND, if false, do not try to link to LIBOVR # LIBOVR_INCLUDE_DIR, where to find headers. IF(LIBOVR_LIBRARIES AND LIBOVR_INCLUDE_DIR) # in cache already SET(LIBOVR_FIND_QUIETLY TRUE) ENDIF(LIBOVR_LIBRARIES AND LIBOVR_INCLUDE_DIR) FIND_PATH(LIBOVR_INCLUDE_DIR OVR.h PATHS $ENV{LIBOVR_DIR}/Include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include ) IF(UNIX) IF(TARGET_X64) SET(LIBOVR_LIBRARY_BUILD_PATH "Lib/Linux/Release/x86_64") ELSE(TARGET_X64) SET(LIBOVR_LIBRARY_BUILD_PATH "Lib/Linux/Release/i386") ENDIF(TARGET_X64) ELSEIF(APPLE) SET(LIBOVR_LIBRARY_BUILD_PATH "Lib/MacOS/Release") ELSEIF(WIN32) IF(TARGET_X64) SET(LIBOVR_LIBRARY_BUILD_PATH "Lib/x64") ELSE(TARGET_X64) SET(LIBOVR_LIBRARY_BUILD_PATH "Lib/Win32") ENDIF(TARGET_X64) ENDIF(UNIX) FIND_LIBRARY(LIBOVR_LIBRARY NAMES ovr libovr PATHS $ENV{LIBOVR_DIR}/${LIBOVR_LIBRARY_BUILD_PATH} /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(LIBOVR_LIBRARY AND LIBOVR_INCLUDE_DIR) IF(NOT LIBOVR_FIND_QUIETLY) MESSAGE(STATUS "Found LibOVR: ${LIBOVR_LIBRARY}") ENDIF(NOT LIBOVR_FIND_QUIETLY) SET(LIBOVR_FOUND "YES") SET(LIBOVR_DEFINITIONS "-DHAVE_LIBOVR") IF(UNIX) SET(LIBOVR_LIBRARIES ${LIBOVR_LIBRARY} X11 Xinerama udev pthread) ELSE(UNIX) SET(LIBOVR_LIBRARIES ${LIBOVR_LIBRARY}) ENDIF(UNIX) ELSE(LIBOVR_LIBRARY AND LIBOVR_INCLUDE_DIR) IF(NOT LIBOVR_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find LibOVR!") ENDIF(NOT LIBOVR_FIND_QUIETLY) ENDIF(LIBOVR_LIBRARY AND LIBOVR_INCLUDE_DIR) ================================================ FILE: code/CMakeModules/FindLibVR.cmake ================================================ # - Locate LibVR library # This module defines # LIBVR_LIBRARIES, the libraries to link against # LIBVR_FOUND, if false, do not try to link to LIBVR # LIBVR_INCLUDE_DIR, where to find headers. IF(LIBVR_LIBRARIES AND LIBVR_INCLUDE_DIR) # in cache already SET(LIBVR_FIND_QUIETLY TRUE) ENDIF(LIBVR_LIBRARIES AND LIBVR_INCLUDE_DIR) FIND_PATH(LIBVR_INCLUDE_DIR hmd.h PATH_SUFFIXES include/LibVR ) FIND_LIBRARY(LIBVR_LIBRARY NAMES vr PATH_SUFFIXES lib PATHS ) IF(LIBVR_LIBRARY AND LIBVR_INCLUDE_DIR) IF(NOT LIBVR_FIND_QUIETLY) MESSAGE(STATUS "Found LibVR: ${LIBVR_LIBRARY}") ENDIF(NOT LIBVR_FIND_QUIETLY) SET(LIBVR_FOUND "YES") SET(LIBVR_DEFINITIONS "-DHAVE_LIBVR") ELSE(LIBVR_LIBRARY AND LIBVR_INCLUDE_DIR) IF(NOT LIBVR_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find LibVR!") ENDIF(NOT LIBVR_FIND_QUIETLY) ENDIF(LIBVR_LIBRARY AND LIBVR_INCLUDE_DIR) ================================================ FILE: code/CMakeModules/FindLibwww.cmake ================================================ # # Find the W3C libwww includes and library # # This module defines # LIBWWW_INCLUDE_DIR, where to find tiff.h, etc. # LIBWWW_LIBRARY, where to find the Libwww library. # LIBWWW_FOUND, If false, do not try to use Libwww. OPTION(WITH_LIBWWW_STATIC "Use only static libraries for libwww" OFF) # also defined, but not for general use are IF(LIBWWW_LIBRARIES AND LIBWWW_INCLUDE_DIR) # in cache already SET(Libwww_FIND_QUIETLY TRUE) ENDIF(LIBWWW_LIBRARIES AND LIBWWW_INCLUDE_DIR) FIND_PATH(LIBWWW_INCLUDE_DIR WWWInit.h PATHS /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include PATH_SUFFIXES libwww w3c-libwww ) # when installing libwww on mac os x using macports the file wwwconf.h resides # in /opt/local/include and not in the real libwww include dir :/ FIND_PATH(LIBWWW_ADDITIONAL_INCLUDE_DIR wwwconf.h PATHS /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include ) # combine both include directories into one variable IF(LIBWWW_ADDITIONAL_INCLUDE_DIR) SET(LIBWWW_INCLUDE_DIR ${LIBWWW_INCLUDE_DIR} ${LIBWWW_ADDITIONAL_INCLUDE_DIR}) ENDIF(LIBWWW_ADDITIONAL_INCLUDE_DIR) # helper to find all the libwww sub libraries MACRO(FIND_WWW_LIBRARY MYLIBRARY OPTION FILE) IF(WITH_LIBWWW_STATIC AND UNIX AND NOT APPLE AND NOT WITH_STATIC_EXTERNAL) SET(CMAKE_FIND_LIBRARY_SUFFIXES_OLD ${CMAKE_FIND_LIBRARY_SUFFIXES}) SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") ENDIF(WITH_LIBWWW_STATIC AND UNIX AND NOT APPLE AND NOT WITH_STATIC_EXTERNAL) FIND_LIBRARY(${MYLIBRARY}_RELEASE NAMES ${FILE} PATHS /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) FIND_LIBRARY(${MYLIBRARY}_DEBUG NAMES ${FILE}d PATHS /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(CMAKE_FIND_LIBRARY_SUFFIXES_OLD) SET(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_OLD}) ENDIF(CMAKE_FIND_LIBRARY_SUFFIXES_OLD) IF(${MYLIBRARY}_RELEASE AND ${MYLIBRARY}_DEBUG) IF(${OPTION} STREQUAL REQUIRED OR WITH_STATIC OR WITH_LIBWWW_STATIC) SET(LIBWWW_LIBRARIES ${LIBWWW_LIBRARIES} optimized ${${MYLIBRARY}_RELEASE} debug ${${MYLIBRARY}_DEBUG}) ENDIF(${OPTION} STREQUAL REQUIRED OR WITH_STATIC OR WITH_LIBWWW_STATIC) ELSEIF(${MYLIBRARY}_RELEASE) IF(${OPTION} STREQUAL REQUIRED OR WITH_STATIC OR WITH_LIBWWW_STATIC) SET(LIBWWW_LIBRARIES ${LIBWWW_LIBRARIES} ${${MYLIBRARY}_RELEASE}) ENDIF(${OPTION} STREQUAL REQUIRED OR WITH_STATIC OR WITH_LIBWWW_STATIC) ELSEIF(${MYLIBRARY}_DEBUG) IF(${OPTION} STREQUAL REQUIRED OR WITH_STATIC OR WITH_LIBWWW_STATIC) SET(LIBWWW_LIBRARIES ${LIBWWW_LIBRARIES} ${${MYLIBRARY}_DEBUG}) ENDIF(${OPTION} STREQUAL REQUIRED OR WITH_STATIC OR WITH_LIBWWW_STATIC) ELSE(${MYLIBRARY}_RELEASE AND ${MYLIBRARY}_DEBUG) IF(NOT Libwww_FIND_QUIETLY AND NOT WIN32) MESSAGE(STATUS "Warning: Libwww: Library not found: ${MYLIBRARY}") ENDIF(NOT Libwww_FIND_QUIETLY AND NOT WIN32) ENDIF(${MYLIBRARY}_RELEASE AND ${MYLIBRARY}_DEBUG) MARK_AS_ADVANCED(${MYLIBRARY}_RELEASE ${MYLIBRARY}_DEBUG) ENDMACRO(FIND_WWW_LIBRARY) MACRO(LINK_WWW_LIBRARY MYLIBRARY OTHERLIBRARY SYMBOL) IF(NOT WITH_LIBWWW_STATIC AND NOT WITH_STATIC_EXTERNAL) LINK_DEPENDS(LIBWWW_LIBRARIES ${MYLIBRARY} ${OTHERLIBRARY} ${SYMBOL}) ENDIF(NOT WITH_LIBWWW_STATIC AND NOT WITH_STATIC_EXTERNAL) ENDMACRO(LINK_WWW_LIBRARY) # Find and link required libs for static or dynamic FIND_WWW_LIBRARY(LIBWWWAPP_LIBRARY REQUIRED wwwapp) # cache core file ftp gopher html http mime news stream telnet trans utils zip xml xmlparse FIND_WWW_LIBRARY(LIBWWWCORE_LIBRARY REQUIRED wwwcore) # utils FIND_WWW_LIBRARY(LIBWWWFILE_LIBRARY REQUIRED wwwfile) # core trans utils html FIND_WWW_LIBRARY(LIBWWWHTML_LIBRARY REQUIRED wwwhtml) # core utils FIND_WWW_LIBRARY(LIBWWWHTTP_LIBRARY REQUIRED wwwhttp) # md5 core mime stream utils FIND_WWW_LIBRARY(LIBWWWMIME_LIBRARY REQUIRED wwwmime) # core cache stream utils # Required for static or if underlinking FIND_WWW_LIBRARY(LIBWWWCACHE_LIBRARY OPTIONAL wwwcache) # core trans utils FIND_WWW_LIBRARY(LIBWWWSTREAM_LIBRARY OPTIONAL wwwstream) # core file utils FIND_WWW_LIBRARY(LIBWWWTRANS_LIBRARY REQUIRED wwwtrans) # core utils FIND_WWW_LIBRARY(LIBWWWUTILS_LIBRARY REQUIRED wwwutils) # Required only if underlinking # Unused protocols FIND_WWW_LIBRARY(LIBWWWFTP_LIBRARY OPTIONAL wwwftp) # core file utils FIND_WWW_LIBRARY(LIBWWWGOPHER_LIBRARY OPTIONAL wwwgopher) # core html utils file FIND_WWW_LIBRARY(LIBWWWNEWS_LIBRARY OPTIONAL wwwnews) # core html mime stream utils FIND_WWW_LIBRARY(LIBWWWTELNET_LIBRARY OPTIONAL wwwtelnet) # core utils # Other used by app FIND_WWW_LIBRARY(LIBWWWDIR_LIBRARY OPTIONAL wwwdir) # file FIND_WWW_LIBRARY(LIBWWWINIT_LIBRARY OPTIONAL wwwinit) # app cache core file html utils FIND_WWW_LIBRARY(LIBWWWMUX_LIBRARY OPTIONAL wwwmux) # core stream trans utils FIND_WWW_LIBRARY(LIBWWWXML_LIBRARY OPTIONAL wwwxml) # core utils xmlparse FIND_WWW_LIBRARY(LIBWWWZIP_LIBRARY OPTIONAL wwwzip) # core utils FIND_WWW_LIBRARY(LIBXMLPARSE_LIBRARY OPTIONAL xmlparse) # xmltok # Other used by other FIND_WWW_LIBRARY(LIBXMLTOK_LIBRARY OPTIONAL xmltok) FIND_WWW_LIBRARY(LIBWWWSSL_LIBRARY OPTIONAL wwwssl) FIND_WWW_LIBRARY(LIBMD5_LIBRARY OPTIONAL md5) FIND_WWW_LIBRARY(LIBPICS_LIBRARY OPTIONAL pics) # Other external libraries FIND_PACKAGE(EXPAT QUIET) FIND_PACKAGE(OpenSSL QUIET) FIND_WWW_LIBRARY(LIBREGEX_LIBRARY OPTIONAL gnu_regex) # Now link all libs together LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWCACHE_LIBRARY HTLoadCache) LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWCACHE_LIBRARY HTCacheAppend) LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWFTP_LIBRARY HTLoadFTP) LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWGOPHER_LIBRARY HTLoadGopher) LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWNEWS_LIBRARY HTLoadNews) LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWTELNET_LIBRARY HTLoadTelnet) LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWSTREAM_LIBRARY HTStreamToChunk) LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWSTREAM_LIBRARY HTGuess_new) LINK_WWW_LIBRARY(LIBWWWFILE_LIBRARY LIBWWWDIR_LIBRARY HTDir_new) LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWINIT_LIBRARY HTProtocolInit) LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWXML_LIBRARY HTXML_new) LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWZIP_LIBRARY HTZLib_inflate) # libwwwxml can be linked to xmlparse or expat LINK_WWW_LIBRARY(LIBWWWXML_LIBRARY LIBXMLPARSE_LIBRARY XML_ParserCreate) IF(LIBXMLPARSE_LIBRARY_LINKED) LINK_WWW_LIBRARY(LIBXMLPARSE_LIBRARY EXPAT_LIBRARY XmlInitEncoding) ELSE(LIBXMLPARSE_LIBRARY_LINKED) LINK_WWW_LIBRARY(LIBWWWXML_LIBRARY EXPAT_LIBRARY XML_ParserCreate) ENDIF(LIBXMLPARSE_LIBRARY_LINKED) LINK_WWW_LIBRARY(LIBWWWHTTP_LIBRARY LIBMD5_LIBRARY MD5Init) LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBREGEX_LIBRARY regexec) LINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY OPENSSL_LIBRARIES SSL_new) INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Libwww DEFAULT_MSG LIBWWW_LIBRARIES LIBWWW_INCLUDE_DIR ) ================================================ FILE: code/CMakeModules/FindLua51.cmake ================================================ # Locate Lua library # This module defines # LUA51_FOUND, if false, do not try to link to Lua # LUA_LIBRARIES # LUA_INCLUDE_DIR, where to find lua.h # LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8) # # Note that the expected include convention is # #include "lua.h" # and not # #include # This is because, the lua location is not standardized and may exist # in locations other than lua/ #============================================================================= # Copyright 2007-2009 Kitware, Inc. # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) find_path(LUA_INCLUDE_DIR lua.h HINTS ENV LUA_DIR PATH_SUFFIXES include/lua51 include/lua5.1 include/lua-5.1 include/lua include PATHS ~/Library/Frameworks /Library/Frameworks /sw # Fink /opt/local # DarwinPorts /opt/csw # Blastwave /opt ) find_library(LUA_LIBRARY NAMES lua51 lua5.1 lua-5.1 lua HINTS ENV LUA_DIR PATH_SUFFIXES lib PATHS ~/Library/Frameworks /Library/Frameworks /sw /opt/local /opt/csw /opt /usr/lib/x86_64-linux-gnu /usr/lib/arm-linux-gnueabihf ) if(LUA_LIBRARY) # include the math library for Unix if(UNIX AND NOT APPLE AND NOT BEOS) find_library(LUA_MATH_LIBRARY m) set( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries") # For Windows and Mac, don't need to explicitly include the math library else() set( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries") endif() endif() if(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h") file(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"") string(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}") unset(lua_version_str) endif() include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if # all listed variables are TRUE FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua51 REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR VERSION_VAR LUA_VERSION_STRING) mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY) ================================================ FILE: code/CMakeModules/FindLua52.cmake ================================================ # Locate Lua library # This module defines # LUA52_FOUND, if false, do not try to link to Lua # LUA_LIBRARIES # LUA_INCLUDE_DIR, where to find lua.h # LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8) # # Note that the expected include convention is # #include "lua.h" # and not # #include # This is because, the lua location is not standardized and may exist # in locations other than lua/ #============================================================================= # Copyright 2007-2009 Kitware, Inc. # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) find_path(LUA_INCLUDE_DIR lua.h HINTS ENV LUA_DIR PATH_SUFFIXES include/lua52 include/lua5.2 include/lua-5.2 include/lua include PATHS ~/Library/Frameworks /Library/Frameworks /sw # Fink /opt/local # DarwinPorts /opt/csw # Blastwave /opt ) find_library(LUA_LIBRARY NAMES lua52 lua5.2 lua-5.2 lua HINTS ENV LUA_DIR PATH_SUFFIXES lib PATHS ~/Library/Frameworks /Library/Frameworks /sw /opt/local /opt/csw /opt ) if(LUA_LIBRARY) # include the math library for Unix if(UNIX AND NOT APPLE AND NOT BEOS) find_library(LUA_MATH_LIBRARY m) set( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries") # For Windows and Mac, don't need to explicitly include the math library else() set( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries") endif() endif() if(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h") file(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"") string(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}") unset(lua_version_str) endif() include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if # all listed variables are TRUE FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua52 REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR VERSION_VAR LUA_VERSION_STRING) mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY) ================================================ FILE: code/CMakeModules/FindLua53.cmake ================================================ # Locate Lua library # This module defines # LUA51_FOUND, if false, do not try to link to Lua # LUA_LIBRARIES # LUA_INCLUDE_DIR, where to find lua.h # LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8) # # Note that the expected include convention is # #include "lua.h" # and not # #include # This is because, the lua location is not standardized and may exist # in locations other than lua/ #============================================================================= # Copyright 2007-2009 Kitware, Inc. # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) find_path(LUA_INCLUDE_DIR lua.h PATH_SUFFIXES lua53 PATHS /usr/local/include ~/Library/Frameworks ) find_library(LUA_LIBRARY NAMES lua53 liblua.a PATH_SUFFIXES lib PATHS /usr/local/lib ) if(LUA_LIBRARY) # include the math library for Unix if(UNIX AND NOT APPLE AND NOT BEOS) find_library(LUA_MATH_LIBRARY m) set( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries") # For Windows and Mac, don't need to explicitly include the math library else() set( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries") endif() endif() if(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h") file(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"") string(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}") unset(lua_version_str) endif() include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if # all listed variables are TRUE FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua53 REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR VERSION_VAR LUA_VERSION_STRING) mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY) ================================================ FILE: code/CMakeModules/FindLuabind.cmake ================================================ # - Locate Luabind library # This module defines # LUABIND_LIBRARIES, the libraries to link against # LUABIND_FOUND, if false, do not try to link to LUABIND # LUABIND_INCLUDE_DIR, where to find headers. MACRO(FIND_CORRECT_LUA_VERSION) # Check Lua version linked to Luabind under Linux IF(LUABIND_LIBRARY_RELEASE MATCHES "\\.so") INCLUDE(CheckDepends) SET(LUA52_LIBRARY "liblua5.2") CHECK_LINKED_LIBRARY(LUABIND_LIBRARY_RELEASE LUA52_LIBRARY LUALIB_FOUND) IF(NOT LUALIB_FOUND) # fedora (v20) SET(LUA52_LIBRARY "liblua-5.2") CHECK_LINKED_LIBRARY(LUABIND_LIBRARY_RELEASE LUA52_LIBRARY LUALIB_FOUND) ENDIF(NOT LUALIB_FOUND) IF(LUALIB_FOUND) MESSAGE(STATUS "Luabind is using Lua 5.2") FIND_PACKAGE(Lua52 REQUIRED) ELSE(LUALIB_FOUND) SET(LUA51_LIBRARY "liblua5.1") CHECK_LINKED_LIBRARY(LUABIND_LIBRARY_RELEASE LUA51_LIBRARY LUALIB_FOUND) IF(LUALIB_FOUND) MESSAGE(STATUS "Luabind is using Lua 5.1") FIND_PACKAGE(Lua51 REQUIRED) ELSE(LUALIB_FOUND) SET(LUA50_LIBRARY "liblua5.0") CHECK_LINKED_LIBRARY(LUABIND_LIBRARY_RELEASE LUA50_LIBRARY LUALIB_FOUND) IF(LUALIB_FOUND) MESSAGE(STATUS "Luabind is using Lua 5.0") FIND_PACKAGE(Lua50 REQUIRED) ELSE(LUALIB_FOUND) MESSAGE(FATAL_ERROR "Can't determine Lua version used by Luabind") ENDIF(LUALIB_FOUND) ENDIF(LUALIB_FOUND) ENDIF(LUALIB_FOUND) ELSE(LUABIND_LIBRARY_RELEASE MATCHES "\\.so") # TODO: find a way to detect Lua version IF(WITH_LUA52) FIND_PACKAGE(Lua52 REQUIRED) ELSEIF(WITH_LUA51) FIND_PACKAGE(Lua51 REQUIRED) ELSE(WITH_LUA52) FIND_PACKAGE(Lua50 REQUIRED) ENDIF(WITH_LUA52) ENDIF(LUABIND_LIBRARY_RELEASE MATCHES "\\.so") ENDMACRO(FIND_CORRECT_LUA_VERSION) IF(LUABIND_LIBRARIES AND LUABIND_INCLUDE_DIR) # in cache already SET(Luabind_FIND_QUIETLY TRUE) ENDIF(LUABIND_LIBRARIES AND LUABIND_INCLUDE_DIR) FIND_PATH(LUABIND_INCLUDE_DIR luabind/luabind.hpp PATHS $ENV{LUABIND_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include ) SET(LIBRARY_NAME_RELEASE) SET(LIBRARY_NAME_DEBUG) IF(WITH_LUA52) IF(WITH_STLPORT) LIST(APPEND LIBRARY_NAME_RELEASE luabind_stlport_lua52) LIST(APPEND LIBRARY_NAME_DEBUG luabind_stlport_lua52d) ENDIF(WITH_STLPORT) LIST(APPEND LIBRARY_NAME_RELEASE luabind_lua52) LIST(APPEND LIBRARY_NAME_DEBUG luabind_lua52d) ENDIF() IF(WITH_LUA51) IF(WITH_STLPORT) LIST(APPEND LIBRARY_NAME_RELEASE luabind_stlport_lua51) LIST(APPEND LIBRARY_NAME_DEBUG luabind_stlport_lua51d) ENDIF(WITH_STLPORT) LIST(APPEND LIBRARY_NAME_RELEASE luabind_lua51) LIST(APPEND LIBRARY_NAME_DEBUG luabind_lua51d) ENDIF() IF(WITH_LUA50) IF(WITH_STLPORT) LIST(APPEND LIBRARY_NAME_RELEASE luabind_stlport_lua50) LIST(APPEND LIBRARY_NAME_DEBUG luabind_stlport_lua50d) ENDIF(WITH_STLPORT) LIST(APPEND LIBRARY_NAME_RELEASE luabind_lua50) LIST(APPEND LIBRARY_NAME_DEBUG luabind_lua50d) ENDIF() IF(WITH_STLPORT) LIST(APPEND LIBRARY_NAME_RELEASE luabind_stlport) LIST(APPEND LIBRARY_NAME_DEBUG luabind_stlportd) ENDIF(WITH_STLPORT) # generic libraries names LIST(APPEND LIBRARY_NAME_RELEASE luabind libluabind) LIST(APPEND LIBRARY_NAME_DEBUG luabind_d luabindd libluabind_d libluabindd) FIND_LIBRARY(LUABIND_LIBRARY_RELEASE NAMES ${LIBRARY_NAME_RELEASE} PATHS $ENV{LUABIND_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) FIND_LIBRARY(LUABIND_LIBRARY_DEBUG NAMES ${LIBRARY_NAME_DEBUG} PATHS $ENV{LUABIND_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) FIND_PACKAGE(Boost REQUIRED) IF(LUABIND_INCLUDE_DIR AND Boost_INCLUDE_DIR) IF(LUABIND_LIBRARY_RELEASE AND LUABIND_LIBRARY_DEBUG) # Case where both Release and Debug versions are provided SET(LUABIND_FOUND TRUE) SET(LUABIND_LIBRARIES optimized ${LUABIND_LIBRARY_RELEASE} debug ${LUABIND_LIBRARY_DEBUG}) ELSEIF(LUABIND_LIBRARY_RELEASE) # Normal case SET(LUABIND_FOUND TRUE) SET(LUABIND_LIBRARIES ${LUABIND_LIBRARY_RELEASE}) ELSEIF(LUABIND_LIBRARY_DEBUG) # Case where Luabind is compiled from sources (debug version is compiled by default) SET(LUABIND_FOUND TRUE) SET(LUABIND_LIBRARIES ${LUABIND_LIBRARY_DEBUG}) ENDIF(LUABIND_LIBRARY_RELEASE AND LUABIND_LIBRARY_DEBUG) ENDIF(LUABIND_INCLUDE_DIR AND Boost_INCLUDE_DIR) IF(LUABIND_FOUND) SET(LUABIND_INCLUDE_DIR ${LUABIND_INCLUDE_DIR} ${Boost_INCLUDE_DIR}) # Check if luabind/version.hpp exists FIND_FILE(LUABIND_VERSION_FILE luabind/version.hpp PATHS ${LUABIND_INCLUDE_DIR}) IF(LUABIND_VERSION_FILE) SET(LUABIND_DEFINITIONS "-DHAVE_LUABIND_VERSION") ENDIF(LUABIND_VERSION_FILE) FIND_CORRECT_LUA_VERSION() IF(NOT Luabind_FIND_QUIETLY) MESSAGE(STATUS "Found Luabind: ${LUABIND_LIBRARIES}") ENDIF(NOT Luabind_FIND_QUIETLY) ELSE(LUABIND_FOUND) IF(NOT Luabind_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find Luabind!") ENDIF(NOT Luabind_FIND_QUIETLY) ENDIF(LUABIND_FOUND) MARK_AS_ADVANCED(LUABIND_LIBRARY_RELEASE LUABIND_LIBRARY_DEBUG Boost_LIB_DIAGNOSTIC_DEFINITIONS) ================================================ FILE: code/CMakeModules/FindMSVC.cmake ================================================ # - Find MS Visual C++ # # VC_INCLUDE_DIR - where to find headers # VC_INCLUDE_DIRS - where to find headers # VC_LIBRARY_DIR - where to find libraries # VC_FOUND - True if MSVC found. MACRO(DETECT_VC_VERSION_HELPER _ROOT _VERSION) # Software/Wow6432Node/... GET_FILENAME_COMPONENT(VC${_VERSION}_DIR "[${_ROOT}\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7;${_VERSION}]" ABSOLUTE) IF(VC${_VERSION}_DIR AND VC${_VERSION}_DIR STREQUAL "/registry") SET(VC${_VERSION}_DIR) GET_FILENAME_COMPONENT(VC${_VERSION}_DIR "[${_ROOT}\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7;${_VERSION}]" ABSOLUTE) IF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL "/registry") SET(VC${_VERSION}_DIR "${VC${_VERSION}_DIR}VC/") ENDIF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL "/registry") ENDIF(VC${_VERSION}_DIR AND VC${_VERSION}_DIR STREQUAL "/registry") IF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL "/registry") SET(VC${_VERSION}_FOUND ON) DETECT_EXPRESS_VERSION(${_VERSION}) IF(NOT MSVC_FIND_QUIETLY) SET(_VERSION_STR ${_VERSION}) IF(MSVC_EXPRESS) SET(_VERSION_STR "${_VERSION_STR} Express") ENDIF(MSVC_EXPRESS) MESSAGE(STATUS "Found Visual C++ ${_VERSION_STR} in ${VC${_VERSION}_DIR}") ENDIF(NOT MSVC_FIND_QUIETLY) ELSEIF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL "/registry") SET(VC${_VERSION}_FOUND OFF) SET(VC${_VERSION}_DIR "") ENDIF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL "/registry") ENDMACRO(DETECT_VC_VERSION_HELPER) MACRO(DETECT_VC_VERSION _VERSION) SET(VC${_VERSION}_FOUND OFF) DETECT_VC_VERSION_HELPER("HKEY_CURRENT_USER" ${_VERSION}) IF(NOT VC${_VERSION}_FOUND) DETECT_VC_VERSION_HELPER("HKEY_LOCAL_MACHINE" ${_VERSION}) ENDIF(NOT VC${_VERSION}_FOUND) IF(VC${_VERSION}_FOUND) SET(VC_FOUND ON) SET(VC_DIR "${VC${_VERSION}_DIR}") ENDIF(VC${_VERSION}_FOUND) ENDMACRO(DETECT_VC_VERSION) MACRO(DETECT_EXPRESS_VERSION _VERSION) GET_FILENAME_COMPONENT(MSVC_EXPRESS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\${_VERSION}\\Setup\\VC;ProductDir]" ABSOLUTE) IF(MSVC_EXPRESS AND NOT MSVC_EXPRESS STREQUAL "/registry") SET(MSVC_EXPRESS ON) ENDIF(MSVC_EXPRESS AND NOT MSVC_EXPRESS STREQUAL "/registry") ENDMACRO(DETECT_EXPRESS_VERSION) IF(MSVC12) DETECT_VC_VERSION("12.0") SET(MSVC_TOOLSET "120") IF(NOT MSVC12_REDIST_DIR) # If you have VC++ 2013 Express, put x64/Microsoft.VC120.CRT/*.dll in ${EXTERNAL_PATH}/redist SET(MSVC12_REDIST_DIR "${EXTERNAL_PATH}/redist") ENDIF(NOT MSVC12_REDIST_DIR) ELSEIF(MSVC11) DETECT_VC_VERSION("11.0") SET(MSVC_TOOLSET "110") IF(NOT MSVC11_REDIST_DIR) # If you have VC++ 2012 Express, put x64/Microsoft.VC110.CRT/*.dll in ${EXTERNAL_PATH}/redist SET(MSVC11_REDIST_DIR "${EXTERNAL_PATH}/redist") ENDIF(NOT MSVC11_REDIST_DIR) ELSEIF(MSVC10) DETECT_VC_VERSION("10.0") SET(MSVC_TOOLSET "100") IF(NOT MSVC10_REDIST_DIR) # If you have VC++ 2010 Express, put x64/Microsoft.VC100.CRT/*.dll in ${EXTERNAL_PATH}/redist SET(MSVC10_REDIST_DIR "${EXTERNAL_PATH}/redist") ENDIF(NOT MSVC10_REDIST_DIR) ELSEIF(MSVC90) DETECT_VC_VERSION("9.0") SET(MSVC_TOOLSET "90") ELSEIF(MSVC80) DETECT_VC_VERSION("8.0") SET(MSVC_TOOLSET "80") ENDIF(MSVC12) # If you plan to use VC++ compilers with WINE, set VC_DIR environment variable IF(NOT VC_DIR) SET(VC_DIR $ENV{VC_DIR}) ENDIF(NOT VC_DIR) IF(NOT VC_DIR) STRING(REGEX REPLACE "/bin/.+" "" VC_DIR ${CMAKE_CXX_COMPILER}) ENDIF(NOT VC_DIR) SET(VC_INCLUDE_DIR "${VC_DIR}/include") SET(VC_INCLUDE_DIRS ${VC_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${VC_INCLUDE_DIR}) ================================================ FILE: code/CMakeModules/FindMercurial.cmake ================================================ # - Extract information from a subversion working copy # The module defines the following variables: # Mercurial_HG_EXECUTABLE - path to hg command line client # Mercurial_VERSION_HG - version of hg command line client # Mercurial_FOUND - true if the command line client was found # MERCURIAL_FOUND - same as Mercurial_FOUND, set for compatiblity reasons # # The minimum required version of Mercurial can be specified using the # standard syntax, e.g. FIND_PACKAGE(Mercurial 1.4) # # If the command line client executable is found two macros are defined: # Mercurial_WC_INFO( ) # Mercurial_WC_LOG( ) # Mercurial_WC_INFO extracts information of a subversion working copy at # a given location. This macro defines the following variables: # _WC_URL - url of the repository (at ) # _WC_ROOT - root url of the repository # _WC_REVISION - current revision # _WC_LAST_CHANGED_AUTHOR - author of last commit # _WC_LAST_CHANGED_DATE - date of last commit # _WC_LAST_CHANGED_REV - revision of last commit # _WC_INFO - output of command `hg info ' # Mercurial_WC_LOG retrieves the log message of the base revision of a # subversion working copy at a given location. This macro defines the # variable: # _LAST_CHANGED_LOG - last log of base revision # Example usage: # FIND_PACKAGE(Mercurial) # IF(MERCURIAL_FOUND) # Mercurial_WC_INFO(${PROJECT_SOURCE_DIR} Project) # MESSAGE("Current revision is ${Project_WC_REVISION}") # Mercurial_WC_LOG(${PROJECT_SOURCE_DIR} Project) # MESSAGE("Last changed log is ${Project_LAST_CHANGED_LOG}") # ENDIF(MERCURIAL_FOUND) #============================================================================= # Copyright 2006-2009 Kitware, Inc. # Copyright 2006 Tristan Carel # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) FIND_PROGRAM(Mercurial_HG_EXECUTABLE hg DOC "mercurial command line client" PATHS /opt/local/bin "C:/Program Files/TortoiseHg" "C:/Program Files (x86)/TortoiseHg" ) MARK_AS_ADVANCED(Mercurial_HG_EXECUTABLE) IF(Mercurial_HG_EXECUTABLE) EXECUTE_PROCESS(COMMAND ${Mercurial_HG_EXECUTABLE} --version OUTPUT_VARIABLE Mercurial_VERSION_HG OUTPUT_STRIP_TRAILING_WHITESPACE) STRING(REGEX REPLACE ".*version ([\\.0-9]+).*" "\\1" Mercurial_VERSION_HG "${Mercurial_VERSION_HG}") MACRO(Mercurial_WC_INFO dir prefix) EXECUTE_PROCESS(COMMAND ${Mercurial_HG_EXECUTABLE} tip --template "{rev};{node};{tags};{author}" WORKING_DIRECTORY ${dir} OUTPUT_VARIABLE ${prefix}_WC_INFO ERROR_VARIABLE Mercurial_hg_info_error RESULT_VARIABLE Mercurial_hg_info_result OUTPUT_STRIP_TRAILING_WHITESPACE) IF(NOT ${Mercurial_hg_info_result} EQUAL 0) MESSAGE(SEND_ERROR "Command \"${Mercurial_HG_EXECUTABLE} tip\" failed with output:\n${Mercurial_hg_info_error}") ELSE(NOT ${Mercurial_hg_info_result} EQUAL 0) LIST(LENGTH ${prefix}_WC_INFO _COUNT) IF(_COUNT EQUAL 4) LIST(GET ${prefix}_WC_INFO 0 ${prefix}_WC_REVISION) LIST(GET ${prefix}_WC_INFO 1 ${prefix}_WC_CHANGESET) LIST(GET ${prefix}_WC_INFO 2 ${prefix}_WC_BRANCH) LIST(GET ${prefix}_WC_INFO 3 ${prefix}_WC_LAST_CHANGED_AUTHOR) ELSE(_COUNT EQUAL 4) MESSAGE(STATUS "Bad output from HG") SET(${prefix}_WC_REVISION "unknown") SET(${prefix}_WC_CHANGESET "unknown") SET(${prefix}_WC_BRANCH "unknown") ENDIF(_COUNT EQUAL 4) ENDIF(NOT ${Mercurial_hg_info_result} EQUAL 0) ENDMACRO(Mercurial_WC_INFO) MACRO(Mercurial_WC_LOG dir prefix) # This macro can block if the certificate is not signed: # hg ask you to accept the certificate and wait for your answer # This macro requires a hg server network access (Internet most of the time) # and can also be slow since it access the hg server EXECUTE_PROCESS(COMMAND ${Mercurial_HG_EXECUTABLE} --non-interactive log -r BASE ${dir} OUTPUT_VARIABLE ${prefix}_LAST_CHANGED_LOG ERROR_VARIABLE Mercurial_hg_log_error RESULT_VARIABLE Mercurial_hg_log_result OUTPUT_STRIP_TRAILING_WHITESPACE) IF(NOT ${Mercurial_hg_log_result} EQUAL 0) MESSAGE(SEND_ERROR "Command \"${Mercurial_HG_EXECUTABLE} log -r BASE ${dir}\" failed with output:\n${Mercurial_hg_log_error}") ENDIF(NOT ${Mercurial_hg_log_result} EQUAL 0) ENDMACRO(Mercurial_WC_LOG) ENDIF(Mercurial_HG_EXECUTABLE) INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Mercurial DEFAULT_MSG Mercurial_HG_EXECUTABLE) ================================================ FILE: code/CMakeModules/FindMySQL.cmake ================================================ # - Find MySQL # Find the MySQL includes and client library # This module defines # MYSQL_INCLUDE_DIR, where to find mysql.h # MYSQL_LIBRARIES, the libraries needed to use MySQL. # MYSQL_FOUND, If false, do not try to use MySQL. # # Copyright (c) 2006, Jaroslaw Staniek, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. IF(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES) SET(MYSQL_FOUND TRUE) ELSE() FIND_PATH(MYSQL_INCLUDE_DIR mysql.h PATH_SUFFIXES mysql /usr/include/mysql /usr/local/include/mysql /opt/local/include/mysql5/mysql $ENV{ProgramFiles}/MySQL/*/include $ENV{SystemDrive}/MySQL/*/include) IF(WIN32 AND MSVC) FIND_LIBRARY(MYSQL_LIBRARY_RELEASE NAMES libmysql mysqlclient PATHS $ENV{ProgramFiles}/MySQL/*/lib/opt $ENV{SystemDrive}/MySQL/*/lib/opt) FIND_LIBRARY(MYSQL_LIBRARY_DEBUG NAMES libmysqld mysqlclientd PATHS $ENV{ProgramFiles}/MySQL/*/lib/opt $ENV{SystemDrive}/MySQL/*/lib/opt) ELSE() FIND_LIBRARY(MYSQL_LIBRARY_RELEASE NAMES libmysqlclient mysqlclient PATHS /usr/lib /usr/local/lib /usr/lib/mysql /usr/local/lib/mysql /opt/local/lib/mysql5/mysql ) FIND_LIBRARY(MYSQL_LIBRARY_DEBUG NAMES mysqlclientd PATHS /usr/lib /usr/local/lib /usr/lib/mysql /usr/local/lib/mysql /opt/local/lib/mysql5/mysql ) ENDIF() IF(MYSQL_INCLUDE_DIR) IF(MYSQL_LIBRARY_RELEASE) IF(MYSQL_LIBRARY_DEBUG) SET(MYSQL_LIBRARIES optimized ${MYSQL_LIBRARY_RELEASE} debug ${MYSQL_LIBRARY_DEBUG}) ELSE() SET(MYSQL_LIBRARIES ${MYSQL_LIBRARY_RELEASE}) ENDIF() FIND_PACKAGE(OpenSSL) IF(OPENSSL_FOUND) SET(MYSQL_LIBRARIES ${MYSQL_LIBRARIES} ${OPENSSL_LIBRARIES}) ENDIF() ENDIF() ENDIF() IF(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES) SET(MYSQL_FOUND TRUE) MESSAGE(STATUS "Found MySQL: ${MYSQL_INCLUDE_DIR}, ${MYSQL_LIBRARIES}") ELSE() SET(MYSQL_FOUND FALSE) MESSAGE(STATUS "MySQL not found.") ENDIF() MARK_AS_ADVANCED(MYSQL_LIBRARY_RELEASE MYSQL_LIBRARY_DEBUG) ENDIF() ================================================ FILE: code/CMakeModules/FindMysqlConnector.cmake ================================================ # - Find MySQL # Find the MySQL includes and client library # This module defines # MYSQL_INCLUDE_DIR, where to find mysql.h # MYSQL_LIBRARIES, the libraries needed to use MySQL. # MYSQL_FOUND, If false, do not try to use MySQL. # # Copyright (c) 2006, Jaroslaw Staniek, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. IF(MYSQLCONNECTOR_INCLUDE_DIR AND MYSQLCONNECTOR_LIBRARIES) SET(MYSQLCONNECTOR_FOUND TRUE) ELSE(MYSQLCONNECTOR_INCLUDE_DIR AND MYSQLCONNECTOR_LIBRARIES) FIND_PATH(MYSQLCONNECTOR_INCLUDE_DIR mysql_connection.h PATH_SUFFIXES mysqlconnector /usr/include/mysqlcppconn-static) # mysqlcppconn-static.lib IF(WIN32 AND MSVC) FIND_LIBRARY(MYSQLCONNECTOR_STATIC_LIBRARY_RELEASE NAMES mysqlcppconn-static PATHS $ENV{ProgramFiles}/MySQL/*/lib/opt $ENV{SystemDrive}/MySQL/*/lib/opt) FIND_LIBRARY(MYSQLCONNECTOR_STATIC_LIBRARY_DEBUG NAMES mysqlcppconn-static PATHS $ENV{ProgramFiles}/MySQL/*/lib/opt $ENV{SystemDrive}/MySQL/*/lib/opt) ELSE(WIN32 AND MSVC) FIND_LIBRARY(MYSQLCONNECTOR_STATIC_LIBRARY_RELEASE NAMES mysqlcppconn-static PATHS /usr/lib /usr/local/lib /usr/lib/mysql /usr/local/lib/mysql /opt/local/lib/mysql5/mysql ) FIND_LIBRARY(MYSQLCONNECTOR_STATIC_LIBRARY_DEBUG NAMES mysqlcppconn-static PATHS /usr/lib /usr/local/lib /usr/lib/mysql /usr/local/lib/mysql /opt/local/lib/mysql5/mysql ) ENDIF(WIN32 AND MSVC) # mysqlcppconn.lib IF(WIN32 AND MSVC) FIND_LIBRARY(MYSQLCONNECTOR_LIBRARY_RELEASE NAMES "mysqlcppconn.lib" PATHS $ENV{ProgramFiles}/MySQL/*/lib/opt $ENV{SystemDrive}/MySQL/*/lib/opt) FIND_LIBRARY(MYSQLCONNECTOR_LIBRARY_DEBUG NAMES "mysqlcppconn.lib" PATHS $ENV{ProgramFiles}/MySQL/*/lib/opt $ENV{SystemDrive}/MySQL/*/lib/opt) ELSE(WIN32 AND MSVC) FIND_LIBRARY(MYSQLCONNECTOR_LIBRARY_RELEASE NAMES "mysqlcppconn.lib" PATHS /usr/lib /usr/local/lib /usr/lib/mysql /usr/local/lib/mysql /opt/local/lib/mysql5/mysql ) FIND_LIBRARY(MYSQLCONNECTOR_LIBRARY_DEBUG NAMES "mysqlcppconn.lib" PATHS /usr/lib /usr/local/lib /usr/lib/mysql /usr/local/lib/mysql /opt/local/lib/mysql5/mysql ) ENDIF(WIN32 AND MSVC) IF(MYSQLCONNECTOR_INCLUDE_DIR) IF(MYSQLCONNECTOR_STATIC_LIBRARY_RELEASE AND MYSQLCONNECTOR_LIBRARY_RELEASE) SET(MYSQLCONNECTOR_LIBRARIES optimized ${MYSQLCONNECTOR_STATIC_LIBRARY_RELEASE} ${MYSQLCONNECTOR_LIBRARY_RELEASE}) IF(MYSQLCONNECTOR_STATIC_LIBRARY_DEBUG AND MYSQLCONNECTOR_LIBRARY_DEBUG) SET(MYSQLCONNECTOR_LIBRARIES ${MYSQLCONNECTOR_LIBRARIES} debug ${MYSQLCONNECTOR_STATIC_LIBRARY_DEBUG} ${MYSQLCONNECTOR_LIBRARY_DEBUG}) ENDIF(MYSQLCONNECTOR_STATIC_LIBRARY_DEBUG AND MYSQLCONNECTOR_LIBRARY_DEBUG) FIND_PACKAGE(OpenSSL) IF(OPENSSL_FOUND) SET(MYSQLCONNECTOR_LIBRARIES ${MYSQLCONNECTOR_LIBRARIES} ${OPENSSL_LIBRARIES}) ENDIF(OPENSSL_FOUND) ENDIF(MYSQLCONNECTOR_STATIC_LIBRARY_RELEASE AND MYSQLCONNECTOR_LIBRARY_RELEASE) ENDIF(MYSQLCONNECTOR_INCLUDE_DIR) IF(MYSQLCONNECTOR_INCLUDE_DIR AND MYSQLCONNECTOR_LIBRARIES) SET(MYSQLCONNECTOR_INCLUDE_DIR ${MYSQLCONNECTOR_INCLUDE_DIR}) SET(MYSQL_FOUND TRUE) MESSAGE(STATUS "Found MySQL Connector: ${MYSQLCONNECTOR_INCLUDE_DIR}, ${MYSQLCONNECTOR_LIBRARIES}") ELSE(MYSQLCONNECTOR_INCLUDE_DIR AND MYSQLCONNECTOR_LIBRARIES) SET(MYSQL_FOUND FALSE) MESSAGE(STATUS "MySQL not found.") ENDIF(MYSQLCONNECTOR_INCLUDE_DIR AND MYSQLCONNECTOR_LIBRARIES) MARK_AS_ADVANCED(MYSQLCONNECTOR_STATIC_LIBRARY_RELEASE MYSQLCONNECTOR_STATIC_LIBRARY_DEBUG MYSQLCONNECTOR_LIBRARY_RELEASE MYSQLCONNECTOR_LIBRARY_DEBUG) ENDIF(MYSQLCONNECTOR_INCLUDE_DIR AND MYSQLCONNECTOR_LIBRARIES) ================================================ FILE: code/CMakeModules/FindOgg.cmake ================================================ # - Locate Ogg library # This module defines # OGG_LIBRARY, the library to link against # OGG_FOUND, if false, do not try to link to OGG # OGG_INCLUDE_DIR, where to find headers. IF(OGG_LIBRARY AND OGG_INCLUDE_DIR) # in cache already SET(OGG_FIND_QUIETLY TRUE) ENDIF(OGG_LIBRARY AND OGG_INCLUDE_DIR) FIND_PATH(OGG_INCLUDE_DIR ogg/ogg.h PATHS $ENV{OGG_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include ) FIND_LIBRARY(OGG_LIBRARY NAMES ogg libogg PATHS $ENV{OGG_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(OGG_LIBRARY AND OGG_INCLUDE_DIR) SET(OGG_FOUND "YES") IF(NOT OGG_FIND_QUIETLY) MESSAGE(STATUS "Found Ogg: ${OGG_LIBRARY}") ENDIF(NOT OGG_FIND_QUIETLY) ELSE(OGG_LIBRARY AND OGG_INCLUDE_DIR) IF(NOT OGG_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find Ogg!") ENDIF(NOT OGG_FIND_QUIETLY) ENDIF(OGG_LIBRARY AND OGG_INCLUDE_DIR) ================================================ FILE: code/CMakeModules/FindOpenGLES.cmake ================================================ # - Try to find OpenGL ES # Once done this will define # # OPENGLES_FOUND - system has OpenGL ES # OPENGLES_EGL_FOUND - system has EGL # OPENGLES_LIBRARIES - Link these to use OpenGL ES and EGL # # If you want to use just GL ES you can use these values # OPENGLES_GLES_LIBRARY - Path to OpenGL ES Library # OPENGLES_EGL_LIBRARY - Path to EGL Library FIND_LIBRARY(OPENGLES_GLES_LIBRARY NAMES GLESv1_CM libGLESv1_CM gles_cm libgles_cm PATHS /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) FIND_LIBRARY(OPENGLES_EGL_LIBRARY NAMES EGL libEGL PATHS /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(OPENGLES_GLES_LIBRARY) SET(OPENGLES_FOUND "YES") SET(OPENGLES_LIBRARIES ${OPENGLES_GLES_LIBRARY} ${OPENGLES_LIBRARIES}) IF(OPENGLES_EGL_LIBRARY) SET(OPENGLES_EGL_FOUND "YES") SET(OPENGLES_LIBRARIES ${OPENGLES_EGL_LIBRARY} ${OPENGLES_LIBRARIES}) ELSE(OPENGLES_EGL_LIBRARY) SET(OPENGLES_EGL_FOUND "NO") ENDIF(OPENGLES_EGL_LIBRARY) ENDIF(OPENGLES_GLES_LIBRARY) ================================================ FILE: code/CMakeModules/FindOpenSSL.cmake ================================================ # - Locate OpenSSL library # This module defines # OPENSSL_INCLUDE_DIRS - where to find openssl/ssl.h, etc. # OPENSSL_LIBRARIES - List of libraries when using openssl. # OPENSSL_FOUND - True if openssl found. # OPENSSL_VERSION_STRING - the version of openssl found (since CMake 2.8.8) IF(OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIR) # in cache already SET(OPENSSL_FIND_QUIETLY TRUE) ENDIF(OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIR) FIND_PATH(OPENSSL_INCLUDE_DIR ssl.h PATH_SUFFIXES openssl $ENV{OPENSSL_DIR}/include /usr/local/include /usr/local/include/openssl ) SET(LIBRARY_NAME_RELEASE libssl libssl.a) SET(LIBRARY_NAME_DEBUG libssl libssl.a) FIND_LIBRARY(OPENSSL_LIBRARIE_RELEASE NAMES ${LIBRARY_NAME_RELEASE} PATHS $ENV{OPENSSL_DIR}/lib /usr/local/lib64 ) FIND_LIBRARY(OPENSSL_LIBRARY_DEBUG NAMES ${LIBRARY_NAME_DEBUG} PATHS $ENV{OPENSSL_DIR}/lib /usr/local/lib64 ) SET(LIBRARY_NAME_CRYPTO libcrypto libcrypto.a) FIND_LIBRARY(CRYPTO_LIBRARIE_RELEASE NAMES ${LIBRARY_NAME_CRYPTO} PATHS $ENV{OPENSSL_DIR}/lib /usr/local/lib64 ) IF(OPENSSL_INCLUDE_DIR) IF(OPENSSL_LIBRARIE_RELEASE AND CRYPTO_LIBRARIE_RELEASE) # Case where both Release and Debug versions are provided SET(OPENSSL_FOUND TRUE) #SET(OPENSSL_LIBRARIES optimized ${OPENSSL_LIBRARIE_RELEASE} debug ${OPENSSL_LIBRARY_DEBUG}) SET(OPENSSL_LIBRARIES "${OPENSSL_LIBRARIE_RELEASE};${CRYPTO_LIBRARIE_RELEASE}" CACHE STRING "OpenSSL Libraries") ENDIF(OPENSSL_LIBRARIE_RELEASE AND CRYPTO_LIBRARIE_RELEASE) ENDIF(OPENSSL_INCLUDE_DIR) IF(OPENSSL_FOUND) IF(NOT OPENSSL_FIND_QUIETLY) MESSAGE(STATUS "Found OpenSSL: ${OPENSSL_INCLUDE_DIR} ${OPENSSL_LIBRARIES}") ENDIF(NOT OPENSSL_FIND_QUIETLY) ELSE(OPENSSL_FOUND) IF(NOT OPENSSL_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find OpenSSL! INCLUDE: ${OPENSSL_INCLUDE_DIR} LIB:${OPENSSL_LIBRARIES} ") ENDIF(NOT OPENSSL_FIND_QUIETLY) ENDIF(OPENSSL_FOUND) MARK_AS_ADVANCED(OPENSSL_LIBRARIE_RELEASE OPENSSL_LIBRARY_DEBUG) ================================================ FILE: code/CMakeModules/FindPBC.cmake ================================================ # - Locate PBC library # This module defines # PBC_INCLUDE_DIRS - where to find pbc/pbc.h, etc. # PBC_LIBRARIES - List of libraries when using pbc. # PBC_FOUND - True if pbc found. # PBC_VERSION_STRING - the version of pbc found (since CMake 2.8.8) FIND_PATH(PBC_INCLUDE_DIR pbc.h PATH_SUFFIXES pbc $ENV{PBC_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include /usr/local/include/pbc /mingw/include ) SET(LIBRARY_NAME_RELEASE pbc) SET(LIBRARY_NAME_DEBUG pbc) FIND_LIBRARY(PBC_LIBRARY_RELEASE NAMES ${LIBRARY_NAME_RELEASE} PATHS $ENV{PBC_DIR}/lib /usr/local/lib /usr/lib /usr/lib64 /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 /usr/local/lib/pbc /mingw/lib ) FIND_LIBRARY(PBC_LIBRARY_DEBUG NAMES ${LIBRARY_NAME_DEBUG} PATHS $ENV{PBC_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 /usr/local/lib/pbc /mingw/lib ) IF(PBC_INCLUDE_DIR) IF(PBC_LIBRARY_RELEASE AND PBC_LIBRARY_DEBUG) # Case where both Release and Debug versions are provided SET(PBC_FOUND TRUE) SET(PBC_LIBRARY optimized ${PBC_LIBRARY_RELEASE} debug ${PBC_LIBRARY_DEBUG}) ELSEIF(PBC_LIBRARY_RELEASE) # Normal case SET(PBC_FOUND TRUE) SET(PBC_LIBRARY ${PBC_LIBRARY_RELEASE}) ELSEIF(PBC_LIBRARY_DEBUG) # Case where PBC is compiled from sources (debug version is compiled by default) SET(PBC_FOUND TRUE) SET(PBC_LIBRARY ${PBC_LIBRARY_DEBUG}) ENDIF(PBC_LIBRARY_RELEASE AND PBC_LIBRARY_DEBUG) ENDIF(PBC_INCLUDE_DIR) IF(PBC_FOUND) MESSAGE(STATUS "Found PBC: ${PBC_INCLUDE_DIR} ${PBC_LIBRARY}") ELSE(PBC_FOUND) MESSAGE(STATUS "Warning: Unable to find PBC! INCLUDE: ${PBC_INCLUDE_DIR} LIB:${PBC_LIBRARY} ") ENDIF(PBC_FOUND) MARK_AS_ADVANCED(PBC_LIBRARY_RELEASE PBC_LIBRARY_DEBUG) ================================================ FILE: code/CMakeModules/FindProtoBuf.cmake ================================================ # - Locate ProtoBuf library # This module defines # PROTOBUF_LIBRARIES, the libraries to link against # PROTOBUF_FOUND, if false, do not try to link to PROTO_BUF # PROTOBUF_INCLUDE_DIR, where to find headers. IF(PROTOBUF_LIBRARIES AND PROTOBUF_INCLUDE_DIR) # in cache already SET(PROTOBUF_FIND_QUIETLY TRUE) ENDIF(PROTOBUF_LIBRARIES AND PROTOBUF_INCLUDE_DIR) FIND_PATH(PROTOBUF_INCLUDE_DIR generated_message_util.h PATH_SUFFIXES google/protobuf $ENV{PROTOBUF_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include /usr/local/include/google/protobuf /usr/local/include/google-protobuf ) SET(LIBRARY_NAME_RELEASE protobuf libprotobuf) SET(LIBRARY_NAME_DEBUG protobufd libprotobufd) IF(WITH_STLPORT AND WIN32) SET(LIBRARY_NAME_RELEASE libprotobuf_stlport ${LIBRARY_NAME_RELEASE}) SET(LIBRARY_NAME_DEBUG libprotobuf_stlportd ${LIBRARY_NAME_RELEASE}) ENDIF(WITH_STLPORT AND WIN32) SET(PROTOBUF_LIBRARY_RELEASE NOTFOUND) SET(PROTOBUF_LIBRARY_DEBUG NOTFOUND) FIND_LIBRARY(PROTOBUF_LIBRARY_RELEASE NAMES ${LIBRARY_NAME_RELEASE} PATHS $ENV{PROTOBUF_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 /usr/local/lib/google-protobuf ) FIND_LIBRARY(PROTOBUF_LIBRARY_DEBUG NAMES ${LIBRARY_NAME_DEBUG} PATHS $ENV{PROTOBUF_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 /usr/local/lib/google-protobuf ) IF(PROTOBUF_INCLUDE_DIR) IF(PROTOBUF_LIBRARY_RELEASE AND PROTOBUF_LIBRARY_DEBUG) # Case where both Release and Debug versions are provided SET(PROTOBUF_FOUND TRUE) SET(PROTOBUF_LIBRARIES optimized ${PROTOBUF_LIBRARY_RELEASE} debug ${PROTOBUF_LIBRARY_DEBUG}) ELSEIF(PROTOBUF_LIBRARY_RELEASE) # Normal case SET(PROTOBUF_FOUND TRUE) SET(PROTOBUF_LIBRARIES ${PROTOBUF_LIBRARY_RELEASE}) ELSEIF(PROTOBUF_LIBRARY_DEBUG) # Case where ProtoBuf is compiled from sources (debug version is compiled by default) SET(PROTOBUF_FOUND TRUE) SET(PROTOBUF_LIBRARIES ${PROTOBUF_LIBRARY_DEBUG}) ENDIF(PROTOBUF_LIBRARY_RELEASE AND PROTOBUF_LIBRARY_DEBUG) ENDIF(PROTOBUF_INCLUDE_DIR) IF(PROTOBUF_FOUND) IF(NOT PROTOBUF_FIND_QUIETLY) MESSAGE(STATUS "Found ProtoBuf: ${PROTOBUF_INCLUDE_DIR} ${PROTOBUF_LIBRARIES}") ENDIF(NOT PROTOBUF_FIND_QUIETLY) ELSE(PROTOBUF_FOUND) IF(NOT PROTOBUF_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find ProtoBuf!") ENDIF(NOT PROTOBUF_FIND_QUIETLY) ENDIF(PROTOBUF_FOUND) MARK_AS_ADVANCED(PROTOBUF_LIBRARY_RELEASE PROTOBUF_LIBRARY_DEBUG) ================================================ FILE: code/CMakeModules/FindS3TC.cmake ================================================ # - Locate S3TC library # This module defines # S3TC_LIBRARY, the library to link against # S3TC_FOUND, if false, do not try to link to S3TC # S3TC_INCLUDE_DIR, where to find headers. IF(S3TC_LIBRARY AND S3TC_INCLUDE_DIR) # in cache already SET(S3TC_FIND_QUIETLY TRUE) ENDIF(S3TC_LIBRARY AND S3TC_INCLUDE_DIR) FIND_PATH(S3TC_INCLUDE_DIR s3_intrf.h PATHS $ENV{S3TC_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include PATH_SUFFIXES S3TC ) FIND_LIBRARY(S3TC_LIBRARY NAMES s3tc libs3tc PATHS $ENV{S3TC_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(S3TC_LIBRARY AND S3TC_INCLUDE_DIR) SET(S3TC_FOUND "YES") IF(NOT S3TC_FIND_QUIETLY) MESSAGE(STATUS "Found S3TC: ${S3TC_LIBRARY}") ENDIF(NOT S3TC_FIND_QUIETLY) ELSE(S3TC_LIBRARY AND S3TC_INCLUDE_DIR) IF(NOT S3TC_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find S3TC!") ENDIF(NOT S3TC_FIND_QUIETLY) ENDIF(S3TC_LIBRARY AND S3TC_INCLUDE_DIR) ================================================ FILE: code/CMakeModules/FindSTLport.cmake ================================================ # Look for a directory containing STLport. # # The following values are defined # STLPORT_INCLUDE_DIR - where to find vector, etc. # STLPORT_LIBRARIES - link against these to use STLport # STLPORT_FOUND - True if the STLport is available. # also defined, but not for general use are IF(STLPORT_LIBRARIES AND STLPORT_INCLUDE_DIR) # in cache already SET(STLPORT_FIND_QUIETLY TRUE) ENDIF(STLPORT_LIBRARIES AND STLPORT_INCLUDE_DIR) FIND_PATH(STLPORT_INCLUDE_DIR iostream PATHS /usr/local/include/stlport /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include PATH_SUFFIXES stlport ) FIND_LIBRARY(STLPORT_LIBRARY_DEBUG NAMES stlport_cygwin_debug stlport_cygwin_stldebug stlport_gcc_debug stlport_gcc_stldebug stlportstld_x stlportstld_x.5.2 stlportd stlportd.5.2 stlportd_statix stlportd_static PATHS /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) FIND_LIBRARY(STLPORT_LIBRARY_RELEASE NAMES stlport_cygwin stlport_gcc stlport stlport_x stlport_x.5.2 stlport.5.2 stlport_statix stlport_static PATHS /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(STLPORT_INCLUDE_DIR) IF(STLPORT_LIBRARY_RELEASE) SET(STLPORT_FOUND TRUE) SET(STLPORT_LIBRARIES ${STLPORT_LIBRARY_RELEASE}) IF(STLPORT_LIBRARY_DEBUG) SET(STLPORT_LIBRARIES optimized ${STLPORT_LIBRARIES} debug ${STLPORT_LIBRARY_DEBUG}) ENDIF(STLPORT_LIBRARY_DEBUG) ENDIF(STLPORT_LIBRARY_RELEASE) ENDIF(STLPORT_INCLUDE_DIR) IF(STLPORT_FOUND) IF(NOT STLPORT_FIND_QUIETLY) MESSAGE(STATUS "Found STLport: ${STLPORT_INCLUDE_DIR} ${STLPORT_LIBRARIES}") ENDIF(NOT STLPORT_FIND_QUIETLY) ELSE(STLPORT_FOUND) IF(NOT STLPORT_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find STLport!") ENDIF(NOT STLPORT_FIND_QUIETLY) ENDIF(STLPORT_FOUND) MARK_AS_ADVANCED(STLPORT_LIBRARY_RELEASE STLPORT_LIBRARY_DEBUG) ================================================ FILE: code/CMakeModules/FindSquish.cmake ================================================ # # Find the LibSquish includes and library # # This module defines # SQUISH_INCLUDE_DIR, where to find squish.h # SQUISH_LIBRARIES, where to find the Squish libraries. # SQUISH_FOUND, If false, do not try to use Squish. # also defined, but not for general use are IF(SQUISH_LIBRARIES AND SQUISH_INCLUDE_DIR) # in cache already SET(SQUISH_FIND_QUIETLY TRUE) ENDIF(SQUISH_LIBRARIES AND SQUISH_INCLUDE_DIR) FIND_PATH(SQUISH_INCLUDE_DIR squish.h PATHS /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include PATH_SUFFIXES cppunit ) FIND_LIBRARY(SQUISH_LIBRARY_RELEASE squish PATHS /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) FIND_LIBRARY(SQUISH_LIBRARY_DEBUG squishd PATHS /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(SQUISH_INCLUDE_DIR) IF(SQUISH_LIBRARY_RELEASE) SET(SQUISH_FOUND "YES") SET(SQUISH_LIBRARIES "optimized;${SQUISH_LIBRARY_RELEASE}") IF(SQUISH_LIBRARY_DEBUG) SET(SQUISH_LIBRARIES "${SQUISH_LIBRARIES};debug;${SQUISH_LIBRARY_DEBUG}") ELSE(SQUISH_LIBRARY_DEBUG) SET(SQUISH_LIBRARIES "${SQUISH_LIBRARIES};debug;${SQUISH_LIBRARY_RELEASE}") MESSAGE("Debug Squish NOT found, using the release version!") ENDIF(SQUISH_LIBRARY_DEBUG) ENDIF(SQUISH_LIBRARY_RELEASE) ENDIF(SQUISH_INCLUDE_DIR) IF(SQUISH_FOUND) IF(NOT SQUISH_FIND_QUIETLY) MESSAGE(STATUS "Found Squish: ${SQUISH_LIBRARIES}") ENDIF(NOT SQUISH_FIND_QUIETLY) FILE(STRINGS ${SQUISH_INCLUDE_DIR}/squish.h METRIC REGEX "metric = 0") IF(METRIC) SET(SQUISH_COMPRESS_HAS_METRIC ON) SET(SQUISH_DEFINITIONS -DSQUISH_COMPRESS_HAS_METRIC) ENDIF(METRIC) ELSE(SQUISH_FOUND) IF(NOT SQUISH_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find Squish!") ENDIF(NOT SQUISH_FIND_QUIETLY) ENDIF(SQUISH_FOUND) MARK_AS_ADVANCED(SQUISH_LIBRARY_RELEASE SQUISH_LIBRARY_DEBUG) ================================================ FILE: code/CMakeModules/FindTinyXml.cmake ================================================ # - Locate TinyXml library # This module defines # TINYXML_LIBRARIES, the libraries to link against # TINYXML_FOUND, if false, do not try to link to TINYXML # TINYXML_INCLUDE_DIR, where to find headers. IF(TINYXML_LIBRARIES AND TINYXML_INCLUDE_DIR) # in cache already SET(TINYXML_FIND_QUIETLY TRUE) ENDIF(TINYXML_LIBRARIES AND TINYXML_INCLUDE_DIR) FIND_PATH(TINYXML_INCLUDE_DIR tinyxml.h PATH_SUFFIXES tinyxml $ENV{TINYXML_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include ) SET(LIBRARY_NAME_RELEASE tinyxml libtinyxml) SET(LIBRARY_NAME_DEBUG tinyxml_d tinyxmld libtinyxml_d libtinyxmld) FIND_LIBRARY(TINYXML_LIBRARY_RELEASE NAMES ${LIBRARY_NAME_RELEASE} PATHS $ENV{TINYXML_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) FIND_LIBRARY(TINYXML_LIBRARY_DEBUG NAMES ${LIBRARY_NAME_DEBUG} PATHS $ENV{TINYXML_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(TINYXML_INCLUDE_DIR) IF(TINYXML_LIBRARY_RELEASE AND TINYXML_LIBRARY_DEBUG) # Case where both Release and Debug versions are provided SET(TINYXML_FOUND TRUE) SET(TINYXML_LIBRARIES optimized ${TINYXML_LIBRARY_RELEASE} debug ${TINYXML_LIBRARY_DEBUG}) ELSEIF(TINYXML_LIBRARY_RELEASE) # Normal case SET(TINYXML_FOUND TRUE) SET(TINYXML_LIBRARIES ${TINYXML_LIBRARY_RELEASE}) ELSEIF(TINYXML_LIBRARY_DEBUG) # Case where TinyXml is compiled from sources (debug version is compiled by default) SET(TINYXML_FOUND TRUE) SET(TINYXML_LIBRARIES ${TINYXML_LIBRARY_DEBUG}) ENDIF(TINYXML_LIBRARY_RELEASE AND TINYXML_LIBRARY_DEBUG) ENDIF(TINYXML_INCLUDE_DIR) IF(TINYXML_FOUND) IF(NOT TINYXML_FIND_QUIETLY) MESSAGE(STATUS "Found TinyXml: ${TINYXML_INCLUDE_DIR} ${TINYXML_LIBRARIES}") ENDIF(NOT TINYXML_FIND_QUIETLY) ELSE(TINYXML_FOUND) IF(NOT TINYXML_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find TinyXml!") ENDIF(NOT TINYXML_FIND_QUIETLY) ENDIF(TINYXML_FOUND) MARK_AS_ADVANCED(TINYXML_LIBRARY_RELEASE TINYXML_LIBRARY_DEBUG) ================================================ FILE: code/CMakeModules/FindToLua.cmake ================================================ # - Locate ToLua library # This module defines # TOLUA_LIBRARIES, the libraries to link against # TOLUA_FOUND, if false, do not try to link to TOLUA # TOLUA_INCLUDE_DIR, where to find headers. IF(TOLUA_LIBRARIES AND TOLUA_INCLUDE_DIR) # in cache already SET(TOLUA_FIND_QUIETLY TRUE) ENDIF(TOLUA_LIBRARIES AND TOLUA_INCLUDE_DIR) FIND_PACKAGE(Lua51 REQUIRED) FIND_PATH(TOLUA_INCLUDE_DIR tolua++.h PATH_SUFFIXES tolua lua51 $ENV{TOLUA_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include /usr/local/include/lua51 /mingw/include ) SET(LIBRARY_NAME_RELEASE tolua++5.1 libtolua++.a libtolua++5.1.a libtolua++.so) SET(LIBRARY_NAME_DEBUG tolua++5.1 libtolua++.a libtolua++5.1.a libtolua++.so) FIND_LIBRARY(TOLUA_LIBRARY_RELEASE NAMES ${LIBRARY_NAME_RELEASE} PATHS $ENV{TOLUA_DIR}/lib /usr/local/lib /usr/lib /usr/lib64 /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 /usr/local/lib/lua51 /mingw/lib ) FIND_LIBRARY(TOLUA_LIBRARY_DEBUG NAMES ${LIBRARY_NAME_DEBUG} PATHS $ENV{TOLUA_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 /usr/local/lib/lua51 /mingw/lib ) IF(TOLUA_INCLUDE_DIR) IF(TOLUA_LIBRARY_RELEASE AND TOLUA_LIBRARY_DEBUG) # Case where both Release and Debug versions are provided SET(TOLUA_FOUND TRUE) SET(TOLUA_LIBRARIES optimized ${TOLUA_LIBRARY_RELEASE} debug ${TOLUA_LIBRARY_DEBUG}) ELSEIF(TOLUA_LIBRARY_RELEASE) # Normal case SET(TOLUA_FOUND TRUE) SET(TOLUA_LIBRARIES ${TOLUA_LIBRARY_RELEASE}) ELSEIF(TOLUA_LIBRARY_DEBUG) # Case where ToLua is compiled from sources (debug version is compiled by default) SET(TOLUA_FOUND TRUE) SET(TOLUA_LIBRARIES ${TOLUA_LIBRARY_DEBUG}) ENDIF(TOLUA_LIBRARY_RELEASE AND TOLUA_LIBRARY_DEBUG) ENDIF(TOLUA_INCLUDE_DIR) IF(TOLUA_FOUND) IF(NOT TOLUA_FIND_QUIETLY) MESSAGE(STATUS "Found ToLua: ${TOLUA_INCLUDE_DIR} ${TOLUA_LIBRARIES}") ENDIF(NOT TOLUA_FIND_QUIETLY) ELSE(TOLUA_FOUND) IF(NOT TOLUA_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find ToLua! INCLUDE: ${TOLUA_INCLUDE_DIR} LIB:${TOLUA_LIBRARIES} ") ENDIF(NOT TOLUA_FIND_QUIETLY) ENDIF(TOLUA_FOUND) MARK_AS_ADVANCED(TOLUA_LIBRARY_RELEASE TOLUA_LIBRARY_DEBUG) ================================================ FILE: code/CMakeModules/FindVorbis.cmake ================================================ # - Locate Vorbis library # This module defines # VORBIS_LIBRARY, the library to link against # VORBIS_FOUND, if false, do not try to link to VORBIS # VORBIS_INCLUDE_DIR, where to find headers. IF(VORBIS_LIBRARY AND VORBIS_INCLUDE_DIR) # in cache already SET(VORBIS_FIND_QUIETLY TRUE) ENDIF(VORBIS_LIBRARY AND VORBIS_INCLUDE_DIR) FIND_PATH(VORBIS_INCLUDE_DIR vorbis/vorbisfile.h PATHS $ENV{VORBIS_DIR}/include /usr/local/include /usr/include /sw/include /opt/local/include /opt/csw/include /opt/include ) FIND_LIBRARY(VORBIS_LIBRARY NAMES vorbis libvorbis PATHS $ENV{VORBIS_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) FIND_LIBRARY(VORBISFILE_LIBRARY NAMES vorbisfile libvorbisfile PATHS $ENV{VORBIS_DIR}/lib /usr/local/lib /usr/lib /usr/local/X11R6/lib /usr/X11R6/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(VORBIS_LIBRARY AND VORBISFILE_LIBRARY AND VORBIS_INCLUDE_DIR) SET(VORBIS_FOUND "YES") SET(VORBIS_LIBRARIES ${VORBIS_LIBRARY} ${VORBISFILE_LIBRARY}) IF(NOT VORBIS_FIND_QUIETLY) MESSAGE(STATUS "Found Vorbis: ${VORBIS_LIBRARY}") ENDIF(NOT VORBIS_FIND_QUIETLY) ELSE(VORBIS_LIBRARY AND VORBISFILE_LIBRARY AND VORBIS_INCLUDE_DIR) IF(NOT VORBIS_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find Vorbis!") ENDIF(NOT VORBIS_FIND_QUIETLY) ENDIF(VORBIS_LIBRARY AND VORBISFILE_LIBRARY AND VORBIS_INCLUDE_DIR) ================================================ FILE: code/CMakeModules/FindWindowsSDK.cmake ================================================ # - Find Windows Platform SDK # Find the Windows includes # # WINSDK_INCLUDE_DIR - where to find Windows.h # WINSDK_INCLUDE_DIRS - where to find all Windows headers # WINSDK_LIBRARY_DIR - where to find libraries # WINSDK_FOUND - True if Windows SDK found. IF(WINSDK_FOUND) # If Windows SDK already found, skip it RETURN() ENDIF() # Values can be CURRENT or any existing versions 7.1, 8.0A, etc... SET(WINSDK_VERSION "CURRENT" CACHE STRING "Windows SDK version to prefer") MACRO(DETECT_WINSDK_VERSION_HELPER _ROOT _VERSION) GET_FILENAME_COMPONENT(WINSDK${_VERSION}_DIR "[${_ROOT}\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v${_VERSION};InstallationFolder]" ABSOLUTE) IF(WINSDK${_VERSION}_DIR AND NOT WINSDK${_VERSION}_DIR STREQUAL "/registry" AND EXISTS "${WINSDK${_VERSION}_DIR}/Include") SET(WINSDK${_VERSION}_FOUND ON) GET_FILENAME_COMPONENT(WINSDK${_VERSION}_VERSION_FULL "[${_ROOT}\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v${_VERSION};ProductVersion]" NAME) IF(NOT WindowsSDK_FIND_QUIETLY) MESSAGE(STATUS "Found Windows SDK ${_VERSION} in ${WINSDK${_VERSION}_DIR}") ENDIF() ELSE() SET(WINSDK${_VERSION}_DIR "") ENDIF() ENDMACRO() MACRO(DETECT_WINKIT_VERSION _VERSION _SUFFIX) GET_FILENAME_COMPONENT(WINSDK${_VERSION}_DIR "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot${_SUFFIX}]" ABSOLUTE) IF(WINSDK${_VERSION}_DIR AND NOT WINSDK${_VERSION}_DIR STREQUAL "/registry") SET(WINSDK${_VERSION}_FOUND ON) SET(WINSDK${_VERSION}_VERSION_FULL "${_VERSION}") IF(NOT WindowsSDK_FIND_QUIETLY) MESSAGE(STATUS "Found Windows Kit ${_VERSION} in ${WINSDK${_VERSION}_DIR}") ENDIF() LIST(APPEND WINSDK_DETECTED_VERSIONS ${_VERSION}) ELSE() SET(WINSDK${_VERSION}_DIR "") ENDIF() ENDMACRO() MACRO(DETECT_WINSDK_VERSION _VERSION) SET(WINSDK${_VERSION}_FOUND OFF) DETECT_WINSDK_VERSION_HELPER("HKEY_CURRENT_USER" ${_VERSION}) IF(NOT WINSDK${_VERSION}_FOUND) DETECT_WINSDK_VERSION_HELPER("HKEY_LOCAL_MACHINE" ${_VERSION}) ENDIF() ENDMACRO() SET(WINSDK_DETECTED_VERSIONS) # Fixed versions for Windows Kits (VC++ from 2012) DETECT_WINKIT_VERSION("10.0" "10") DETECT_WINKIT_VERSION("8.1" "81") DETECT_WINKIT_VERSION("8.0" "") # For VC++ up to 2010 SET(WINSDK_VERSIONS "7.1" "7.1A" "7.0" "7.0A" "6.1" "6.0" "6.0A") # Search all supported Windows SDKs FOREACH(_VERSION ${WINSDK_VERSIONS}) DETECT_WINSDK_VERSION(${_VERSION}) IF(WINSDK${_VERSION}_FOUND) LIST(APPEND WINSDK_DETECTED_VERSIONS ${_VERSION}) ENDIF() ENDFOREACH() SET(WINSDK_SUFFIXES) IF(TARGET_ARM64) SET(WINSDK8_SUFFIX "arm64") ELSEIF(TARGET_ARM) SET(WINSDK8_SUFFIX "arm") ELSEIF(TARGET_X64) SET(WINSDK8_SUFFIX "x64") SET(WINSDK_SUFFIXES "x64" "amd64") ELSEIF(TARGET_X86) SET(WINSDK8_SUFFIX "x86") ENDIF() SET(WINSDKCURRENT_VERSION_INCLUDE $ENV{INCLUDE}) IF(WINSDKCURRENT_VERSION_INCLUDE) FILE(TO_CMAKE_PATH "${WINSDKCURRENT_VERSION_INCLUDE}" WINSDKCURRENT_VERSION_INCLUDE) ENDIF() SET(WINSDKENV_DIR $ENV{WINSDK_DIR}) IF(NOT WINSDKENV_DIR) SET(WINSDKENV_DIR $ENV{WindowsSDKDir}) ENDIF() MACRO(FIND_WINSDK_VERSION_HEADERS) IF(WINSDK_DIR AND NOT WINSDK_VERSION) # Search version in headers FIND_FILE(_MSI_FILE Msi.h PATHS ${WINSDK_DIR}/Include/um ${WINSDK_DIR}/Include ) IF(_MSI_FILE) IF(NOT WINSDK_VERSION) # Look for Windows SDK 8.1 FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX "^#ifndef NTDDI_WINBLUE") IF(_CONTENT) SET(WINSDK_VERSION "8.1") ENDIF() ENDIF() IF(NOT WINSDK_VERSION) # Look for Windows SDK 8.0 FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX "^#ifndef NTDDI_WIN8") IF(_CONTENT) SET(WINSDK_VERSION "8.0") ENDIF() ENDIF() IF(NOT WINSDK_VERSION) # Look for Windows SDK 7.0 FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX "^#ifndef NTDDI_WIN7") IF(_CONTENT) FIND_FILE(_WINSDKVER_FILE winsdkver.h WinSDKVer.h PATHS ${WINSDK_DIR}/Include/um ${WINSDK_DIR}/Include ) IF(_WINSDKVER_FILE) # Load WinSDKVer.h content FILE(STRINGS ${_WINSDKVER_FILE} _CONTENT REGEX "^#define NTDDI_MAXVER") # Get NTDDI_MAXVER value STRING(REGEX REPLACE "^.*0x([0-9A-Fa-f]+).*$" "\\1" _WINSDKVER "${_CONTENT}") # In Windows SDK 7.1, NTDDI_MAXVER is wrong IF(_WINSDKVER STREQUAL "06010000") SET(WINSDK_VERSION "7.1") ELSEIF(_WINSDKVER STREQUAL "0601") SET(WINSDK_VERSION "7.0A") ELSE() MESSAGE(FATAL_ERROR "Can't determine Windows SDK version with NTDDI_MAXVER 0x${_WINSDKVER}") ENDIF() ELSE() SET(WINSDK_VERSION "7.0") ENDIF() ENDIF() ENDIF() IF(NOT WINSDK_VERSION) # Look for Windows SDK 6.0 FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX "^#ifndef NTDDI_VISTA") IF(_CONTENT) SET(WINSDK_VERSION "6.0") ENDIF() ENDIF() IF(NOT WINSDK_VERSION) # Look for Windows SDK 5.2 FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX "^#ifndef NTDDI_WS03SP1") IF(_CONTENT) SET(WINSDK_VERSION "5.2") ENDIF() ENDIF() IF(NOT WINSDK_VERSION) # Look for Windows SDK 5.1 FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX "^#ifndef NTDDI_WINXP") IF(_CONTENT) SET(WINSDK_VERSION "5.1") ENDIF() ENDIF() IF(NOT WINSDK_VERSION) # Look for Windows SDK 5.0 FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX "^#ifndef NTDDI_WIN2K") IF(_CONTENT) SET(WINSDK_VERSION "5.0") ENDIF() ENDIF() ELSE() MESSAGE(FATAL_ERROR "Unable to find Msi.h in ${WINSDK_DIR}") ENDIF() ENDIF() ENDMACRO() MACRO(USE_CURRENT_WINSDK) SET(WINSDK_DIR "") SET(WINSDK_VERSION "") SET(WINSDK_VERSION_FULL "") # Use WINSDK environment variable IF(WINSDKENV_DIR) FIND_PATH(WINSDK_DIR Windows.h HINTS ${WINSDKENV_DIR}/Include/um ${WINSDKENV_DIR}/Include ) ENDIF() # Use INCLUDE environment variable IF(NOT WINSDK_DIR AND WINSDKCURRENT_VERSION_INCLUDE) FOREACH(_INCLUDE ${WINSDKCURRENT_VERSION_INCLUDE}) FILE(TO_CMAKE_PATH ${_INCLUDE} _INCLUDE) # Look for Windows.h because there are several paths IF(EXISTS ${_INCLUDE}/Windows.h) STRING(REGEX REPLACE "/(include|INCLUDE|Include)(.*)" "" WINSDK_DIR ${_INCLUDE}) MESSAGE(STATUS "Found Windows SDK in INCLUDE environment variable: ${WINSDK_DIR}") BREAK() ENDIF() ENDFOREACH() ENDIF() IF(WINSDK_DIR) # Compare WINSDK_DIR with registered Windows SDKs FOREACH(_VERSION ${WINSDK_DETECTED_VERSIONS}) IF(WINSDK_DIR STREQUAL "${WINSDK${_VERSION}_DIR}") SET(WINSDK_VERSION ${_VERSION}) SET(WINSDK_VERSION_FULL "${WINSDK${WINSDK_VERSION}_VERSION_FULL}") BREAK() ENDIF() ENDFOREACH() FIND_WINSDK_VERSION_HEADERS() ENDIF() IF(NOT WINSDK_DIR) # Use Windows SDK versions installed with VC++ when possible IF(MSVC_VERSION GREATER 1909) # Special case, use Kits for SDK SET(WINSDK_VERSION "10.0") SET(WINSDK_DIR ${WINSDK_UCRT_DIR}) ELSEIF(MSVC14) SET(WINSDK_VERSION "8.1") ELSEIF(MSVC12) SET(WINSDK_VERSION "8.1") ELSEIF(MSVC11) SET(WINSDK_VERSION "8.0") ELSEIF(MSVC10) IF(NOT TARGET_X64 OR NOT MSVC_EXPRESS) SET(WINSDK_VERSION "7.0A") ENDIF() ELSEIF(MSVC90) IF(NOT MSVC_EXPRESS) SET(WINSDK_VERSION "6.0A") ENDIF() ELSEIF(MSVC80) SET(WINSDK_MSVC80_COMPATIBLES "7.1" "7.1A" "7.0" "7.0A" "6.1" "6.0" "6.0A" "5.2A") # look for each Windows SDK supported by VC++ 2005 (7.1 is the latest) FOREACH(_VERSION ${WINSDK_DETECTED_VERSIONS}) # look if this version of Windows SDK is installed LIST(FIND WINSDK_MSVC80_COMPATIBLES ${_VERSION} _FOUND) IF(NOT _FOUND EQUAL -1) SET(WINSDK_VERSION "${_VERSION}") BREAK() ENDIF() ENDFOREACH() IF(NOT MSVC_EXPRESS AND NOT WINSDK_VERSION) SET(WINSDK_VERSION "5.2A") ENDIF() ELSE() MESSAGE(FATAL_ERROR "Your compiler is either too old or too recent, please update this CMake module.") ENDIF() # Use installed Windows SDK IF(NOT WINSDK_VERSION) IF(WINSDK8.1_FOUND) SET(WINSDK_VERSION "8.1") ELSEIF(WINSDK8.0_FOUND) SET(WINSDK_VERSION "8.0") ELSEIF(WINSDK7.1_FOUND) SET(WINSDK_VERSION "7.1") ELSEIF(WINSDK7.0_FOUND) SET(WINSDK_VERSION "7.0") ELSEIF(WINSDK6.1_FOUND) SET(WINSDK_VERSION "6.1") ELSEIF(WINSDK6.0_FOUND) SET(WINSDK_VERSION "6.0") ELSE() MESSAGE(FATAL_ERROR "You have no compatible Windows SDK installed.") ENDIF() ENDIF() # Look for correct registered Windows SDK version FOREACH(_VERSION ${WINSDK_DETECTED_VERSIONS}) IF(WINSDK_VERSION STREQUAL _VERSION) SET(WINSDK_VERSION_FULL "${WINSDK${WINSDK_VERSION}_VERSION_FULL}") SET(WINSDK_DIR "${WINSDK${WINSDK_VERSION}_DIR}") BREAK() ENDIF() ENDFOREACH() ENDIF() ENDMACRO() IF(MSVC14) # Under VC++ 2015 and 2017, stdio.h, stdlib.h, etc... are part of UCRT SET(WINSDK_UCRT_VERSION "10.0") ENDIF() # Look for correct UCRT IF(WINSDK_UCRT_VERSION AND WINSDK${WINSDK_UCRT_VERSION}_FOUND) SET(WINSDK_UCRT_DIR "${WINSDK${WINSDK_UCRT_VERSION}_DIR}") ENDIF() IF(WINSDK_UCRT_DIR) # determine exact UCRT version SET(WINSDK_UCRT_INCLUDE_ROOT_DIR ${WINSDK_UCRT_DIR}/Include) SET(WINSDK_UCRT_LIB_ROOT_DIR ${WINSDK_UCRT_DIR}/Lib) FILE(GLOB UCRT_SUBDIRS RELATIVE ${WINSDK_UCRT_INCLUDE_ROOT_DIR} ${WINSDK_UCRT_INCLUDE_ROOT_DIR}/*) SET(UCRT_VERSION) FOREACH(UCRT_SUBDIR ${UCRT_SUBDIRS}) IF(NOT UCRT_VERSION OR UCRT_SUBDIR VERSION_GREATER UCRT_VERSION) SET(UCRT_VERSION ${UCRT_SUBDIR}) ENDIF() ENDFOREACH() IF(UCRT_VERSION) MESSAGE(STATUS "Using Windows UCRT ${UCRT_VERSION}") SET(WINSDK10_INCLUDE_DIR ${WINSDK_UCRT_INCLUDE_ROOT_DIR}/${UCRT_VERSION}) SET(WINSDK10_LIBRARY_DIR ${WINSDK_UCRT_LIB_ROOT_DIR}/${UCRT_VERSION}) # directory where UCRT headers are found FIND_PATH(WINSDK_UCRT_INCLUDE_DIR corecrt.h HINTS ${WINSDK10_INCLUDE_DIR}/ucrt ) # directory where UCRT libraries are found FIND_PATH(WINSDK_UCRT_LIBRARY_DIR ucrt.lib HINTS ${WINSDK10_LIBRARY_DIR}/ucrt/${WINSDK8_SUFFIX} ) ENDIF() ENDIF() IF(WINSDK_VERSION STREQUAL "CURRENT") USE_CURRENT_WINSDK() ELSE() IF(WINSDK${WINSDK_VERSION}_FOUND) SET(WINSDK_VERSION_FULL "${WINSDK${WINSDK_VERSION}_VERSION_FULL}") SET(WINSDK_DIR "${WINSDK${WINSDK_VERSION}_DIR}") ELSE() USE_CURRENT_WINSDK() ENDIF() ENDIF() IF(WINSDK_DIR) MESSAGE(STATUS "Using Windows SDK ${WINSDK_VERSION}") ELSE() MESSAGE(FATAL_ERROR "Unable to find Windows SDK!") ENDIF() # directory where Win32 headers are found FIND_PATH(WINSDK_INCLUDE_DIR Windows.h HINTS ${WINSDK_DIR}/Include/${UCRT_VERSION}/um ${WINSDK_DIR}/Include/um ${WINSDK_DIR}/Include NO_DEFAULT_PATH ) MESSAGE(STATUS "Found Windows.h in ${WINSDK_INCLUDE_DIR}") # directory where WinRT headers are found FIND_PATH(WINSDK_WINRT_INCLUDE_DIR winstring.h HINTS ${WINSDK_DIR}/Include/${UCRT_VERSION}/winrt ${WINSDK_DIR}/Include/winrt NO_DEFAULT_PATH ) MESSAGE(STATUS "Found winstring.h in ${WINSDK_WINRT_INCLUDE_DIR}") # directory where DirectX headers are found FIND_PATH(WINSDK_SHARED_INCLUDE_DIR d3d9.h HINTS ${WINSDK_DIR}/Include/${UCRT_VERSION}/shared ${WINSDK_DIR}/Include/shared NO_DEFAULT_PATH ) MESSAGE(STATUS "Found d3d9.h in ${WINSDK_SHARED_INCLUDE_DIR}") # directory where OpenGL headers are found FIND_PATH(WINSDK_OPENGL_INCLUDE_DIR GL.h HINTS ${WINSDK_INCLUDE_DIR}/gl ${WINSDK_DIR}/Include/um/gl ${WINSDK_DIR}/Include/gl NO_DEFAULT_PATH ) MESSAGE(STATUS "Found GL.h in ${WINSDK_OPENGL_INCLUDE_DIR}") SET(WINSDK_LIBRARY_DIRS ${WINSDK_DIR}/Lib/${UCRT_VERSION}/um/${WINSDK8_SUFFIX} ${WINSDK_DIR}/Lib/winv6.3/um/${WINSDK8_SUFFIX} ${WINSDK_DIR}/Lib/win8/um/${WINSDK8_SUFFIX} ) IF(WINSDK_SUFFIXES) FOREACH(_SUFFIX ${WINSDK_SUFFIXES}) LIST(APPEND WINSDK_LIBRARY_DIRS ${WINSDK_DIR}/Lib/${_SUFFIX}) ENDFOREACH() ELSE() LIST(APPEND WINSDK_LIBRARY_DIRS ${WINSDK_DIR}/Lib) ENDIF() # directory where all libraries are found FIND_PATH(WINSDK_LIBRARY_DIR ComCtl32.lib HINTS ${WINSDK_LIBRARY_DIRS} NO_DEFAULT_PATH ) MESSAGE(STATUS "Found ComCtl32.lib in ${WINSDK_LIBRARY_DIR}") SET(WINSDK_BINARY_DIRS ${WINSDK_DIR}/Bin/${UCRT_VERSION}/${WINSDK8_SUFFIX} ${WINSDK_DIR}/Bin/${WINSDK8_SUFFIX} ${WINSDK_DIR}/Bin/x86 ${WINSDK_DIR}/Bin ) # signtool is used to sign executables FIND_PROGRAM(WINSDK_SIGNTOOL signtool HINTS ${WINSDK_BINARY_DIRS} NO_DEFAULT_PATH ) # midl is used to generate IDL interfaces FIND_PROGRAM(WINSDK_MIDL midl HINTS ${WINSDK_BINARY_DIRS} NO_DEFAULT_PATH ) IF(WINSDK_INCLUDE_DIR) SET(WINSDK_FOUND ON) IF(WINSDK_UCRT_INCLUDE_DIR) SET(WINSDK_INCLUDE_DIRS ${WINSDK_INCLUDE_DIRS} ${WINSDK_UCRT_INCLUDE_DIR}) ENDIF() IF(WINSDK_SHARED_INCLUDE_DIR) SET(WINSDK_INCLUDE_DIRS ${WINSDK_INCLUDE_DIRS} ${WINSDK_SHARED_INCLUDE_DIR}) ENDIF() SET(WINSDK_INCLUDE_DIRS ${WINSDK_INCLUDE_DIRS} ${WINSDK_INCLUDE_DIR}) IF(WINSDK_OPENGL_INCLUDE_DIR) SET(WINSDK_INCLUDE_DIRS ${WINSDK_INCLUDE_DIRS} ${WINSDK_OPENGL_INCLUDE_DIR}) ENDIF() IF(WINSDK_WINRT_INCLUDE_DIR) SET(WINSDK_INCLUDE_DIRS ${WINSDK_INCLUDE_DIRS} ${WINSDK_WINRT_INCLUDE_DIR}) ENDIF() INCLUDE_DIRECTORIES(${WINSDK_INCLUDE_DIRS}) IF(WINSDK_UCRT_LIBRARY_DIR) SET(CMAKE_LIBRARY_PATH ${WINSDK_UCRT_LIBRARY_DIR} ${CMAKE_LIBRARY_PATH}) ENDIF() SET(CMAKE_LIBRARY_PATH ${WINSDK_LIBRARY_DIR} ${CMAKE_LIBRARY_PATH}) # Fix for using Windows SDK 7.1 with Visual C++ 2012, 2013, 2015 and 2017 IF(WINSDK_VERSION STREQUAL "7.1" AND (MSVC11 OR MSVC12 OR MSVC14)) ADD_DEFINITIONS(-D_USING_V110_SDK71_) ENDIF() ELSE() IF(NOT WindowsSDK_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find Windows SDK!") ENDIF() ENDIF() ================================================ FILE: code/CMakeModules/FindXF86VidMode.cmake ================================================ # - Locate Jpeg library # This module defines # XF86VidMode_LIBRARY, the library to link against # XF86VidMode_FOUND, if false, do not try to link to XF86VidMode # XF86VidMode_INCLUDE_DIR, where to find headers. IF(XF86VidMode_LIBRARY AND XF86VidMode_INCLUDE_DIR) # in cache already SET(XF86VidMode_FIND_QUIETLY TRUE) ENDIF(XF86VidMode_LIBRARY AND XF86VidMode_INCLUDE_DIR) FIND_PATH(XF86VidMode_INCLUDE_DIR xf86vmode.h PATHS $ENV{XF86VidMode_DIR}/include /usr/include/X11/ /usr/X11R6/include/ PATH_SUFFIXES extensions ) FIND_LIBRARY(XF86VidMode_LIBRARY Xxf86vm PATHS $ENV{XF86VidMode_DIR}/lib /usr/X11R6/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 ) IF(XF86VidMode_LIBRARY AND XF86VidMode_INCLUDE_DIR) SET(XF86VidMode_FOUND "YES") SET(XF86VidMode_DEFINITIONS -DXF86VIDMODE) IF(NOT XF86VidMode_FIND_QUIETLY) MESSAGE(STATUS "Found XF86VidMode: ${XF86VidMode_LIBRARY}") ENDIF(NOT XF86VidMode_FIND_QUIETLY) ELSE(XF86VidMode_LIBRARY AND XF86VidMode_INCLUDE_DIR) IF(NOT XF86VidMode_FIND_QUIETLY) MESSAGE(STATUS "Warning: Unable to find XF86VidMode!") ENDIF(NOT XF86VidMode_FIND_QUIETLY) ENDIF(XF86VidMode_LIBRARY AND XF86VidMode_INCLUDE_DIR) ================================================ FILE: code/CMakeModules/GetRevision.cmake ================================================ CMAKE_MINIMUM_REQUIRED(VERSION 2.6.3) # ROOT_DIR should be set to root of the repository (where to find the .svn or .hg directory) # SOURCE_DIR should be set to root of your code (where to find CMakeLists.txt) IF(SOURCE_DIR) # Replace spaces by semi-columns IF(CMAKE_MODULE_PATH) STRING(REPLACE " " ";" CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) ENDIF(CMAKE_MODULE_PATH) SET(CMAKE_MODULE_PATH ${SOURCE_DIR}/CMakeModules ${CMAKE_MODULE_PATH}) IF(NOT ROOT_DIR AND SOURCE_DIR) SET(ROOT_DIR ${SOURCE_DIR}) ENDIF() IF(NOT SOURCE_DIR AND ROOT_DIR) SET(SOURCE_DIR ${ROOT_DIR}) ENDIF() ELSE() SET(SOURCE_DIR ${CMAKE_SOURCE_DIR}) SET(ROOT_DIR ${CMAKE_SOURCE_DIR}) ENDIF() MACRO(NOW RESULT) IF (WIN32) EXECUTE_PROCESS(COMMAND "wmic" "os" "get" "localdatetime" OUTPUT_VARIABLE DATETIME) IF(NOT DATETIME MATCHES "ERROR") STRING(REGEX REPLACE ".*\n([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9]).*" "\\1-\\2-\\3 \\4:\\5:\\6" ${RESULT} "${DATETIME}") ENDIF() ELSEIF(UNIX) EXECUTE_PROCESS(COMMAND "date" "+%Y-%m-%d %H:%M:%S" OUTPUT_VARIABLE DATETIME) STRING(REGEX REPLACE "([0-9: -]+).*" "\\1" ${RESULT} "${DATETIME}") ELSE() MESSAGE(SEND_ERROR "date not implemented") SET(${RESULT} "0000-00-00 00:00:00") ENDIF() ENDMACRO(NOW) IF(EXISTS "${ROOT_DIR}/.svn/") FIND_PACKAGE(Subversion QUIET) IF(SUBVERSION_FOUND) Subversion_WC_INFO(${ROOT_DIR} ER) SET(REVISION ${ER_WC_REVISION}) ENDIF(SUBVERSION_FOUND) FIND_PACKAGE(TortoiseSVN QUIET) IF(TORTOISESVN_FOUND) TORTOISESVN_GET_REVISION(${ROOT_DIR} REVISION) ENDIF(TORTOISESVN_FOUND) ENDIF(EXISTS "${ROOT_DIR}/.svn/") IF(EXISTS "${ROOT_DIR}/.hg/") FIND_PACKAGE(Mercurial) IF(MERCURIAL_FOUND) Mercurial_WC_INFO(${ROOT_DIR} ER) SET(REVISION ${ER_WC_REVISION}) SET(CHANGESET ${ER_WC_CHANGESET}) SET(BRANCH ${ER_WC_BRANCH}) ENDIF() ENDIF() # if processing exported sources, use "revision" file if exists IF(SOURCE_DIR AND NOT DEFINED REVISION) SET(REVISION_FILE ${SOURCE_DIR}/revision) IF(EXISTS ${REVISION_FILE}) FILE(STRINGS ${REVISION_FILE} REVISION LIMIT_COUNT 1) MESSAGE(STATUS "Read revision ${REVISION} from file") ENDIF() ENDIF() IF(SOURCE_DIR AND DEFINED REVISION) IF(EXISTS ${SOURCE_DIR}/revision.h.in) MESSAGE(STATUS "Revision: ${REVISION}") NOW(BUILD_DATE) CONFIGURE_FILE(${SOURCE_DIR}/revision.h.in revision.h.txt) EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy revision.h.txt revision.h) # copy_if_different ENDIF() ENDIF() ================================================ FILE: code/CMakeModules/PCHSupport.cmake ================================================ # - Try to find precompiled headers support for GCC 3.4 and 4.x (and MSVC) # Once done this will define: # # Variable: # PCHSupport_FOUND # # ADD_PRECOMPILED_HEADER _targetName _inputh _inputcpp # ADD_PRECOMPILED_HEADER_TO_TARGET _targetName _input _pch_output_to_use # ADD_NATIVE_PRECOMPILED_HEADER _targetName _inputh _inputcpp IF(MSVC) SET(PCHSupport_FOUND TRUE) ELSE(MSVC) IF(CMAKE_COMPILER_IS_GNUCXX) EXEC_PROGRAM(${CMAKE_CXX_COMPILER} ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion OUTPUT_VARIABLE gcc_compiler_version) IF(gcc_compiler_version MATCHES "^4\\.1(\\.[0-9]+)?") SET(PCHSupport_FOUND FALSE) ELSEIF(gcc_compiler_version MATCHES "^4\\.[0-9]+(\\.[0-9]+)?") SET(PCHSupport_FOUND TRUE) ENDIF(gcc_compiler_version MATCHES "^4\\.1(\\.[0-9]+)?") ELSE(CMAKE_COMPILER_IS_GNUCXX) # TODO: make tests for other compilers than GCC SET(PCHSupport_FOUND TRUE) ENDIF(CMAKE_COMPILER_IS_GNUCXX) ENDIF(MSVC) # Set PCH_FLAGS for common flags, PCH_ARCH_XXX_FLAGS for specific archs flags and PCH_ARCHS for archs MACRO(PCH_SET_COMPILE_FLAGS _target) SET(PCH_FLAGS) SET(PCH_ARCHS) SET(_FLAGS) LIST(APPEND _FLAGS ${CMAKE_CXX_FLAGS}) STRING(TOUPPER "${CMAKE_BUILD_TYPE}" _UPPER_BUILD) LIST(APPEND _FLAGS " ${CMAKE_CXX_FLAGS_${_UPPER_BUILD}}") GET_TARGET_PROPERTY(_targetType ${_target} TYPE) IF(${_targetType} STREQUAL SHARED_LIBRARY OR ${_targetType} STREQUAL MODULE_LIBRARY) LIST(APPEND _FLAGS " ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") ELSE(${_targetType} STREQUAL SHARED_LIBRARY OR ${_targetType} STREQUAL MODULE_LIBRARY) GET_TARGET_PROPERTY(_pic ${_target} POSITION_INDEPENDENT_CODE) IF(_pic) LIST(APPEND _FLAGS " ${CMAKE_CXX_COMPILE_OPTIONS_PIE}") ENDIF(_pic) ENDIF(${_targetType} STREQUAL SHARED_LIBRARY OR ${_targetType} STREQUAL MODULE_LIBRARY) GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES) FOREACH(item ${DIRINC}) LIST(APPEND _FLAGS " -I\"${item}\"") ENDFOREACH(item) # Required for CMake 2.6 SET(GLOBAL_DEFINITIONS) GET_DIRECTORY_PROPERTY(DEFINITIONS COMPILE_DEFINITIONS) IF(DEFINITIONS) FOREACH(item ${DEFINITIONS}) LIST(APPEND GLOBAL_DEFINITIONS " -D${item}") ENDFOREACH(item) ENDIF(DEFINITIONS) GET_DIRECTORY_PROPERTY(DEFINITIONS COMPILE_DEFINITIONS_${_UPPER_BUILD}) IF(DEFINITIONS) FOREACH(item ${DEFINITIONS}) LIST(APPEND GLOBAL_DEFINITIONS " -D${item}") ENDFOREACH(item) ENDIF(DEFINITIONS) GET_TARGET_PROPERTY(oldProps ${_target} COMPILE_FLAGS) IF(oldProps) LIST(APPEND _FLAGS " ${oldProps}") ENDIF(oldProps) GET_TARGET_PROPERTY(oldPropsBuild ${_target} COMPILE_FLAGS_${_UPPER_BUILD}) IF(oldPropsBuild) LIST(APPEND _FLAGS " ${oldPropsBuild}") ENDIF(oldPropsBuild) GET_TARGET_PROPERTY(DIRINC ${_target} INCLUDE_DIRECTORIES) IF(DIRINC) FOREACH(item ${DIRINC}) LIST(APPEND _FLAGS " -I\"${item}\"") ENDFOREACH(item) ENDIF(DIRINC) GET_TARGET_PROPERTY(DEFINITIONS ${_target} COMPILE_DEFINITIONS) IF(DEFINITIONS) FOREACH(item ${DEFINITIONS}) LIST(APPEND GLOBAL_DEFINITIONS " -D${item}") ENDFOREACH(item) ENDIF(DEFINITIONS) GET_TARGET_PROPERTY(DEFINITIONS ${_target} COMPILE_DEFINITIONS_${_UPPER_BUILD}) IF(DEFINITIONS) FOREACH(item ${DEFINITIONS}) LIST(APPEND GLOBAL_DEFINITIONS " -D${item}") ENDFOREACH(item) ENDIF(DEFINITIONS) GET_DIRECTORY_PROPERTY(_directory_flags DEFINITIONS) GET_DIRECTORY_PROPERTY(_directory_definitions DIRECTORY ${CMAKE_SOURCE_DIR} DEFINITIONS) LIST(APPEND _FLAGS " ${GLOBAL_DEFINITIONS}") LIST(APPEND _FLAGS " ${_directory_flags}") LIST(APPEND _FLAGS " ${_directory_definitions}") # Format definitions IF(MSVC) # Fix path with space SEPARATE_ARGUMENTS(_FLAGS UNIX_COMMAND "${_FLAGS}") ELSE(MSVC) STRING(REGEX REPLACE " +" " " _FLAGS ${_FLAGS}) SEPARATE_ARGUMENTS(_FLAGS) ENDIF(MSVC) IF(CLANG) # Determining all architectures and get common flags SET(_ARCH_NEXT) SET(_XARCH_NEXT) FOREACH(item ${_FLAGS}) IF(_ARCH_NEXT) LIST(FIND PCH_ARCHS ${item} ITEM_FOUND) IF(ITEM_FOUND EQUAL -1) LIST(APPEND PCH_ARCHS ${item}) STRING(TOUPPER "${item}" _UPPER_ARCH) SET(PCH_ARCH_${_UPPER_ARCH}_FLAGS "-arch" ${item}) ENDIF(ITEM_FOUND EQUAL -1) SET(_ARCH_NEXT OFF) ELSEIF(_XARCH_NEXT) SET(_XARCH_NEXT OFF) ELSE(_ARCH_NEXT) IF(item MATCHES "^-arch") SET(_ARCH_NEXT ON) ELSEIF(item MATCHES "^-Xarch_") STRING(REGEX REPLACE "-Xarch_([a-z0-9_]+)" "\\1" item ${item}) LIST(FIND PCH_ARCHS ${item} ITEM_FOUND) IF(ITEM_FOUND EQUAL -1) LIST(APPEND PCH_ARCHS ${item}) STRING(TOUPPER "${item}" _UPPER_ARCH) SET(PCH_ARCH_${_UPPER_ARCH}_FLAGS "-arch" ${item}) ENDIF(ITEM_FOUND EQUAL -1) SET(_XARCH_NEXT ON) ELSE(item MATCHES "^-arch") LIST(APPEND PCH_FLAGS ${item}) ENDIF(item MATCHES "^-arch") ENDIF(_ARCH_NEXT) ENDFOREACH(item) # Get architcture specific flags SET(_XARCH_NEXT) FOREACH(item ${_FLAGS}) IF(_XARCH_NEXT) STRING(TOUPPER "${_XARCH_NEXT}" _UPPER_XARCH) LIST(APPEND PCH_ARCH_${_UPPER_XARCH}_FLAGS ${item}) SET(_XARCH_NEXT OFF) ELSE(_XARCH_NEXT) IF(item MATCHES "^-Xarch_") STRING(SUBSTRING "${item}" 7 -1 _XARCH_NEXT) ENDIF(item MATCHES "^-Xarch_") ENDIF(_XARCH_NEXT) ENDFOREACH(item) # Remove duplicated architectures IF(_ARCHS AND PCH_ARCHS) LIST(REMOVE_DUPLICATES PCH_ARCHS) ENDIF(_ARCHS AND PCH_ARCHS) ELSE(CLANG) SET(PCH_FLAGS ${_FLAGS}) ENDIF(CLANG) IF(PCH_FLAGS) LIST(REMOVE_DUPLICATES PCH_FLAGS) ENDIF(PCH_FLAGS) ENDMACRO(PCH_SET_COMPILE_FLAGS) MACRO(GET_PDB_FILENAME _out_filename _target) # determine output directory based on target type GET_TARGET_PROPERTY(_targetType ${_target} TYPE) IF(${_targetType} STREQUAL EXECUTABLE) SET(_targetOutput ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) ELSEIF(${_targetType} STREQUAL STATIC_LIBRARY) SET(_targetOutput ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) ELSE(${_targetType} STREQUAL EXECUTABLE) SET(_targetOutput ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) ENDIF(${_targetType} STREQUAL EXECUTABLE) # determine target postfix STRING(TOUPPER "${CMAKE_BUILD_TYPE}_POSTFIX" _postfix_var_name) GET_TARGET_PROPERTY(_targetPostfix ${_target} ${_postfix_var_name}) IF(${_targetPostfix} MATCHES NOTFOUND) SET(_targetPostfix "") ENDIF(${_targetPostfix} MATCHES NOTFOUND) SET(${_out_filename} "${_targetOutput}/${_target}${_targetPostfix}.pdb") ENDMACRO(GET_PDB_FILENAME) MACRO(PCH_SET_COMPILE_COMMAND _inputcpp _compile_FLAGS) IF(CMAKE_CXX_COMPILER_ARG1) # remove leading space in compiler argument STRING(REGEX REPLACE "^ +" "" pchsupport_compiler_cxx_arg1 ${CMAKE_CXX_COMPILER_ARG1}) ELSE(CMAKE_CXX_COMPILER_ARG1) SET(pchsupport_compiler_cxx_arg1 "") ENDIF(CMAKE_CXX_COMPILER_ARG1) IF(MSVC) GET_PDB_FILENAME(PDB_FILE ${_PCH_current_target}) SET(PCH_COMMAND ${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} /Yc /Fp"${PCH_OUTPUT}" ${_inputcpp} /Fd"${PDB_FILE}" /c /Fo"${PCH_OUTPUT}.obj") # Ninja PCH Support # http://public.kitware.com/pipermail/cmake-developers/2012-March/003653.html SET_SOURCE_FILES_PROPERTIES(${_inputcpp} PROPERTIES OBJECT_OUTPUTS "${PCH_OUTPUT}.obj") ELSE(MSVC) SET(HEADER_FORMAT "c++-header") SET(_FLAGS "") IF(APPLE) SET(HEADER_FORMAT "objective-${HEADER_FORMAT}") SET(_FLAGS -fobjc-abi-version=2 -fobjc-legacy-dispatch) ENDIF(APPLE) SET(PCH_COMMAND ${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} ${_FLAGS} -x ${HEADER_FORMAT} -o ${PCH_OUTPUT} -c ${PCH_INPUT}) ENDIF(MSVC) ENDMACRO(PCH_SET_COMPILE_COMMAND) MACRO(PCH_SET_PRECOMPILED_HEADER_OUTPUT _targetName _input _arch _language) SET(_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch") IF(MSVC) FILE(MAKE_DIRECTORY ${_OUTPUT_DIR}) GET_FILENAME_COMPONENT(_name ${_input} NAME_WE) SET(PCH_INPUT ${_input}) SET(PCH_OUTPUT "${_OUTPUT_DIR}/${_name}.pch") ELSE(MSVC) IF(NOT "${_arch}" STREQUAL "") SET(_OUTPUT_DIR "${_OUTPUT_DIR}_${_arch}") ENDIF(NOT "${_arch}" STREQUAL "") IF(NOT "${_language}" STREQUAL "") SET(_OUTPUT_DIR "${_OUTPUT_DIR}_${_language}") ENDIF(NOT "${_language}" STREQUAL "") GET_FILENAME_COMPONENT(_name ${_input} NAME) # Copy .h to output dir SET(PCH_INPUT "${_OUTPUT_DIR}/${_name}") ADD_CUSTOM_COMMAND(OUTPUT ${PCH_INPUT} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_input} ${PCH_INPUT} DEPENDS ${_input} COMMENT "[${_targetName}] Update precompiled header - done" ) IF(CLANG) SET(PCH_EXT "pth") ELSE(CLANG) SET(PCH_EXT "gch") ENDIF(CLANG) # For GCC and Clang, PCH needs to be in the same directory as .h SET(PCH_OUTPUT "${_OUTPUT_DIR}/${_name}.${PCH_EXT}") ENDIF(MSVC) ENDMACRO(PCH_SET_PRECOMPILED_HEADER_OUTPUT) # Add common flags MACRO(ADD_PRECOMPILED_HEADER_TO_TARGET _targetName) GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS) IF(${oldProps} MATCHES NOTFOUND) SET(oldProps "") ENDIF(${oldProps} MATCHES NOTFOUND) IF(MSVC) SET(_target_cflags "${oldProps} /Yu\"${PCH_INPUT}\" /FI\"${PCH_INPUT}\" /Fp\"${PCH_OUTPUT}\"") # Ninja PCH Support # http://public.kitware.com/pipermail/cmake-developers/2012-March/003653.html SET_TARGET_PROPERTIES(${_targetName} PROPERTIES OBJECT_DEPENDS "${PCH_OUTPUT}") # NMAKE-VS2012 Error LNK2011 (NMAKE-VS2010 do not complain) # we need to link the pch.obj file, see http://msdn.microsoft.com/en-us/library/3ay26wa2(v=vs.110).aspx GET_TARGET_PROPERTY(_STATIC_LIBRARY_FLAGS ${_targetName} STATIC_LIBRARY_FLAGS) IF(NOT _STATIC_LIBRARY_FLAGS) SET(_STATIC_LIBRARY_FLAGS) ENDIF(NOT _STATIC_LIBRARY_FLAGS) SET(_STATIC_LIBRARY_FLAGS "${PCH_OUTPUT}.obj ${_STATIC_LIBRARY_FLAGS}") GET_TARGET_PROPERTY(_LINK_FLAGS ${_targetName} LINK_FLAGS) IF(NOT _LINK_FLAGS) SET(_LINK_FLAGS) ENDIF(NOT _LINK_FLAGS) SET(_LINK_FLAGS "${PCH_OUTPUT}.obj ${_LINK_FLAGS}") SET_TARGET_PROPERTIES(${_targetName} PROPERTIES STATIC_LIBRARY_FLAGS ${_STATIC_LIBRARY_FLAGS} LINK_FLAGS ${_LINK_FLAGS}) ELSE(MSVC) # for use with distcc and gcc >4.0.1 if preprocessed files are accessible # on all remote machines set # PCH_ADDITIONAL_COMPILER_FLAGS to -fpch-preprocess SET(PCH_ADDITIONAL_COMPILER_FLAGS) LIST(LENGTH PCH_ARCHS PCH_ARCHS_COUNT) # If no arch is specified, create common flags IF(PCH_ARCHS_COUNT LESS 2) SET(PCH_ADDITIONAL_COMPILER_FLAGS "-include ${PCH_INPUT} ${PCH_ADDITIONAL_COMPILER_FLAGS}") ENDIF(PCH_ARCHS_COUNT LESS 2) IF(APPLE) SET(PCH_ADDITIONAL_COMPILER_FLAGS "-fobjc-abi-version=2 -fobjc-legacy-dispatch -x objective-c++ ${PCH_ADDITIONAL_COMPILER_FLAGS}") ENDIF(APPLE) IF(WITH_PCH_DEBUG) SET(PCH_ADDITIONAL_COMPILER_FLAGS "-H ${PCH_ADDITIONAL_COMPILER_FLAGS}") ENDIF(WITH_PCH_DEBUG) SET(_target_cflags "${oldProps} ${PCH_ADDITIONAL_COMPILER_FLAGS} -Winvalid-pch") ENDIF(MSVC) SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS ${_target_cflags}) ENDMACRO(ADD_PRECOMPILED_HEADER_TO_TARGET) # Add specific flags for an arch MACRO(ADD_PRECOMPILED_HEADER_TO_TARGET_ARCH _targetName _arch) LIST(LENGTH PCH_ARCHS PCH_ARCHS_COUNT) IF(PCH_ARCHS_COUNT GREATER 1) GET_TARGET_PROPERTY(_FLAGS ${_targetName} COMPILE_FLAGS) IF(${_FLAGS} MATCHES NOTFOUND) SET(_FLAGS "") ENDIF(${_FLAGS} MATCHES NOTFOUND) SET(_FLAGS "${_FLAGS} -Xarch_${_arch} -include${PCH_INPUT}") SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS ${_FLAGS}) ENDIF(PCH_ARCHS_COUNT GREATER 1) ENDMACRO(ADD_PRECOMPILED_HEADER_TO_TARGET_ARCH) MACRO(PCH_CREATE_TARGET _targetName _targetNamePCH) ADD_CUSTOM_COMMAND(OUTPUT ${PCH_OUTPUT} COMMAND ${PCH_COMMAND} COMMENT "Generating ${_targetNamePCH}" DEPENDS ${PCH_INPUT}) ADD_CUSTOM_TARGET(${_targetNamePCH} DEPENDS ${PCH_INPUT} ${PCH_OUTPUT}) ADD_DEPENDENCIES(${_targetName} ${_targetNamePCH}) ENDMACRO(PCH_CREATE_TARGET _targetName _inputh _inputcpp) MACRO(ADD_PRECOMPILED_HEADER _targetName _inputh _inputcpp) SET(_PCH_current_target ${_targetName}) IF(NOT CMAKE_BUILD_TYPE) MESSAGE(FATAL_ERROR "This is the ADD_PRECOMPILED_HEADER macro. " "You must set CMAKE_BUILD_TYPE!" ) ENDIF(NOT CMAKE_BUILD_TYPE) PCH_SET_COMPILE_FLAGS(${_targetName}) IF(PCH_ARCHS) SET(PCH_OUTPUTS) FOREACH(_ARCH ${PCH_ARCHS}) STRING(TOUPPER "${_ARCH}" _UPPER_ARCH) PCH_SET_PRECOMPILED_HEADER_OUTPUT(${_targetName} ${_inputh} ${_ARCH} "") LIST(APPEND PCH_OUTPUTS ${PCH_OUTPUT}) PCH_SET_COMPILE_COMMAND(${_inputcpp} "${PCH_ARCH_${_UPPER_ARCH}_FLAGS};${PCH_FLAGS}") PCH_CREATE_TARGET(${_targetName} ${_targetName}_pch_${_ARCH}) ADD_PRECOMPILED_HEADER_TO_TARGET_ARCH(${_targetName} ${_ARCH}) ENDFOREACH(_ARCH) ELSE(PCH_ARCHS) PCH_SET_PRECOMPILED_HEADER_OUTPUT(${_targetName} ${_inputh} "" "") LIST(APPEND PCH_OUTPUTS ${PCH_OUTPUT}) PCH_SET_COMPILE_COMMAND(${_inputcpp} "${PCH_FLAGS}") PCH_CREATE_TARGET(${_targetName} ${_targetName}_pch) ENDIF(PCH_ARCHS) ADD_PRECOMPILED_HEADER_TO_TARGET(${_targetName}) SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PCH_OUTPUTS}") ENDMACRO(ADD_PRECOMPILED_HEADER) MACRO(ADD_NATIVE_PRECOMPILED_HEADER _targetName _inputh _inputcpp) IF(NOT PCHSupport_FOUND) MESSAGE(STATUS "PCH disabled because compiler doesn't support them") RETURN() ENDIF(NOT PCHSupport_FOUND) # 0 => creating a new target for PCH, works for all makefiles # 1 => setting PCH for VC++ project, works for VC++ projects # 2 => setting PCH for XCode project, works for XCode projects IF(CMAKE_GENERATOR MATCHES "Visual Studio") SET(PCH_METHOD 1) ELSEIF(CMAKE_GENERATOR MATCHES "Xcode") SET(PCH_METHOD 2) ELSE(CMAKE_GENERATOR MATCHES "Visual Studio") SET(PCH_METHOD 0) ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio") IF(PCH_METHOD EQUAL 1) # Auto include the precompile (useful for moc processing, since the use of # precompiled is specified at the target level # and I don't want to specifiy /F- for each moc/res/ui generated files (using Qt) GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS) IF(${oldProps} MATCHES NOTFOUND) SET(oldProps "") ENDIF(${oldProps} MATCHES NOTFOUND) SET(newProperties "${oldProps} /Yu\"${_inputh}\" /FI\"${_inputh}\"") SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS "${newProperties}") #also inlude ${oldProps} to have the same compile options SET_SOURCE_FILES_PROPERTIES(${_inputcpp} PROPERTIES COMPILE_FLAGS "${oldProps} /Yc\"${_inputh}\"") ELSEIF(PCH_METHOD EQUAL 2) # For Xcode, cmake needs my patch to process # GCC_PREFIX_HEADER and GCC_PRECOMPILE_PREFIX_HEADER as target properties # When buiding out of the tree, precompiled may not be located # Use full path instead. GET_FILENAME_COMPONENT(fullPath ${_inputh} ABSOLUTE) SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${fullPath}") SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES") ELSE(PCH_METHOD EQUAL 1) #Fallback to the "old" precompiled suppport ADD_PRECOMPILED_HEADER(${_targetName} ${_inputh} ${_inputcpp}) ENDIF(PCH_METHOD EQUAL 1) IF(TARGET ${_targetName}_static) ADD_NATIVE_PRECOMPILED_HEADER(${_targetName}_static ${_inputh} ${_inputcpp}) ENDIF(TARGET ${_targetName}_static) ENDMACRO(ADD_NATIVE_PRECOMPILED_HEADER) ================================================ FILE: code/CMakeModules/iOSToolChain.cmake ================================================ # This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake # files which are included with CMake 2.8.4 # It has been altered for iOS development # # Options: # # IOS_VERSION = last(default) or specific one (4.3, 5.0, 4.1) # This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders # OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. # SIMULATOR - used to build for the Simulator platforms, which have an x86 arch. # # IOS_PLATFORM = OS (default) or SIMULATOR or ALL # This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders # OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. # SIMULATOR - used to build for the Simulator platforms, which have an x86 arch. # # CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder # By default this location is automatcially chosen based on the IOS_PLATFORM value above. # If set manually, it will override the default location and force the user of a particular Developer Platform # # CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder # By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value. # In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path. # If set manually, this will force the use of a specific SDK version IF(DEFINED CMAKE_CROSSCOMPILING) # subsequent toolchain loading is not really needed RETURN() ENDIF() # Standard settings SET(CMAKE_SYSTEM_NAME Darwin) SET(CMAKE_SYSTEM_VERSION 1) # TODO: determine target Darwin version SET(UNIX ON) SET(APPLE ON) SET(IOS ON) # Force the compilers to Clang for iOS include (CMakeForceCompiler) CMAKE_FORCE_C_COMPILER (clang Clang) CMAKE_FORCE_CXX_COMPILER (clang++ Clang) # Setup iOS platform if (NOT DEFINED IOS_PLATFORM) set (IOS_PLATFORM "OS") endif (NOT DEFINED IOS_PLATFORM) set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") SET(IOS_PLATFORM_LOCATION "iPhoneOS.platform") SET(IOS_SIMULATOR_PLATFORM_LOCATION "iPhoneSimulator.platform") # Check the platform selection and setup for developer root if (${IOS_PLATFORM} STREQUAL "OS") # This causes the installers to properly locate the output libraries set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") # This causes the installers to properly locate the output libraries set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") elseif (${IOS_PLATFORM} STREQUAL "ALL") # This causes the installers to properly locate the output libraries set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator;-iphoneos") else (${IOS_PLATFORM} STREQUAL "OS") message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR") endif (${IOS_PLATFORM} STREQUAL "OS") set (CMAKE_XCODE_EFFECTIVE_PLATFORMS ${CMAKE_XCODE_EFFECTIVE_PLATFORMS} CACHE PATH "iOS Platform") # Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT # Note Xcode 4.3 changed the installation location, choose the most recent one available SET(XCODE_POST_43_ROOT "/Applications/Xcode.app/Contents/Developer/Platforms") SET(XCODE_PRE_43_ROOT "/Developer/Platforms") IF(NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) IF(EXISTS ${XCODE_POST_43_ROOT}) SET(CMAKE_XCODE_ROOT ${XCODE_POST_43_ROOT}) ELSEIF(EXISTS ${XCODE_PRE_43_ROOT}) SET(CMAKE_XCODE_ROOT ${XCODE_PRE_43_ROOT}) ENDIF(EXISTS ${XCODE_POST_43_ROOT}) IF(EXISTS ${CMAKE_XCODE_ROOT}/${IOS_PLATFORM_LOCATION}/Developer) SET(CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_XCODE_ROOT}/${IOS_PLATFORM_LOCATION}/Developer) ENDIF(EXISTS ${CMAKE_XCODE_ROOT}/${IOS_PLATFORM_LOCATION}/Developer) IF(EXISTS ${CMAKE_XCODE_ROOT}/${IOS_SIMULATOR_PLATFORM_LOCATION}/Developer) SET(CMAKE_IOS_SIMULATOR_DEVELOPER_ROOT ${CMAKE_XCODE_ROOT}/${IOS_SIMULATOR_PLATFORM_LOCATION}/Developer) ENDIF(EXISTS ${CMAKE_XCODE_ROOT}/${IOS_SIMULATOR_PLATFORM_LOCATION}/Developer) ENDIF(NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) SET(CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform") SET(CMAKE_IOS_SIMULATOR_DEVELOPER_ROOT ${CMAKE_IOS_SIMULATOR_DEVELOPER_ROOT} CACHE PATH "Location of iOS Simulator Platform") MACRO(GET_AVAILABLE_SDK_VERSIONS ROOT VERSIONS) FILE(GLOB _CMAKE_IOS_SDKS "${ROOT}/SDKs/iPhoneOS*") IF(_CMAKE_IOS_SDKS) LIST(SORT _CMAKE_IOS_SDKS) LIST(REVERSE _CMAKE_IOS_SDKS) FOREACH(_CMAKE_IOS_SDK ${_CMAKE_IOS_SDKS}) STRING(REGEX REPLACE ".+iPhoneOS([0-9.]+)\\.sdk" "\\1" _IOS_SDK "${_CMAKE_IOS_SDK}") LIST(APPEND ${VERSIONS} ${_IOS_SDK}) ENDFOREACH(_CMAKE_IOS_SDK) ENDIF(_CMAKE_IOS_SDKS) ENDMACRO(GET_AVAILABLE_SDK_VERSIONS) # Find and use the most recent iOS sdk IF(NOT DEFINED CMAKE_IOS_SDK_ROOT) # Search for a specific version of a SDK GET_AVAILABLE_SDK_VERSIONS(${CMAKE_IOS_DEVELOPER_ROOT} IOS_VERSIONS) IF(NOT IOS_VERSIONS) MESSAGE(FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.") ENDIF(NOT IOS_VERSIONS) IF(IOS_VERSION) LIST(FIND IOS_VERSIONS "${IOS_VERSION}" _INDEX) IF(_INDEX EQUAL -1) LIST(GET IOS_VERSIONS 0 IOS_SDK_VERSION) ELSE(_INDEX EQUAL -1) SET(IOS_SDK_VERSION ${IOS_VERSION}) ENDIF(_INDEX EQUAL -1) ELSE(IOS_VERSION) LIST(GET IOS_VERSIONS 0 IOS_VERSION) SET(IOS_SDK_VERSION ${IOS_VERSION}) ENDIF(IOS_VERSION) MESSAGE(STATUS "Target iOS ${IOS_VERSION} and use SDK ${IOS_SDK_VERSION}") SET(CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/iPhoneOS${IOS_SDK_VERSION}.sdk) SET(CMAKE_IOS_SIMULATOR_SDK_ROOT ${CMAKE_IOS_SIMULATOR_DEVELOPER_ROOT}/SDKs/iPhoneSimulator${IOS_SDK_VERSION}.sdk) endif (NOT DEFINED CMAKE_IOS_SDK_ROOT) SET(CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK") SET(CMAKE_IOS_SIMULATOR_SDK_ROOT ${CMAKE_IOS_SIMULATOR_SDK_ROOT} CACHE PATH "Location of the selected iOS Simulator SDK") SET(IOS_VERSION ${IOS_VERSION} CACHE STRING "iOS target version") # Set the sysroot default to the most recent SDK SET(CMAKE_IOS_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support") SET(CMAKE_IOS_SIMULATOR_SYSROOT ${CMAKE_IOS_SIMULATOR_SDK_ROOT} CACHE PATH "Sysroot used for iOS Simulator support") IF(CMAKE_GENERATOR MATCHES Xcode) SET(ARCHS "$(ARCHS_STANDARD_32_BIT)") IF(${IOS_PLATFORM} STREQUAL "OS") SET(CMAKE_SYSTEM_PROCESSOR "armv7") ELSEIF(${IOS_PLATFORM} STREQUAL "SIMULATOR") SET(CMAKE_SYSTEM_PROCESSOR "x86") ELSEIF(${IOS_PLATFORM} STREQUAL "ALL") SET(CMAKE_SYSTEM_PROCESSOR "armv7") ENDIF(${IOS_PLATFORM} STREQUAL "OS") ELSE(CMAKE_GENERATOR MATCHES Xcode) IF(${IOS_PLATFORM} STREQUAL "OS") SET(ARCHS "armv7") SET(CMAKE_SYSTEM_PROCESSOR "armv7") ELSEIF(${IOS_PLATFORM} STREQUAL "SIMULATOR") # iPhone simulator targets i386 SET(ARCHS "i386") SET(CMAKE_SYSTEM_PROCESSOR "x86") ELSEIF(${IOS_PLATFORM} STREQUAL "ALL") SET(ARCHS "armv7;i386") SET(CMAKE_SYSTEM_PROCESSOR "armv7") ENDIF(${IOS_PLATFORM} STREQUAL "OS") ENDIF(CMAKE_GENERATOR MATCHES Xcode) # set the architecture for iOS - using ARCHS_STANDARD_32_BIT sets armv7,armv7s and appears to be XCode's standard. # The other value that works is ARCHS_UNIVERSAL_IPHONE_OS but that sets armv7 only set (CMAKE_OSX_ARCHITECTURES ${ARCHS} CACHE string "Build architecture for iOS") # Set the find root to the iOS developer roots and to user defined paths set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} ${CMAKE_INSTALL_PREFIX} $ENV{EXTERNAL_IOS_PATH} CACHE string "iOS find search path root") # default to searching for frameworks first set (CMAKE_FIND_FRAMEWORK FIRST) # set up the default search directories for frameworks set (CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks ) # only search the iOS sdks, not the remainder of the host filesystem set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) #SET(CMAKE_SYSTEM_INCLUDE_PATH /include /usr/include) #SET(CMAKE_SYSTEM_LIBRARY_PATH /lib /usr/lib) #SET(CMAKE_SYSTEM_PROGRAM_PATH /bin /usr/bin) ================================================ FILE: code/CMakeModules/nel.cmake ================================================ # Force Release configuration for compiler checks SET(CMAKE_TRY_COMPILE_CONFIGURATION "Release") # Force Release configuration by default IF(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) ENDIF(NOT CMAKE_BUILD_TYPE) # Declare CMAKE_CONFIGURATION_TYPES before PROJECT SET(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) ### # Helper macro that generates .pc and installs it. # Argument: name - the name of the .pc package, e.g. "nel-pacs.pc" ### MACRO(NL_GEN_PC name) IF(NOT WIN32 AND WITH_INSTALL_LIBRARIES) CONFIGURE_FILE(${name}.in "${CMAKE_CURRENT_BINARY_DIR}/${name}") INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/${name}" DESTINATION ${NL_LIB_PREFIX}/pkgconfig) ENDIF(NOT WIN32 AND WITH_INSTALL_LIBRARIES) ENDMACRO(NL_GEN_PC) ### # Helper macro that generates revision.h from revision.h.in ### MACRO(NL_GEN_REVISION_H) IF(EXISTS ${CMAKE_SOURCE_DIR}/revision.h.in) SET(TOOL_FOUND OFF) IF(EXISTS "${CMAKE_SOURCE_DIR}/../.svn/") FIND_PACKAGE(Subversion) IF(SUBVERSION_FOUND) SET(TOOL_FOUND ON) ENDIF(SUBVERSION_FOUND) ENDIF(EXISTS "${CMAKE_SOURCE_DIR}/../.svn/") IF(EXISTS "${CMAKE_SOURCE_DIR}/../.hg/") FIND_PACKAGE(Mercurial) IF(MERCURIAL_FOUND) SET(TOOL_FOUND ON) ENDIF(MERCURIAL_FOUND) ENDIF(EXISTS "${CMAKE_SOURCE_DIR}/../.hg/") # if already generated IF(EXISTS ${CMAKE_SOURCE_DIR}/revision.h) # copy it MESSAGE(STATUS "Copying provided revision.h...") FILE(COPY ${CMAKE_SOURCE_DIR}/revision.h DESTINATION ${CMAKE_BINARY_DIR}) SET(HAVE_REVISION_H ON) ENDIF(EXISTS ${CMAKE_SOURCE_DIR}/revision.h) IF(TOOL_FOUND) # a custom target that is always built ADD_CUSTOM_TARGET(revision ALL COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR} -DROOT_DIR=${CMAKE_SOURCE_DIR}/.. -DCMAKE_MODULE_PATH=${CMAKE_SOURCE_DIR}/CMakeModules -P ${CMAKE_SOURCE_DIR}/CMakeModules/GetRevision.cmake) # revision.h is a generated file SET_SOURCE_FILES_PROPERTIES(${CMAKE_BINARY_DIR}/revision.h PROPERTIES GENERATED TRUE HEADER_FILE_ONLY TRUE) SET(HAVE_REVISION_H ON) ENDIF(TOOL_FOUND) IF(HAVE_REVISION_H) INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}) ADD_DEFINITIONS(-DHAVE_REVISION_H) ENDIF(HAVE_REVISION_H) ENDIF(EXISTS ${CMAKE_SOURCE_DIR}/revision.h.in) ENDMACRO(NL_GEN_REVISION_H) ### # ### MACRO(NL_TARGET_LIB name) IF(WITH_STATIC) ADD_LIBRARY(${name} STATIC ${ARGN}) ELSE(WITH_STATIC) ADD_LIBRARY(${name} SHARED ${ARGN}) ENDIF(WITH_STATIC) ENDMACRO(NL_TARGET_LIB) ### # ### MACRO(NL_TARGET_DRIVER name) IF(WITH_STATIC_DRIVERS) ADD_LIBRARY(${name} STATIC ${ARGN}) ELSE(WITH_STATIC_DRIVERS) ADD_LIBRARY(${name} MODULE ${ARGN}) ENDIF(WITH_STATIC_DRIVERS) ENDMACRO(NL_TARGET_DRIVER) ### # Helper macro that sets the default library properties. # Argument: name - the target name whose properties are being set # Argument: ### MACRO(NL_DEFAULT_PROPS name label) IF(HAVE_REVISION_H) # explicitly say that the target depends on revision.h ADD_DEPENDENCIES(${name} revision) ENDIF(HAVE_REVISION_H) # Note: This is just a workaround for a CMake bug generating VS10 files with a colon in the project name. # CMake Bug ID: http://www.cmake.org/Bug/view.php?id=11819 STRING(REGEX REPLACE "\\:" " -" proj_label ${label}) SET_TARGET_PROPERTIES(${name} PROPERTIES PROJECT_LABEL ${proj_label}) GET_TARGET_PROPERTY(type ${name} TYPE) IF(${type} STREQUAL SHARED_LIBRARY) # Set versions only if target is a shared library SET_TARGET_PROPERTIES(${name} PROPERTIES VERSION ${NL_VERSION} SOVERSION ${NL_VERSION_MAJOR}) IF(NL_LIB_PREFIX) SET_TARGET_PROPERTIES(${name} PROPERTIES INSTALL_NAME_DIR ${NL_LIB_PREFIX}) ENDIF(NL_LIB_PREFIX) ENDIF(${type} STREQUAL SHARED_LIBRARY) IF(${type} STREQUAL EXECUTABLE AND WIN32 AND NOT MINGW) SET_TARGET_PROPERTIES(${name} PROPERTIES VERSION ${NL_VERSION} SOVERSION ${NL_VERSION_MAJOR} COMPILE_FLAGS "/GA" LINK_FLAGS "/VERSION:${NL_VERSION_MAJOR}.${NL_VERSION_MINOR}") ENDIF(${type} STREQUAL EXECUTABLE AND WIN32 AND NOT MINGW) ENDMACRO(NL_DEFAULT_PROPS) ### # Adds the target suffix on Windows. # Argument: name - the library's target name. ### MACRO(NL_ADD_LIB_SUFFIX name) IF(WIN32) SET_TARGET_PROPERTIES(${name} PROPERTIES DEBUG_POSTFIX "_d" RELEASE_POSTFIX "_r") ENDIF(WIN32) ENDMACRO(NL_ADD_LIB_SUFFIX) ### # Adds the runtime link flags for Win32 binaries and links STLport. # Argument: name - the target to add the link flags to. ### MACRO(NL_ADD_RUNTIME_FLAGS name) IF(WIN32) # SET_TARGET_PROPERTIES(${name} PROPERTIES # LINK_FLAGS_DEBUG "${CMAKE_LINK_FLAGS_DEBUG}" # LINK_FLAGS_RELEASE "${CMAKE_LINK_FLAGS_RELEASE}") ENDIF(WIN32) IF(WITH_STLPORT) TARGET_LINK_LIBRARIES(${name} ${STLPORT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) ENDIF(WITH_STLPORT) ENDMACRO(NL_ADD_RUNTIME_FLAGS) MACRO(NL_ADD_STATIC_VID_DRIVERS name) IF(WITH_STATIC_DRIVERS) IF(WIN32) IF(WITH_DRIVER_DIRECT3D) TARGET_LINK_LIBRARIES(${name} nel_drv_direct3d_win) ENDIF(WITH_DRIVER_DIRECT3D) ENDIF(WIN32) IF(WITH_DRIVER_OPENGL) IF(WIN32) TARGET_LINK_LIBRARIES(${name} nel_drv_opengl_win) ELSE(WIN32) TARGET_LINK_LIBRARIES(${name} nel_drv_opengl) ENDIF(WIN32) ENDIF(WITH_DRIVER_OPENGL) IF(WITH_DRIVER_OPENGLES) IF(WIN32) TARGET_LINK_LIBRARIES(${name} nel_drv_opengles_win) ELSE(WIN32) TARGET_LINK_LIBRARIES(${name} nel_drv_opengles) ENDIF(WIN32) ENDIF(WITH_DRIVER_OPENGLES) ENDIF(WITH_STATIC_DRIVERS) ENDMACRO(NL_ADD_STATIC_VID_DRIVERS) MACRO(NL_ADD_STATIC_SND_DRIVERS name) IF(WITH_STATIC_DRIVERS) IF(WIN32) IF(WITH_DRIVER_DSOUND) TARGET_LINK_LIBRARIES(${name} nel_drv_dsound_win) ENDIF(WITH_DRIVER_DSOUND) IF(WITH_DRIVER_XAUDIO2) TARGET_LINK_LIBRARIES(${name} nel_drv_xaudio2_win) ENDIF(WITH_DRIVER_XAUDIO2) IF(WITH_DRIVER_OPENAL) TARGET_LINK_LIBRARIES(${name} nel_drv_openal_win) ENDIF(WITH_DRIVER_OPENAL) IF(WITH_DRIVER_FMOD) TARGET_LINK_LIBRARIES(${name} nel_drv_fmod_win) ENDIF(WITH_DRIVER_FMOD) ELSE(WIN32) IF(WITH_DRIVER_OPENAL) TARGET_LINK_LIBRARIES(${name} nel_drv_openal) ENDIF(WITH_DRIVER_OPENAL) IF(WITH_DRIVER_FMOD) TARGET_LINK_LIBRARIES(${name} nel_drv_fmod) ENDIF(WITH_DRIVER_FMOD) ENDIF(WIN32) ENDIF(WITH_STATIC_DRIVERS) ENDMACRO(NL_ADD_STATIC_SND_DRIVERS) ### # Checks build vs. source location. Prevents In-Source builds. ### MACRO(CHECK_OUT_OF_SOURCE) IF(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) MESSAGE(FATAL_ERROR " CMake generation for this project is not allowed within the source directory! Remove the CMakeCache.txt file and try again from another folder, e.g.: rm CMakeCache.txt mkdir cmake cd cmake cmake .. ") ENDIF(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) ENDMACRO(CHECK_OUT_OF_SOURCE) MACRO(NL_SETUP_DEFAULT_OPTIONS) ### # Features ### OPTION(WITH_LOGGING "With Logging" ON ) OPTION(WITH_COVERAGE "With Code Coverage Support" OFF) OPTION(WITH_PCH "With Precompiled Headers" ON ) OPTION(FINAL_VERSION "Build in Final Version mode" OFF) # Default to static building on Windows. #IF(WIN32) OPTION(WITH_STATIC "With static libraries." ON ) #ELSE(WIN32) # OPTION(WITH_STATIC "With static libraries." OFF) #ENDIF(WIN32) #IF (WITH_STATIC) OPTION(WITH_STATIC_LIBXML2 "With static libxml2" ON ) #ELSE(WITH_STATIC) # OPTION(WITH_STATIC_LIBXML2 "With static libxml2" OFF) #ENDIF(WITH_STATIC) OPTION(WITH_STATIC_DRIVERS "With static drivers." OFF) IF(WIN32) OPTION(WITH_EXTERNAL "With provided external." ON ) ELSE(WIN32) OPTION(WITH_EXTERNAL "With provided external." OFF) ENDIF(WIN32) OPTION(WITH_STATIC_EXTERNAL "With static external libraries" OFF) OPTION(WITH_INSTALL_LIBRARIES "Install development files." OFF) IF(WIN32) OPTION(WITH_GTK "With GTK Support" OFF) ELSE(WIN32) OPTION(WITH_GTK "With GTK Support" OFF) ENDIF(WIN32) ### # Optional support ### OPTION(WITH_SYMBOLS "Keep debug symbols in binaries" ON ) #IF(WIN32) OPTION(WITH_STLPORT "With STLport support." OFF ) #ELSE(WIN32) # OPTION(WITH_STLPORT "With STLport support." OFF) #ENDIF(WIN32) OPTION(BUILD_DASHBOARD "Build to the CDash dashboard" OFF) OPTION(WITH_NEL "Build NeL (nearly always required)." ON ) # OPTION(WITH_NELNS "Build NeL Network Services." OFF) OPTION(WITH_EVA "Build EVA." ON) OPTION(WITH_TOOLS "Build Tools." OFF) ENDMACRO(NL_SETUP_DEFAULT_OPTIONS) MACRO(NL_SETUP_NEL_DEFAULT_OPTIONS) ### # Core libraries ### OPTION(WITH_NET "Build NLNET" ON ) # OPTION(WITH_GEORGES "Build NLGEORGES" ON) # OPTION(WITH_LIGO "Build NLLIGO" OFF) # OPTION(WITH_LOGIC "Build NLLOGIC" OFF) ### # Optional support ### OPTION(WITH_NEL_TOOLS "Build NeL Tools" OFF) OPTION(WITH_NEL_SAMPLES "Build NeL Samples" OFF) OPTION(WITH_NEL_TESTS "Build NeL Unit Tests" OFF) #OPTION(WITH_LUA51 "Build EVA using Lua 5.1" ON ) #OPTION(WITH_LUA52 "Build EVA using Lua 5.2" OFF) OPTION(WITH_SSE2 "With SSE2" OFF ) OPTION(WITH_SSE3 "With SSE3" ON ) IF(NOT MSVC) OPTION(WITH_GCC_FPMATH_BOTH "With GCC -mfpmath=both" OFF) OPTION(WITH_GCC_FPERMISSIVE "With GCC -fpermissive" ON) ENDIF(NOT MSVC) ENDMACRO(NL_SETUP_NEL_DEFAULT_OPTIONS) MACRO(NL_SETUP_NELNS_DEFAULT_OPTIONS) ### # Core libraries ### #OPTION(WITH_NELNS_SERVER "Build NeLNS Services" OFF ) #OPTION(WITH_NELNS_LOGIN_SYSTEM "Build NeLNS Login System Tools" OFF ) ### # Optional support ### OPTION(WITH_ROBOT "Build Robot" OFF) ENDMACRO(NL_SETUP_NELNS_DEFAULT_OPTIONS) MACRO(ADD_PLATFORM_FLAGS _FLAGS) SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} ${_FLAGS}") SET(PLATFORM_CXXFLAGS "${PLATFORM_CXXFLAGS} ${_FLAGS}") ENDMACRO() MACRO(ADD_PLATFORM_LINKFLAGS _FLAGS) SET(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} ${_FLAGS}") ENDMACRO() MACRO(NL_SETUP_BUILD) #----------------------------------------------------------------------------- # Setup the buildmode variables. # # None = NL_RELEASE # Debug = NL_DEBUG # Release = NL_RELEASE IF(CMAKE_BUILD_TYPE MATCHES "Debug") SET(NL_BUILD_MODE "NL_DEBUG") ELSE() IF(CMAKE_BUILD_TYPE MATCHES "Release") SET(NL_BUILD_MODE "NL_RELEASE") ELSE() SET(NL_BUILD_MODE "NL_RELEASE") # enforce release mode if it's neither Debug nor Release SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) ENDIF() ENDIF() IF(CMAKE_CXX_LIBRARY_ARCHITECTURE) SET(HOST_CPU ${CMAKE_CXX_LIBRARY_ARCHITECTURE}) ELSE() SET(HOST_CPU ${CMAKE_HOST_SYSTEM_PROCESSOR}) ENDIF() IF(HOST_CPU MATCHES "(amd|AMD|x86_)64") SET(HOST_CPU "x86_64") ELSEIF(HOST_CPU MATCHES "i.86") SET(HOST_CPU "x86") ENDIF() # Determine target CPU # If not specified, use the same CPU as host IF(NOT TARGET_CPU) SET(TARGET_CPU ${HOST_CPU}) ENDIF() IF(TARGET_CPU MATCHES "(amd|AMD|x86_)64") SET(TARGET_CPU "x86_64") ELSEIF(TARGET_CPU MATCHES "i.86") SET(TARGET_CPU "x86") ENDIF() IF(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") SET(CLANG ON) MESSAGE(STATUS "Using Clang ${CMAKE_CXX_COMPILER_VERSION} compiler") ENDIF() IF(CMAKE_GENERATOR MATCHES "Xcode") SET(XCODE ON) MESSAGE(STATUS "Generating Xcode project") ENDIF() IF(CMAKE_GENERATOR MATCHES "NMake") SET(NMAKE ON) MESSAGE(STATUS "Generating NMake project") ENDIF() IF(CMAKE_GENERATOR MATCHES "Ninja") SET(NINJA ON) MESSAGE(STATUS "Generating Ninja project") ENDIF() # If target and host CPU are the same IF("${HOST_CPU}" STREQUAL "${TARGET_CPU}" AND NOT CMAKE_CROSSCOMPILING) # x86-compatible CPU IF(HOST_CPU MATCHES "x86") IF(NOT CMAKE_SIZEOF_VOID_P) INCLUDE (CheckTypeSize) CHECK_TYPE_SIZE("void*" CMAKE_SIZEOF_VOID_P) ENDIF() # Using 32 or 64 bits libraries IF(CMAKE_SIZEOF_VOID_P EQUAL 8) SET(TARGET_CPU "x86_64") ELSE() SET(TARGET_CPU "x86") ENDIF() ELSEIF(HOST_CPU MATCHES "arm") SET(TARGET_CPU "arm") ELSE() SET(TARGET_CPU "unknown") MESSAGE(STATUS "Unknown architecture: ${HOST_CPU}") ENDIF() # TODO: add checks for PPC ELSE() MESSAGE(STATUS "Compiling on ${HOST_CPU} for ${TARGET_CPU}") ENDIF() # Use values from environment variables SET(PLATFORM_CFLAGS "$ENV{CFLAGS} $ENV{CPPFLAGS} ${PLATFORM_CFLAGS}") SET(PLATFORM_CXXFLAGS "$ENV{CXXFLAGS} $ENV{CPPFLAGS} ${PLATFORM_CXXFLAGS}") SET(PLATFORM_LINKFLAGS "$ENV{LDFLAGS} ${PLATFORM_LINKFLAGS}") # Remove -g and -O flag because we are managing them ourself STRING(REPLACE "-g" "" PLATFORM_CFLAGS ${PLATFORM_CFLAGS}) STRING(REPLACE "-g" "" PLATFORM_CXXFLAGS ${PLATFORM_CXXFLAGS}) STRING(REGEX REPLACE "-O[0-9s]" "" PLATFORM_CFLAGS ${PLATFORM_CFLAGS}) STRING(REGEX REPLACE "-O[0-9s]" "" PLATFORM_CXXFLAGS ${PLATFORM_CXXFLAGS}) # Strip spaces STRING(STRIP ${PLATFORM_CFLAGS} PLATFORM_CFLAGS) STRING(STRIP ${PLATFORM_CXXFLAGS} PLATFORM_CXXFLAGS) STRING(STRIP ${PLATFORM_LINKFLAGS} PLATFORM_LINKFLAGS) IF(NOT CMAKE_OSX_ARCHITECTURES) IF(TARGET_CPU STREQUAL "x86_64") SET(TARGET_X64 1) SET(TARGET_X86 1) ELSEIF(TARGET_CPU STREQUAL "x86") SET(TARGET_X86 1) ELSEIF(TARGET_CPU STREQUAL "arm64") SET(TARGET_ARM 1) SET(TARGET_ARM64 1) ELSEIF(TARGET_CPU STREQUAL "armv7s") SET(TARGET_ARM 1) SET(TARGET_ARMV7S 1) ELSEIF(TARGET_CPU STREQUAL "armv7") SET(TARGET_ARM 1) SET(TARGET_ARMV7 1) ELSEIF(TARGET_CPU STREQUAL "armv6") SET(TARGET_ARM 1) SET(TARGET_ARMV6 1) ELSEIF(TARGET_CPU STREQUAL "armv5") SET(TARGET_ARM 1) SET(TARGET_ARMV5 1) ELSEIF(TARGET_CPU STREQUAL "arm") SET(TARGET_ARM 1) ELSEIF(TARGET_CPU STREQUAL "mips") SET(TARGET_MIPS 1) ENDIF() IF(TARGET_ARM) IF(TARGET_ARM64) ADD_PLATFORM_FLAGS("-DHAVE_ARM64") ENDIF() IF(TARGET_ARMV7S) ADD_PLATFORM_FLAGS("-DHAVE_ARMV7S") ENDIF() IF(TARGET_ARMV7) ADD_PLATFORM_FLAGS("-DHAVE_ARMV7") ENDIF() IF(TARGET_ARMV6) ADD_PLATFORM_FLAGS("-HAVE_ARMV6") ENDIF() ADD_PLATFORM_FLAGS("-DHAVE_ARM") ENDIF() IF(TARGET_X86) ADD_PLATFORM_FLAGS("-DHAVE_X86") ENDIF() IF(TARGET_X64) ADD_PLATFORM_FLAGS("-DHAVE_X64 -DHAVE_X86_64") ENDIF() IF(TARGET_MIPS) ADD_PLATFORM_FLAGS("-DHAVE_MIPS") ENDIF() ENDIF() # Fix library paths suffixes for Debian MultiArch IF(LIBRARY_ARCHITECTURE) SET(CMAKE_LIBRARY_PATH /lib/${LIBRARY_ARCHITECTURE} /usr/lib/${LIBRARY_ARCHITECTURE} ${CMAKE_LIBRARY_PATH}) IF(TARGET_X64) SET(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /lib64 /usr/lib64) ELSEIF(TARGET_X86) SET(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /lib32 /usr/lib32) ENDIF() ENDIF() IF(APPLE AND NOT IOS) SET(CMAKE_INCLUDE_PATH /opt/local/include ${CMAKE_INCLUDE_PATH}) SET(CMAKE_LIBRARY_PATH /opt/local/lib ${CMAKE_LIBRARY_PATH}) ENDIF() IF(WITH_LOGGING) ADD_PLATFORM_FLAGS("-DENABLE_LOGS") ENDIF() IF(MSVC) # Ignore default include paths ADD_PLATFORM_FLAGS("/X") IF(MSVC14) ADD_PLATFORM_FLAGS("/Gy-") # /Ox is working with VC++ 2015 and 2017, but custom optimizations don't exist SET(RELEASE_CFLAGS "/Ox /GF /GS- ${RELEASE_CFLAGS}") # without inlining it's unusable, use custom optimizations again SET(DEBUG_CFLAGS "/Od /Ob1 /GF- ${DEBUG_CFLAGS}") # Special cases for VC++ 2017 IF(MSVC_VERSION EQUAL "1911") SET(MSVC1411 ON) ELSEIF(MSVC_VERSION EQUAL "1910") SET(MSVC1410 ON) ENDIF() ELSEIF(MSVC12) ADD_PLATFORM_FLAGS("/Gy-") # /Ox is working with VC++ 2013, but custom optimizations don't exist SET(RELEASE_CFLAGS "/Ox /GF /GS- ${RELEASE_CFLAGS}") # without inlining it's unusable, use custom optimizations again SET(DEBUG_CFLAGS "/Od /Ob1 /GF- ${DEBUG_CFLAGS}") ELSEIF(MSVC11) ADD_PLATFORM_FLAGS("/Gy-") # /Ox is working with VC++ 2012, but custom optimizations don't exist SET(RELEASE_CFLAGS "/Ox /GF /GS- ${RELEASE_CFLAGS}") # without inlining it's unusable, use custom optimizations again SET(DEBUG_CFLAGS "/Od /Ob1 /GF- ${DEBUG_CFLAGS}") ELSEIF(MSVC10) ADD_PLATFORM_FLAGS("/Gy-") # /Ox is working with VC++ 2010, but custom optimizations don't exist SET(RELEASE_CFLAGS "/Ox /GF /GS- ${RELEASE_CFLAGS}") # without inlining it's unusable, use custom optimizations again SET(DEBUG_CFLAGS "/Od /Ob1 /GF- ${DEBUG_CFLAGS}") ELSEIF(MSVC90) ADD_PLATFORM_FLAGS("/Gy-") # don't use a /O[012x] flag if you want custom optimizations SET(RELEASE_CFLAGS "/Ob2 /Oi /Ot /Oy /GT /GF /GS- ${RELEASE_CFLAGS}") # without inlining it's unusable, use custom optimizations again SET(DEBUG_CFLAGS "/Ob1 /GF- ${DEBUG_CFLAGS}") ELSEIF(MSVC80) ADD_PLATFORM_FLAGS("/Gy- /Wp64") # don't use a /O[012x] flag if you want custom optimizations SET(RELEASE_CFLAGS "/Ox /GF /GS- ${RELEASE_CFLAGS}") # without inlining it's unusable, use custom optimizations again SET(DEBUG_CFLAGS "/Od /Ob1 ${DEBUG_CFLAGS}") ELSE() MESSAGE(FATAL_ERROR "Can't determine compiler version ${MSVC_VERSION}") ENDIF() ADD_PLATFORM_FLAGS("/D_CRT_SECURE_NO_DEPRECATE /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /D_SCL_SECURE_NO_WARNINGS /D_WIN32 /DWIN32 /D_WINDOWS /wd4250") # huge PCH ADD_PLATFORM_FLAGS("/Zm1000") IF(TARGET_X64) # Fix a bug with Intellisense ADD_PLATFORM_FLAGS("/D_WIN64") # Fix a compilation error for some big C++ files ADD_PLATFORM_FLAGS("/bigobj") ELSE() # Allows 32 bits applications to use 3 GB of RAM ADD_PLATFORM_LINKFLAGS("/LARGEADDRESSAWARE") ENDIF() # Exceptions are only set for C++ SET(PLATFORM_CXXFLAGS "${PLATFORM_CXXFLAGS} /EHa") IF(WITH_SYMBOLS) SET(NL_RELEASE_CFLAGS "/Zi ${NL_RELEASE_CFLAGS}") SET(NL_RELEASE_LINKFLAGS "/DEBUG ${NL_RELEASE_LINKFLAGS}") ELSE() SET(NL_RELEASE_LINKFLAGS "/RELEASE ${NL_RELEASE_LINKFLAGS}") ENDIF() SET(NL_DEBUG_CFLAGS "/Zi /MDd /RTC1 /D_DEBUG ${DEBUG_CFLAGS} ${NL_DEBUG_CFLAGS}") SET(NL_RELEASE_CFLAGS "/MD /DNDEBUG ${RELEASE_CFLAGS} ${NL_RELEASE_CFLAGS}") SET(NL_DEBUG_LINKFLAGS "/DEBUG /OPT:NOREF /OPT:NOICF /NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib ${MSVC_INCREMENTAL_YES_FLAG} ${NL_DEBUG_LINKFLAGS}") SET(NL_RELEASE_LINKFLAGS "/OPT:REF /OPT:ICF /INCREMENTAL:NO /NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib ${NL_RELEASE_LINKFLAGS}") IF(WITH_WARNINGS) SET(DEBUG_CFLAGS "/W4 ${DEBUG_CFLAGS}") ELSE() SET(DEBUG_CFLAGS "/W3 ${DEBUG_CFLAGS}") ENDIF() ELSE() IF(WIN32) ADD_PLATFORM_FLAGS("-DWIN32 -D_WIN32") IF(CLANG) ADD_PLATFORM_FLAGS("-nobuiltininc") ENDIF() ENDIF() IF(WITH_SSE3) ADD_PLATFORM_FLAGS("-msse3") ENDIF() IF(WITH_GCC_FPMATH_BOTH) ADD_PLATFORM_FLAGS("-mfpmath=both") ENDIF() IF(WITH_GCC_FPERMISSIVE) ADD_PLATFORM_FLAGS("-fpermissive") ENDIF() IF(APPLE) SET(OBJC_FLAGS -fobjc-abi-version=2 -fobjc-legacy-dispatch -fobjc-weak) IF(NOT XCODE) IF(CMAKE_OSX_ARCHITECTURES) SET(TARGETS_COUNT 0) SET(_ARCHS) FOREACH(_ARCH ${CMAKE_OSX_ARCHITECTURES}) IF(_ARCH STREQUAL "i386") SET(_ARCHS "${_ARCHS} i386") SET(TARGET_X86 1) MATH(EXPR TARGETS_COUNT "${TARGETS_COUNT}+1") ELSEIF(_ARCH STREQUAL "x86_64") SET(_ARCHS "${_ARCHS} x86_64") SET(TARGET_X64 1) MATH(EXPR TARGETS_COUNT "${TARGETS_COUNT}+1") ELSEIF(_ARCH STREQUAL "armv7s") SET(_ARCHS "${_ARCHS} armv7s") SET(TARGET_ARMV7S 1) SET(TARGET_ARM 1) MATH(EXPR TARGETS_COUNT "${TARGETS_COUNT}+1") ELSEIF(_ARCH STREQUAL "armv7") SET(_ARCHS "${_ARCHS} armv7") SET(TARGET_ARMV7 1) SET(TARGET_ARM 1) MATH(EXPR TARGETS_COUNT "${TARGETS_COUNT}+1") ELSEIF(_ARCH STREQUAL "armv6") SET(_ARCHS "${_ARCHS} armv6") SET(TARGET_ARMV6 1) SET(TARGET_ARM 1) MATH(EXPR TARGETS_COUNT "${TARGETS_COUNT}+1") ELSEIF(_ARCH STREQUAL "mips") SET(_ARCHS "${_ARCHS} mips") SET(TARGET_MIPS 1) MATH(EXPR TARGETS_COUNT "${TARGETS_COUNT}+1") ELSE() SET(_ARCHS "${_ARCHS} unknwon(${_ARCH})") ENDIF() ENDFOREACH(_ARCH) MESSAGE(STATUS "Compiling under Mac OS X for ${TARGETS_COUNT} architectures: ${_ARCHS}") ELSE() SET(TARGETS_COUNT 0) ENDIF() IF(TARGETS_COUNT EQUAL 1) IF(TARGET_ARM) IF(TARGET_ARMV7S) ADD_PLATFORM_FLAGS("-arch armv7s -DHAVE_ARMV7S") ENDIF() IF(TARGET_ARMV7) ADD_PLATFORM_FLAGS("-arch armv7 -DHAVE_ARMV7") ENDIF() IF(TARGET_ARMV6) ADD_PLATFORM_FLAGS("-arch armv6 -DHAVE_ARMV6") ENDIF() IF(TARGET_ARMV5) ADD_PLATFORM_FLAGS("-arch armv5 -DHAVE_ARMV5") ENDIF() ADD_PLATFORM_FLAGS("-mthumb -DHAVE_ARM") ENDIF() IF(TARGET_X64) ADD_PLATFORM_FLAGS("-arch x86_64 -DHAVE_X64 -DHAVE_X86_64 -DHAVE_X86") ELSEIF(TARGET_X86) ADD_PLATFORM_FLAGS("-arch i386 -DHAVE_X86") ENDIF() IF(TARGET_MIPS) ADD_PLATFORM_FLAGS("-arch mips -DHAVE_MIPS") ENDIF() ELSEIF(TARGETS_COUNT EQUAL 0) # Not using CMAKE_OSX_ARCHITECTURES, HAVE_XXX already defined before IF(TARGET_ARM) IF(TARGET_ARMV7S) ADD_PLATFORM_FLAGS("-arch armv7s") ENDIF() IF(TARGET_ARMV7) ADD_PLATFORM_FLAGS("-arch armv7") ENDIF() IF(TARGET_ARMV6) ADD_PLATFORM_FLAGS("-arch armv6") ENDIF() IF(TARGET_ARMV5) ADD_PLATFORM_FLAGS("-arch armv5") ENDIF() ADD_PLATFORM_FLAGS("-mthumb") ENDIF() IF(TARGET_X64) ADD_PLATFORM_FLAGS("-arch x86_64") ELSEIF(TARGET_X86) ADD_PLATFORM_FLAGS("-arch i386") ENDIF() IF(TARGET_MIPS) ADD_PLATFORM_FLAGS("-arch mips") ENDIF() ELSE() IF(TARGET_ARMV6) ADD_PLATFORM_FLAGS("-Xarch_armv6 -mthumb -Xarch_armv6 -DHAVE_ARM -Xarch_armv6 -DHAVE_ARMV6") ENDIF() IF(TARGET_ARMV7) ADD_PLATFORM_FLAGS("-Xarch_armv7 -mthumb -Xarch_armv7 -DHAVE_ARM -Xarch_armv7 -DHAVE_ARMV7") ENDIF() IF(TARGET_X86) ADD_PLATFORM_FLAGS("-Xarch_i386 -DHAVE_X86") ENDIF() IF(TARGET_X64) ADD_PLATFORM_FLAGS("-Xarch_x86_64 -DHAVE_X64 -Xarch_x86_64 -DHAVE_X86_64") ENDIF() IF(TARGET_MIPS) ADD_PLATFORM_FLAGS("-Xarch_mips -DHAVE_MIPS") ENDIF() ENDIF() IF(IOS) SET(CMAKE_OSX_SYSROOT "" CACHE PATH "" FORCE) IF(IOS_VERSION) PARSE_VERSION_STRING(${IOS_VERSION} IOS_VERSION_MAJOR IOS_VERSION_MINOR IOS_VERSION_PATCH) CONVERT_VERSION_NUMBER(${IOS_VERSION_MAJOR} ${IOS_VERSION_MINOR} ${IOS_VERSION_PATCH} IOS_VERSION_NUMBER) ADD_PLATFORM_FLAGS("-D__IPHONE_OS_VERSION_MIN_REQUIRED=${IOS_VERSION_NUMBER}") ENDIF() IF(CMAKE_IOS_SYSROOT) IF(TARGET_ARMV7S) IF(TARGETS_COUNT GREATER 1) SET(XARCH "-Xarch_armv7s ") ENDIF() ADD_PLATFORM_FLAGS("${XARCH}-isysroot${CMAKE_IOS_SYSROOT}") ADD_PLATFORM_FLAGS("${XARCH}-miphoneos-version-min=${IOS_VERSION}") ADD_PLATFORM_LINKFLAGS("${XARCH}-Wl,-iphoneos_version_min,${IOS_VERSION}") ENDIF() IF(TARGET_ARMV7) IF(TARGETS_COUNT GREATER 1) SET(XARCH "-Xarch_armv7 ") ENDIF() ADD_PLATFORM_FLAGS("${XARCH}-isysroot${CMAKE_IOS_SYSROOT}") ADD_PLATFORM_FLAGS("${XARCH}-miphoneos-version-min=${IOS_VERSION}") ADD_PLATFORM_LINKFLAGS("${XARCH}-Wl,-iphoneos_version_min,${IOS_VERSION}") ENDIF() IF(TARGET_ARMV6) IF(TARGETS_COUNT GREATER 1) SET(XARCH "-Xarch_armv6 ") ENDIF() ADD_PLATFORM_FLAGS("${XARCH}-isysroot${CMAKE_IOS_SYSROOT}") ADD_PLATFORM_FLAGS("${XARCH}-miphoneos-version-min=${IOS_VERSION}") ADD_PLATFORM_LINKFLAGS("${XARCH}-Wl,-iphoneos_version_min,${IOS_VERSION}") ENDIF() ENDIF() IF(CMAKE_IOS_SIMULATOR_SYSROOT AND TARGET_X86) IF(TARGETS_COUNT GREATER 1) SET(XARCH "-Xarch_i386 ") ENDIF() ADD_PLATFORM_FLAGS("${XARCH}-isysroot${CMAKE_IOS_SIMULATOR_SYSROOT}") ADD_PLATFORM_FLAGS("${XARCH}-mios-simulator-version-min=${IOS_VERSION}") IF(CMAKE_OSX_DEPLOYMENT_TARGET) ADD_PLATFORM_LINKFLAGS("${XARCH}-Wl,-macosx_version_min,${CMAKE_OSX_DEPLOYMENT_TARGET}") ENDIF() ENDIF() ELSE() # Always force -mmacosx-version-min to override environement variable IF(CMAKE_OSX_DEPLOYMENT_TARGET) IF(CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS "10.7") MESSAGE(FATAL_ERROR "Minimum target for OS X is 10.7 but you're using ${CMAKE_OSX_DEPLOYMENT_TARGET}") ENDIF() ADD_PLATFORM_LINKFLAGS("-Wl,-macosx_version_min,${CMAKE_OSX_DEPLOYMENT_TARGET}") ENDIF() ENDIF() # use libc++ under OX X to be able to use new C++ features (and else it'll use GCC 4.2.1 STL) # minimum target is now OS X 10.7 SET(PLATFORM_CXXFLAGS "${PLATFORM_CXXFLAGS} -stdlib=libc++") ADD_PLATFORM_LINKFLAGS("-Wl,-headerpad_max_install_names") IF(HAVE_FLAG_SEARCH_PATHS_FIRST) ADD_PLATFORM_LINKFLAGS("-Wl,-search_paths_first") ENDIF() ENDIF() ELSE() IF(HOST_CPU STREQUAL "x86_64" AND TARGET_CPU STREQUAL "x86") ADD_PLATFORM_FLAGS("-m32 -march=i686") ENDIF() IF(HOST_CPU STREQUAL "x86" AND TARGET_CPU STREQUAL "x86_64") ADD_PLATFORM_FLAGS("-m64") ENDIF() ENDIF() # use c++0x standard to use std::unique_ptr and std::shared_ptr SET(PLATFORM_CXXFLAGS "${PLATFORM_CXXFLAGS} -std=c++0x") ADD_PLATFORM_FLAGS("-D_REENTRANT") # hardening ADD_PLATFORM_FLAGS("-D_FORTIFY_SOURCE=2") IF(NOT WITH_LOW_MEMORY) ADD_PLATFORM_FLAGS("-pipe") ENDIF() IF(WITH_COVERAGE) ADD_PLATFORM_FLAGS("-fprofile-arcs -ftest-coverage") ENDIF() IF(WITH_WARNINGS) ADD_PLATFORM_FLAGS("-Wall") ELSE() # Check wrong formats in printf-like functions ADD_PLATFORM_FLAGS("-Wformat -Werror=format-security") ENDIF() # never display these warnings because they are minor ADD_PLATFORM_FLAGS("-Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-value") IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "6.0.0") ADD_PLATFORM_FLAGS("-Wno-unused-local-typedefs") ELSEIF(CLANG) ADD_PLATFORM_FLAGS("-Wno-unused-private-field -Wno-unused-local-typedef") ENDIF() IF(ANDROID) ADD_PLATFORM_FLAGS("--sysroot=${PLATFORM_ROOT}") ADD_PLATFORM_FLAGS("-ffunction-sections -funwind-tables") ADD_PLATFORM_FLAGS("-DANDROID") ADD_PLATFORM_FLAGS("-Wa,--noexecstack") IF(TARGET_ARM) ADD_PLATFORM_FLAGS("-fpic") ADD_PLATFORM_FLAGS("-D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__") IF(TARGET_ARMV7) ADD_PLATFORM_FLAGS("-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16") ADD_PLATFORM_LINKFLAGS("-march=armv7-a -Wl,--fix-cortex-a8") ELSEIF(TARGET_ARMV5) ADD_PLATFORM_FLAGS("-march=armv5te -mtune=xscale -msoft-float") ENDIF() SET(TARGET_THUMB ON) IF(TARGET_THUMB) ADD_PLATFORM_FLAGS("-mthumb -finline-limit=64") SET(DEBUG_CFLAGS "${DEBUG_CFLAGS} -marm") ELSE() ADD_PLATFORM_FLAGS("-funswitch-loops -finline-limit=300") ENDIF() ELSEIF(TARGET_X86) # Optimizations for Intel Atom ADD_PLATFORM_FLAGS("-march=i686 -mtune=atom -mstackrealign -msse3 -mfpmath=sse -m32 -flto -ffast-math -funroll-loops") ADD_PLATFORM_FLAGS("-funswitch-loops -finline-limit=300") ELSEIF(TARGET_MIPS) ADD_PLATFORM_FLAGS("-fpic -finline-functions -fmessage-length=0 -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers") SET(RELEASE_CFLAGS "${RELEASE_CFLAGS} -funswitch-loops -finline-limit=300") ENDIF() ADD_PLATFORM_LINKFLAGS("-Wl,-z,noexecstack") ADD_PLATFORM_LINKFLAGS("-L${PLATFORM_ROOT}/usr/lib") ENDIF() IF(APPLE) ADD_PLATFORM_FLAGS("-gdwarf-2 -D_DARWIN_UNLIMITED_STREAMS") ENDIF() # Fix "relocation R_X86_64_32 against.." error on x64 platforms IF(NOT MINGW) ADD_PLATFORM_FLAGS("-fPIC") ENDIF() SET(PLATFORM_CXXFLAGS "${PLATFORM_CXXFLAGS} -ftemplate-depth-48") # hardening ADD_PLATFORM_FLAGS("-fstack-protector --param=ssp-buffer-size=4") # If -fstack-protector or -fstack-protector-all enabled, enable too new warnings and fix possible link problems IF(WITH_WARNINGS) ADD_PLATFORM_FLAGS("-Wstack-protector") ENDIF() # Fix undefined reference to `__stack_chk_fail' error ADD_PLATFORM_LINKFLAGS("-lc") IF(NOT APPLE) ADD_PLATFORM_LINKFLAGS("-Wl,--no-undefined -Wl,--as-needed") ENDIF() IF(NOT APPLE) # hardening ADD_PLATFORM_LINKFLAGS("-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now") ENDIF() IF(WITH_SYMBOLS) SET(NL_RELEASE_CFLAGS "${NL_RELEASE_CFLAGS} -g") ELSE() IF(APPLE) SET(NL_RELEASE_LINKFLAGS "-Wl,-dead_strip ${NL_RELEASE_LINKFLAGS}") ELSE() SET(NL_RELEASE_LINKFLAGS "-Wl,-s ${NL_RELEASE_LINKFLAGS}") ENDIF() ENDIF() SET(NL_DEBUG_CFLAGS "-g -DNL_DEBUG -D_DEBUG ${NL_DEBUG_CFLAGS}") SET(NL_RELEASE_CFLAGS "-DNL_RELEASE -DNDEBUG -O3 ${NL_RELEASE_CFLAGS}") ENDIF() ENDMACRO() MACRO(NL_SETUP_BUILD_FLAGS) SET(CMAKE_C_FLAGS ${PLATFORM_CFLAGS} CACHE STRING "" FORCE) SET(CMAKE_CXX_FLAGS ${PLATFORM_CXXFLAGS} CACHE STRING "" FORCE) SET(CMAKE_EXE_LINKER_FLAGS ${PLATFORM_LINKFLAGS} CACHE STRING "" FORCE) SET(CMAKE_MODULE_LINKER_FLAGS ${PLATFORM_LINKFLAGS} CACHE STRING "" FORCE) SET(CMAKE_SHARED_LINKER_FLAGS ${PLATFORM_LINKFLAGS} CACHE STRING "" FORCE) ## Debug SET(CMAKE_C_FLAGS_DEBUG ${NL_DEBUG_CFLAGS} CACHE STRING "" FORCE) SET(CMAKE_CXX_FLAGS_DEBUG ${NL_DEBUG_CFLAGS} CACHE STRING "" FORCE) SET(CMAKE_EXE_LINKER_FLAGS_DEBUG ${NL_DEBUG_LINKFLAGS} CACHE STRING "" FORCE) SET(CMAKE_MODULE_LINKER_FLAGS_DEBUG ${NL_DEBUG_LINKFLAGS} CACHE STRING "" FORCE) SET(CMAKE_SHARED_LINKER_FLAGS_DEBUG ${NL_DEBUG_LINKFLAGS} CACHE STRING "" FORCE) ## Release SET(CMAKE_C_FLAGS_RELEASE ${NL_RELEASE_CFLAGS} CACHE STRING "" FORCE) SET(CMAKE_CXX_FLAGS_RELEASE ${NL_RELEASE_CFLAGS} CACHE STRING "" FORCE) SET(CMAKE_EXE_LINKER_FLAGS_RELEASE ${NL_RELEASE_LINKFLAGS} CACHE STRING "" FORCE) SET(CMAKE_MODULE_LINKER_FLAGS_RELEASE ${NL_RELEASE_LINKFLAGS} CACHE STRING "" FORCE) SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE ${NL_RELEASE_LINKFLAGS} CACHE STRING "" FORCE) ENDMACRO(NL_SETUP_BUILD_FLAGS) # Macro to create x_ABSOLUTE_PREFIX from x_PREFIX MACRO(NL_MAKE_ABSOLUTE_PREFIX NAME_RELATIVE NAME_ABSOLUTE) IF(IS_ABSOLUTE "${${NAME_RELATIVE}}") SET(${NAME_ABSOLUTE} ${${NAME_RELATIVE}}) ELSE() IF(WITH_UNIX_STRUCTURE) SET(${NAME_ABSOLUTE} ${CMAKE_INSTALL_PREFIX}/${${NAME_RELATIVE}}) ELSE() SET(${NAME_ABSOLUTE} ${${NAME_RELATIVE}}) ENDIF() ENDIF() ENDMACRO(NL_MAKE_ABSOLUTE_PREFIX) MACRO(NL_SETUP_PREFIX_PATHS) ## Allow override of install_prefix/etc path. IF(NOT NL_ETC_PREFIX) IF(WITH_UNIX_STRUCTURE) SET(NL_ETC_PREFIX "etc/nel" CACHE PATH "Installation path for configurations") ELSE() SET(NL_ETC_PREFIX "." CACHE PATH "Installation path for configurations") ENDIF() ENDIF() NL_MAKE_ABSOLUTE_PREFIX(NL_ETC_PREFIX NL_ETC_ABSOLUTE_PREFIX) ## Allow override of install_prefix/share path. IF(NOT NL_SHARE_PREFIX) IF(WITH_UNIX_STRUCTURE) SET(NL_SHARE_PREFIX "share/nel" CACHE PATH "Installation path for data.") ELSE() SET(NL_SHARE_PREFIX "." CACHE PATH "Installation path for data.") ENDIF() ENDIF() NL_MAKE_ABSOLUTE_PREFIX(NL_SHARE_PREFIX NL_SHARE_ABSOLUTE_PREFIX) ## Allow override of install_prefix/sbin path. IF(NOT NL_SBIN_PREFIX) IF(WITH_UNIX_STRUCTURE) SET(NL_SBIN_PREFIX "sbin" CACHE PATH "Installation path for admin tools and services.") ELSE() SET(NL_SBIN_PREFIX "." CACHE PATH "Installation path for admin tools and services.") ENDIF() ENDIF() NL_MAKE_ABSOLUTE_PREFIX(NL_SBIN_PREFIX NL_SBIN_ABSOLUTE_PREFIX) ## Allow override of install_prefix/bin path. IF(NOT NL_BIN_PREFIX) IF(WITH_UNIX_STRUCTURE) SET(NL_BIN_PREFIX "bin" CACHE PATH "Installation path for tools and applications.") ELSE() SET(NL_BIN_PREFIX "." CACHE PATH "Installation path for tools and applications.") ENDIF() ENDIF() NL_MAKE_ABSOLUTE_PREFIX(NL_BIN_PREFIX NL_BIN_ABSOLUTE_PREFIX) ## Allow override of install_prefix/lib path. IF(NOT NL_LIB_PREFIX) IF(LIBRARY_ARCHITECTURE) SET(NL_LIB_PREFIX "lib/${LIBRARY_ARCHITECTURE}" CACHE PATH "Installation path for libraries.") ELSE() SET(NL_LIB_PREFIX "lib" CACHE PATH "Installation path for libraries.") ENDIF() ENDIF() NL_MAKE_ABSOLUTE_PREFIX(NL_LIB_PREFIX NL_LIB_ABSOLUTE_PREFIX) ## Allow override of install_prefix/lib path. IF(NOT NL_DRIVER_PREFIX) IF(WITH_UNIX_STRUCTURE) IF(LIBRARY_ARCHITECTURE) SET(NL_DRIVER_PREFIX "lib/${LIBRARY_ARCHITECTURE}/nel" CACHE PATH "Installation path for drivers.") ELSE() SET(NL_DRIVER_PREFIX "lib/nel" CACHE PATH "Installation path for drivers.") ENDIF() ELSE() SET(NL_DRIVER_PREFIX "." CACHE PATH "Installation path for drivers.") ENDIF() ENDIF() NL_MAKE_ABSOLUTE_PREFIX(NL_DRIVER_PREFIX NL_DRIVER_ABSOLUTE_PREFIX) ENDMACRO(NL_SETUP_PREFIX_PATHS) MACRO(EVA_SETUP_PREFIX_PATHS) ## Allow override of install_prefix/etc path. IF(NOT EVA_ETC_PREFIX) IF(WITH_UNIX_STRUCTURE) SET(EVA_ETC_PREFIX "etc/ryzom" CACHE PATH "Installation path for configurations") ELSE() SET(EVA_ETC_PREFIX "." CACHE PATH "Installation path for configurations") ENDIF() ENDIF() NL_MAKE_ABSOLUTE_PREFIX(EVA_ETC_PREFIX EVA_ETC_ABSOLUTE_PREFIX) ## Allow override of install_prefix/share path. IF(NOT EVA_SHARE_PREFIX) IF(WITH_UNIX_STRUCTURE) SET(EVA_SHARE_PREFIX "share/ryzom" CACHE PATH "Installation path for data.") ELSE() SET(EVA_SHARE_PREFIX "." CACHE PATH "Installation path for data.") ENDIF() ENDIF() NL_MAKE_ABSOLUTE_PREFIX(EVA_SHARE_PREFIX EVA_SHARE_ABSOLUTE_PREFIX) ## Allow override of install_prefix/sbin path. IF(NOT EVA_SBIN_PREFIX) IF(WITH_UNIX_STRUCTURE) SET(EVA_SBIN_PREFIX "sbin" CACHE PATH "Installation path for admin tools and services.") ELSE() SET(EVA_SBIN_PREFIX "." CACHE PATH "Installation path for admin tools and services.") ENDIF() ENDIF() NL_MAKE_ABSOLUTE_PREFIX(EVA_SBIN_PREFIX EVA_SBIN_ABSOLUTE_PREFIX) ## Allow override of install_prefix/bin path. IF(NOT EVA_BIN_PREFIX) IF(WITH_UNIX_STRUCTURE) SET(EVA_BIN_PREFIX "bin" CACHE PATH "Installation path for tools.") ELSE() SET(EVA_BIN_PREFIX "." CACHE PATH "Installation path for tools and applications.") ENDIF() ENDIF() NL_MAKE_ABSOLUTE_PREFIX(EVA_BIN_PREFIX EVA_BIN_ABSOLUTE_PREFIX) ## Allow override of install_prefix/lib path. IF(NOT EVA_LIB_PREFIX) IF(LIBRARY_ARCHITECTURE) SET(EVA_LIB_PREFIX "lib/${LIBRARY_ARCHITECTURE}" CACHE PATH "Installation path for libraries.") ELSE() SET(EVA_LIB_PREFIX "lib" CACHE PATH "Installation path for libraries.") ENDIF() ENDIF() NL_MAKE_ABSOLUTE_PREFIX(EVA_LIB_PREFIX EVA_LIB_ABSOLUTE_PREFIX) ## Allow override of install_prefix/games path. IF(NOT EVA_GAMES_PREFIX) IF(WITH_UNIX_STRUCTURE) SET(EVA_GAMES_PREFIX "games" CACHE PATH "Installation path for client.") ELSE() SET(EVA_GAMES_PREFIX "." CACHE PATH "Installation path for tools and applications.") ENDIF() ENDIF() NL_MAKE_ABSOLUTE_PREFIX(EVA_GAMES_PREFIX EVA_GAMES_ABSOLUTE_PREFIX) ENDMACRO(EVA_SETUP_PREFIX_PATHS) MACRO(SETUP_EXTERNAL) IF(WITH_EXTERNAL) FIND_PACKAGE(External REQUIRED) ENDIF() IF(WIN32) FIND_PACKAGE(External REQUIRED) # If using custom boost, we need to define the right variables used by official boost CMake module IF(DEFINED BOOST_DIR) SET(BOOST_INCLUDEDIR ${BOOST_DIR}/include) SET(BOOST_LIBRARYDIR ${BOOST_DIR}/lib) ENDIF() ELSE() FIND_PACKAGE(External QUIET) IF(APPLE) IF(WITH_STATIC_EXTERNAL) # Look only for static libraries because systems libraries are using Frameworks SET(CMAKE_FIND_LIBRARY_SUFFIXES .a) ELSE() SET(CMAKE_FIND_LIBRARY_SUFFIXES .dylib .so .a) ENDIF() ELSE() IF(WITH_STATIC_EXTERNAL) SET(CMAKE_FIND_LIBRARY_SUFFIXES .a .so) ELSE() SET(CMAKE_FIND_LIBRARY_SUFFIXES .so .a) ENDIF() ENDIF() ENDIF() # Android, iOS and Mac OS X have pthread, but no need to link to libpthread IF(ANDROID OR APPLE) SET(CMAKE_USE_PTHREADS_INIT 1) SET(Threads_FOUND TRUE) ELSE() SET(THREADS_HAVE_PTHREAD_ARG ON) FIND_PACKAGE(Threads) # TODO: replace all -l by absolute path to in CMAKE_THREAD_LIBS_INIT ENDIF() IF(WITH_STLPORT) FIND_PACKAGE(STLport REQUIRED) INCLUDE_DIRECTORIES(${STLPORT_INCLUDE_DIR}) ENDIF() IF(WIN32) # Must include DXSDK before WINSDK #FIND_PACKAGE(DirectXSDK REQUIRED) # IF(DXSDK_INCLUDE_DIR) # INCLUDE_DIRECTORIES(${DXSDK_INCLUDE_DIR}) # ENDIF() ENDIF() IF(MSVC) FIND_PACKAGE(MSVC REQUIRED) FIND_PACKAGE(WindowsSDK REQUIRED) ENDIF() ENDMACRO(SETUP_EXTERNAL) ================================================ FILE: code/CMakePackaging.txt ================================================ cpack_add_install_type(Full DISPLAY_NAME "Full Install") cpack_add_install_type(Developer DISPLAY_NAME "Developer Install") cpack_add_install_type(Runtime DISPLAY_NAME "Runtime Files") cpack_add_component_group(Drivers EXPANDED DESCRPTION "The drivers needed to run NeL-based software.") cpack_add_component_group(Samples EXPANDED DESCRPTION "Sample applications and configurations demonstrating NeL.") cpack_add_component_group(Tools EXPANDED DESCRPTION "Tools for NeL development and media creation.") ############### # # # Development # # # ############### cpack_add_component(libraries DISPLAY_NAME "Libraries" DESCRIPTION "Libraries used to build programs with NeL" GROUP Development INSTALL_TYPES Full Developer) cpack_add_component(headers DISPLAY_NAME "C++ Headers" DESCRIPTION "C++ headers used to build programs with NeL" GROUP Development INSTALL_TYPES Full Developer) ########### # # # Drivers # # # ########### cpack_add_component(drivers3d DISPLAY_NAME "3D Drivers" DESCRIPTION "3D Drivers for running NeL based applications." GROUP Drivers INSTALL_TYPES Full Runtime) cpack_add_component(driverssound DISPLAY_NAME "Sound Drivers" DESCRIPTION "Sound Drivers for running NeL based applications." GROUP Drivers INSTALL_TYPES Full Runtime) ######### # # # Tools # # # ######### cpack_add_component(toolsmisc DISPLAY_NAME "Misc Tools" DESCRIPTION "Misc. NeL Tools" GROUP Tools INSTALL_TYPES Full Runtime) cpack_add_component(tools3d DISPLAY_NAME "3D Tools" DESCRIPTION "3D NeL Tools" GROUP Tools INSTALL_TYPES Full Runtime) cpack_add_component(toolsgeorges DISPLAY_NAME "Georges Tools" DESCRIPTION "NeL Georges Tools" GROUP Tools INSTALL_TYPES Full Runtime) cpack_add_component(toolspacs DISPLAY_NAME "PACS Tools" DESCRIPTION "NeL PACS Tools" GROUP Tools INSTALL_TYPES Full Runtime) ########### # # # Samples # # # ########### cpack_add_component(samplespacs DISPLAY_NAME "PACS Samples" DESCRIPTION "Sample applications demonstrating the PACS collision library." GROUP Samples INSTALL_TYPES Full) cpack_add_component(samples3d DISPLAY_NAME "3D Samples" DESCRIPTION "Sample applications demonstrating the NeL 3D library." GROUP Samples INSTALL_TYPES Full) cpack_add_component(samplesgeorges DISPLAY_NAME "Georges Samples" DESCRIPTION "Sample applications demonstrating the Georges data loading module." GROUP Samples INSTALL_TYPES Full) cpack_add_component(samplesmisc DISPLAY_NAME "Misc Samples" DESCRIPTION "Sample applications demonstrating the core NeL functionality module." GROUP Samples INSTALL_TYPES Full) cpack_add_component(samplesnet DISPLAY_NAME "Net Samples" DESCRIPTION "Sample applications demonstrating the NeL Network functionality." GROUP Samples INSTALL_TYPES Full) cpack_add_component(samplessound DISPLAY_NAME "Sound Samples" DESCRIPTION "Sample applications demonstrating the NeL Sound functionality." GROUP Samples INSTALL_TYPES Full) ================================================ FILE: code/COPYING ================================================ GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . ================================================ FILE: code/CTestConfig.cmake ================================================ ## This file should be placed in the root directory of your project. ## Then modify the CMakeLists.txt file in the root directory of your ## project to incorporate the testing dashboard. ## # The following are required to uses Dart and the Cdash dashboard ## ENABLE_TESTING() ## INCLUDE(Dart) set(CTEST_PROJECT_NAME "RyzomCore") set(CTEST_NIGHTLY_START_TIME "00:00:00 CST") set(CTEST_UPDATE_TYPE "hg") set(CTEST_DROP_METHOD "http") set(CTEST_DROP_SITE "ci.ryzomcore.org") set(CTEST_DROP_LOCATION "/submit.php?project=RyzomCore") set(CTEST_DROP_SITE_CDASH TRUE) ================================================ FILE: code/EVA/CMakeLists.txt ================================================ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/server ) #SET(SERVER_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/server) IF(WITH_EVA) ADD_DEFINITIONS(-DEVA) ENDIF(WITH_EVA) ADD_SUBDIRECTORY(server) IF(WITH_TOOLS) ADD_SUBDIRECTORY(tools) ENDIF(WITH_TOOLS) ================================================ FILE: code/EVA/server/CMakeLists.txt ================================================ FIND_PACKAGE(CURL) FIND_PACKAGE(MySQL) #FIND_PACKAGE(ToLua) # move to server_share/CMakeLists.txt INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) ADD_SUBDIRECTORY(server_share) #ADD_SUBDIRECTORY(admin_modules) ADD_SUBDIRECTORY(naming_service) ADD_SUBDIRECTORY(frontend_service) ADD_SUBDIRECTORY(player_logic_service) ADD_SUBDIRECTORY(schedule_service) #ADD_SUBDIRECTORY(admin_service) #ADD_SUBDIRECTORY(client_robot) #INSTALL(FILES common.cfg DESTINATION ~/service COMPONENT services) ================================================ FILE: code/EVA/server/_del_log.bat ================================================ @echo off del *.log del log /q del aes_*.txt del pid.state del rns /q rd rns /q del aes /q rd aes /q del egs /q rd egs /q del ras /q rd ras /q del fes_0 /q rd fes_0 /q del lgc_0 /q rd lgc_0 /q del pds /q rd pds /q ================================================ FILE: code/EVA/server/_robot_start .bat ================================================ @echo off REM This script will start all the services with good parameters REM set MODE=Debug REM set MODE=. set MODE=..\..\..\build\bin\Debug taskkill /IM client_robot.exe /F rem ns start %MODE%\client_robot --nolog ping -n 2 127.0.0.1 > NUL 2>&1 ================================================ FILE: code/EVA/server/_robot_stop .bat ================================================ @echo off REM This script will kill all the services launched by _robot_start.bat rem robot taskkill /IM client_robot.exe /F ================================================ FILE: code/EVA/server/_shard_start.bat ================================================ @echo off REM This script will start all the services with good parameters call _shard_stop.bat REM set MODE=Debug REM set MODE=. set MODE=..\..\..\build\bin\Debug rem ns start %MODE%\naming_service --nolog ping -n 2 127.0.0.1 > NUL 2>&1 rem pls start %MODE%\player_logic_service --nolog ping -n 2 127.0.0.1 > NUL 2>&1 rem fes start %MODE%\frontend_service --nolog ping -n 2 127.0.0.1 > NUL 2>&1 rem sch start %MODE%\schedule_service --nolog ping -n 2 127.0.0.1 > NUL 2>&1 ================================================ FILE: code/EVA/server/_shard_stop.bat ================================================ @echo off REM This script will kill all the services launched by _shard_start.bat rem ns taskkill /IM naming_service.exe /F rem fes taskkill /IM frontend_service.exe /F rem pls taskkill /IM player_logic_service.exe /F rem pls taskkill /IM schedule_service.exe /F ================================================ FILE: code/EVA/server/admin_executor_service.cfg ================================================ // Use with commandline: admin_service -A. -C. -L. --nobreak --fulladminname=admin_executor_service --shortadminname=AES #include "common.cfg" // I don't need a connection to a naming service DontUseNS = 1; // Address of the admin service (default port is 49996) ASHost = "localhost"; ASPort="46701"; // ---- service NeL variables (used by ConfigFile class) AESAliasName= "aes"; StartCommands= { // Create a gateway module "moduleManager.createModule StandardGateway gw", // add a layer 5 transport "gw.transportAdd L5Transport l5", // open the transport "gw.transportCmd l5(open)", /// Create default connection with admin executor service // Create a gateway module "moduleManager.createModule StandardGateway gw_aes", // create the admin executor service module "moduleManager.createModule AdminExecutorServiceClient aes_client", "aes_client.plug gw_aes", // create a layer 3 client to connect to aes gateway "gw_aes.transportAdd L3Client aes_l3c", "gw_aes.transportCmd aes_l3c(connect addr="+AESHost+":"+AESPort+")", // create the admin executor service module "moduleManager.createModule AdminExecutorService aes", // create a gateway to connect to as "moduleManager.createModule StandardGateway asc_gw", // create a layer 3 client "asc_gw.transportAdd L3Client l3c", "asc_gw.transportCmd l3c(connect addr="+ASHost+":"+ASPort+")", // create a gateway for services to connect "moduleManager.createModule StandardGateway aes_gw", // create a layer 3 server "aes_gw.transportAdd L3Server l3s", "aes_gw.transportOptions l3s(PeerInvisible)", "aes_gw.transportCmd l3s(open port="+AESPort+")", // plug the as "aes.plug asc_gw", "aes.plug aes_gw", }; StartCommands += { "aes.addRegisteredService ras 本地服务器", "aes.addRegisteredService aes 本地服务器", "aes.addRegisteredService rns 本地服务器", "aes.addRegisteredService pds 本地服务器", "aes.addRegisteredService egs 本地服务器", "aes.addRegisteredService fes_0 本地服务器", "aes.addRegisteredService lgc_0 本地服务器", }; /// server_daemon command ras = { "D:/MT/trunk/code/EVA/server/", "D:/MT/trunk/build/bin/Debug/admin_service.exe", "--fulladminname=admin_service --shortadminname=AS -C. -L. --nobreak --writepid" }; aes = { "D:/MT/trunk/code/EVA/server/", "D:/MT/trunk/build/bin/Debug/admin_service.exe", "--fulladminname=admin_executor_service --shortadminname=AES -C. -L. --nobreak --writepid" }; rns = { "D:/MT/trunk/code/EVA/server/", "D:/MT/trunk/build/bin/Debug/naming_service.exe", "-C. -L. --nobreak --writepid" }; pds = { "D:/MT/trunk/code/EVA/server/", "D:/MT/trunk/build/bin/Debug/persistant_data_service.exe", "-C. -L. --nobreak --writepid" }; egs = { "D:/MT/trunk/code/EVA/server/", "D:/MT/trunk/build/bin/Debug/entities_game_service.exe", "-C. -L. --nobreak --writepid" }; fes_0 = { "D:/MT/trunk/code/EVA/server/", "D:/MT/trunk/build/bin/Debug/frontend_service.exe", "-C. -L. --nobreak --writepid" }; lgc_0 = { "D:/MT/trunk/code/EVA/server/", "D:/MT/trunk/build/bin/Debug/player_logic_service.exe", "-C. -L. --nobreak --writepid" }; /// for server_daemon RegisteredServices= { "ras", "aes", "rns", "pds", "egs", "fes_0", "lgc_0", }; // DontUseStdIn = 0; // ---- service NeL variables (used by CVariable class) // If the update loop is too slow, a thread will produce an assertion. // By default, the value is set to 10 minutes. // Set to 0 for no assertion. UpdateAssertionThreadTimeout = 0; // ---- service custom variables (used by CVariable class) // in second, -1 for not restarting RestartDelay = 60; // how many second before aborting the request if not finished RequestTimeout = 5; // log path for advanced log report LogPath = "/."; // setup for deployment environment with exeternal configuration system responsible for launching apps and // for configuring AES services DontLaunchServicesDirectly = 1; UseExplicitAESRegistration = 1; KillServicesOnDisconnect = 1; ShardName="dev"; ================================================ FILE: code/EVA/server/admin_modules/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp *.h) NL_TARGET_LIB(eva_adminmodules ${SRC}) INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) TARGET_LINK_LIBRARIES(eva_adminmodules nelmisc nelnet) NL_DEFAULT_PROPS(eva_adminmodules "Base, Library: Service Admin Modules") NL_ADD_RUNTIME_FLAGS(eva_adminmodules) NL_ADD_LIB_SUFFIX(eva_adminmodules) ADD_DEFINITIONS(${LIBXML2_DEFINITIONS}) #INSTALL(TARGETS eva_adminmodules LIBRARY DESTINATION ${EVA_LIB_PREFIX} ARCHIVE DESTINATION ${EVA_LIB_PREFIX} COMPONENT libraries) IF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC) INSTALL(TARGETS eva_adminmodules LIBRARY DESTINATION lib ARCHIVE DESTINATION lib COMPONENT libraries) ENDIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC) ================================================ FILE: code/EVA/server/admin_modules/admin_modules.cpp ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /** This file declare a pure nel module library */ #include "nel/net/module_manager.h" #include "nel/net/module.h" #include "nel/net/module_builder_parts.h" using namespace std; using namespace NLMISC; using namespace NLNET; extern void as_forceLink(); extern void aes_forceLink(); extern void aesclient_forceLink(); void admin_modules_forceLink() { as_forceLink(); aes_forceLink(); aesclient_forceLink(); } //NLMISC_DECL_PURE_LIB(CNelModuleLibrary); ================================================ FILE: code/EVA/server/admin_modules/admin_modules_itf.cpp ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// #include "admin_modules_itf.h" namespace ADMIN { ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// const CAdminServiceSkel::TMessageHandlerMap &CAdminServiceSkel::getMessageHandlers() const { static TMessageHandlerMap handlers; static bool init = false; if (!init) { std::pair < TMessageHandlerMap::iterator, bool > res; res = handlers.insert(std::make_pair(std::string("USU"), &CAdminServiceSkel::upServiceUpdate_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); res = handlers.insert(std::make_pair(std::string("GU"), &CAdminServiceSkel::graphUpdate_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); res = handlers.insert(std::make_pair(std::string("HRGU"), &CAdminServiceSkel::highRezGraphUpdate_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); res = handlers.insert(std::make_pair(std::string("CR"), &CAdminServiceSkel::commandResult_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); init = true; } return handlers; } bool CAdminServiceSkel::fwdOnProcessModuleMessage(NLNET::IModuleProxy *sender, const NLNET::CMessage &message) { const TMessageHandlerMap &mh = getMessageHandlers(); TMessageHandlerMap::const_iterator it(mh.find(message.getName())); if (it == mh.end()) { return false; } TMessageHandler cmd = it->second; (this->*cmd)(sender, message); return true; } void CAdminServiceSkel::upServiceUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminServiceSkel_upServiceUpdate_USU); std::vector < TServiceStatus > serviceStatus; nlRead(__message, serialCont, serviceStatus); upServiceUpdate(sender, serviceStatus); } void CAdminServiceSkel::graphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminServiceSkel_graphUpdate_GU); TGraphDatas graphDatas; nlRead(__message, serial, graphDatas); graphUpdate(sender, graphDatas); } void CAdminServiceSkel::highRezGraphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminServiceSkel_highRezGraphUpdate_HRGU); THighRezDatas graphDatas; nlRead(__message, serial, graphDatas); highRezGraphUpdate(sender, graphDatas); } void CAdminServiceSkel::commandResult_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminServiceSkel_commandResult_CR); uint32 commandId; nlRead(__message, serial, commandId); std::string serviceAlias; nlRead(__message, serial, serviceAlias); std::string result; nlRead(__message, serial, result); commandResult(sender, commandId, serviceAlias, result); } // An AES send an update of the list of service up void CAdminServiceProxy::upServiceUpdate(NLNET::IModule *sender, const std::vector < TServiceStatus > &serviceStatus) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->upServiceUpdate(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), serviceStatus); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_upServiceUpdate(__message, serviceStatus); _ModuleProxy->sendModuleMessage(sender, __message); } } // An AES send graph data update void CAdminServiceProxy::graphUpdate(NLNET::IModule *sender, const TGraphDatas &graphDatas) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->graphUpdate(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), graphDatas); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_graphUpdate(__message, graphDatas); _ModuleProxy->sendModuleMessage(sender, __message); } } // An AES send high rez graph data update void CAdminServiceProxy::highRezGraphUpdate(NLNET::IModule *sender, const THighRezDatas &graphDatas) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->highRezGraphUpdate(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), graphDatas); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_highRezGraphUpdate(__message, graphDatas); _ModuleProxy->sendModuleMessage(sender, __message); } } // AES send back the result of execution of a command void CAdminServiceProxy::commandResult(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->commandResult(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), commandId, serviceAlias, result); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_commandResult(__message, commandId, serviceAlias, result); _ModuleProxy->sendModuleMessage(sender, __message); } } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminServiceProxy::buildMessageFor_upServiceUpdate(NLNET::CMessage &__message, const std::vector < TServiceStatus > &serviceStatus) { __message.setType("USU"); nlWrite(__message, serialCont, const_cast < std::vector < TServiceStatus >& > (serviceStatus)); return __message; } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminServiceProxy::buildMessageFor_graphUpdate(NLNET::CMessage &__message, const TGraphDatas &graphDatas) { __message.setType("GU"); nlWrite(__message, serial, const_cast < TGraphDatas& > (graphDatas)); return __message; } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminServiceProxy::buildMessageFor_highRezGraphUpdate(NLNET::CMessage &__message, const THighRezDatas &graphDatas) { __message.setType("HRGU"); nlWrite(__message, serial, const_cast < THighRezDatas& > (graphDatas)); return __message; } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminServiceProxy::buildMessageFor_commandResult(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &result) { __message.setType("CR"); nlWrite(__message, serial, commandId); nlWrite(__message, serial, const_cast < std::string& > (serviceAlias)); nlWrite(__message, serial, const_cast < std::string& > (result)); return __message; } ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// const CAdminExecutorServiceSkel::TMessageHandlerMap &CAdminExecutorServiceSkel::getMessageHandlers() const { static TMessageHandlerMap handlers; static bool init = false; if (!init) { std::pair < TMessageHandlerMap::iterator, bool > res; res = handlers.insert(std::make_pair(std::string("SCO"), &CAdminExecutorServiceSkel::setShardOrders_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); res = handlers.insert(std::make_pair(std::string("SDS"), &CAdminExecutorServiceSkel::shutdownShard_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); res = handlers.insert(std::make_pair(std::string("CC"), &CAdminExecutorServiceSkel::controlCmd_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); res = handlers.insert(std::make_pair(std::string("SCMD"), &CAdminExecutorServiceSkel::serviceCmd_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); res = handlers.insert(std::make_pair(std::string("CR"), &CAdminExecutorServiceSkel::commandResult_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); res = handlers.insert(std::make_pair(std::string("GU"), &CAdminExecutorServiceSkel::graphUpdate_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); res = handlers.insert(std::make_pair(std::string("HRGU"), &CAdminExecutorServiceSkel::highRezGraphUpdate_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); res = handlers.insert(std::make_pair(std::string("SSU"), &CAdminExecutorServiceSkel::serviceStatusUpdate_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); init = true; } return handlers; } bool CAdminExecutorServiceSkel::fwdOnProcessModuleMessage(NLNET::IModuleProxy *sender, const NLNET::CMessage &message) { const TMessageHandlerMap &mh = getMessageHandlers(); TMessageHandlerMap::const_iterator it(mh.find(message.getName())); if (it == mh.end()) { return false; } TMessageHandler cmd = it->second; (this->*cmd)(sender, message); return true; } void CAdminExecutorServiceSkel::setShardOrders_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminExecutorServiceSkel_setShardOrders_SCO); std::string shardName; nlRead(__message, serial, shardName); TShardOrders shardOrders; nlRead(__message, serial, shardOrders); setShardOrders(sender, shardName, shardOrders); } void CAdminExecutorServiceSkel::shutdownShard_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminExecutorServiceSkel_shutdownShard_SDS); std::string shardName; nlRead(__message, serial, shardName); uint32 delay; nlRead(__message, serial, delay); shutdownShard(sender, shardName, delay); } void CAdminExecutorServiceSkel::controlCmd_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminExecutorServiceSkel_controlCmd_CC); uint32 commandId; nlRead(__message, serial, commandId); std::string serviceAlias; nlRead(__message, serial, serviceAlias); std::string command; nlRead(__message, serial, command); controlCmd(sender, commandId, serviceAlias, command); } void CAdminExecutorServiceSkel::serviceCmd_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminExecutorServiceSkel_serviceCmd_SCMD); uint32 commandId; nlRead(__message, serial, commandId); std::string serviceAlias; nlRead(__message, serial, serviceAlias); std::string command; nlRead(__message, serial, command); serviceCmd(sender, commandId, serviceAlias, command); } void CAdminExecutorServiceSkel::commandResult_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminExecutorServiceSkel_commandResult_CR); uint32 commandId; nlRead(__message, serial, commandId); std::string serviceAlias; nlRead(__message, serial, serviceAlias); std::string result; nlRead(__message, serial, result); commandResult(sender, commandId, serviceAlias, result); } void CAdminExecutorServiceSkel::graphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminExecutorServiceSkel_graphUpdate_GU); TGraphDatas graphDatas; nlRead(__message, serial, graphDatas); graphUpdate(sender, graphDatas); } void CAdminExecutorServiceSkel::highRezGraphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminExecutorServiceSkel_highRezGraphUpdate_HRGU); THighRezDatas graphDatas; nlRead(__message, serial, graphDatas); highRezGraphUpdate(sender, graphDatas); } void CAdminExecutorServiceSkel::serviceStatusUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminExecutorServiceSkel_serviceStatusUpdate_SSU); std::string status; nlRead(__message, serial, status); serviceStatusUpdate(sender, status); } // AS send orders for a shard void CAdminExecutorServiceProxy::setShardOrders(NLNET::IModule *sender, const std::string &shardName, const TShardOrders &shardOrders) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->setShardOrders(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), shardName, shardOrders); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_setShardOrders(__message, shardName, shardOrders); _ModuleProxy->sendModuleMessage(sender, __message); } } // AS send a command to shutdown a shard with a delay void CAdminExecutorServiceProxy::shutdownShard(NLNET::IModule *sender, const std::string &shardName, uint32 delay) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->shutdownShard(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), shardName, delay); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_shutdownShard(__message, shardName, delay); _ModuleProxy->sendModuleMessage(sender, __message); } } // AS send a control command to this AES void CAdminExecutorServiceProxy::controlCmd(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->controlCmd(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), commandId, serviceAlias, command); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_controlCmd(__message, commandId, serviceAlias, command); _ModuleProxy->sendModuleMessage(sender, __message); } } // Send a command to a service. void CAdminExecutorServiceProxy::serviceCmd(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->serviceCmd(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), commandId, serviceAlias, command); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_serviceCmd(__message, commandId, serviceAlias, command); _ModuleProxy->sendModuleMessage(sender, __message); } } // AES client send back the result of execution of a command void CAdminExecutorServiceProxy::commandResult(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->commandResult(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), commandId, serviceAlias, result); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_commandResult(__message, commandId, serviceAlias, result); _ModuleProxy->sendModuleMessage(sender, __message); } } // A service send graph data update void CAdminExecutorServiceProxy::graphUpdate(NLNET::IModule *sender, const TGraphDatas &graphDatas) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->graphUpdate(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), graphDatas); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_graphUpdate(__message, graphDatas); _ModuleProxy->sendModuleMessage(sender, __message); } } // A service high rez graph data update void CAdminExecutorServiceProxy::highRezGraphUpdate(NLNET::IModule *sender, const THighRezDatas &graphDatas) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->highRezGraphUpdate(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), graphDatas); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_highRezGraphUpdate(__message, graphDatas); _ModuleProxy->sendModuleMessage(sender, __message); } } // A service send an update of of it's status string void CAdminExecutorServiceProxy::serviceStatusUpdate(NLNET::IModule *sender, const std::string &status) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->serviceStatusUpdate(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), status); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_serviceStatusUpdate(__message, status); _ModuleProxy->sendModuleMessage(sender, __message); } } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_setShardOrders(NLNET::CMessage &__message, const std::string &shardName, const TShardOrders &shardOrders) { __message.setType("SCO"); nlWrite(__message, serial, const_cast < std::string& > (shardName)); nlWrite(__message, serial, shardOrders); return __message; } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_shutdownShard(NLNET::CMessage &__message, const std::string &shardName, uint32 delay) { __message.setType("SDS"); nlWrite(__message, serial, const_cast < std::string& > (shardName)); nlWrite(__message, serial, delay); return __message; } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_controlCmd(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &command) { __message.setType("CC"); nlWrite(__message, serial, commandId); nlWrite(__message, serial, const_cast < std::string& > (serviceAlias)); nlWrite(__message, serial, const_cast < std::string& > (command)); return __message; } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_serviceCmd(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &command) { __message.setType("SCMD"); nlWrite(__message, serial, commandId); nlWrite(__message, serial, const_cast < std::string& > (serviceAlias)); nlWrite(__message, serial, const_cast < std::string& > (command)); return __message; } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_commandResult(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &result) { __message.setType("CR"); nlWrite(__message, serial, commandId); nlWrite(__message, serial, const_cast < std::string& > (serviceAlias)); nlWrite(__message, serial, const_cast < std::string& > (result)); return __message; } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_graphUpdate(NLNET::CMessage &__message, const TGraphDatas &graphDatas) { __message.setType("GU"); nlWrite(__message, serial, const_cast < TGraphDatas& > (graphDatas)); return __message; } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_highRezGraphUpdate(NLNET::CMessage &__message, const THighRezDatas &graphDatas) { __message.setType("HRGU"); nlWrite(__message, serial, const_cast < THighRezDatas& > (graphDatas)); return __message; } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_serviceStatusUpdate(NLNET::CMessage &__message, const std::string &status) { __message.setType("SSU"); nlWrite(__message, serial, const_cast < std::string& > (status)); return __message; } ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// const CAdminExecutorServiceClientSkel::TMessageHandlerMap &CAdminExecutorServiceClientSkel::getMessageHandlers() const { static TMessageHandlerMap handlers; static bool init = false; if (!init) { std::pair < TMessageHandlerMap::iterator, bool > res; res = handlers.insert(std::make_pair(std::string("SCMD"), &CAdminExecutorServiceClientSkel::serviceCmd_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); res = handlers.insert(std::make_pair(std::string("SCMDNR"), &CAdminExecutorServiceClientSkel::serviceCmdNoReturn_skel)); // if this assert, you have a doubly message name in your interface definition ! nlassert(res.second); init = true; } return handlers; } bool CAdminExecutorServiceClientSkel::fwdOnProcessModuleMessage(NLNET::IModuleProxy *sender, const NLNET::CMessage &message) { const TMessageHandlerMap &mh = getMessageHandlers(); TMessageHandlerMap::const_iterator it(mh.find(message.getName())); if (it == mh.end()) { return false; } TMessageHandler cmd = it->second; (this->*cmd)(sender, message); return true; } void CAdminExecutorServiceClientSkel::serviceCmd_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminExecutorServiceClientSkel_serviceCmd_SCMD); uint32 commandId; nlRead(__message, serial, commandId); std::string command; nlRead(__message, serial, command); serviceCmd(sender, commandId, command); } void CAdminExecutorServiceClientSkel::serviceCmdNoReturn_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message) { H_AUTO(CAdminExecutorServiceClientSkel_serviceCmdNoReturn_SCMDNR); std::string command; nlRead(__message, serial, command); serviceCmdNoReturn(sender, command); } // execute a command and return the result. void CAdminExecutorServiceClientProxy::serviceCmd(NLNET::IModule *sender, uint32 commandId, const std::string &command) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->serviceCmd(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), commandId, command); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_serviceCmd(__message, commandId, command); _ModuleProxy->sendModuleMessage(sender, __message); } } // Send a command to a service without waiting for the return value. void CAdminExecutorServiceClientProxy::serviceCmdNoReturn(NLNET::IModule *sender, const std::string &command) { if (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported()) { // immediate local synchronous dispatching _LocalModuleSkel->serviceCmdNoReturn(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), command); } else { // send the message for remote dispatching and execution or local queing NLNET::CMessage __message; buildMessageFor_serviceCmdNoReturn(__message, command); _ModuleProxy->sendModuleMessage(sender, __message); } } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminExecutorServiceClientProxy::buildMessageFor_serviceCmd(NLNET::CMessage &__message, uint32 commandId, const std::string &command) { __message.setType("SCMD"); nlWrite(__message, serial, commandId); nlWrite(__message, serial, const_cast < std::string& > (command)); return __message; } // Message serializer. Return the message received in reference for easier integration const NLNET::CMessage &CAdminExecutorServiceClientProxy::buildMessageFor_serviceCmdNoReturn(NLNET::CMessage &__message, const std::string &command) { __message.setType("SCMDNR"); nlWrite(__message, serial, const_cast < std::string& > (command)); return __message; } } ================================================ FILE: code/EVA/server/admin_modules/admin_modules_itf.h ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// #ifndef ADMIN_MODULES_ITF #define ADMIN_MODULES_ITF #include "nel/misc/types_nl.h" #include #include "nel/misc/hierarchical_timer.h" #include "nel/misc/string_conversion.h" #include "nel/net/message.h" #include "nel/net/module.h" #include "nel/net/module_builder_parts.h" #include "nel/net/module_message.h" #include "nel/net/module_gateway.h" #include "server_share/callback_adaptor.h" #include "nel/misc/time_nl.h" namespace ADMIN { class TGraphData; class TGraphDatas; class THighRezData; class THighRezDatas; class TServiceStatus; // This is the interface used by PHP to call methods // on the Admin service module class CAdminServiceWebItf { protected: /// the callback server adaptor std::auto_ptr _CallbackServer; void getCallbakArray(NLNET::TCallbackItem *&arrayPtr, uint32 &arraySize) { static NLNET::TCallbackItem callbackArray[] = { { "GCMD", CAdminServiceWebItf::cb_globalCmd }, { "CCMD", CAdminServiceWebItf::cb_controlCmd }, { "SCMD", CAdminServiceWebItf::cb_serviceCmd }, { "GSO", CAdminServiceWebItf::cb_getShardOrders }, { "GS", CAdminServiceWebItf::cb_getStates }, { "GHRGI", CAdminServiceWebItf::cb_getHighRezGraphInfo }, { "GHRG", CAdminServiceWebItf::cb_getHighRezGraph }, }; arrayPtr = callbackArray; arraySize = sizeofarray(callbackArray); } static void _cbConnection(NLNET::TSockId from, void *arg) { H_AUTO(CAdminServiceWeb__cbConnection); CAdminServiceWebItf *_this = reinterpret_cast(arg); _this->on_CAdminServiceWeb_Connection(from); } static void _cbDisconnection(NLNET::TSockId from, void *arg) { H_AUTO(CAdminServiceWeb__cbDisconnection); CAdminServiceWebItf *_this = reinterpret_cast(arg); _this->on_CAdminServiceWeb_Disconnection(from); } public: /** Constructor, if you specify a replacement adaptor, then the object * become owner of the adaptor (and it will be released with the * interface). */ CAdminServiceWebItf(ICallbackServerAdaptor *replacementAdaptor = NULL) { if (replacementAdaptor == NULL) { // use default callback server _CallbackServer = std::auto_ptr(new CNelCallbackServerAdaptor(this)); } else { // use the replacement one _CallbackServer = std::auto_ptr(replacementAdaptor); } } virtual ~CAdminServiceWebItf() { } /// Open the interface socket in the specified port void openItf(uint16 port) { NLNET::TCallbackItem *arrayPtr; uint32 arraySize; getCallbakArray(arrayPtr, arraySize); _CallbackServer->addCallbackArray(arrayPtr, arraySize); _CallbackServer->setConnectionCallback (_cbConnection, this); _CallbackServer->setDisconnectionCallback (_cbDisconnection, this); _CallbackServer->init(port); } /** Must be called evenly, update the network subclass to receive message * and dispatch method invokation. */ void update() { H_AUTO(CAdminServiceWeb_update); try { _CallbackServer->update(); } catch (...) { nlwarning("CAdminServiceWeb : Exception launch in callback server update"); } } void commandResult(NLNET::TSockId dest, const std::string &serviceAlias, const std::string &result) { H_AUTO(commandResult_commandResult); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::commandResult called"); #endif NLNET::CMessage message("CMDR"); nlWrite(message, serial, const_cast < std::string& > (serviceAlias)); nlWrite(message, serial, const_cast < std::string& > (result)); _CallbackServer->send(message, dest); } static void cb_globalCmd (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase) { H_AUTO(globalCmd_on_globalCmd); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_globalCmd received from class '%s'", typeid(netbase).name()); #endif ICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData()); CAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass(); if (callback == NULL) return; std::string command; nlRead(message, serial, command); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_globalCmd : calling on_globalCmd"); #endif callback->on_globalCmd(from, command); } static void cb_controlCmd (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase) { H_AUTO(controlCmd_on_controlCmd); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_controlCmd received from class '%s'", typeid(netbase).name()); #endif ICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData()); CAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass(); if (callback == NULL) return; std::string serviceAlias; std::string command; nlRead(message, serial, serviceAlias); nlRead(message, serial, command); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_controlCmd : calling on_controlCmd"); #endif callback->on_controlCmd(from, serviceAlias, command); } static void cb_serviceCmd (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase) { H_AUTO(serviceCmd_on_serviceCmd); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_serviceCmd received from class '%s'", typeid(netbase).name()); #endif ICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData()); CAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass(); if (callback == NULL) return; std::string serviceAlias; std::string command; nlRead(message, serial, serviceAlias); nlRead(message, serial, command); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_serviceCmd : calling on_serviceCmd"); #endif callback->on_serviceCmd(from, serviceAlias, command); } static void cb_getShardOrders (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase) { H_AUTO(getShardOrders_on_getShardOrders); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_getShardOrders received from class '%s'", typeid(netbase).name()); #endif ICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData()); CAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass(); if (callback == NULL) return; #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_getShardOrders : calling on_getShardOrders"); #endif std::vector retValue; retValue = callback->on_getShardOrders(from); NLNET::CMessage retMsg("R_GSO"); nlWrite(retMsg, serialCont, retValue); callback->_CallbackServer->send(retMsg, from); } static void cb_getStates (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase) { H_AUTO(getStates_on_getStates); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_getStates received from class '%s'", typeid(netbase).name()); #endif ICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData()); CAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass(); if (callback == NULL) return; #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_getStates : calling on_getStates"); #endif std::vector retValue; retValue = callback->on_getStates(from); NLNET::CMessage retMsg("R_GS"); nlWrite(retMsg, serialCont, retValue); callback->_CallbackServer->send(retMsg, from); } static void cb_getHighRezGraphInfo (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase) { H_AUTO(getHighRezGraphInfo_on_getHighRezGraphInfo); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_getHighRezGraphInfo received from class '%s'", typeid(netbase).name()); #endif ICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData()); CAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass(); if (callback == NULL) return; std::string varAddr; nlRead(message, serial, varAddr); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_getHighRezGraphInfo : calling on_getHighRezGraphInfo"); #endif std::vector retValue; retValue = callback->on_getHighRezGraphInfo(from, varAddr); NLNET::CMessage retMsg("R_GHRGI"); nlWrite(retMsg, serialCont, retValue); callback->_CallbackServer->send(retMsg, from); } static void cb_getHighRezGraph (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase) { H_AUTO(getHighRezGraph_on_getHighRezGraph); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_getHighRezGraph received from class '%s'", typeid(netbase).name()); #endif ICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData()); CAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass(); if (callback == NULL) return; std::string varAddr; uint32 startDate; uint32 endDate; uint32 milliStep; nlRead(message, serial, varAddr); nlRead(message, serial, startDate); nlRead(message, serial, endDate); nlRead(message, serial, milliStep); #ifdef NL_DEBUG nldebug("CAdminServiceWeb::cb_getHighRezGraph : calling on_getHighRezGraph"); #endif std::vector retValue; retValue = callback->on_getHighRezGraph(from, varAddr, startDate, endDate, milliStep); NLNET::CMessage retMsg("R_GHRG"); nlWrite(retMsg, serialCont, retValue); callback->_CallbackServer->send(retMsg, from); } /// Connection callback : a new interface client connect virtual void on_CAdminServiceWeb_Connection(NLNET::TSockId from) =0; /// Disconnection callback : one of the interface client disconnect virtual void on_CAdminServiceWeb_Disconnection(NLNET::TSockId from) =0; // Send a command to the AS. // This is used to issue global commands like 'as.allStart' or 'as.allStop'. // The result is returned by the return message // serviceCmdResult. virtual void on_globalCmd(NLNET::TSockId from, const std::string &command) =0; // Send a service related command to the executor // (not to the controled service) // The result is returned by the return message // controlCmdResult. virtual void on_controlCmd(NLNET::TSockId from, const std::string &serviceAlias, const std::string &command) =0; // Send a command to a service. // The result is returned by the return message // serviceCmdResult. virtual void on_serviceCmd(NLNET::TSockId from, const std::string &serviceAlias, const std::string &command) =0; // Get the orders of each known shard. // The return value is a vector of string, one entry by shard virtual std::vector on_getShardOrders(NLNET::TSockId from) =0; // Get the last known state of all services. // The return value is a vector of string, one entry by service virtual std::vector on_getStates(NLNET::TSockId from) =0; // Get information about a high rez graph. // The return is a string array containing // the name of the var, the available sample // period as two unix date (start dans end) // and the number of samples available // If the var is not found, an empty array is returned virtual std::vector on_getHighRezGraphInfo(NLNET::TSockId from, const std::string &varAddr) =0; // Get the data for a high resolution graph. // The return is a string array, each // string containing 'time:milliOffset:value // Set endDate to 0 to specify a start date relative // to the last sample date. In this case, start date // is interpreted as the number of second before // the last sample. virtual std::vector on_getHighRezGraph(NLNET::TSockId from, const std::string &varAddr, uint32 startDate, uint32 endDate, uint32 milliStep) =0; }; // This is the interface used by PHP to call methods // on the Admin service module /** This is the client side of the interface * Derive from this class to invoke method on the callback server */ class CAdminServiceWebClientItf { protected: /// the callback client adaptor std::auto_ptr < ICallbackClientAdaptor > _CallbackClient; void getCallbakArray(NLNET::TCallbackItem *&arrayPtr, uint32 &arraySize) { static NLNET::TCallbackItem callbackArray[] = { { "CMDR", CAdminServiceWebClientItf::cb_commandResult }, }; arrayPtr = callbackArray; arraySize = sizeofarray(callbackArray); } static void _cbDisconnection(NLNET::TSockId from, void *arg) { CAdminServiceWebClientItf *_this = reinterpret_cast(arg); _this->on_CAdminServiceWebClient_Disconnection(from); } public: /// Retreive the message name for a given callback name static const std::string &getMessageName(const std::string &methodName) { static std::map messageNames; static bool initialized = false; if (!initialized) { messageNames.insert(std::make_pair(std::string("on_commandResult"), std::string("CMDR"))); initialized = true; } std::map < std::string, std::string>::const_iterator it(messageNames.find(methodName)); if (it != messageNames.end()) return it->second; static std::string emptyString; return emptyString; } CAdminServiceWebClientItf(ICallbackClientAdaptor *adaptorReplacement = NULL) { if (adaptorReplacement == NULL) { // use the default Nel adaptor _CallbackClient = std::auto_ptr < ICallbackClientAdaptor >(new CNelCallbackClientAdaptor(this)); } else { // use the replacement one _CallbackClient = std::auto_ptr < ICallbackClientAdaptor >(adaptorReplacement); } } /// Connect the interface client to the callback server at the specified address and port virtual void connectItf(NLNET::CInetAddress address) { NLNET::TCallbackItem *arrayPtr; uint32 arraySize; static bool callbackAdded = false; if (!callbackAdded) { getCallbakArray(arrayPtr, arraySize); _CallbackClient->addCallbackArray(arrayPtr, arraySize); } _CallbackClient->setDisconnectionCallback (_cbDisconnection, this); _CallbackClient->connect(address); } /** Must be called evenly, update the network subclass to receive message * and dispatch invokation returns. */ virtual void update() { H_AUTO(CAdminServiceWeb_update); try { _CallbackClient->update(); } catch (...) { nlwarning("CAdminServiceWeb : Exception launch in callback client update"); } } // Send a command to the AS. // This is used to issue global commands like 'as.allStart' or 'as.allStop'. // The result is returned by the return message // serviceCmdResult. void globalCmd(const std::string &command) { #ifdef NL_DEBUG nldebug("CAdminServiceWebClient::globalCmd called"); #endif NLNET::CMessage message("GCMD"); nlWrite(message, serial, const_cast < std::string& > (command)); _CallbackClient->send(message); } // Send a service related command to the executor // (not to the controled service) // The result is returned by the return message // controlCmdResult. void controlCmd(const std::string &serviceAlias, const std::string &command) { #ifdef NL_DEBUG nldebug("CAdminServiceWebClient::controlCmd called"); #endif NLNET::CMessage message("CCMD"); nlWrite(message, serial, const_cast < std::string& > (serviceAlias)); nlWrite(message, serial, const_cast < std::string& > (command)); _CallbackClient->send(message); } // Send a command to a service. // The result is returned by the return message // serviceCmdResult. void serviceCmd(const std::string &serviceAlias, const std::string &command) { #ifdef NL_DEBUG nldebug("CAdminServiceWebClient::serviceCmd called"); #endif NLNET::CMessage message("SCMD"); nlWrite(message, serial, const_cast < std::string& > (serviceAlias)); nlWrite(message, serial, const_cast < std::string& > (command)); _CallbackClient->send(message); } // Get the orders of each known shard. // The return value is a vector of string, one entry by shard void getShardOrders() { #ifdef NL_DEBUG nldebug("CAdminServiceWebClient::getShardOrders called"); #endif NLNET::CMessage message("GSO"); _CallbackClient->send(message); } // Get the last known state of all services. // The return value is a vector of string, one entry by service void getStates() { #ifdef NL_DEBUG nldebug("CAdminServiceWebClient::getStates called"); #endif NLNET::CMessage message("GS"); _CallbackClient->send(message); } // Get information about a high rez graph. // The return is a string array containing // the name of the var, the available sample // period as two unix date (start dans end) // and the number of samples available // If the var is not found, an empty array is returned void getHighRezGraphInfo(const std::string &varAddr) { #ifdef NL_DEBUG nldebug("CAdminServiceWebClient::getHighRezGraphInfo called"); #endif NLNET::CMessage message("GHRGI"); nlWrite(message, serial, const_cast < std::string& > (varAddr)); _CallbackClient->send(message); } // Get the data for a high resolution graph. // The return is a string array, each // string containing 'time:milliOffset:value // Set endDate to 0 to specify a start date relative // to the last sample date. In this case, start date // is interpreted as the number of second before // the last sample. void getHighRezGraph(const std::string &varAddr, uint32 startDate, uint32 endDate, uint32 milliStep) { #ifdef NL_DEBUG nldebug("CAdminServiceWebClient::getHighRezGraph called"); #endif NLNET::CMessage message("GHRG"); nlWrite(message, serial, const_cast < std::string& > (varAddr)); nlWrite(message, serial, startDate); nlWrite(message, serial, endDate); nlWrite(message, serial, milliStep); _CallbackClient->send(message); } static void cb_commandResult (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase) { #ifdef NL_DEBUG nldebug("CAdminServiceWebClient::cb_commandResult received from class '%s'", typeid(netbase).name()); #endif ICallbackClientAdaptor *adaptor = static_cast< ICallbackClientAdaptor *>(netbase.getUserData()); CAdminServiceWebClientItf *callback = (CAdminServiceWebClientItf *)adaptor->getContainerClass(); if (callback == NULL) return; std::string serviceAlias; std::string result; nlRead(message, serial, serviceAlias); nlRead(message, serial, result); #ifdef NL_DEBUG nldebug("CAdminServiceWebClient::cb_commandResult : calling on_commandResult"); #endif callback->on_commandResult(from, serviceAlias, result); } /// Disconnection callback : the connection to the server is lost virtual void on_CAdminServiceWebClient_Disconnection(NLNET::TSockId from) =0; virtual void on_commandResult(NLNET::TSockId from, const std::string &serviceAlias, const std::string &result) =0; }; ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// class TGraphData { protected: // std::string _ServiceAlias; // std::string _VarName; // uint32 _SamplePeriod; // double _Value; public: // const std::string &getServiceAlias() const { return _ServiceAlias; } std::string &getServiceAlias() { return _ServiceAlias; } void setServiceAlias(const std::string &value) { _ServiceAlias = value; } // const std::string &getVarName() const { return _VarName; } std::string &getVarName() { return _VarName; } void setVarName(const std::string &value) { _VarName = value; } // uint32 getSamplePeriod() const { return _SamplePeriod; } void setSamplePeriod(uint32 value) { _SamplePeriod = value; } // double getValue() const { return _Value; } void setValue(double value) { _Value = value; } bool operator == (const TGraphData &other) const { return _ServiceAlias == other._ServiceAlias && _VarName == other._VarName && _SamplePeriod == other._SamplePeriod && _Value == other._Value; } // constructor TGraphData() { } void serial(NLMISC::IStream &s) { s.serial(_ServiceAlias); s.serial(_VarName); s.serial(_SamplePeriod); s.serial(_Value); } private: }; ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// class TGraphDatas { protected: // uint32 _CurrentTime; // std::vector < TGraphData > _Datas; public: // uint32 getCurrentTime() const { return _CurrentTime; } void setCurrentTime(uint32 value) { _CurrentTime = value; } // const std::vector < TGraphData > &getDatas() const { return _Datas; } std::vector < TGraphData > &getDatas() { return _Datas; } void setDatas(const std::vector < TGraphData > &value) { _Datas = value; } bool operator == (const TGraphDatas &other) const { return _CurrentTime == other._CurrentTime && _Datas == other._Datas; } // constructor TGraphDatas() { } void serial(NLMISC::IStream &s) { s.serial(_CurrentTime); s.serialCont(_Datas); } private: }; ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// class THighRezData { protected: // NLMISC::TTime _SampleTick; // double _Value; public: // NLMISC::TTime getSampleTick() const { return _SampleTick; } void setSampleTick(NLMISC::TTime value) { _SampleTick = value; } // double getValue() const { return _Value; } void setValue(double value) { _Value = value; } bool operator == (const THighRezData &other) const { return _SampleTick == other._SampleTick && _Value == other._Value; } // constructor THighRezData() { } void serial(NLMISC::IStream &s) { s.serial(_SampleTick); s.serial(_Value); } private: }; ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// class THighRezDatas { protected: // std::string _ServiceAlias; // std::string _VarName; // uint32 _CurrentTime; // std::vector < THighRezData > _Datas; public: // const std::string &getServiceAlias() const { return _ServiceAlias; } std::string &getServiceAlias() { return _ServiceAlias; } void setServiceAlias(const std::string &value) { _ServiceAlias = value; } // const std::string &getVarName() const { return _VarName; } std::string &getVarName() { return _VarName; } void setVarName(const std::string &value) { _VarName = value; } // uint32 getCurrentTime() const { return _CurrentTime; } void setCurrentTime(uint32 value) { _CurrentTime = value; } // const std::vector < THighRezData > &getDatas() const { return _Datas; } std::vector < THighRezData > &getDatas() { return _Datas; } void setDatas(const std::vector < THighRezData > &value) { _Datas = value; } bool operator == (const THighRezDatas &other) const { return _ServiceAlias == other._ServiceAlias && _VarName == other._VarName && _CurrentTime == other._CurrentTime && _Datas == other._Datas; } // constructor THighRezDatas() { } void serial(NLMISC::IStream &s) { s.serial(_ServiceAlias); s.serial(_VarName); s.serial(_CurrentTime); s.serialCont(_Datas); } private: }; struct TShardOrders { enum TValues { so_autostart_on, so_autostart_off, /// the highest valid value in the enum last_enum_item = so_autostart_off, /// a value equal to the last enum item +1 end_of_enum, invalid_val, /// Number of enumerated values nb_enum_items = 2 }; /// Index table to convert enum value to linear index table const std::map &getIndexTable() const { static std::map indexTable; static bool init = false; if (!init) { // fill the index table indexTable.insert(std::make_pair(so_autostart_on, 0)); indexTable.insert(std::make_pair(so_autostart_off, 1)); init = true; } return indexTable; } static const NLMISC::CStringConversion &getConversionTable() { NL_BEGIN_STRING_CONVERSION_TABLE(TValues) NL_STRING_CONVERSION_TABLE_ENTRY(so_autostart_on) NL_STRING_CONVERSION_TABLE_ENTRY(so_autostart_off) NL_STRING_CONVERSION_TABLE_ENTRY(invalid_val) }; static NLMISC::CStringConversion conversionTable(TValues_nl_string_conversion_table, sizeof(TValues_nl_string_conversion_table) / sizeof(TValues_nl_string_conversion_table[0]), invalid_val); return conversionTable; } TValues _Value; public: TShardOrders() : _Value(invalid_val) { } TShardOrders(TValues value) : _Value(value) { } TShardOrders(const std::string &str) { _Value = getConversionTable().fromString(str); } void serial(NLMISC::IStream &s) { s.serialEnum(_Value); } bool operator == (const TShardOrders &other) const { return _Value == other._Value; } bool operator != (const TShardOrders &other) const { return ! (_Value == other._Value); } bool operator < (const TShardOrders &other) const { return _Value < other._Value; } bool operator <= (const TShardOrders &other) const { return _Value <= other._Value; } bool operator > (const TShardOrders &other) const { return !(_Value <= other._Value); } bool operator >= (const TShardOrders &other) const { return !(_Value < other._Value); } const std::string &toString() const { return getConversionTable().toString(_Value); } static const std::string &toString(TValues value) { return getConversionTable().toString(value); } TValues getValue() const { return _Value; } // return true if the actual value of the enum is valid, otherwise false bool isValid() { if (_Value == invalid_val) return false; // not invalid, check other enum value return getConversionTable().isValid(_Value); } uint32 asIndex() { std::map::const_iterator it(getIndexTable().find(_Value)); nlassert(it != getIndexTable().end()); return it->second; } }; struct TRunningOrders { enum TValues { ro_deactivated, ro_activated, /// the highest valid value in the enum last_enum_item = ro_activated, /// a value equal to the last enum item +1 end_of_enum, invalid_val, /// Number of enumerated values nb_enum_items = 2 }; /// Index table to convert enum value to linear index table const std::map &getIndexTable() const { static std::map indexTable; static bool init = false; if (!init) { // fill the index table indexTable.insert(std::make_pair(ro_deactivated, 0)); indexTable.insert(std::make_pair(ro_activated, 1)); init = true; } return indexTable; } static const NLMISC::CStringConversion &getConversionTable() { NL_BEGIN_STRING_CONVERSION_TABLE(TValues) NL_STRING_CONVERSION_TABLE_ENTRY(ro_deactivated) NL_STRING_CONVERSION_TABLE_ENTRY(ro_activated) NL_STRING_CONVERSION_TABLE_ENTRY(invalid_val) }; static NLMISC::CStringConversion conversionTable(TValues_nl_string_conversion_table, sizeof(TValues_nl_string_conversion_table) / sizeof(TValues_nl_string_conversion_table[0]), invalid_val); return conversionTable; } TValues _Value; public: TRunningOrders() : _Value(invalid_val) { } TRunningOrders(TValues value) : _Value(value) { } TRunningOrders(const std::string &str) { _Value = getConversionTable().fromString(str); } void serial(NLMISC::IStream &s) { s.serialEnum(_Value); } bool operator == (const TRunningOrders &other) const { return _Value == other._Value; } bool operator != (const TRunningOrders &other) const { return ! (_Value == other._Value); } bool operator < (const TRunningOrders &other) const { return _Value < other._Value; } bool operator <= (const TRunningOrders &other) const { return _Value <= other._Value; } bool operator > (const TRunningOrders &other) const { return !(_Value <= other._Value); } bool operator >= (const TRunningOrders &other) const { return !(_Value < other._Value); } const std::string &toString() const { return getConversionTable().toString(_Value); } static const std::string &toString(TValues value) { return getConversionTable().toString(value); } TValues getValue() const { return _Value; } // return true if the actual value of the enum is valid, otherwise false bool isValid() { if (_Value == invalid_val) return false; // not invalid, check other enum value return getConversionTable().isValid(_Value); } uint32 asIndex() { std::map::const_iterator it(getIndexTable().find(_Value)); nlassert(it != getIndexTable().end()); return it->second; } }; struct TRunningState { enum TValues { rs_stopped, rs_running, rs_online, /// the highest valid value in the enum last_enum_item = rs_online, /// a value equal to the last enum item +1 end_of_enum, invalid_val, /// Number of enumerated values nb_enum_items = 3 }; /// Index table to convert enum value to linear index table const std::map &getIndexTable() const { static std::map indexTable; static bool init = false; if (!init) { // fill the index table indexTable.insert(std::make_pair(rs_stopped, 0)); indexTable.insert(std::make_pair(rs_running, 1)); indexTable.insert(std::make_pair(rs_online, 2)); init = true; } return indexTable; } static const NLMISC::CStringConversion &getConversionTable() { NL_BEGIN_STRING_CONVERSION_TABLE(TValues) NL_STRING_CONVERSION_TABLE_ENTRY(rs_stopped) NL_STRING_CONVERSION_TABLE_ENTRY(rs_running) NL_STRING_CONVERSION_TABLE_ENTRY(rs_online) NL_STRING_CONVERSION_TABLE_ENTRY(invalid_val) }; static NLMISC::CStringConversion conversionTable(TValues_nl_string_conversion_table, sizeof(TValues_nl_string_conversion_table) / sizeof(TValues_nl_string_conversion_table[0]), invalid_val); return conversionTable; } TValues _Value; public: TRunningState() : _Value(invalid_val) { } TRunningState(TValues value) : _Value(value) { } TRunningState(const std::string &str) { _Value = getConversionTable().fromString(str); } void serial(NLMISC::IStream &s) { s.serialEnum(_Value); } bool operator == (const TRunningState &other) const { return _Value == other._Value; } bool operator != (const TRunningState &other) const { return ! (_Value == other._Value); } bool operator < (const TRunningState &other) const { return _Value < other._Value; } bool operator <= (const TRunningState &other) const { return _Value <= other._Value; } bool operator > (const TRunningState &other) const { return !(_Value <= other._Value); } bool operator >= (const TRunningState &other) const { return !(_Value < other._Value); } const std::string &toString() const { return getConversionTable().toString(_Value); } static const std::string &toString(TValues value) { return getConversionTable().toString(value); } TValues getValue() const { return _Value; } // return true if the actual value of the enum is valid, otherwise false bool isValid() { if (_Value == invalid_val) return false; // not invalid, check other enum value return getConversionTable().isValid(_Value); } uint32 asIndex() { std::map::const_iterator it(getIndexTable().find(_Value)); nlassert(it != getIndexTable().end()); return it->second; } }; struct TRunningTag { enum TValues { rt_chain_crashing, rt_locally_started, rt_locally_stopped, rt_globally_stopped, rt_stopped_for_patch, rt_externaly_started, rt_slow_to_stop, rt_slow_to_start, /// the highest valid value in the enum last_enum_item = rt_slow_to_start, /// a value equal to the last enum item +1 end_of_enum, invalid_val, /// Number of enumerated values nb_enum_items = 8 }; /// Index table to convert enum value to linear index table const std::map &getIndexTable() const { static std::map indexTable; static bool init = false; if (!init) { // fill the index table indexTable.insert(std::make_pair(rt_chain_crashing, 0)); indexTable.insert(std::make_pair(rt_locally_started, 1)); indexTable.insert(std::make_pair(rt_locally_stopped, 2)); indexTable.insert(std::make_pair(rt_globally_stopped, 3)); indexTable.insert(std::make_pair(rt_stopped_for_patch, 4)); indexTable.insert(std::make_pair(rt_externaly_started, 5)); indexTable.insert(std::make_pair(rt_slow_to_stop, 6)); indexTable.insert(std::make_pair(rt_slow_to_start, 7)); init = true; } return indexTable; } static const NLMISC::CStringConversion &getConversionTable() { NL_BEGIN_STRING_CONVERSION_TABLE(TValues) NL_STRING_CONVERSION_TABLE_ENTRY(rt_chain_crashing) NL_STRING_CONVERSION_TABLE_ENTRY(rt_locally_started) NL_STRING_CONVERSION_TABLE_ENTRY(rt_locally_stopped) NL_STRING_CONVERSION_TABLE_ENTRY(rt_globally_stopped) NL_STRING_CONVERSION_TABLE_ENTRY(rt_stopped_for_patch) NL_STRING_CONVERSION_TABLE_ENTRY(rt_externaly_started) NL_STRING_CONVERSION_TABLE_ENTRY(rt_slow_to_stop) NL_STRING_CONVERSION_TABLE_ENTRY(rt_slow_to_start) NL_STRING_CONVERSION_TABLE_ENTRY(invalid_val) }; static NLMISC::CStringConversion conversionTable(TValues_nl_string_conversion_table, sizeof(TValues_nl_string_conversion_table) / sizeof(TValues_nl_string_conversion_table[0]), invalid_val); return conversionTable; } TValues _Value; public: TRunningTag() : _Value(invalid_val) { } TRunningTag(TValues value) : _Value(value) { } TRunningTag(const std::string &str) { _Value = getConversionTable().fromString(str); } void serial(NLMISC::IStream &s) { s.serialEnum(_Value); } bool operator == (const TRunningTag &other) const { return _Value == other._Value; } bool operator != (const TRunningTag &other) const { return ! (_Value == other._Value); } bool operator < (const TRunningTag &other) const { return _Value < other._Value; } bool operator <= (const TRunningTag &other) const { return _Value <= other._Value; } bool operator > (const TRunningTag &other) const { return !(_Value <= other._Value); } bool operator >= (const TRunningTag &other) const { return !(_Value < other._Value); } const std::string &toString() const { return getConversionTable().toString(_Value); } static const std::string &toString(TValues value) { return getConversionTable().toString(value); } TValues getValue() const { return _Value; } // return true if the actual value of the enum is valid, otherwise false bool isValid() { if (_Value == invalid_val) return false; // not invalid, check other enum value return getConversionTable().isValid(_Value); } uint32 asIndex() { std::map::const_iterator it(getIndexTable().find(_Value)); nlassert(it != getIndexTable().end()); return it->second; } }; ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// class TServiceStatus { protected: // std::string _ShardName; // std::string _ServiceLongName; // std::string _ServiceShortName; // std::string _ServiceAliasName; // TRunningState _RunningState; // TRunningOrders _RunningOrders; // std::set < TRunningTag > _RunningTags; // std::string _Status; public: // const std::string &getShardName() const { return _ShardName; } std::string &getShardName() { return _ShardName; } void setShardName(const std::string &value) { _ShardName = value; } // const std::string &getServiceLongName() const { return _ServiceLongName; } std::string &getServiceLongName() { return _ServiceLongName; } void setServiceLongName(const std::string &value) { _ServiceLongName = value; } // const std::string &getServiceShortName() const { return _ServiceShortName; } std::string &getServiceShortName() { return _ServiceShortName; } void setServiceShortName(const std::string &value) { _ServiceShortName = value; } // const std::string &getServiceAliasName() const { return _ServiceAliasName; } std::string &getServiceAliasName() { return _ServiceAliasName; } void setServiceAliasName(const std::string &value) { _ServiceAliasName = value; } // TRunningState getRunningState() const { return _RunningState; } void setRunningState(TRunningState value) { _RunningState = value; } // TRunningOrders getRunningOrders() const { return _RunningOrders; } void setRunningOrders(TRunningOrders value) { _RunningOrders = value; } // const std::set < TRunningTag > &getRunningTags() const { return _RunningTags; } std::set < TRunningTag > &getRunningTags() { return _RunningTags; } void setRunningTags(const std::set < TRunningTag > &value) { _RunningTags = value; } // const std::string &getStatus() const { return _Status; } std::string &getStatus() { return _Status; } void setStatus(const std::string &value) { _Status = value; } bool operator == (const TServiceStatus &other) const { return _ShardName == other._ShardName && _ServiceLongName == other._ServiceLongName && _ServiceShortName == other._ServiceShortName && _ServiceAliasName == other._ServiceAliasName && _RunningState == other._RunningState && _RunningOrders == other._RunningOrders && _RunningTags == other._RunningTags && _Status == other._Status; } // constructor TServiceStatus() { } void serial(NLMISC::IStream &s) { s.serial(_ShardName); s.serial(_ServiceLongName); s.serial(_ServiceShortName); s.serial(_ServiceAliasName); s.serial(_RunningState); s.serial(_RunningOrders); s.serialCont(_RunningTags); s.serial(_Status); } private: }; ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// class CAdminServiceSkel { public: /// the interceptor type typedef NLNET::CInterceptorForwarder < CAdminServiceSkel> TInterceptor; protected: CAdminServiceSkel() { // do early run time check for message table getMessageHandlers(); } virtual ~CAdminServiceSkel() { } void init(NLNET::IModule *module) { _Interceptor.init(this, module); } // unused interceptors std::string fwdBuildModuleManifest() const { return std::string(); } void fwdOnModuleUp(NLNET::IModuleProxy *moduleProxy) {} void fwdOnModuleDown(NLNET::IModuleProxy *moduleProxy) {} void fwdOnModuleSecurityChange(NLNET::IModuleProxy *moduleProxy) {} // process module message interceptor bool fwdOnProcessModuleMessage(NLNET::IModuleProxy *sender, const NLNET::CMessage &message); private: typedef void (CAdminServiceSkel::*TMessageHandler)(NLNET::IModuleProxy *sender, const NLNET::CMessage &message); typedef std::map TMessageHandlerMap; const TMessageHandlerMap &getMessageHandlers() const; void upServiceUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); void graphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); void highRezGraphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); void commandResult_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); // declare one interceptor member of the skeleton TInterceptor _Interceptor; // declare the interceptor forwarder as friend of this class friend class NLNET::CInterceptorForwarder < CAdminServiceSkel>; public: ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// // An AES send an update of the list of service up virtual void upServiceUpdate(NLNET::IModuleProxy *sender, const std::vector < TServiceStatus > &serviceStatus) =0; // An AES send graph data update virtual void graphUpdate(NLNET::IModuleProxy *sender, const TGraphDatas &graphDatas) =0; // An AES send high rez graph data update virtual void highRezGraphUpdate(NLNET::IModuleProxy *sender, const THighRezDatas &graphDatas) =0; // AES send back the result of execution of a command virtual void commandResult(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result) =0; }; ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// class CAdminServiceProxy { /// Smart pointer on the module proxy NLNET::TModuleProxyPtr _ModuleProxy; // Pointer on the local module that implement the interface (if the proxy is for a local module) NLNET::TModulePtr _LocalModule; // Direct pointer on the server implementation interface for collocated module CAdminServiceSkel *_LocalModuleSkel; public: CAdminServiceProxy(NLNET::IModuleProxy *proxy) { _ModuleProxy = proxy; // initialize collocated servant interface if (proxy->getModuleDistance() == 0) { _LocalModule = proxy->getLocalModule(); nlassert(_LocalModule != NULL); CAdminServiceSkel::TInterceptor *interceptor = NULL; interceptor = static_cast < NLNET::CModuleBase* >(_LocalModule.getPtr())->getInterceptor(interceptor); nlassert(interceptor != NULL); _LocalModuleSkel = interceptor->getParent(); nlassert(_LocalModuleSkel != NULL); } else _LocalModuleSkel = 0; } virtual ~CAdminServiceProxy() { } NLNET::IModuleProxy *getModuleProxy() { return _ModuleProxy; } // An AES send an update of the list of service up void upServiceUpdate(NLNET::IModule *sender, const std::vector < TServiceStatus > &serviceStatus); // An AES send graph data update void graphUpdate(NLNET::IModule *sender, const TGraphDatas &graphDatas); // An AES send high rez graph data update void highRezGraphUpdate(NLNET::IModule *sender, const THighRezDatas &graphDatas); // AES send back the result of execution of a command void commandResult(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_upServiceUpdate(NLNET::CMessage &__message, const std::vector < TServiceStatus > &serviceStatus); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_graphUpdate(NLNET::CMessage &__message, const TGraphDatas &graphDatas); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_highRezGraphUpdate(NLNET::CMessage &__message, const THighRezDatas &graphDatas); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_commandResult(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &result); }; ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// class CAdminExecutorServiceSkel { public: /// the interceptor type typedef NLNET::CInterceptorForwarder < CAdminExecutorServiceSkel> TInterceptor; protected: CAdminExecutorServiceSkel() { // do early run time check for message table getMessageHandlers(); } virtual ~CAdminExecutorServiceSkel() { } void init(NLNET::IModule *module) { _Interceptor.init(this, module); } // unused interceptors std::string fwdBuildModuleManifest() const { return std::string(); } void fwdOnModuleUp(NLNET::IModuleProxy *moduleProxy) {} void fwdOnModuleDown(NLNET::IModuleProxy *moduleProxy) {} void fwdOnModuleSecurityChange(NLNET::IModuleProxy *moduleProxy) {} // process module message interceptor bool fwdOnProcessModuleMessage(NLNET::IModuleProxy *sender, const NLNET::CMessage &message); private: typedef void (CAdminExecutorServiceSkel::*TMessageHandler)(NLNET::IModuleProxy *sender, const NLNET::CMessage &message); typedef std::map TMessageHandlerMap; const TMessageHandlerMap &getMessageHandlers() const; void setShardOrders_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); void shutdownShard_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); void controlCmd_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); void serviceCmd_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); void commandResult_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); void graphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); void highRezGraphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); void serviceStatusUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); // declare one interceptor member of the skeleton TInterceptor _Interceptor; // declare the interceptor forwarder as friend of this class friend class NLNET::CInterceptorForwarder < CAdminExecutorServiceSkel>; public: ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// // AS send orders for a shard virtual void setShardOrders(NLNET::IModuleProxy *sender, const std::string &shardName, const TShardOrders &shardOrders) =0; // AS send a command to shutdown a shard with a delay virtual void shutdownShard(NLNET::IModuleProxy *sender, const std::string &shardName, uint32 delay) =0; // AS send a control command to this AES virtual void controlCmd(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command) =0; // Send a command to a service. virtual void serviceCmd(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command) =0; // AES client send back the result of execution of a command virtual void commandResult(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result) =0; // A service send graph data update virtual void graphUpdate(NLNET::IModuleProxy *sender, const TGraphDatas &graphDatas) =0; // A service high rez graph data update virtual void highRezGraphUpdate(NLNET::IModuleProxy *sender, const THighRezDatas &graphDatas) =0; // A service send an update of of it's status string virtual void serviceStatusUpdate(NLNET::IModuleProxy *sender, const std::string &status) =0; }; ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// class CAdminExecutorServiceProxy { /// Smart pointer on the module proxy NLNET::TModuleProxyPtr _ModuleProxy; // Pointer on the local module that implement the interface (if the proxy is for a local module) NLNET::TModulePtr _LocalModule; // Direct pointer on the server implementation interface for collocated module CAdminExecutorServiceSkel *_LocalModuleSkel; public: CAdminExecutorServiceProxy(NLNET::IModuleProxy *proxy) { _ModuleProxy = proxy; // initialize collocated servant interface if (proxy->getModuleDistance() == 0) { _LocalModule = proxy->getLocalModule(); nlassert(_LocalModule != NULL); CAdminExecutorServiceSkel::TInterceptor *interceptor = NULL; interceptor = static_cast < NLNET::CModuleBase* >(_LocalModule.getPtr())->getInterceptor(interceptor); nlassert(interceptor != NULL); _LocalModuleSkel = interceptor->getParent(); nlassert(_LocalModuleSkel != NULL); } else _LocalModuleSkel = 0; } virtual ~CAdminExecutorServiceProxy() { } NLNET::IModuleProxy *getModuleProxy() { return _ModuleProxy; } // AS send orders for a shard void setShardOrders(NLNET::IModule *sender, const std::string &shardName, const TShardOrders &shardOrders); // AS send a command to shutdown a shard with a delay void shutdownShard(NLNET::IModule *sender, const std::string &shardName, uint32 delay); // AS send a control command to this AES void controlCmd(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command); // Send a command to a service. void serviceCmd(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command); // AES client send back the result of execution of a command void commandResult(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result); // A service send graph data update void graphUpdate(NLNET::IModule *sender, const TGraphDatas &graphDatas); // A service high rez graph data update void highRezGraphUpdate(NLNET::IModule *sender, const THighRezDatas &graphDatas); // A service send an update of of it's status string void serviceStatusUpdate(NLNET::IModule *sender, const std::string &status); // AS send orders for a shard // This is the broadcast version of the method. template < class ProxyIterator > static void broadcast_setShardOrders(ProxyIterator first, ProxyIterator last, NLNET::IModule *sender, const std::string &shardName, const TShardOrders &shardOrders) { NLNET::CMessage message; // create the message to send to multiple dest buildMessageFor_setShardOrders(message , shardName, shardOrders); for (; first != last; ++first) { NLNET::IModuleProxy *proxy = *first; proxy->sendModuleMessage(sender, message); } } // AS send a command to shutdown a shard with a delay // This is the broadcast version of the method. template < class ProxyIterator > static void broadcast_shutdownShard(ProxyIterator first, ProxyIterator last, NLNET::IModule *sender, const std::string &shardName, uint32 delay) { NLNET::CMessage message; // create the message to send to multiple dest buildMessageFor_shutdownShard(message , shardName, delay); for (; first != last; ++first) { NLNET::IModuleProxy *proxy = *first; proxy->sendModuleMessage(sender, message); } } // AS send a control command to this AES // This is the broadcast version of the method. template < class ProxyIterator > static void broadcast_controlCmd(ProxyIterator first, ProxyIterator last, NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command) { NLNET::CMessage message; // create the message to send to multiple dest buildMessageFor_controlCmd(message , commandId, serviceAlias, command); for (; first != last; ++first) { NLNET::IModuleProxy *proxy = *first; proxy->sendModuleMessage(sender, message); } } // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_setShardOrders(NLNET::CMessage &__message, const std::string &shardName, const TShardOrders &shardOrders); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_shutdownShard(NLNET::CMessage &__message, const std::string &shardName, uint32 delay); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_controlCmd(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &command); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_serviceCmd(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &command); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_commandResult(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &result); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_graphUpdate(NLNET::CMessage &__message, const TGraphDatas &graphDatas); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_highRezGraphUpdate(NLNET::CMessage &__message, const THighRezDatas &graphDatas); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_serviceStatusUpdate(NLNET::CMessage &__message, const std::string &status); }; ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// class CAdminExecutorServiceClientSkel { public: /// the interceptor type typedef NLNET::CInterceptorForwarder < CAdminExecutorServiceClientSkel> TInterceptor; protected: CAdminExecutorServiceClientSkel() { // do early run time check for message table getMessageHandlers(); } virtual ~CAdminExecutorServiceClientSkel() { } void init(NLNET::IModule *module) { _Interceptor.init(this, module); } // unused interceptors std::string fwdBuildModuleManifest() const { return std::string(); } void fwdOnModuleUp(NLNET::IModuleProxy *moduleProxy) {} void fwdOnModuleDown(NLNET::IModuleProxy *moduleProxy) {} void fwdOnModuleSecurityChange(NLNET::IModuleProxy *moduleProxy) {} // process module message interceptor bool fwdOnProcessModuleMessage(NLNET::IModuleProxy *sender, const NLNET::CMessage &message); private: typedef void (CAdminExecutorServiceClientSkel::*TMessageHandler)(NLNET::IModuleProxy *sender, const NLNET::CMessage &message); typedef std::map TMessageHandlerMap; const TMessageHandlerMap &getMessageHandlers() const; void serviceCmd_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); void serviceCmdNoReturn_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message); // declare one interceptor member of the skeleton TInterceptor _Interceptor; // declare the interceptor forwarder as friend of this class friend class NLNET::CInterceptorForwarder < CAdminExecutorServiceClientSkel>; public: ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// // execute a command and return the result. virtual void serviceCmd(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &command) =0; // Send a command to a service without waiting for the return value. virtual void serviceCmdNoReturn(NLNET::IModuleProxy *sender, const std::string &command) =0; }; ///////////////////////////////////////////////////////////////// // WARNING : this is a generated file, don't change it ! ///////////////////////////////////////////////////////////////// class CAdminExecutorServiceClientProxy { /// Smart pointer on the module proxy NLNET::TModuleProxyPtr _ModuleProxy; // Pointer on the local module that implement the interface (if the proxy is for a local module) NLNET::TModulePtr _LocalModule; // Direct pointer on the server implementation interface for collocated module CAdminExecutorServiceClientSkel *_LocalModuleSkel; public: CAdminExecutorServiceClientProxy(NLNET::IModuleProxy *proxy) { _ModuleProxy = proxy; // initialize collocated servant interface if (proxy->getModuleDistance() == 0) { _LocalModule = proxy->getLocalModule(); nlassert(_LocalModule != NULL); CAdminExecutorServiceClientSkel::TInterceptor *interceptor = NULL; interceptor = static_cast < NLNET::CModuleBase* >(_LocalModule.getPtr())->getInterceptor(interceptor); nlassert(interceptor != NULL); _LocalModuleSkel = interceptor->getParent(); nlassert(_LocalModuleSkel != NULL); } else _LocalModuleSkel = 0; } virtual ~CAdminExecutorServiceClientProxy() { } NLNET::IModuleProxy *getModuleProxy() { return _ModuleProxy; } // execute a command and return the result. void serviceCmd(NLNET::IModule *sender, uint32 commandId, const std::string &command); // Send a command to a service without waiting for the return value. void serviceCmdNoReturn(NLNET::IModule *sender, const std::string &command); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_serviceCmd(NLNET::CMessage &__message, uint32 commandId, const std::string &command); // Message serializer. Return the message received in reference for easier integration static const NLNET::CMessage &buildMessageFor_serviceCmdNoReturn(NLNET::CMessage &__message, const std::string &command); }; } #endif ================================================ FILE: code/EVA/server/admin_modules/admin_modules_itf.xml ================================================ ================================================ FILE: code/EVA/server/admin_modules/aes_client_module.cpp ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "nel/misc/singleton.h" #include "nel/net/module.h" #include "nel/net/module_builder_parts.h" #include "nel/net/unified_network.h" #include "nel/net/service.h" #include "admin_modules_itf.h" using namespace std; using namespace NLMISC; using namespace NLNET; void aesclient_forceLink() {} namespace ADMIN { class CAdminExecutorServiceClient : /*public CManualSingleton,*/ public CEmptyModuleServiceBehav > >, public CAdminExecutorServiceClientSkel { enum { // Maximum time without sending report string (a kind of 'keep alive') MAX_DELAY_BETWEEN_REPORT = 30, // 30 seconds }; /// Flag to inform AES that we don't want to be affected by shard orders bool _DontUseShardOrders; /// Admin executor service module TModuleProxyPtr _AdminExecutorService; /// Date of last state reporting to AES uint32 _LastStateReport; /// Last date of status string update uint32 _LastStatusStringReport; /// Last status string sent (to avoid double send) string _LastSentStatus; /// The service alias (must be an unique name) string _ServiceAlias; /// A cache of the value because reading it is very slow uint32 _ProcessUsedMemory; struct TGraphSample { // The date of the sample (in second) uint32 TimeStamp; // The date of the sample (in ms) TTime HighRezTimeStamp; // sample value double SampleValue; }; struct TGraphVarInfo { /// Name of the graphed var string VarName; /** Mean time between two sample in ms * (in fact, if will be the min period) * Set it to 1 to have a sample at each tick * If the period is set less than 1000 ms, * then the var is considered 'high rez'. * Otherwise, the period is rounded at the * nearest integer second. * For 'high rez' var, the service buffer * the relative timestamp in ms at each * tick loop and send update every seconds * to the AES service. * In addition, HighRez var are also sent * every second as normal sample. */ uint32 MeanSamplePeriod; /// Date of last sample (low rez) uint32 LastSampleTimeStamp; /// Date of last sample (high rez) TTime LastHighRezTimeStamp; /// The vector of buffered samples vector Samples; TGraphVarInfo() : MeanSamplePeriod(1000), LastSampleTimeStamp(0), LastHighRezTimeStamp(0) { } }; /// The list of variable to graph (build from service config file var 'GraphVars') vector _GraphVars; /// Date of last graph public: CAdminExecutorServiceClient() : _DontUseShardOrders(false), _LastStateReport(0), _LastStatusStringReport(0), _ProcessUsedMemory(0) { CAdminExecutorServiceClientSkel::init(this); } std::string makeServiceAlias() { string serviceAlias = IService::getInstance()->getServiceAliasName(); if (serviceAlias.empty()) { serviceAlias = IService::getInstance()->getHostName()+"."+IService::getInstance()->getServiceUnifiedName(); } return serviceAlias; } string getModuleManifest() const { uint32 pid = getpid (); string serviceAlias = _ServiceAlias; CSString manifest; manifest << "LongName=" << IService::getInstance()->getServiceLongName() << " ShortName=" << IService::getInstance()->getServiceShortName() << " AliasName=" << serviceAlias << " PID=" << pid << " DontUseShardOrders=" << _DontUseShardOrders; return manifest; } bool initModule(const TParsedCommandLine &pcl) { if (!CModuleBase::initModule(pcl)) return false; // try to read the config file IService *service = IService::getInstance(); if (service == NULL) { nlwarning("Failed to get the IService singleton instance"); return false; } CConfigFile::CVar *gv = service->ConfigFile.getVarPtr("GraphVars"); if (gv) { _GraphVars.clear(); for (uint i =0; isize()/2; ++i) { TGraphVarInfo gvi; gvi.VarName = gv->asString(i*2); gvi.MeanSamplePeriod = max(1, gv->asInt((i*2)+1)); _GraphVars.push_back(gvi); } } // precompute the service name _ServiceAlias = makeServiceAlias(); // loop for an optional 'dontUseShardOrders' flag in init params const TParsedCommandLine *duso = pcl.getParam("dontUseShardOrders"); if (duso != NULL) _DontUseShardOrders = (duso->ParamValue == "true" || duso->ParamName == "1"); return true; } void onModuleUp(IModuleProxy *proxy) { if (proxy->getModuleClassName() == "AdminExecutorService") { nldebug("CAdminExecutorServiceClient : admin executor service up as '%s'", proxy->getModuleName().c_str()); // we found the manager of AES if (_AdminExecutorService != NULL) { nlwarning("CAdminExecutorServiceClient : admin executor service already known as '%s', replacing with new one", _AdminExecutorService->getModuleName().c_str()); } _AdminExecutorService = proxy; // // send basic service info to AES // CAdminExecutorServiceProxy aes(proxy); // // uint32 pid = getpid (); // // string serviceAlias = IService::getInstance()->getServiceAliasName(); // if (serviceAlias.empty()) // serviceAlias = getModuleFullyQualifiedName(); // // aes.serviceConnected(this, // IService::getInstance()->getServiceLongName(), // IService::getInstance()->getServiceShortName(), // serviceAlias, // pid); // for resend of the current status to the new AES _LastSentStatus = ""; sendServiceStatus(); } } void onModuleDown(IModuleProxy *proxy) { if (proxy == _AdminExecutorService) { nldebug("CAdminExecutorServiceClient : admin executor service '%s' is down", proxy->getModuleName().c_str()); _AdminExecutorService = NULL; } } void onModuleUpdate() { H_AUTO(CAdminExecutorServiceClient_onModuleUpdate); uint32 now = CTime::getSecondsSince1970(); TTime timer = CTime::getLocalTime(); // update every HR variables for (uint i=0; i<_GraphVars.size(); ++i) { if (_GraphVars[i].MeanSamplePeriod < 1000) { // this is a HR var TGraphVarInfo &gvi = _GraphVars[i]; if (gvi.LastHighRezTimeStamp + gvi.MeanSamplePeriod < timer) { // it's time to get a sample // create a sample gvi.Samples.push_back(TGraphSample()); TGraphSample &gs = gvi.Samples.back(); // inialise it gs.TimeStamp = now; gs.HighRezTimeStamp = timer; IVariable *var = dynamic_cast(ICommand::getCommand(gvi.VarName)); if (var != NULL) gs.SampleValue = atof(var->toString().c_str()); } } } if (_LastStateReport != now) { if ((now & 0xf) == 0) { // every 16 seconds because very slow IVariable *var = dynamic_cast(ICommand::getCommand("ProcessUsedMemory")); if (var != NULL) NLMISC::fromString(var->toString(), _ProcessUsedMemory); } // at least one second as passed, check for updates to send to // AES TGraphDatas graphDatas; graphDatas.setCurrentTime(now); THighRezDatas highRezDatas; highRezDatas.setServiceAlias(_ServiceAlias); highRezDatas.setCurrentTime(now); vector &datas = graphDatas.getDatas(); for (uint i=0; i<_GraphVars.size(); ++i) { if (_GraphVars[i].LastSampleTimeStamp+(_GraphVars[i].MeanSamplePeriod/1000) < now) { TGraphVarInfo &gvi = _GraphVars[i]; // it's time to send update for this var // create a new sample entry datas.push_back(TGraphData()); // and fill it TGraphData &gd = datas.back(); gd.setServiceAlias(_ServiceAlias); gd.setVarName(gvi.VarName); gd.setSamplePeriod(max(uint32(1), uint32(gvi.MeanSamplePeriod/1000))); if (gvi.Samples.empty()) { // no sample collected yet, just ask a new one IVariable *var = dynamic_cast(ICommand::getCommand(gvi.VarName)); if (var != NULL) gd.setValue(atof(var->toString().c_str())); } else { // we have some sample collected, just use the last one gd.setValue(gvi.Samples.back().SampleValue); } // if it's a high rez sampler, send the complete buffer if (gvi.MeanSamplePeriod < 1000 && _AdminExecutorService != NULL) { // build the message highRezDatas.setVarName(gvi.VarName); highRezDatas.getDatas().clear(); for (uint j=0; jgetServiceStatusString(); } if ((status != _LastSentStatus || (now - _LastStatusStringReport) > MAX_DELAY_BETWEEN_REPORT) && _AdminExecutorService != NULL) { CAdminExecutorServiceProxy aes(_AdminExecutorService); aes.serviceStatusUpdate(this, status); _LastSentStatus = status; _LastStatusStringReport = now; } } /////////////////////////////////////////////////////////////// // implementation from Admin executor service client /////////////////////////////////////////////////////////////// // execute a command and return the result. virtual void serviceCmd(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &command) { // create a displayer to gather the output of the command class CStringDisplayer: public IDisplayer { public: virtual void doDisplay( const CLog::TDisplayInfo& args, const char *message) { _Data += message; } std::string _Data; }; CStringDisplayer stringDisplayer; IService::getInstance()->CommandLog.addDisplayer(&stringDisplayer); // retrieve the command from the input message and execute it nlinfo ("ADMIN: Executing command from network : '%s'", command.c_str()); ICommand::execute (command, IService::getInstance()->CommandLog); // unhook our displayer as it's work is now done IService::getInstance()->CommandLog.removeDisplayer(&stringDisplayer); string serviceAlias = IService::getInstance()->getServiceAliasName(); if (serviceAlias.empty()) serviceAlias = getModuleFullyQualifiedName(); // return the result to AES CAdminExecutorServiceProxy aes(sender); aes.commandResult(this, commandId, serviceAlias, stringDisplayer._Data); } // execute a command without result virtual void serviceCmdNoReturn(NLNET::IModuleProxy *sender, const std::string &command) { // retrieve the command from the input message and execute it nlinfo ("ADMIN: Executing command from network : '%s'", command.c_str()); ICommand::execute (command, IService::getInstance()->CommandLog); } }; NLNET_REGISTER_MODULE_FACTORY(CAdminExecutorServiceClient, "AdminExecutorServiceClient"); } // namespace ADMIN ================================================ FILE: code/EVA/server/admin_modules/aes_module.cpp ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "nel/misc/singleton.h" #include #include "nel/misc/path.h" #include "nel/net/module.h" #include "nel/net/module_builder_parts.h" #include "nel/net/unified_network.h" #include "nel/net/service.h" #include "server_share/utils.h" #include "admin_modules_itf.h" using namespace std; using namespace NLMISC; using namespace NLNET; void aes_forceLink() {} namespace ADMIN { const char* LAUNCH_CTRL_START = "LAUNCH"; const char* LAUNCH_CTRL_STOP = "STOP"; const char *AESPersistentStateFilename = "aes_state.txt"; /// We want 10 slot (you can change this, but need at least 3 slots) const uint32 CRASH_COUNTER_SLOT = 10; /// The delay (in second) between slots roll. This value * CRASH_COUNTER_SLOT give the total sampling period const uint32 CRASH_COUNTER_ROLL_DELAY = 10*60; // 10 mn /// If we have more than 5 start of a service in the sampling period, we tag the service as 'chain crashing' const uint32 CRASH_COUNTER_CHAIN_THRESHOLD = 5; /** the name of the file written by the patch man to request a global shutdown * of all registered the services before switching to a new version. */ CVariable ShutdownRequestFileName("aes","ShutdownRequestFileName", "name of the file to use for shutdown requests", "./global.launch_ctrl", 0, true); /** A kind rolling buffer used to count services start from the runner * script. */ class CRunnerLoopCounter { /// The slot table. Each slot accumulate the service start for a time frame uint32 _Slots[CRASH_COUNTER_SLOT]; /** The last value read from the runner script. This is used to compute * the delta value to add to the first slot */ uint32 _LastValueRead; /// The total sum of all slot (could be recomputed on demand, but a little more efficient) uint32 _CounterSum; public: CRunnerLoopCounter() { // we need at least 3 slots nlctassert(CRASH_COUNTER_SLOT >= 3); // init all slots with 0 for (uint i=0; i0; --i) { _Slots[i] = _Slots[i-1]; } _Slots[0] = 0; } /// Return the sum of all the slots uint32 getSum() { return _CounterSum; } /// Return the sum of the first slot, the tree first slot and /// the total of all slots. /// This is useful to understand the behavoir of a crashing /// service over the sampling period. void getCounters(uint32 &oneSlot, uint32 &treeSlots, uint32 &allSlots) { oneSlot = _Slots[0]; treeSlots = _Slots[0]+_Slots[1]+_Slots[2]; allSlots = _CounterSum; } /// Reset all counter to zero void resetCounter() { for (uint i=0; i,*/ public CEmptyModuleServiceBehav > >, public CAdminExecutorServiceSkel, public IModuleTrackerCb { public: enum { SLOW_TO_START_THRESHOLD = 60, // 1 mn SLOW_TO_STOP_THRESHOLD = 60, // 1 mn _NagiosReportDelay = 60, // 1 mn }; private: typedef CModuleTracker TServiceTracker; // tracker for admin executor client modules TServiceTracker _ServiceTracker; /// Admin service module TModuleProxyPtr _AdminService; /// Date of last state reporting to AS uint32 _LastStateReport; /// Date of last nagios report output uint32 _LastNagiosReport; typedef string TAliasName; typedef string TShardName; typedef set TRegisteredServices; /// List of 'registered service', ie. those that are configured in aes cfg. TRegisteredServices _RegisteredServices; /// A set of data for each registered or connected service struct TServiceState { string ShardName; bool DontUseShardOrders; TRunningState RunningState; set RunningTags; string LongName; string ShortName; uint32 PID; string State; uint32 LastStateDate; uint32 StopRequestDate; uint32 StartRequestDate; TModuleProxyPtr ServiceModule; CRunnerLoopCounter RunnerLoopCounter; TServiceState() : DontUseShardOrders(false), RunningState(TRunningState::rs_stopped), PID(0), LastStateDate(0), StopRequestDate(0), StartRequestDate(0) {} }; typedef map TServiceStates; /// States for each connected or registered service TServiceStates _ServiceStates; typedef map TConnectedServiceIndex; /// Index of connected service proxy to alias name TConnectedServiceIndex _ConnectedServiceIndex; typedef map TPersistentServiceOrders; /// Persistent service state, i.e state that are restored after a stop/start of the aes TPersistentServiceOrders _PersistentServiceOrders; typedef map TShardsOrders; /// Shard orders (set by AS) TShardsOrders _ShardOrders; /// flag for shutdown request form patch manager. bool _ShutdownForPatch; /// A flag that mean we need to save the persistent state file bool _NeedToWriteStateFile; /// Date of last roll of the runner loop counters uint32 _LastRunnerLoopCounterRoll; /// Data for each command pending result from a service struct TPendingWebCommand { /// Date of reception of the command for timeout uint32 ReceptionDate; /// Name of the target service string ServiceAlias; /// Command string Command; }; typedef uint32 TCommandId; typedef map TPendingWebCommands; /// A list of pending command sent to service and waiting result TPendingWebCommands _PendingWebCommands; /// information about shard being stopped struct TStopingShardInfo { /// Name of the shard to stop string ShardName; /// Delay before stop uint32 Delay; /// Begin date of countdown uint32 BeginDate; }; typedef vector TStopingShardInfos; /// The vector of shard to stop. TStopingShardInfos _StopingShards; public: CAdminExecutorService() : _ServiceTracker(TModuleClassPred("AdminExecutorServiceClient")), _LastStateReport(0), _LastNagiosReport(0), _ShutdownForPatch(false), _NeedToWriteStateFile(false), _LastRunnerLoopCounterRoll(0) { CAdminExecutorServiceSkel::init(this); _ServiceTracker.init(this, this); } bool initModule(const TParsedCommandLine &pcl) { CModuleBase::initModule(pcl); // read the persistent state file if any string filename = CPath::standardizePath(IService::getInstance()->SaveFilesDirectory.toString(), true)+AESPersistentStateFilename; FILE *fp = fopen(filename.c_str(), "rt"); if (fp != NULL) { char buffer[1024]; char *ret; while ((ret=fgets(buffer, 1024, fp)) != NULL) { CSString line(buffer); CSString cmd(line.firstWord(true)); if (cmd == "ServiceState") { CSString serviceAlias = line.firstWord(true); CSString serviceOrders = line.firstWord(true); TRunningOrders runningOrders(serviceOrders); if (!serviceAlias.empty() && runningOrders != TRunningOrders::invalid_val) { // add this one in the list of persistent state _PersistentServiceOrders[serviceAlias] = runningOrders; } } else if (cmd == "ShardOrders") { string shardName(line.firstWord(true)); TShardOrders shardOrders(line.firstWord(true)); if (shardOrders != TShardOrders::invalid_val) _ShardOrders[shardName] = shardOrders; } } // clear the flag because 'setGlobalState' has set it _NeedToWriteStateFile = false; fclose(fp); } return true; } void onModuleUp(IModuleProxy *proxy) { if (proxy->getModuleClassName() == "AdminService") { nldebug("CAdminExecutorService : admin service up as '%s'", proxy->getModuleName().c_str()); // we found the manager of AES if (_AdminService != NULL) { nlwarning("CAdminExecutorService : admin service already known as '%s', replacing with new one", _AdminService->getModuleName().c_str()); } _AdminService = proxy; // cleanup the persistent service state by removing any state not in registered or connected service { set removeList; // first, fill the list with all the persistent state service name { TPersistentServiceOrders::iterator first(_PersistentServiceOrders.begin()), last(_PersistentServiceOrders.end()); for (; first != last; ++first) { removeList.insert(first->first); } } // remove the registered service from the removelist { TRegisteredServices::iterator first(_RegisteredServices.begin()), last(_RegisteredServices.end()); for (; first != last; ++first) { removeList.erase(*first); } } // remove any connected service (even unregistered one) { TServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end()); for (; first != last; ++first) { removeList.erase(first->first); } } // no remove persistent state that left in the remove list while (!removeList.empty()) { _PersistentServiceOrders.erase(*(removeList.begin())); _NeedToWriteStateFile = true; removeList.erase(removeList.begin()); } } // send the current status sendUpServiceUpdate(); } uint32 now = NLMISC::CTime::getSecondsSince1970(); // check pending command timeout TPendingWebCommands::iterator first(_PendingWebCommands.begin()), last(_PendingWebCommands.end()); for (; first != last; ++first) { TPendingWebCommand &pwc = first->second; if (now - pwc.ReceptionDate > 10) { // timeout if (_AdminService != NULL) { CAdminServiceProxy as(_AdminService); as.commandResult(this, first->first, pwc.ServiceAlias, "ERROR : AES : no reponse from service"); } _PendingWebCommands.erase(first); // check other pending commands at next update break; } } } void onModuleDown(IModuleProxy *proxy) { if (proxy == _AdminService) { nldebug("CAdminExecutorService : admin service '%s' is down", proxy->getModuleName().c_str()); _AdminService = NULL; } } void onModuleUpdate() { H_AUTO(CAdminExecutorService_onModuleUpdate); uint32 now = CTime::getSecondsSince1970(); if (_LastStateReport < now) { // every second // check services every second TServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end()); for (; first != last; ++first) { string aliasName = first->first; TServiceState &ss = first->second; if (_RegisteredServices.find(aliasName) != _RegisteredServices.end()) { // this is a registered service, we need to control is running state // read the actual running state from the runner script written file if (getOfflineServiceState(aliasName) == "RUNNING") { // the service is running ss.RunningTags.erase(TRunningTag::rt_locally_stopped); ss.RunningTags.erase(TRunningTag::rt_globally_stopped); ss.RunningTags.erase(TRunningTag::rt_stopped_for_patch); if (ss.StopRequestDate != 0) { // still not stopped, check for slow to stop service if (now - ss.StopRequestDate > SLOW_TO_STOP_THRESHOLD) { // add a running tag ss.RunningTags.insert(TRunningTag::rt_slow_to_stop); } } if (ss.RunningState != TRunningState::rs_online) { // tag slow to start service if (now - ss.StartRequestDate > SLOW_TO_START_THRESHOLD) { // add a running tag ss.RunningTags.insert(TRunningTag::rt_slow_to_start); } else { ss.RunningState = TRunningState::rs_running; } } } else { // the service is stopped ss.RunningState = TRunningState::rs_stopped; ss.RunningTags.erase(TRunningTag::rt_locally_started); ss.RunningTags.erase(TRunningTag::rt_externaly_started); ss.RunningTags.erase(TRunningTag::rt_slow_to_stop); // clean the stop request date ss.StopRequestDate = 0; } // try to obtains service orders from its shard TShardOrders shardOrders(TShardOrders::so_autostart_on); if (_ShardOrders.find(ss.ShardName) != _ShardOrders.end()) { shardOrders = _ShardOrders[ss.ShardName]; } // little check, the service must have a entry in the service orders container. nlassert(_PersistentServiceOrders.find(aliasName) != _PersistentServiceOrders.end()); TRunningOrders serviceOrders = _PersistentServiceOrders[aliasName]; // look if service need to be started if (ss.RunningState == TRunningState::rs_stopped // its stopped && serviceOrders == TRunningOrders::ro_activated // and activated && shardOrders == TShardOrders::so_autostart_on // and shard is autostart on && !ss.DontUseShardOrders // and this service follow its shard orders && !_ShutdownForPatch // and no patch pending ) { // we must start this service ! startService(aliasName); } // look for service that need to be stopped if (ss.RunningState != TRunningState::rs_stopped // its not stopped && (serviceOrders == TRunningOrders::ro_deactivated // and deactivated || _ShutdownForPatch) // or patch pending && ss.StopRequestDate == 0 // no stop request send ) { // we must stop this service stopService(aliasName); // store the sop ss.StopRequestDate = now; } // shuted down for patch ? if (_ShutdownForPatch) ss.RunningTags.insert(TRunningTag::rt_stopped_for_patch); else ss.RunningTags.erase(TRunningTag::rt_stopped_for_patch); // chain crashing ? if (ss.RunnerLoopCounter.getSum() > CRASH_COUNTER_CHAIN_THRESHOLD) ss.RunningTags.insert(TRunningTag::rt_chain_crashing); else ss.RunningTags.erase(TRunningTag::rt_chain_crashing); // update the crash counter ss.RunnerLoopCounter.updateCounter(getServiceStartLoopCounter(aliasName)); } } // if we have an admin service connected, send it an update of service state if (_AdminService != NULL) sendUpServiceUpdate(); if ((now & 0xf) == 0) { // every 8 seconds for low frequency work // check for shutdown request from patchman checkShutdownRequest(); } // check for shard to stop (and warning to send) checkServiceToStop(); // time to output the nagios report ? if (now > _LastNagiosReport+_NagiosReportDelay) { // write the nagios report FILE *fp = fopen("aes_nagios_report.txt", "wt"); if (fp != NULL) { // output the current date time_t t = now; fprintf(fp, "AESReportDate=%s", ::ctime(&t)); fprintf(fp, "NBService=%u\n", (uint32)_ServiceStates.size()); // output state of each service TServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end()); for (; first != last; ++first) { CSString serviceLine; TServiceState &ss = first->second; const string &aliasName = first->first; CSString runningTags; set::iterator rtf(ss.RunningTags.begin()), rte(ss.RunningTags.end()); for (; rtf != rte; ++rtf) { runningTags<<"<"<toString()<<">"; } bool registered = _RegisteredServices.find(aliasName) != _RegisteredServices.end(); serviceLine << "ServiceAlias='"<second.RunnerLoopCounter.rollCounter(); } _LastRunnerLoopCounterRoll = now; } if (_NeedToWriteStateFile) { /// The persistent service orders need to be saved string filename = CPath::standardizePath(IService::getInstance()->SaveFilesDirectory.toString(), true)+AESPersistentStateFilename; FILE *fp = fopen(filename.c_str(), "wt"); if (fp != NULL) { { CSString line; TShardsOrders::iterator first(_ShardOrders.begin()), last(_ShardOrders.end()); for (; first != last; ++first) { line << "ShardOrders "<first<<" "<second.toString()<<"\n"; } fputs(line.c_str(), fp); } { TPersistentServiceOrders::iterator first(_PersistentServiceOrders.begin()), last(_PersistentServiceOrders.end()); for (; first != last; ++first) { CSString line; line << "ServiceState "<first<<" "<second.toString()<<"\n"; fputs(line.c_str(), fp); } } // clear the flag because 'setGlobalState' has set it _NeedToWriteStateFile = false; fclose(fp); } } } void sendUpServiceUpdate() { if (_AdminService != NULL) { vector serviceStatus; set missingServices = _RegisteredServices; // send an updated list to AES TServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end()); for (; first != last; ++first) { const string &aliasName = first->first; bool registered = _RegisteredServices.find(aliasName) != _RegisteredServices.end(); TServiceState &ss = first->second; serviceStatus.push_back(TServiceStatus()); TServiceStatus &ts = serviceStatus.back(); ts.setShardName(ss.ShardName); ts.setServiceLongName(ss.LongName); ts.setServiceShortName(ss.ShortName); ts.setServiceAliasName(aliasName); ts.setRunningState(ss.RunningState); if (registered) ts.setRunningOrders(_PersistentServiceOrders[aliasName]); else ts.setRunningOrders(TRunningOrders::invalid_val); ts.setRunningTags(ss.RunningTags); CSString state; state << ss.State << "\tNoReportSince=" << (NLMISC::CTime::getSecondsSince1970()-ss.LastStateDate); // add the host name state << "\tHostname=" << IService::getInstance()->getHostName(); if (registered) { // this is a registered service, send the start counter uint32 oneSlot, treeSlots, allSlots; ss.RunnerLoopCounter.getCounters(oneSlot, treeSlots, allSlots); state << "\tStartCounter="<second == serviceAlias) { // ok, we found it return first->first; } } // not found return NULL; } void checkShutdownRequest() { // if there's no ctrl file to be found then giveup if (!NLMISC::CFile::fileExists(ShutdownRequestFileName)) return; // if a shutdown ctrl file exists then read it's contents (if the file doesn't exist this returns an empty string) CSString fileContents; fileContents.readFromFile(ShutdownRequestFileName.c_str()); // see if the file exists if (!fileContents.empty()) { NLMISC::CFile::deleteFile(ShutdownRequestFileName); fileContents= fileContents.strip().splitToOneOfSeparators(" \t\n\r\x1a"); NLMISC::fromString(fileContents, _ShutdownForPatch); _ShutdownForPatch = !_ShutdownForPatch; } } void checkServiceToStop() { uint32 now = CTime::getSecondsSince1970(); // for each shard to stop for (uint i=0; i<_StopingShards.size(); ++i) { const TStopingShardInfo &stopShardInfo = _StopingShards[i]; bool timeToStop = stopShardInfo.BeginDate + stopShardInfo.Delay <= now; uint32 timeLeft = (stopShardInfo.BeginDate + stopShardInfo.Delay) - now; // check every service TServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end()); for (; first != last; ++first) { TServiceState &serviceState = first->second; if (serviceState.ServiceModule != NULL && serviceState.ShardName == stopShardInfo.ShardName) { // this one belong to the shard to stop if (!timeToStop) { // send a warning every 30 s if (((now - stopShardInfo.BeginDate) % 30) == 0) { CAdminExecutorServiceClientProxy aec(serviceState.ServiceModule); nlinfo("Sending command 'quitDelay' to service '%s'", first->first.c_str()); aec.serviceCmdNoReturn(this, toString("quitDelay %u", timeLeft)); } } else { // stop the service stopService(first->first); } } } if (timeToStop) { nlinfo("All local service for shard %s are stopped", stopShardInfo.ShardName.c_str()); // shard stopped, erase this entry _StopingShards.erase(_StopingShards.begin()+i); --i; } } } // the following routine reads the text string contained in the ".state" file for this service // it's used to provide a 'state' value for services that are registered but are not connected // to give info on whether they've been launched, whether their launcher is online, etc std::string getOfflineServiceState(const std::string& serviceAlias) { // open the file for reading FILE* f= fopen(getServiceStateFileName(serviceAlias).c_str(),"rt"); if (f==NULL) return "STOPPED"; // setup a buffer to hold the text read from the file uint32 fileSize= NLMISC::CFile::getFileSize(f); std::string txt; txt.resize(fileSize); // read the text from the file - note that the number of bytes read may be less than the // number of bytes requested because we've opened the file in text mode and not binary mode uint32 bytesRead= (uint32)fread(&txt[0],1,fileSize,f); txt.resize(bytesRead); fclose(f); // return the text read from the file return txt; } // the following routine reads the text string contained in the "pid.state" file for this service // it's used to provide a early pid information to the AES (before the service is connected) uint32 getOfflineServicePID(const std::string& serviceAlias) { // open the file for reading FILE* f= fopen(getServicePIDFileName(serviceAlias).c_str(),"rt"); if (f==NULL) return 0; // setup a buffer to hold the text read from the file uint32 fileSize= NLMISC::CFile::getFileSize(f); std::string txt; txt.resize(fileSize); // read the text from the file - note that the number of bytes read may be less than the // number of bytes requested because we've opened the file in text mode and not binary mode uint32 bytesRead= (uint32)fread(&txt[0],1,fileSize,f); txt.resize(bytesRead); fclose(f); // return the pid read from the file uint32 pid; NLMISC::fromString(txt, pid); return pid; } // the following routine reads the text string contained in the ".start_counter" file for this service // it's used to provide the number of start done by the runner loop on the service // This is used for the chain crash detector system. uint32 getServiceStartLoopCounter(const std::string& serviceAlias) { // open the file for reading FILE* f= fopen(getServiceLoopCounterFileName(serviceAlias).c_str(),"rt"); if (f==NULL) return 0; // setup a buffer to hold the text read from the file uint32 fileSize= NLMISC::CFile::getFileSize(f); std::string txt; txt.resize(fileSize); // read the text from the file - note that the number of bytes read may be less than the // number of bytes requested because we've opened the file in text mode and not binary mode uint32 bytesRead= (uint32)fread(&txt[0],1,fileSize,f); txt.resize(bytesRead); fclose(f); // parse the text in the buffer uint32 counter; NLMISC::fromString(txt, counter); return counter; } // retrieve service launch info in the config file bool getServiceLaunchInfo(const string& serviceAlias, string& path) { string basePath; CConfigFile::CVar *launchDir = IService::getInstance()->ConfigFile.getVarPtr("AESLauncherDir"); if (launchDir != NULL) { basePath = launchDir->asString()+"/"; } if (_RegisteredServices.find(serviceAlias) == _RegisteredServices.end()) return false; path = basePath + serviceAlias+"/"; return true; } std::string getServiceStateFileName(const std::string& serviceAlias) { string servicePath; if (getServiceLaunchInfo(serviceAlias, servicePath)) return NLMISC::CPath::standardizePath(servicePath)+serviceAlias+".state"; else return string(); } std::string getServicePIDFileName(const std::string& serviceAlias) { string servicePath; if (getServiceLaunchInfo(serviceAlias, servicePath)) return NLMISC::CPath::standardizePath(servicePath)+"pid.state"; else return string(); } std::string getServiceLoopCounterFileName(const std::string& serviceAlias) { string servicePath; if (getServiceLaunchInfo(serviceAlias, servicePath)) return NLMISC::CPath::standardizePath(servicePath)+serviceAlias+".start_count"; else return string(); } std::string getServiceLaunchCtrlFileName(const std::string& serviceAlias,const std::string& serviceExecutionPath, bool deferred) { return NLMISC::CPath::standardizePath(serviceExecutionPath)+serviceAlias+(deferred?".deferred_":".")+"launch_ctrl"; } bool writeServiceLaunchCtrl(const std::string& serviceAlias, bool deferred, const std::string& txt) { string path; if (!getServiceLaunchInfo(serviceAlias, path)) return false; // make sure the path exists NLMISC::CFile::createDirectoryTree(path); // open the file for writing FILE* f= fopen(getServiceLaunchCtrlFileName(serviceAlias, path, deferred).c_str(),"wt"); if (f==NULL) return false; // write the text to the file fprintf(f,"%s",txt.c_str()); fclose(f); return true; } bool startService(const std::string &serviceAlias) { if (_ServiceStates.find(serviceAlias) != _ServiceStates.end()) { TServiceState &ss = _ServiceStates[serviceAlias]; if (ss.RunningState != TRunningState::rs_stopped) { nlwarning("startService '%s' : the service is already running", serviceAlias.c_str()); return false; } // store the start date ss.StartRequestDate = CTime::getSecondsSince1970(); } if (_RegisteredServices.find(serviceAlias) == _RegisteredServices.end()) { nlwarning("startService '%s' : the service in not registered, can't start it", serviceAlias.c_str()); return false; } // write the start command bool ret = writeServiceLaunchCtrl(serviceAlias, false, LAUNCH_CTRL_START); return ret; } bool stopService(const std::string &serviceAlias) { // check that the service is running TServiceStates::iterator it(_ServiceStates.find(serviceAlias)); if (it == _ServiceStates.end()) { nlwarning("stopService : Failed to found service '%s' in the list of services", serviceAlias.c_str()); return false; } TServiceState &ss = it->second; // write the launch control to stop if (_RegisteredServices.find(serviceAlias) != _RegisteredServices.end()) { if (!writeServiceLaunchCtrl(serviceAlias, false, LAUNCH_CTRL_STOP)) { nlwarning("Failed to write launch control file for service '%s'", serviceAlias.c_str()); return false; } else nlinfo("Service '%s' launch control file updated", serviceAlias.c_str()); } // set the stopre request date if needed if (ss.StopRequestDate != 0) { ss.StopRequestDate = CTime::getSecondsSince1970(); } if (ss.ServiceModule == NULL) { nlwarning("stopService : The service '%s' is not connected, can't ask him to stop", serviceAlias.c_str()); return false; } // send the "quit" command to the service CAdminExecutorServiceClientProxy aec(ss.ServiceModule); nlinfo("Sending command 'quit' to service '%s'", serviceAlias.c_str()); aec.serviceCmdNoReturn(this, "quit"); return true; } /////////////////////////////////////////////////////////////////////// //// Virtuals from IModuleTrackerCb /////////////////////////////////////////////////////////////////////// virtual void onTrackedModuleUp(IModuleProxy *moduleProxy) { nldebug("Service module '%s' UP", moduleProxy->getModuleName().c_str()); TParsedCommandLine pcl; if (!pcl.parseParamList(moduleProxy->getModuleManifest())) { nlwarning("CAdminExecutorService:onTrackedModuleUp : failed to parse manifest"); } const TParsedCommandLine *pclLongName = pcl.getParam("LongName"); const TParsedCommandLine *pclShortName = pcl.getParam("ShortName"); const TParsedCommandLine *pclAliasName = pcl.getParam("AliasName"); const TParsedCommandLine *pclPID = pcl.getParam("PID"); const TParsedCommandLine *pclDontUseShardOrders = pcl.getParam("DontUseShardOrders"); string aliasName = pclAliasName != NULL ? pclAliasName->ParamValue : moduleProxy->getModuleName(); // remove the temporary state and update connected service index _ServiceStates.erase(moduleProxy->getModuleName()); _ConnectedServiceIndex[moduleProxy] = aliasName; nlinfo("AES client module %s for service %s is up", moduleProxy->getModuleName().c_str(), aliasName.c_str()); // create a new entry or get an existing one TServiceState &ss = _ServiceStates[aliasName]; // update the service state ss.RunningState = TRunningState::rs_online; if (pclDontUseShardOrders) NLMISC::fromString(pclDontUseShardOrders->ParamValue, ss.DontUseShardOrders); else ss.DontUseShardOrders = false; ss.LongName = pclLongName != NULL ? pclLongName->ParamValue : "unknown"; ss.ShortName = pclShortName != NULL ? pclShortName->ParamValue : "unknown"; if (pclPID!= NULL) { NLMISC::fromString(pclPID->ParamValue, ss.PID); } else { ss.PID = 0; } ss.State = ""; ss.LastStateDate = NLMISC::CTime::getSecondsSince1970(); ss.ServiceModule = moduleProxy; ss.StartRequestDate = 0; ss.RunningTags.erase(TRunningTag::rt_slow_to_start); if (_RegisteredServices.find(aliasName) == _RegisteredServices.end()) { ss.RunningTags.insert(TRunningTag::rt_externaly_started); } // else // { // // if this service is locally stopped or if the shard it belong to is stopped, // // then flag it as 'localy started' // if (_PersistentServiceOrders.find(aliasName) != _PersistentServiceOrders.end() // && _PersistentServiceOrders[aliasName] == TRunningOrders::ro_stopped) // { // // flag it as started // _PersistentServiceOrders[aliasName] = TRunningOrders::ro_running; // ss.RunningTags.insert(TRunningTag::rt_locally_started); // _NeedToWriteStateFile = true; // } // else if (_ShardOrders.find(ss.ShardName) != _ShardOrders.end() // && _ShardOrders[ss.ShardName] == TRunningOrders::ro_stopped) // { // // the shard is stopped, flag the service as started // _PersistentServiceOrders[aliasName] = TRunningOrders::ro_running; // ss.RunningTags.insert(TRunningTag::rt_locally_started); // _NeedToWriteStateFile = true; // } // } sendUpServiceUpdate(); } virtual void onTrackedModuleDown(IModuleProxy *moduleProxy) { nldebug("Service module '%s' DOWN", moduleProxy->getModuleName().c_str()); TConnectedServiceIndex::iterator it(_ConnectedServiceIndex.find(moduleProxy)); if (it != _ConnectedServiceIndex.end()) { string &aliasName = it->second; nlinfo("AES client module %s of service %s is down", moduleProxy->getModuleName().c_str(), aliasName.c_str()); BOMB_IF(_ServiceStates.find(aliasName) == _ServiceStates.end(), "Service down from "<getModuleName()<<" with alias "< 1) { nlinfo("Killing process %u (%s) because aes client module '%s' is down", ss.PID, aliasName.c_str(), moduleProxy->getModuleName().c_str()); killProgram(ss.PID); } } retry_pending_command_loop: // check for pending command TPendingWebCommands::iterator first(_PendingWebCommands.begin()), last(_PendingWebCommands.end()); for (; first != last; ++first) { TPendingWebCommand &pwc = first->second; if (pwc.ServiceAlias == aliasName) { if (_AdminService != NULL) { CAdminServiceProxy as(_AdminService); as.commandResult(this, first->first, pwc.ServiceAlias, "ERROR : AES : service connection lost during command"); } _PendingWebCommands.erase(first); // goto to avoid iterator dodging goto retry_pending_command_loop; } } // remove the index record _ConnectedServiceIndex.erase(it); } else { nlinfo("AES client module %s is not associated with a service", moduleProxy->getModuleName().c_str()); } sendUpServiceUpdate(); } /////////////////////////////////////////////////////////////////////// //// Virtuals from CAdminExecutorServiceSkel /////////////////////////////////////////////////////////////////////// // AS send orders for a shard virtual void setShardOrders(NLNET::IModuleProxy *sender, const std::string &shardName, const TShardOrders &shardOrders) { nlinfo("AS setShardOrders for shard '%s' to '%s'", shardName.c_str(), shardOrders.toString().c_str()); if (_ShardOrders[shardName] == shardOrders) { // nothing to do return; } _ShardOrders[shardName] = shardOrders; _NeedToWriteStateFile = true; // nothing more to do, if service need to be started, they are started // by the module update function } // AS send a command to shutdown a shard with a delay virtual void shutdownShard(NLNET::IModuleProxy *sender, const std::string &shardName, uint32 delay) { TStopingShardInfo ssi; ssi.ShardName = shardName; ssi.Delay = delay; ssi.BeginDate = CTime::getSecondsSince1970(); _StopingShards.push_back(ssi); nlinfo("Received command to stop all service of shard %s in %us", ssi.ShardName.c_str(), ssi.Delay); // force a first update (to send the first warning message or stop immediately) checkServiceToStop(); } // AS send a control command to this AES virtual void controlCmd(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command) { // create a displayer to gather the output of the command class CStringDisplayer: public IDisplayer { public: virtual void doDisplay( const CLog::TDisplayInfo& args, const char *message) { _Data += message; } std::string _Data; }; nldebug("Control command from '%s' : '%s' '%s'", sender->getModuleName().c_str(), serviceAlias.c_str(), command.c_str()); // look in the list of service for a matching one IModuleProxy *service = findOnlineService(serviceAlias); if (service == NULL && _RegisteredServices.find(serviceAlias) == _RegisteredServices.end()) { CAdminServiceProxy as(sender); as.commandResult(this, commandId, serviceAlias, "ERROR : AES : service not found will dispatching the control command"); return; } // ok, we can execute the command concerning the service. CStringDisplayer stringDisplayer; IService::getInstance()->CommandLog.addDisplayer(&stringDisplayer); // build the command line CSString args(command); CSString cmdName = args.firstWord(true); CSString cmdLine; cmdLine << getCommandHandlerName() << "." << cmdName << " " << serviceAlias << " " << args; // retrieve the command from the input message and execute it nlinfo ("ADMIN: Executing control command : '%s' for service '%s'", cmdLine.c_str(), serviceAlias.c_str()); ICommand::execute (cmdLine, IService::getInstance()->CommandLog); // unhook our displayer as it's work is now done IService::getInstance()->CommandLog.removeDisplayer(&stringDisplayer); // send the result back to AS CAdminServiceProxy as(sender); as.commandResult(this, commandId, serviceAlias, stringDisplayer._Data); } //The return is sent back by another message virtual void serviceCmd(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command) { // look in the list of service for a matching one IModuleProxy *proxy = findOnlineService(serviceAlias); if (proxy == NULL) { CAdminServiceProxy as(sender); as.commandResult(this, commandId, serviceAlias, "ERROR AES : unknown service"); return; } // ok, we found it ! TPendingWebCommand pwc; pwc.Command = command; pwc.ReceptionDate = NLMISC::CTime::getSecondsSince1970(); pwc.ServiceAlias = serviceAlias; _PendingWebCommands.insert(make_pair(commandId, pwc)); CAdminExecutorServiceClientProxy service(proxy); service.serviceCmd(this, commandId, command); } // AES client send back the result of execution of a command virtual void commandResult(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result) { // check for waiting commands TPendingWebCommands::iterator it(_PendingWebCommands.find(commandId)); if (it == _PendingWebCommands.end()) { if (commandId != 0) nlwarning("CAdminExecutor::commandResult : service '%s' sent result for command ID %u but not in pending command table", sender->getModuleName().c_str(), commandId); return; } // send the result back to AS if (_AdminService != NULL) { CAdminServiceProxy as(_AdminService); as.commandResult(this, commandId, serviceAlias, result); } _PendingWebCommands.erase(commandId); } // An AES send graph data update virtual void graphUpdate(NLNET::IModuleProxy *sender, const TGraphDatas &graphDatas) { if (_AdminService != NULL) { CAdminServiceProxy as(_AdminService); as.graphUpdate(this, graphDatas); } } // A service high rez graph data update virtual void highRezGraphUpdate(NLNET::IModuleProxy *sender, const THighRezDatas &graphDatas) { if (_AdminService != NULL) { CAdminServiceProxy as(_AdminService); as.highRezGraphUpdate(this, graphDatas); } } // A service send an update of of it's status string virtual void serviceStatusUpdate(NLNET::IModuleProxy *sender, const std::string &status) { TConnectedServiceIndex::iterator it(_ConnectedServiceIndex.find(sender)); if (it == _ConnectedServiceIndex.end()) { nlwarning("serviceStatusUpdate : service '%s' send status but is unknown !", sender->getModuleName().c_str()); return; } string &aliasName = it->second; TServiceStates::iterator it2(_ServiceStates.find(aliasName)); BOMB_IF(it2 == _ServiceStates.end(), "serviceStateUpdate : service '" <getModuleName() <<"' send an update, but alias '"<second; ss.State = status; ss.LastStateDate = NLMISC::CTime::getSecondsSince1970(); } /////////////////////////////////////////////////////////////////////// //// commands handlers /////////////////////////////////////////////////////////////////////// NLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(CAdminExecutorService, CModuleBase) NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, dump, "Dump a status report to appropriate output logger", "no args") NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, addRegisteredService, "add a registered service", " ") NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, removeRegisteredService, "remove a registered service", "") NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, startService, "start a registered service", "") NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, restartService, "stop then start a registered service", "") NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, stopService, "stop a service (registered or not)", "") NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, killService, "kill a (possibly not responding) service (registered or not)", "") NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, abortService, "abort a (possibly not responding) service with SIGABORT (registered or not)", "") NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, activateService, "activate a service, i.e make it startable either manually or from a shard orders", "") NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, deactivateService, "deactivate a service, i.e make it unstartable (either manually or from a shard orders) and stop it if needed", "") NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, execScript, "execute the predefined bash script '/home/nevrax/patchman/aes_runnable_script.sh' and give it the passed parameters", "") NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, resetStartCounter, "reset the start counter to 0", "no params") NLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, stopShard, "Stop all service of a given shard aftert the provided delay", " ") NLMISC_COMMAND_HANDLER_TABLE_END NLMISC_CLASS_COMMAND_DECL(stopShard) { if (args.size() != 2) return false; string shardName = args[0]; uint32 delay; NLMISC::fromString(args[1], delay); log.displayNL("Received command to stop all service of shard %s in %us", shardName.c_str(), delay); shutdownShard(NULL, shardName, delay); return true; } NLMISC_CLASS_COMMAND_DECL(resetStartCounter) { if (args.size() != 0) return false; TServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end()); for (; first != last; ++first) { TServiceState &ss = first->second; ss.RunnerLoopCounter.resetCounter(); } return true; } NLMISC_CLASS_COMMAND_DECL(execScript) { string cmdLine("/home/nevrax/patchman/aes_runnable_script.sh"); // add parameters for (uint i=0; i lines; output.splitLines(lines); log.displayNL("Command returned value %d", ret); log.displayNL("-------------------- Command output begin -----------------------"); for (uint i=0; isecond; if (ss.RunningState == TRunningState::rs_stopped) { log.displayNL("The service to abort '%s' is currently stopped", serviceAlias.c_str()); return true; } if (ss.PID < 2) { log.displayNL("AES have no valid PID to abort the service '%s'", serviceAlias.c_str()); return true; } // abort it log.displayNL("Aborting service '%s' with pid %u", serviceAlias.c_str(), ss.PID); abortProgram(ss.PID); return true; } NLMISC_CLASS_COMMAND_DECL(killService) { if (args.size() != 1) return false; string serviceAlias = args[0]; // check that the service is running TServiceStates::iterator it(_ServiceStates.find(serviceAlias)); if (it == _ServiceStates.end()) { log.displayNL("Failed to found service '%s' in the list of running services", serviceAlias.c_str()); return true; } TServiceState &ss = it->second; if (ss.RunningState == TRunningState::rs_stopped) { log.displayNL("The service to kill '%s' is currently stopped", serviceAlias.c_str()); return true; } if (ss.PID < 2) { log.displayNL("AES have no valid PID to kill the service '%s'", serviceAlias.c_str()); return true; } // kill it log.displayNL("Killing service '%s' with pid %u", serviceAlias.c_str(), ss.PID); killProgram(ss.PID); return true; } NLMISC_CLASS_COMMAND_DECL(stopService) { if (args.size() != 1) return false; string serviceAlias = args[0]; if (_ServiceStates.find(serviceAlias) == _ServiceStates.end()) { log.displayNL("Unknown service '%s', could not stop it", serviceAlias.c_str()); return true; } TServiceState &ss = _ServiceStates[serviceAlias]; // look for a shard orders for this service TShardsOrders::iterator it(_ShardOrders.find(ss.ShardName)); if (it != _ShardOrders.end()) { TShardOrders &so = it->second; if (so == TShardOrders::so_autostart_on) { log.displayNL("Can't stop service '%s' because shard '%s' is autostarting, considers either to deactivate the service or just restart it", serviceAlias.c_str(), ss.ShardName.c_str()); return true; } } if (stopService(serviceAlias)) log.displayNL("Failed to stop the service '%s'", serviceAlias.c_str()); else log.displayNL("Service '%s' stop request done", serviceAlias.c_str()); return true; } NLMISC_CLASS_COMMAND_DECL(restartService) { if (args.size() != 1) return false; string serviceAlias = args[0]; if (_RegisteredServices.find(serviceAlias) == _RegisteredServices.end()) { log.displayNL("startService %s : the service in not registered, can't restart it", serviceAlias.c_str()); return true; } // look for service orders for this service if (_PersistentServiceOrders.find(serviceAlias) != _PersistentServiceOrders.end()) { if (_PersistentServiceOrders[serviceAlias] == TRunningOrders::ro_deactivated) { log.displayNL("Can't restart service '%s' because it is currently deactivated", serviceAlias.c_str()); return true; } } // check that the service is running TServiceStates::iterator it(_ServiceStates.find(serviceAlias)); if (it == _ServiceStates.end()) { log.displayNL("Failed to found service '%s' in the list of running services", serviceAlias.c_str()); return true; } // write the deferred start command if (!writeServiceLaunchCtrl(serviceAlias, true, LAUNCH_CTRL_START)) { log.displayNL("Failed to write deferred start control file to restart service '%s'", serviceAlias.c_str()); return true; } else log.displayNL("Service '%s' start command written", serviceAlias.c_str()); if (it->second.ServiceModule == NULL) { log.displayNL("The AES client module proxy is null ! can't send 'quit' command"); } // send the "quit" command to the service CAdminExecutorServiceClientProxy aec(it->second.ServiceModule); aec.serviceCmd(this, 0, "quit"); log.displayNL("Service '%s' command 'quit' sent", serviceAlias.c_str()); return true; } NLMISC_CLASS_COMMAND_DECL(startService) { if (args.size() != 1) return false; string serviceAlias = args[0]; if (_ServiceStates.find(serviceAlias) == _ServiceStates.end()) { log.displayNL("Unknown service '%s', could not start it", serviceAlias.c_str()); return true; } TServiceState &ss = _ServiceStates[serviceAlias]; // look for service orders for this service if (_PersistentServiceOrders.find(serviceAlias) != _PersistentServiceOrders.end()) { if (_PersistentServiceOrders[serviceAlias] == TRunningOrders::ro_deactivated) { log.displayNL("Can't start service '%s' because it is curently deactivated", serviceAlias.c_str()); return true; } } // look for a shard orders for this service TShardsOrders::iterator it(_ShardOrders.find(ss.ShardName)); if (it != _ShardOrders.end()) { TShardOrders &so = it->second; if (so == TShardOrders::so_autostart_on) { log.displayNL("Can't start service '%s' because shard '%s' is autostarting, consider to restart it", serviceAlias.c_str(), ss.ShardName.c_str()); return true; } } if (!startService(serviceAlias)) log.displayNL("Failed to start service '%s'", serviceAlias.c_str()); else log.displayNL("Service '%s' start command written", serviceAlias.c_str()); return true; } NLMISC_CLASS_COMMAND_DECL(removeRegisteredService) { if (args.size() != 1) return false; string serviceAlias = args[0]; if (_ServiceStates.find(serviceAlias) == _ServiceStates.end()) { log.displayNL("Unknown service '%s', could not start it", serviceAlias.c_str()); return true; } TServiceState &ss = _ServiceStates[serviceAlias]; _RegisteredServices.erase(serviceAlias); if (ss.RunningState == TRunningState::rs_stopped) { // remove the record _ServiceStates.erase(serviceAlias); } else { // just update some data related the registered service ss.ShardName = ""; ss.RunningTags.erase(TRunningTag::rt_locally_started); ss.RunningTags.erase(TRunningTag::rt_chain_crashing); ss.RunningTags.insert(TRunningTag::rt_externaly_started); } _PersistentServiceOrders.erase(serviceAlias); _NeedToWriteStateFile = true; // update the state of services to the AS sendUpServiceUpdate(); return true; } NLMISC_CLASS_COMMAND_DECL(addRegisteredService) { if (args.size() != 2) return false; string serviceAlias = args[0]; string shardName = args[1]; _RegisteredServices.insert(serviceAlias); _ServiceStates.insert(make_pair(serviceAlias, TServiceState())); _ServiceStates[serviceAlias].ShardName = shardName; // _ServiceRunnerLoopCounters.insert(make_pair(serviceAlias, TRunnerLoopCounter())); if (_PersistentServiceOrders.find(serviceAlias) == _PersistentServiceOrders.end()) { _PersistentServiceOrders[serviceAlias] = TRunningOrders::ro_activated; _NeedToWriteStateFile = true; } // update the state of services to the AS sendUpServiceUpdate(); return true; } NLMISC_CLASS_COMMAND_DECL(dump) { NLMISC_CLASS_COMMAND_CALL_BASE(CModuleBase, dump); log.displayNL("==============================="); log.displayNL(" Dumping Admin executor states"); log.displayNL("==============================="); { log.displayNL(" There are %u known shard :", _ShardOrders.size()); { TShardsOrders::iterator first(_ShardOrders.begin()), last(_ShardOrders.end()); for (; first != last; ++first) { log.displayNL(" + Shard '%s' orders is '%s'", first->first.c_str(), first->second.toString().c_str()); } } if (_ShutdownForPatch) log.displayNL(" All service are shuting down for patch !"); log.displayNL(" There are %u known services :", _ServiceStates.size()); TServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end()); for (; first != last; ++first) { TServiceState &ss = first->second; const string &aliasName = first->first; CSString runningTags; set::iterator rtf(ss.RunningTags.begin()), rte(ss.RunningTags.end()); for (; rtf != rte; ++rtf) { runningTags<<"<"<toString()<<">"; } bool registered = _RegisteredServices.find(aliasName) != _RegisteredServices.end(); log.displayNL(" + Service alias='%s' (%s) ShardName = '%s' RunningState='%s' RunningTag='%s'", aliasName.c_str(), registered ? "REGISTERED" : "NOT REGISTERED", ss.ShardName.c_str(), ss.RunningState.toString().c_str(), runningTags.c_str()); log.display(" | %s", ss.DontUseShardOrders ? "DontUseShardOders" : "UseShardOrders"); if (ss.RunningState != TRunningState::rs_stopped) { // the pid should be valid log.display(" PID=%u", ss.PID); } if (registered) { log.display(" ServiceOrders=%s", _PersistentServiceOrders[aliasName].toString().c_str()); } log.displayNL(""); if (ss.ServiceModule != NULL) { // dump a connected service log.displayNL(" | longName='%s' shortName='%s' moduleName='%s'", ss.LongName.c_str(), ss.ShortName.c_str(), ss.ServiceModule->getModuleName().c_str()); log.displayNL(" | State '%s' (last received %sago)", ss.State.c_str(), NLMISC::CTime::getHumanRelativeTime(NLMISC::CTime::getSecondsSince1970() - ss.LastStateDate).c_str()); } else { // dump a offline registered service // dump a connected service log.displayNL(" | longName='%s' shortName='%s' ", ss.LongName.c_str(), ss.ShortName.c_str()); log.displayNL(" | State '%s' (last received %sago)", ss.State.c_str(), NLMISC::CTime::getHumanRelativeTime(NLMISC::CTime::getSecondsSince1970() - ss.LastStateDate).c_str()); } if (registered) { uint32 c1, c2, c3; ss.RunnerLoopCounter.getCounters(c1, c2, c3); log.displayNL(" | Service Runner Start counter (%u mn:%u run, %u mn:%u run, %u mn:%u run)", CRASH_COUNTER_ROLL_DELAY/60, c1, (CRASH_COUNTER_ROLL_DELAY*3)/60, c2, (CRASH_COUNTER_ROLL_DELAY*CRASH_COUNTER_SLOT)/60, c3); } } } return true; } }; NLNET_REGISTER_MODULE_FACTORY(CAdminExecutorService, "AdminExecutorService"); } // namespace ADMIN ================================================ FILE: code/EVA/server/admin_modules/as_module.cpp ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "nel/misc/types_nl.h" #include #include "nel/misc/file.h" #include "nel/misc/sstring.h" #include "nel/misc/mutable_container.h" #include "nel/net/service.h" #include "nel/net/module.h" #include "nel/net/module_builder_parts.h" #include "admin_modules_itf.h" using namespace std; using namespace NLMISC; using namespace NLNET; void as_forceLink() {} namespace ADMIN { /// name of the persistent state file const char *ASPersistentStateFilename = "as_state.txt"; class CAdminService : public CEmptyModuleServiceBehav > >, CAdminServiceSkel, CAdminServiceWebItf, IModuleTrackerCb { enum { /// The maximum time without report from an AES before flagging it as 'not responding' AES_REPORT_WARNING_DELAY = 5, }; typedef CModuleTracker TAESTracker; /// Tracker for EAS modules TAESTracker _AESTracker; struct TAESServices { /// The date of last report send by this AES. Used to display 'not responding' AES uint32 LastReportDate; /// The list of service known by this AES vector ServiceStatus; TAESServices() : LastReportDate(0) {} }; /// all known service status by known AES typedef map TKnownServices; TKnownServices _KnownServices; /// data for a command comming form web and waiting execution by the module task struct TPendingWebCommand { /// Received command date uint32 ReceptionDate; /// Is this a control command (otherwise it's a service command) bool ControlCommand; /// Sock id of the web connection that wait the command result TSockId Requester; /// Alias of the command target service string ServiceAlias; /// the command and it's parameters string Command; }; typedef uint32 TCommandId; TCommandId _NextCommandId; typedef map TPendingWebCommands; /// A stack of web command request to be treated by module task TPendingWebCommands _PendingWebCommands; /// The global running state of the domain // TRunningOrders _GlobalOrders; typedef string TShardName; typedef map TShardsOrders; /// The running state of each shard TShardsOrders _ShardOrders; /// a flag to write the state file at next module update bool _NeedToWriteStateFile; public: CAdminService() : _AESTracker(TModuleClassPred("AdminExecutorService")), _NextCommandId(0), // _GlobalOrders(TRunningOrders::ro_running), _NeedToWriteStateFile(false) { CAdminServiceSkel::init(this); _AESTracker.init(this, this); } ~CAdminService() {} void setShardOrders(const std::string &shardName, TShardOrders newOrders) { _ShardOrders[shardName] = newOrders; // switch(_GlobalOrders.getValue()) // { // case TRunningOrders::ro_stopped: // IService::getInstance()->addStatusTag("GLOBAL_STOPPED"); // break; // case TRunningOrders::ro_running: // IService::getInstance()->removeStatusTag("GLOBAL_STOPPED"); // break; // } _NeedToWriteStateFile = true; // update all AES with the new state CAdminExecutorServiceProxy::broadcast_setShardOrders(_AESTracker.getTrackedModules().begin(), _AESTracker.getTrackedModules().end(), this, shardName, newOrders); } /// Methods called by a module task to handle web command request void sendCommandToAES(TCommandId commandId, TPendingWebCommand &pwc) { // look in the list of known state to retrieve the target of the command TKnownServices::iterator first(_KnownServices.begin()), last(_KnownServices.end()); for (; first != last; ++first) { const vector &status = first->second.ServiceStatus; for (uint i=0; ifirst); if (pwc.ControlCommand) { // this is a control command aes.controlCmd(this, commandId, pwc.ServiceAlias, pwc.Command); } else { // this is a service command aes.serviceCmd(this, commandId, pwc.ServiceAlias, pwc.Command); } // terminate here ! return; //----------------------------------------------------- } } } // not found ! CAdminServiceWebItf::commandResult(pwc.Requester, pwc.ServiceAlias, "ERROR : AS : unknown service alias"); // remove the pending command _PendingWebCommands.erase(commandId); } bool initModule(const TParsedCommandLine &pcl) { CModuleBase::initModule(pcl); // read the command line const TParsedCommandLine *webPort = pcl.getParam("webPort"); nlassert(webPort != NULL); uint16 port; NLMISC::fromString(webPort->ParamValue, port); // open the web interface CAdminServiceWebItf::openItf(port); // read the persistent state file if any string filename = CPath::standardizePath(IService::getInstance()->SaveFilesDirectory.toString(), true)+ASPersistentStateFilename; FILE *fp = fopen(filename.c_str(), "rt"); if (fp != NULL) { char buffer[1024]; char *ret; while ((ret=fgets(buffer, 1024, fp)) != NULL) { CSString line(buffer); string cmd = line.firstWord(true); if (cmd == "ShardOrders") { string shardName = line.firstWord(true); string orders = line.firstWord(true); TShardOrders shardOrders(orders); if (shardOrders != TShardOrders::invalid_val) setShardOrders(shardName, shardOrders); } } // clear the flag because 'setGlobalState' has set it _NeedToWriteStateFile = false; fclose(fp); } return true; } void onModuleUpdate() { H_AUTO(CAdminService_onModuleUpdate); CAdminServiceWebItf::update(); if (_NeedToWriteStateFile) { string filename = CPath::standardizePath(IService::getInstance()->SaveFilesDirectory.toString(), true)+ASPersistentStateFilename; FILE *fp = fopen(filename.c_str(), "wt"); if (fp != NULL) { CSString line; TShardsOrders::iterator first(_ShardOrders.begin()), last(_ShardOrders.end()); for (; first != last; ++first) { line << "ShardOrders "<first<<" "<second.toString()<<"\n"; } fputs(line.c_str(), fp); fclose(fp); _NeedToWriteStateFile = false; } } uint32 now = NLMISC::CTime::getSecondsSince1970(); // check for timeout commands TPendingWebCommands::iterator first(_PendingWebCommands.begin()), last(_PendingWebCommands.end()); for (; first != last; ++first) { TPendingWebCommand &pwc = first->second; if (now - pwc.ReceptionDate > 10) { CAdminServiceWebItf::commandResult(pwc.Requester, pwc.ServiceAlias, "ERROR : no response from service or AES"); _PendingWebCommands.erase(first); // check at next update for the rest break; } } { // save one high rez graph at a time static string lastCheckedBuffer; THighRezBuffers::iterator it(_HighRezBuffers.upper_bound(lastCheckedBuffer)); if (it == _HighRezBuffers.end()) lastCheckedBuffer = ""; else { lastCheckedBuffer = it->first; THighRezBuffer &hrBuffer = it->second; if (hrBuffer.Dirty) { // save this buffer CMemStream sbuff; // write the updated buffer sbuff.serial(hrBuffer); string filename = getHighRezBufferFilename(it->first); NLMISC::COFile of(filename); if (of.isOpen()) // test added, because sometime on windows, the file fail to open ! { of.serialBuffer((uint8*)sbuff.buffer(), sbuff.size()); hrBuffer.Dirty = false; } else { nlwarning("CAdminService::onUpdateModule : failed to open file %s for writing", filename.c_str()); } } } } } /////////////////////////////////////////////////////////////////////// //// Virtuals from IModuleTrackerCb /////////////////////////////////////////////////////////////////////// virtual void onTrackedModuleUp(IModuleProxy *moduleProxy) { nldebug("AES module '%s' UP", moduleProxy->getModuleName().c_str()); // send it the current global state CAdminExecutorServiceProxy aes(moduleProxy); TShardsOrders::iterator first(_ShardOrders.begin()), last(_ShardOrders.end()); for (; first != last; ++first) { aes.setShardOrders(this, first->first, first->second); } } virtual void onTrackedModuleDown(IModuleProxy *moduleProxy) { nldebug("AES module '%s' DOWN", moduleProxy->getModuleName().c_str()); // check for any pending commands with this AES TAESServices &as = _KnownServices[moduleProxy]; for (uint i=0; isecond; if (pwc.ServiceAlias == aliasName) { // remove this command CAdminServiceWebItf::commandResult(pwc.Requester, pwc.ServiceAlias, "ERROR : connection lost with AES during command"); TCommandId commandId = first->first; _PendingWebCommands.erase(first); // restart the loop to avoid iterator dodging goto retry_pending_command; } } } // remove any service status _KnownServices.erase(moduleProxy); } /////////////////////////////////////////////////////////////////////// //// Virtuals from CAdminServiceSkel /////////////////////////////////////////////////////////////////////// // An AES send an update of the list of service up virtual void upServiceUpdate(NLNET::IModuleProxy *sender, const std::vector < TServiceStatus > &serviceStatus) { if (_AESTracker.getTrackedModules().find(sender) == _AESTracker.getTrackedModules().end()) { nlwarning("'%s' send upServiceUpdate but is not an valid AES", sender->getModuleName().c_str()); return; } _KnownServices[sender].LastReportDate = NLMISC::CTime::getSecondsSince1970(); _KnownServices[sender].ServiceStatus = serviceStatus; // check that we have this shards in the shard orders table for (uint i=0; iConfigFile.getVar("RRDVarPath").asString()); rrdfilename << gd.getServiceAlias() <<"." <ConfigFile.getVar("RRDToolPath").asString(), arg); arg = ""; } arg<<"update "<ConfigFile.getVar("RRDToolPath").asString(), arg); } } enum { HR_BUFFER_SIZE = 5000, }; /// Circular buffer to store high resolution samples struct THighRezBuffer { bool Dirty; uint32 NBSample; uint32 FrameStart; uint32 FrameEnd; // == FrameStart if empty struct THighRezItem { uint32 Date; TTime SampleTick; double Value; void serial(NLMISC::IStream &s) { s.serial(Date); s.serial(SampleTick); s.serial(Value); } }; vector Datas; THighRezBuffer() : Dirty(false), NBSample(HR_BUFFER_SIZE), FrameStart(0), FrameEnd(0) { Datas.resize(NBSample); } void serial(NLMISC::IStream &s) { s.serial(NBSample); s.serial(FrameStart); s.serial(FrameEnd); s.serialCont(Datas); if (s.isReading()) { // make some adjustment in case of HR_BUFFER_SIZE change Datas.resize(HR_BUFFER_SIZE); FrameEnd %= HR_BUFFER_SIZE; FrameStart %= HR_BUFFER_SIZE; NBSample = HR_BUFFER_SIZE; } } }; typedef map THighRezBuffers; THighRezBuffers _HighRezBuffers; string getHighRezBufferFilename(const std::string &varAddr) { CSString filename = CPath::standardizePath (IService::getInstance()->ConfigFile.getVar("RRDVarPath").asString()); filename << varAddr<<".hrd"; return filename; } // An AES send high rez graph data update virtual void highRezGraphUpdate(NLNET::IModuleProxy *sender, const THighRezDatas &graphDatas) { // dump the datas // nldebug("Received high rez graph info for var %s from service %s", // graphDatas.getServiceName().c_str(), // graphDatas.getVarName().c_str()); // // for (uint i=0; igetModuleClassName().c_str(), serviceName.c_str(), commandId); return; } TPendingWebCommand &pwc = it->second; CAdminServiceWebItf::commandResult(pwc.Requester, pwc.ServiceAlias, result); // erase this command _PendingWebCommands.erase(it); } // An AES send it's updated state strings // virtual void updateAESStates(NLNET::IModuleProxy *sender, const std::vector < std::string > &states) // { // nlstop; // } // AES send back the result of execution of a control command virtual void controlCmdResult(NLNET::IModuleProxy *sender, const std::string &serviceName, const std::vector < std::string > &result) { nlstop; } /////////////////////////////////////////////////////////////////////// //// Virtuals from CAdminServiceWebItf /////////////////////////////////////////////////////////////////////// /// Connection callback : a new interface client connect virtual void on_CAdminServiceWeb_Connection(NLNET::TSockId from) { } /// Disconnection callback : one of the interface client disconnect virtual void on_CAdminServiceWeb_Disconnection(NLNET::TSockId from) { } // This is used to issue global commands like 'as.allStart' or 'as.allStop'. // The result is returned by the return message // serviceCmdResult. virtual void on_globalCmd(NLNET::TSockId from, const std::string &command) { // create a displayer to gather the output of the command class CStringDisplayer: public IDisplayer { public: virtual void doDisplay( const CLog::TDisplayInfo& args, const char *message) { _Data += message; } std::string _Data; }; nldebug("Global command from web : '%s'", command.c_str()); // ok, we can execute the command concerning the service. CStringDisplayer stringDisplayer; IService::getInstance()->CommandLog.addDisplayer(&stringDisplayer); // build the command line CSString cmdLine; cmdLine << getCommandHandlerName() << "." << command; // retrieve the command from the input message and execute it nlinfo ("ADMIN: Executing global command : '%s'", cmdLine.c_str()); ICommand::execute (cmdLine, IService::getInstance()->CommandLog); // unhook our displayer as it's work is now done IService::getInstance()->CommandLog.removeDisplayer(&stringDisplayer); // send the result back to the web CAdminServiceWebItf::commandResult(from, "", stringDisplayer._Data); } // Send a service related command to the executor // (not to the controled service) // The return value is a string containing the content // returned by the command. virtual void on_controlCmd(NLNET::TSockId from, const std::string &serviceAlias, const std::string &command) { // push the request info TPendingWebCommand pwc; pwc.ReceptionDate = NLMISC::CTime::getSecondsSince1970(); pwc.Command = command; pwc.ControlCommand = true; pwc.Requester = from; pwc.ServiceAlias = serviceAlias; _PendingWebCommands.insert(make_pair(_NextCommandId, pwc)); // send the request to the AES sendCommandToAES(_NextCommandId++, pwc); } // Send a command to the AS. // Send a command to a service. // The return value is a string containing the content returned by the virtual void on_serviceCmd(NLNET::TSockId from, const std::string &serviceAlias, const std::string &command) { // push the request info TPendingWebCommand pwc; pwc.ReceptionDate = NLMISC::CTime::getSecondsSince1970(); pwc.Command = command; pwc.ControlCommand = false; pwc.Requester = from; pwc.ServiceAlias = serviceAlias; _PendingWebCommands.insert(make_pair(_NextCommandId, pwc)); // send the request to the AES sendCommandToAES(_NextCommandId++, pwc); } // Get the orders of each known shard. // The return value is a vector of string, one entry by shard virtual std::vector on_getShardOrders(NLNET::TSockId from) { vector ret; TShardsOrders::iterator first(_ShardOrders.begin()), last(_ShardOrders.end()); for (; first != last; ++first) { CSString orders; orders << "ShardName=" << first->first; orders << "\tOrders=" << first->second.toString(); ret.push_back(orders); } return ret; } // Get the last known state of all services. // The return value is a vector of string, one entry by service virtual std::vector on_getStates(NLNET::TSockId from) { uint32 now = NLMISC::CTime::getSecondsSince1970(); vector ret; TAESTracker::TTrackedModules::iterator first(_AESTracker.getTrackedModules().begin()), last(_AESTracker.getTrackedModules().end()); for (; first != last; ++first) { IModuleProxy *aes = *first; const vector &status = _KnownServices[*first].ServiceStatus; uint32 aesStallDelay = now - _KnownServices[*first].LastReportDate; bool aesStall = aesStallDelay > AES_REPORT_WARNING_DELAY; for (uint i=0; i") // NLMISC_COMMAND_HANDLER_ADD(CAdminService, stopShard, "stop a shard in the controled domain", "") NLMISC_COMMAND_HANDLER_ADD(CAdminService, setShardStartMode, "set the autostart mode of a shard", " on|off") NLMISC_COMMAND_HANDLER_ADD(CAdminService, stopShard, "stop all service of a shard with a programmable timer (can be 0 for immediate shutdown)", " ") NLMISC_COMMAND_HANDLER_TABLE_END NLMISC_CLASS_COMMAND_DECL(setShardStartMode) { if (args.size() != 2) return false; string shardName = args[0]; if (_ShardOrders.find(shardName) == _ShardOrders.end()) { log.displayNL("Unknown shard '%s'", shardName.c_str()); return true; } TShardOrders shardOrders; if (args[1] == "on") shardOrders = TShardOrders::so_autostart_on; else if (args[1] == "off") shardOrders = TShardOrders::so_autostart_off; else { log.displayNL("Invalid option '%s', must be 'on' or 'off'", args[1].c_str()); return true; } setShardOrders(shardName, shardOrders); return true; } // NLMISC_CLASS_COMMAND_DECL(startShard) // { // if (args.size() != 1) // return false; // // string shardName = args[0]; // // if (_ShardOrders.find(shardName) == _ShardOrders.end()) // { // log.displayNL("Unknown shard '%s'", shardName.c_str()); // return true; // } // // setShardOrders(shardName, TRunningOrders::ro_running); // // return true; // } // NLMISC_CLASS_COMMAND_DECL(stopShard) // { // if (args.size() != 1) // return false; // // string shardName = args[0]; // // if (_ShardOrders.find(shardName) == _ShardOrders.end()) // { // log.displayNL("Unknown shard '%s'", shardName.c_str()); // return true; // } // // setShardOrders(shardName, TRunningOrders::ro_stopped); // // return true; // } // // NLMISC_CLASS_COMMAND_DECL(allStart) // { // if (args.size() != 0) // return false; // // setGlobalOrders(TRunningOrders::ro_running); // // return true; // } // // NLMISC_CLASS_COMMAND_DECL(allStop) // { // if (args.size() != 0) // return false; // // setGlobalOrders(TRunningOrders::ro_stopped); // // return true; // } NLMISC_CLASS_COMMAND_DECL(stopShard) { if (args.size() != 2) return false; string shardName = args[0]; uint32 delay; NLMISC::fromString(args[1], delay); if (_ShardOrders.find(shardName) == _ShardOrders.end()) { log.displayNL("Unknown shard '%s'", shardName.c_str()); return true; } // dispatch the request to all AES (they will apply to the pertinent service) CAdminExecutorServiceProxy::broadcast_shutdownShard(_AESTracker.getTrackedModules().begin(), _AESTracker.getTrackedModules().end(), this, shardName, delay); return true; } NLMISC_CLASS_COMMAND_DECL(dump) { NLMISC_CLASS_COMMAND_CALL_BASE(CModuleBase, dump); log.displayNL("==============================="); log.displayNL(" Dumping Admin states"); log.displayNL("==============================="); // log.displayNL(" Global orders is '%s'", _GlobalOrders.toString().c_str()); log.displayNL(" There are %u known shards :", _ShardOrders.size()); { TShardsOrders::iterator first(_ShardOrders.begin()), last(_ShardOrders.end()); for (; first != last; ++first) { log.displayNL(" + Shard '%s' is '%s'", first->first.c_str(), first->second.toString().c_str()); } } log.displayNL(" There are %u AES services :", _AESTracker.getTrackedModules().size()); TAESTracker::TTrackedModules::iterator first(_AESTracker.getTrackedModules().begin()), last(_AESTracker.getTrackedModules().end()); for (; first != last; ++first) { IModuleProxy *aes = *first; const vector &status = _KnownServices[*first].ServiceStatus; log.displayNL(" + AES '%s', with %u connected services", aes->getModuleName().c_str(), status.size()); for (uint i=0; i // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . //----------------------------------------------------------------------------- // includes //----------------------------------------------------------------------------- #include "nel/net/service.h" #ifdef NL_OS_WINDOWS # define NOMINMAX # include #endif // NL_OS_WINDOWS using namespace std; using namespace NLMISC; using namespace NLNET; // force admin module to link in extern void admin_modules_forceLink(); void foo() { admin_modules_forceLink(); } //----------------------------------------------------------------------------- // class CServiceClass //----------------------------------------------------------------------------- class CServiceClass : public NLNET::IService { public : void init() { } bool update() { return true; } void release() { } }; //----------------------------------------------- // NLNET_SERVICE_MAIN //----------------------------------------------- static const char* getCompleteServiceName(const IService* theService) { static std::string s; s= "admin_service"; if (theService->haveLongArg("adminname")) { s+= "_"+theService->getLongArg("adminname"); } if (theService->haveLongArg("fulladminname")) { s= theService->getLongArg("fulladminname"); } return s.c_str(); } static const char* getShortServiceName(const IService* theService) { static std::string s; s= "RAS"; if (theService->haveLongArg("shortadminname")) { s= theService->getLongArg("shortadminname"); } return s.c_str(); } NLNET_SERVICE_MAIN( CServiceClass, getShortServiceName(scn), getCompleteServiceName(scn), 0, EmptyCallbackArray, "", "" ); ================================================ FILE: code/EVA/server/admin_service.cfg ================================================ // Use with commandline: admin_service --fulladminname=admin_service --shortadminname=AS -C. -L. --nobreak --writepid // ---- config local variables ASWebPort="46700"; ASPort="46701"; #include "common.cfg" // ---- service NeL variables (used by ConfigFile class) DontUseNS = 1; AESAliasName= "ras"; //Paths = { // ".", //}; // ---- service custom variables (used by ConfigFile class) // ---- service custom variables (used by CVariable class) RRDToolPath = "../tools/rrdtool/rrdtool.exe"; RRDVarPath = "save_shard/rrd_graphs"; // Variables required to be defined by other cfgs //AESHost="localhost"; //ASWebPort="46700"; //ASPort="46701"; StartCommands += { // create the admin service module and open the web interface "moduleManager.createModule AdminService as webPort="+ASWebPort, // create a gateway for aes to connect "moduleManager.createModule StandardGateway as_gw", // create a layer 3 server "as_gw.transportAdd L3Server l3s", "as_gw.transportOptions l3s(PeerInvisible)", "as_gw.transportCmd l3s(open port="+ASPort+")", // plug the as "as.plug as_gw", }; ================================================ FILE: code/EVA/server/client_robot/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp *.h) ADD_EXECUTABLE(client_robot WIN32 ${SRC}) INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR}) TARGET_LINK_LIBRARIES( client_robot servershare) NL_DEFAULT_PROPS(client_robot "Base, Client: ClientRobot") NL_ADD_RUNTIME_FLAGS(client_robot) ================================================ FILE: code/EVA/server/client_robot/client_robot.cpp ================================================ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #include using namespace NLMISC; using namespace NLNET; using namespace std; class CClientRobot : public NLNET::IService { public: /// Init the service, load the universal time. void init () { TimerManager->init(); LuaNetworkMgr.Init(); ScriptMgr.init(); LuaThreadMgr.Init(); } bool update () { NLMISC::TTicks curr_ticks = CTime::getLocalTime(); LocalTime.SetCurrTime(curr_ticks); TimerManager->tickUpdate(); ScriptMgr.update(); LuaNetworkMgr.Update(); LuaThreadMgr.Update(); return true; } void release () { TimerManager->release(); ScriptMgr.release(); LuaNetworkMgr.Release(); LuaThreadMgr.Release(); } }; // Service instantiation NLNET_SERVICE_MAIN (CClientRobot, "ROBOT", "client_robot", 0, EmptyCallbackArray, "", ""); ================================================ FILE: code/EVA/server/client_robot.cfg ================================================ RootConfigFilename = "common.cfg"; AESAliasName = "robot"; SId = 1; DontUseNS = 1; DontUseAES = 1; DisplayedVariables += { "", "@Info|info" }; StartLuaScript = "_ClientRobotMain.lua"; Paths = { "./script/__Robot/", // for lua root script }; /* LuaWorkThread = { "thd_player DBSubStart.lua", }; */ ================================================ FILE: code/EVA/server/common.cfg ================================================ // ---- config local variables // Used by ConfigFile in EGS and WS ShardId = 0; UpdateTimeout = 20; // Used to connect to AES (this file) and to set up AES service (admin_executor_service.cfg) AESPort="46702"; AESHost="localhost"; // ---- service NeL variables (used by ConfigFile class) WindowStyle = "WIN"; // don't connect to the old NeLNS AES DontUseAES = 1; // Configure module gateway for layer 5 module comm /* StartCommands += { // Create a gateway module "moduleManager.createModule StandardGateway gw", // add a layer 5 transport "gw.transportAdd L5Transport l5", // open the transport "gw.transportCmd l5(open)", /// Create default connection with admin executor service // Create a gateway module "moduleManager.createModule StandardGateway gw_aes", // create the admin executor service module "moduleManager.createModule AdminExecutorServiceClient aes_client", "aes_client.plug gw_aes", // create a layer 3 client to connect to aes gateway "gw_aes.transportAdd L3Client aes_l3c", "gw_aes.transportCmd aes_l3c(connect addr="+AESHost+":"+AESPort+")", }; */ // by default, use localhost to find the naming service NSHost = "localhost:49901"; NSPort = 49901; // A list of vars to graph for any service GraphVars += { "ProcessUsedMemory", "60000", // every minute }; IgnoredFiles = { "continent.cfg", "__read_me.txt", "bandit.html", "flora_primr.primitive" }; // Set a mainland SessionId. // Live: Must be 0 for ring shards, non-zero (usually ShardId) for mainland shards // Dev: Can be non-zero to initially connect a client to a ring shard NoWSShardId = ShardId; // ---- service NeL variables (used by CVariable class) // Disable generation / display of nldebug messages DisableNLDebug = 0; // Disable nel net verbose logging VerboseNETTC = 1; VerboseLNETL0 = 1; VerboseLNETL1 = 1; VerboseLNETL2 = 1; VerboseLNETL3 = 1; VerboseLNETL4 = 1; VerboseLNETL5 = 1; VerboseLNETL6 = 1; // If the update loop is too slow, a thread will produce an assertion. // By default, the value is set to 10 minutes. // Set to 0 for no assertion. UpdateAssertionThreadTimeout = 6000000; // how to sleep between 2 network updates // 0 = pipe // 1 = usleep // 2 = nanosleep // 3 = sched_yield // 4 = nothing UseYieldMethod = 0; DefaultMaxExpectedBlockSize = 200000000; // 200 M ! DefaultMaxSentBlockSize = 200000000; // 200 M ! // Will SaveFilesDirectory will be converted to a full path? ConvertSaveFilesDirectoryToFullPath = 1; // Where to save specific shard data (ie: player backup), relatively to SaveShardRoot SaveFilesDirectory = ""; // where to save generic shard data (ie: packed_sheet) WriteFilesDirectory = "data_shard"; // ---- service custom variables (used by ConfigFile class) NegFiltersDebug += { "NETL", "NET" }; NegFiltersInfo += { "NETL" }; NegFiltersWarning += { }; // where to send error reports DefaultEmailSMTP = "smtp"; DefaultEmailFrom = "sanguo@0xcc.com"; DefaultEmailTo = "li9chuan@qq.com"; LogDirectory = "./log/"; Language = "cn"; ================================================ FILE: code/EVA/server/frontend_service/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp *.h) ADD_EXECUTABLE(frontend_service WIN32 ${SRC}) INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR} ${LIBEVENT_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR}) TARGET_LINK_LIBRARIES( frontend_service #eva_adminmodules servershare) NL_DEFAULT_PROPS(frontend_service "Base, Services: Frontend Service (FES)") NL_ADD_RUNTIME_FLAGS(frontend_service) #ADD_DEFINITIONS(${LIBXML2_DEFINITIONS}) IF(WITH_PCH AND NOT MINGW) # FIXME: PCH too large (> 130MB), crashes cc1plus under MinGW ADD_NATIVE_PRECOMPILED_HEADER(frontend_service ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.h ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.cpp) ENDIF(WITH_PCH AND NOT MINGW) INSTALL(TARGETS frontend_service RUNTIME DESTINATION sbin COMPONENT services) ================================================ FILE: code/EVA/server/frontend_service/frontend_service.cpp ================================================ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include "frontend_service.h" #include #include #include #ifdef NL_OS_WINDOWS #include #endif using namespace std; using namespace NLMISC; using namespace NLNET; using namespace DEF; //extern void admin_modules_forceLink(); //void foo() { admin_modules_forceLink(); } NLMISC::CVariable VAR_PLAYER_NUM("fes", "NbPlayers" , "memo", 0); void CFrontEndService::init() { LocalTime.SetCurrTime( CTime::getLocalTime() ); //string fn = IService::getInstance()->SaveFilesDirectory.toString(); //fn += ConfigFile.getVar("LogDir").asString(); //fn += "frontend_service.stat"; //nlinfo("Frontend stat in directory '%s'", fn.c_str()); //NLMISC::CFileDisplayer *Fd = new NLMISC::CFileDisplayer(fn); //Loger().addDisplayer(Fd); //if (WindowDisplayer) Loger().addDisplayer (WindowDisplayer); /////////////////////////////////////////////////// MsgDesc.LoadMsgXml(); TimerManager->init(); LuaThreadMgr.Init(); LuaNetworkMgr.Init(); ScriptMgr.init(); } bool CFrontEndService::update() { LocalTime.SetCurrTime( CTime::getLocalTime() ); /////////////////////////////////////// TimerManager->tickUpdate(); ScriptMgr.update(); LuaNetworkMgr.Update(); LuaThreadMgr.Update(); return true; } void CFrontEndService::release() { TimerManager->release(); ScriptMgr.release(); LuaNetworkMgr.Release(); LuaThreadMgr.Release(); google::protobuf::ShutdownProtobufLibrary(); } /**************************************************************************** * FRONTEND SERVICE MAIN Function * * This call create a main function for a service: * * - based on the "CFrontEndService" class * - having the short name "FES" * - having the long name "frontend_service" * - listening on the port "0" (dynamically determined) * - and shard callback set to "CallbackArray" * ****************************************************************************/ NLNET_SERVICE_MAIN (CFrontEndService, "FES", "frontend_service", 0, EmptyCallbackArray, "", "") /* end of file */ ================================================ FILE: code/EVA/server/frontend_service/frontend_service.h ================================================ #ifndef FRONTEND_SERVICE_H #define FRONTEND_SERVICE_H // We're using the NeL Service framework and layer 5 #include #include #include #include //typedef CHashMap< TDataSetIndex, std::string> TEntityNamesMap; /** * CFrontEndService, based on IService5 */ class CFrontEndService : public NLNET::IService { public: CFrontEndService():ReceiveWatch(10), SendWatch(10) {} /// Return the instance of the service static CFrontEndService *instance() { return (CFrontEndService*)IService::getInstance(); } // Initialisation void init(); bool update(); void release(); NLMISC::CStopWatch ReceiveWatch; // All Receive Sub NLMISC::CStopWatch SendWatch; // All Send Sub }; #define FrontEndService CFrontEndService::instance() #endif ================================================ FILE: code/EVA/server/frontend_service/stdpch.cpp ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" ================================================ FILE: code/EVA/server/frontend_service/stdpch.h ================================================ #include "nel/misc/types_nl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef NL_OS_WINDOWS # ifndef NL_COMP_MINGW # define NOMINMAX # endif # include # include #endif ================================================ FILE: code/EVA/server/frontend_service.cfg ================================================ RootConfigFilename = "common.cfg"; AESAliasName = "fes_0"; SId = 66; NegFiltersDebug = { "NET" }; GraphVars += { "FPSProcessMsg", "60000", // every minute }; StartLuaScript = "_FESMain.lua"; Paths = { "./script/_FES/", // for lua root script }; DisplayedVariables += { "", "@Info|info", "@LoadMsg|loadmsg" }; MsgCount = true; SaveEvent = false; ================================================ FILE: code/EVA/server/msg.xml ================================================  ================================================ FILE: code/EVA/server/naming_service/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp *.h) ADD_EXECUTABLE(naming_service WIN32 ${SRC}) INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR}) TARGET_LINK_LIBRARIES( naming_service #eva_adminmodules ${LIBXML2_LIBRARIES} nelmisc nelnet) NL_DEFAULT_PROPS(naming_service "Base, Services: Naming Service (NS)") NL_ADD_RUNTIME_FLAGS(naming_service) ADD_DEFINITIONS(${LIBXML2_DEFINITIONS}) INSTALL(TARGETS naming_service RUNTIME DESTINATION sbin COMPONENT ns) #INSTALL(FILES naming_service.cfg common.cfg DESTINATION ~/service COMPONENT ns) ================================================ FILE: code/EVA/server/naming_service/naming_service.cpp ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // // Includes // #include "nel/misc/types_nl.h" #include #include #include "nel/misc/debug.h" #include "nel/misc/command.h" #include "nel/misc/variable.h" #include "nel/misc/displayer.h" #include "nel/net/callback_server.h" #include "nel/net/service.h" #include "nel/net/module_manager.h" // // Namespaces // using namespace std; using namespace NLMISC; using namespace NLNET; NLMISC_COMMAND(test, "none", "none") { log.displayNL("Raw cmd line : '%s'", rawCommandString.c_str()); log.displayNL("Dumping %u parameters :", args.size()); for (uint i=0; i &a, const string &n, TServiceId s) : SockId(sock), Addr(a), Name(n), SId (s), WaitingUnregistration(false), RunningState(ServiceClose) { } TSockId SockId; // the connection between the service and the naming service vector Addr; // address to send to the service who wants to lookup this service // it s possible to have more than one addr, anyway, the naming service // will send good address depending of the sub net address of the service string Name; // name of the service TServiceId SId; // id of the service bool WaitingUnregistration; // true if this service is in unregistration process (wait other service ACK) TTime WaitingUnregistrationTime; // time of the beginning of the inregistration process list WaitingUnregistrationServices; // list of service that we wait the answer TServiceRunningState RunningState; }; // Helper that emulates layer5's send() //void sendToService( uint16 sid, CMessage& msgout ); // Helper that emulate layer5's getServiceName() string getServiceName( TServiceId sid ); // Helper that returns the first address of a service CInetAddress getHostAddress( TServiceId sid ); // Asks a service to stop and tell every one void doUnregisterService (TServiceId sid); //extern void admin_modules_forceLink(); //void foo() //{ // admin_modules_forceLink(); //} /** * Manager for services instances * (Moved from the TICKS to the NS) * Implementable with layer 5, here implemented in NS (layer 3) * \author Olivier Cado * \author Nevrax France * \date 2003 */ class CServiceInstanceManager { public: /// Constructor CServiceInstanceManager(); /** Add the name of a service which must not be duplicated * If uniqueOnShard is true, only one service is allowed. * If uniqueOnShard is false, one service is allowed by physical machine. */ void addUniqueService( const std::string& serviceName, bool uniqueOnShard ) { _UniqueServices.insert( std::make_pair( serviceName, uniqueOnShard ) ); } /// Check if a service is allowed to start (if so, add it) bool queryStartService( const std::string& serviceName, TServiceId serviceId, const std::vector &addr, string& reason ); /// Release a service instance void releaseService( NLNET::TServiceId serviceId ); /// Display information void displayInfo( NLMISC::CLog *log = NLMISC::InfoLog ) const; /// Make all controlled services quit void killAllServices(); private: /// List of restricted services std::map< std::string, bool > _UniqueServices; /// List of granted (online) services std::set< TServiceId > _OnlineServices; }; CServiceInstanceManager *SIMInstance = NULL; /* * Constructor */ CServiceInstanceManager::CServiceInstanceManager() { nlassert( ! SIMInstance ); SIMInstance = this; // Note: addCallbackArray() done in CRangeMirrorManager::init() } /* * Check if a service is allowed to start. Answer with a GSTS (Grant Start Service) message */ bool CServiceInstanceManager::queryStartService( const std::string& serviceName, TServiceId serviceId, const vector &addr, string& reason ) { bool grantStarting = true; std::map< std::string, bool >::iterator ius = _UniqueServices.find( serviceName ); if ( ius != _UniqueServices.end() ) { // Service is restricted set< TServiceId >::iterator ios; bool uniqueOnShard = (*ius).second; for ( ios=_OnlineServices.begin(); ios!=_OnlineServices.end(); ++ios ) { string name = getServiceName( *ios ); if ( name == serviceName ) { if ( uniqueOnShard ) { // Only one service by shard is allowed => deny grantStarting = false; reason = toString( "Service %s already found as %hu, must be unique on shard", serviceName.c_str(), ios->get() ); nlinfo( reason.c_str() ); break; } else { // Only one service by physical machine is allowed // Implementation for layer5 //TSockId hostid1, hostid2; /*CCallbackNetBase *cnb1 = CUnifiedNetwork::getInstance()->getNetBase( serviceId, hostid1 ); CCallbackNetBase *cnb2 = CUnifiedNetwork::getInstance()->getNetBase( *ios, hostid2 ); if ( cnb1->hostAddress( hostid1 ).internalIPAddress() == cnb2->hostAddress( hostid2 ).internalIPAddress() )*/ // Implementation for NS if ( addr[0].internalIPAddress() == getHostAddress( *ios ).internalIPAddress() ) { grantStarting = false; reason = toString( "Service %s already found as %hu on same machine", serviceName.c_str(), ios->get() ); nlinfo( reason.c_str() ); break; } } } } } if ( grantStarting ) { _OnlineServices.insert( serviceId ); } return grantStarting; } /* * Release a service instance */ void CServiceInstanceManager::releaseService( NLNET::TServiceId serviceId ) { _OnlineServices.erase( serviceId ); // not a problem if not found } /* * Display information */ void CServiceInstanceManager::displayInfo( NLMISC::CLog *log ) const { log->displayNL( "Restricted services:" ); std::map< std::string, bool >::const_iterator ius; for ( ius=_UniqueServices.begin(); ius!=_UniqueServices.end(); ++ius ) { log->displayNL( "%s -> only one per %s", (*ius).first.c_str(), (*ius).second?"shard":"machine" ); } log->displayNL( "Online registered services:" ); std::set< TServiceId >::const_iterator ios; for ( ios=_OnlineServices.begin(); ios!=_OnlineServices.end(); ++ios ) { log->displayNL( "%s", CUnifiedNetwork::getInstance()->getServiceUnifiedName( *ios ).c_str() ); } } /* * Make all controlled services quit */ void CServiceInstanceManager::killAllServices() { // Send to all known online services std::set< TServiceId >::const_iterator ios; for ( ios=_OnlineServices.begin(); ios!=_OnlineServices.end(); ++ios ) { doUnregisterService( (TServiceId)(*ios) ); } } // // Variables // list RegisteredServices; /// List of all registred services uint16 MinBasePort = 51000; /// Ports begin at 51000 uint16 MaxBasePort = 52000; /// (note: in this implementation there can be no more than 1000 services) const TServiceId BaseSId(128); /// Allocated SIds begin at 128 (except for Agent Service) const TTime UnregisterTimeout = 10000; /// After 10s we remove an unregister service if every server didn't ACK the message CCallbackServer *CallbackServer = NULL; // // Functions // bool canAccess (const vector &addr, const CServiceEntry &entry, vector &accessibleAddr) { accessibleAddr.clear (); if (entry.WaitingUnregistration) return false; for (uint i = 0; i < addr.size(); i++) { uint32 net = addr[i].internalNetAddress(); for (uint j = 0; j < entry.Addr.size(); j++) { if (net == entry.Addr[j].internalNetAddress()) { accessibleAddr.push_back (entry.Addr[j]); } } } if (accessibleAddr.empty()) { nldebug ("service %s-%hu is not accessible by '%s'", entry.Name.c_str(), entry.SId.get(), vectorCInetAddressToString (addr).c_str ()); } else { nldebug ("service %s-%hu is accessible by '%s'", entry.Name.c_str(), entry.SId.get(), vectorCInetAddressToString (accessibleAddr).c_str ()); } return !accessibleAddr.empty (); } void displayRegisteredServices (CLog *log = InfoLog) { log->displayNL ("Display the %d registered services :", RegisteredServices.size()); for (list::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { TSockId id = (*it).SockId; if (id == NULL) { log->displayNL ("> %s-%hu %s '%s' %s %d addr", (*it).Name.c_str(), it->SId.get(), "", "", (*it).WaitingUnregistration?"WaitUnreg":"", (*it).Addr.size()); for(uint i = 0; i < (*it).Addr.size(); i++) log->displayNL (" '%s'", (*it).Addr[i].asString().c_str()); } else { log->displayNL ("> %s-%hu %s '%s' %s %d addr", (*it).Name.c_str(), it->SId.get(), (*it).SockId->asString().c_str(), CallbackServer->hostAddress((*it).SockId).asString().c_str(), (*it).WaitingUnregistration?"WaitUnreg":"", (*it).Addr.size()); for(uint i = 0; i < (*it).Addr.size(); i++) log->displayNL (" '%s'", (*it).Addr[i].asString().c_str()); } } log->displayNL ("End of the list"); } list::iterator effectivelyRemove (list::iterator &it) { // remove the service from the registered service list nlinfo ("Effectively remove the service %s-%hu", (*it).Name.c_str(), it->SId.get()); return RegisteredServices.erase (it); } /* * Helper procedure for cbLookupAlternate and cbUnregister. * Note: name is used for a LOGS. */ list::iterator doRemove (list::iterator it) { nldebug ("Unregister the service %s-%hu '%s'", (*it).Name.c_str(), it->SId.get(), (*it).Addr[0].asString().c_str()); // tell to everybody that this service is unregistered CMessage msgout ("UNB"); msgout.serial ((*it).Name); msgout.serial ((*it).SId); vector accessibleAddress; nlinfo ("Broadcast the Unregistration of %s-%hu to all registered services", (*it).Name.c_str(), it->SId.get()); for (list::iterator it3 = RegisteredServices.begin(); it3 != RegisteredServices.end (); it3++) { if (canAccess((*it).Addr, (*it3), accessibleAddress)) { CallbackServer->send (msgout, (*it3).SockId); //CNetManager::send ("NS", msgout, (*it3).SockId); nldebug ("Broadcast to %s-%hu", (*it3).Name.c_str(), it3->SId.get()); } } // new system, after the unregistation broadcast, we wait ACK from all services before really remove // the service, before, we tag the service as 'wait before unregister' // if everybody didn't answer before the time out, we remove it (*it).SockId = NULL; (*it).WaitingUnregistration = true; (*it).WaitingUnregistrationTime = CTime::getLocalTime(); // we remove all services awaiting his ACK because this service is down so it'll never ACK for (list::iterator itr = RegisteredServices.begin(); itr != RegisteredServices.end (); itr++) { for (list::iterator itw = (*itr).WaitingUnregistrationServices.begin(); itw != (*itr).WaitingUnregistrationServices.end ();) { if ((*itw) == (*it).SId) { itw = (*itr).WaitingUnregistrationServices.erase (itw); } else { itw++; } } } string res; for (list::iterator it2 = RegisteredServices.begin(); it2 != RegisteredServices.end (); it2++) { if (!(*it2).WaitingUnregistration) { (*it).WaitingUnregistrationServices.push_back ((*it2).SId); res += toString((*it2).SId.get()) + " "; } } nlinfo ("Before removing the service %s-%hu, we wait the ACK of '%s'", (*it).Name.c_str(), (*it).SId.get(), res.c_str()); if ((*it).WaitingUnregistrationServices.empty()) { return effectivelyRemove (it); } else { return ++it; } // Release from the service instance manager SIMInstance->releaseService( (*it).SId ); } void doUnregisterService (TServiceId sid) { list::iterator it; for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ((*it).SId == sid) { // found it, remove it doRemove (it); return; } } nlwarning ("Service %hu not found", sid.get()); } void doUnregisterService (TSockId from) { list::iterator it; for (it = RegisteredServices.begin(); it != RegisteredServices.end ();) { if ((*it).SockId == from) { // it's possible that one "from" have more than one registred service, so we have to find in all the list // found it, remove it it = doRemove (it); } else { it++; } } } /*void doUnregisterService (const CInetAddress &addr) { list::iterator it; for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ((*it).Addr == addr) { // found it, remove it doRemove (it); return; } } nlwarning ("Service %s not found", addr.asString().c_str()); }*/ /* * Helper function for cbRegister. * If alloc_sid is true, sid is ignored * Returns false in case of failure of sid allocation or bad sid provided * Note: the reply is included in this function, because it must be done before things such as syncUniTime() */ bool doRegister (const string &name, const vector &addr, TServiceId sid, TSockId from, CCallbackNetBase &netbase, bool reconnection = false) { // Find if the service is not already registered string reason; uint8 ok = true; bool needRegister = true; /*for (list::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ((*it).Addr.asIPString() == addr.asIPString() ) { // we already have a service on this address, remplace it if it's the same name if ((*it).Name == name) { // it's the same service, replace it (*it).SockId = from; sid = (*it).SId; nlinfo ("Replace the service %s", name.c_str()); } else { nlwarning ("Try to register %s to %s but the service %s already on this address. ignore it!", name.c_str(), addr.asIPString().c_str(), (*it).Name.c_str()); ok = false; } needRegister = false; break; } }*/ if (needRegister) { if (sid.get() == 0) { // we have to find a sid sid = BaseSId; bool found = false; while (!found) { list::iterator it; for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ((*it).SId == sid) { break; } } if (it == RegisteredServices.end ()) { // ok, we have an empty sid found = true; } else { sid.set(sid.get()+1); if (sid.get() == 0) // round the clock { nlwarning ("Service identifier allocation overflow"); ok = false; break; } } } } else { // we have to check that the user provided sid is available list::iterator it; for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ((*it).SId == sid) { nlwarning ("Sid %d already used by another service", sid.get()); ok = false; break; } } if (it != RegisteredServices.end ()) { ok = true; } } // if ok, register the service and send a broadcast to other people if (ok) { // Check if the instance is allowed to start, according to the restriction in the config file if ( SIMInstance->queryStartService( name, sid, addr, reason ) ) { // add him in the registered list RegisteredServices.push_back (CServiceEntry(from, addr, name, sid)); // tell to everybody but not him that this service is registered if (!reconnection) { CMessage msgout ("RGB"); TServiceId::size_type s = 1; msgout.serial (s); msgout.serial (const_cast(name)); msgout.serial (sid); // we need to send all addr to all services even if the service can't access because we use the address index // to know which connection comes. msgout.serialCont (const_cast &>(addr)); nlinfo ("The service is %s-%d, broadcast the Registration to everybody", name.c_str(), sid.get()); vector accessibleAddress; for (list::iterator it3 = RegisteredServices.begin(); it3 != RegisteredServices.end (); it3++) { // send only services that can be accessed and not itself if ((*it3).SId != sid && canAccess(addr, (*it3), accessibleAddress)) { CallbackServer->send (msgout, (*it3).SockId); //CNetManager::send ("NS", msgout, (*it3).SockId); nldebug ("Broadcast to %s-%hu", (*it3).Name.c_str(), it3->SId.get()); } } } // set the sid only if it s ok from->setAppId (sid.get()); } else { // Reply "startup denied", and do not send registration to other services ok = false; } } // send the message to the service to say if it s ok or not if (!reconnection) { // send the answer to the client CMessage msgout ("RG"); msgout.serial (ok); if (ok) { msgout.serial (sid); // send him all services available (also itself) TServiceId::size_type nb = 0; vector accessibleAddress; for (list::iterator it2 = RegisteredServices.begin(); it2 != RegisteredServices.end (); it2++) { // send only services that are available if (canAccess(addr, (*it2), accessibleAddress)) nb++; } msgout.serial (nb); for (list::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { // send only services that are available if (canAccess(addr, (*it), accessibleAddress)) { msgout.serial ((*it).Name); msgout.serial ((*it).SId); msgout.serialCont ((*it).Addr); } } } else { msgout.serial( reason ); } netbase.send (msgout, from); netbase.flush (from); } } //displayRegisteredServices (); return ok!=0; } void checkWaitingUnregistrationServices () { for (list::iterator it = RegisteredServices.begin(); it != RegisteredServices.end ();) { if ((*it).WaitingUnregistration && ((*it).WaitingUnregistrationServices.empty() || CTime::getLocalTime() > (*it).WaitingUnregistrationTime + UnregisterTimeout)) { if ((*it).WaitingUnregistrationServices.empty()) { nlinfo ("Removing the service %s-%hu because all services ACKd the removal", (*it).Name.c_str(), (*it).SId.get()); } else { string res; for (list::iterator it2 = (*it).WaitingUnregistrationServices.begin(); it2 != (*it).WaitingUnregistrationServices.end (); it2++) { res += toString(it2->get()) + " "; } nlwarning ("Removing the service %s-%hu because time out occurs (service numbers %s didn't ACK)", (*it).Name.c_str(), (*it).SId.get(), res.c_str()); } it = effectivelyRemove (it); } else { it++; } } } /** * Callback for service unregistration ACK. Mean that a service was ACK the unregistration broadcast */ static void cbACKUnregistration (CMessage& msgin, TSockId from, CCallbackNetBase &netbase) { TServiceId sid; msgin.serial (sid); for (list::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ((*it).SId == sid && (*it).WaitingUnregistration) { for (list::iterator it2 = (*it).WaitingUnregistrationServices.begin(); it2 != (*it).WaitingUnregistrationServices.end (); it2++) { if (*it2 == TServiceId(uint16(from->appId()))) { // remove the acked service (*it).WaitingUnregistrationServices.erase (it2); checkWaitingUnregistrationServices (); return; } } } } } /** * Callback for service registration when the naming service goes down and up (don't need to broadcast) */ static void cbResendRegisteration (CMessage& msgin, TSockId from, CCallbackNetBase &netbase) { string name; vector addr; TServiceId sid; msgin.serial (name); msgin.serialCont (addr); msgin.serial (sid); doRegister (name, addr, sid, from, netbase, true); } /** * Callback for service registration. * * Message expected : RG * - Name of service to register (string) * - Address of service (CInetAddress) * * Message emitted : RG * - Allocated service identifier (TServiceId) or 0 if failed */ static void cbRegister (CMessage& msgin, TSockId from, CCallbackNetBase &netbase) { string name; vector addr; TServiceId sid; msgin.serial (name); msgin.serialCont (addr); msgin.serial (sid); doRegister (name, addr, sid, from, netbase); } /** * Callback for service unregistration. * * Message expected : UNI * - Service identifier (TServiceId) */ static void cbUnregisterSId (CMessage& msgin, TSockId from, CCallbackNetBase &netbase) { TServiceId sid; msgin.serial( sid ); doUnregisterService (sid); //displayRegisteredServices (); } /** * Callback for service set state. * * Message expected : SSS */ static void cbSetSerivceState (CMessage& msgin, TSockId from, CCallbackNetBase &netbase) { TServiceId sid; uint32 state; msgin.serial( sid ); msgin.serial( state ); CMessage msgout ("USS"); msgout.serial (sid); msgout.serial (state); for (list::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ( it->SId == sid ) { it->RunningState = (TServiceRunningState)state; } CallbackServer->send (msgout, (*it).SockId); } } /* * Helper function for cbQueryPort * * \warning QueryPort + Registration is not atomic so more than one service could ask a port before register */ uint16 doAllocatePort (const CInetAddress &addr) { static uint16 nextAvailablePort = MinBasePort; // check if nextavailableport is free if (nextAvailablePort >= MaxBasePort) nextAvailablePort = MinBasePort; bool ok; do { ok = true; list::iterator it; for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ((*it).Addr[0].port () == nextAvailablePort) { nextAvailablePort++; ok = false; break; } } } while (!ok); return nextAvailablePort++; } /** * Callback for port allocation * Note: if a service queries a port but does not register itself to the naming service, the * port will remain allocated and unused. * * Message expected : QP * - Name of service to register (string) * - Address of service (CInetAddress) (its port can be 0) * * Message emitted : QP * - Allocated port number (uint16) */ static void cbQueryPort (CMessage& msgin, TSockId from, CCallbackNetBase &netbase) { // Allocate port uint16 port = doAllocatePort (netbase.hostAddress (from)); // Send port back CMessage msgout ("QP"); msgout.serial (port); netbase.send (msgout, from); nlinfo ("The service got port %hu", port); } /* * Unregisters a service if it has not been done before. * Note: this callback is called whenever someone disconnects from the NS. * May be there are too many calls if many clients perform many transactional lookups. */ static void cbDisconnect /*(const string &serviceName, TSockId from, void *arg)*/ ( TSockId from, void *arg ) { doUnregisterService (from); //displayRegisteredServices (); } /* * a service is connected, send him all services infos */ static void cbConnect /*(const string &serviceName, TSockId from, void *arg)*/ ( TSockId from, void *arg ) { // we have to wait the registred services message to send all services because it this points, we can't know which sub net // the service can use //displayRegisteredServices (); // set the appid with a bad id (-1) from->setAppId (~0); } /*// returns the list of accessible services with a list of address static void cbRegisteredServices(CMessage& msgin, TSockId from, CCallbackNetBase &netbase) { vector addr; msgin.serialCont (addr); nlinfo ("New service ask me the available services, sending him all services available"); // send to the new service the list of all services that this service can access (depending of his sub net) CMessage msgout ("RGB"); uint8 nb = 0; vector accessibleAddress; for (list::iterator it2 = RegisteredServices.begin(); it2 != RegisteredServices.end (); it2++) { // send only services that are available if (canAccess(addr, (*it2), accessibleAddress)) nb++; } msgout.serial (nb); for (list::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { // send only services that are available if (canAccess(addr, (*it), accessibleAddress)) { msgout.serial ((*it).Name); msgout.serial ((*it).SId); msgout.serialCont (accessibleAddress); } } CNetManager::send ("NS", msgout, from); }*/ /* * Helper that emulates layer5 send() */ /*void sendToService( uint16 sid, CMessage& msgout ) { list::iterator it; for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ((*it).SId == sid) { CallbackServer->send (msgout, (*it).SockId); } } }*/ /* * Helper that emulate layer5's getServiceName() */ string getServiceName( TServiceId sid ) { list::iterator it; for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ((*it).SId == sid) { return (*it).Name; } } return ""; // not found } /* * Helper that returns the first address of a service */ CInetAddress getHostAddress( TServiceId sid ) { list::iterator it; for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ((*it).SId == sid) { return (*it).Addr[0]; } } return CInetAddress(); } // // Callback array // TCallbackItem CallbackArray[] = { { "RG", cbRegister }, { "RRG", cbResendRegisteration }, { "QP", cbQueryPort }, { "UNI", cbUnregisterSId }, { "ACK_UNI", cbACKUnregistration }, // { "RS", cbRegisteredServices }, { "SSS", cbSetSerivceState }, }; // // Service // class CNamingService : public NLNET::IService { public: /** * Init */ void init() { // if a baseport is available in the config file, get it CConfigFile::CVar *var; if ((var = ConfigFile.getVarPtr ("BasePort")) != NULL) { uint16 newBasePort = var->asInt (); nlinfo ("Changing the MinBasePort number from %hu to %hu", MinBasePort, newBasePort); sint32 delta = MaxBasePort - MinBasePort; nlassert (delta > 0); MinBasePort = newBasePort; MaxBasePort = MinBasePort + uint16 (delta); } // Parameters for the service instance manager try { CConfigFile::CVar& uniqueServices = ConfigFile.getVar("UniqueOnShardServices"); for ( uint i=0; i!=uniqueServices.size(); ++i ) { _ServiceInstances.addUniqueService( uniqueServices.asString(i), true ); } } catch(const Exception &) {} try { CConfigFile::CVar& uniqueServicesM = ConfigFile.getVar("UniqueByMachineServices"); for ( uint i=0; i!=uniqueServicesM.size(); ++i ) { _ServiceInstances.addUniqueService( uniqueServicesM.asString(i), false ); } } catch(const Exception &) {} /* // we don't try to associate message from client CNetManager::getNetBase ("NS")->ignoreAllUnknownId (true); // add the callback in case of disconnection CNetManager::setConnectionCallback ("NS", cbConnect, NULL); // add the callback in case of disconnection CNetManager::setDisconnectionCallback ("NS", cbDisconnect, NULL); */ // DEBUG // DebugLog->addDisplayer( new CStdDisplayer() ); vector v = CInetAddress::localAddresses(); nlinfo ("%d detected local addresses:", v.size()); for (uint i = 0; i < v.size(); i++) { nlinfo (" %d - '%s'",i, v[i].asString().c_str()); } uint16 nsport = 50000; if ((var = ConfigFile.getVarPtr ("NSPort")) != NULL) { nsport = var->asInt (); } CallbackServer = new CCallbackServer; CallbackServer->init(nsport); CallbackServer->addCallbackArray(CallbackArray, sizeof(CallbackArray)/sizeof(CallbackArray[0])); CallbackServer->setConnectionCallback(cbConnect, NULL); CallbackServer->setDisconnectionCallback(cbDisconnect, NULL); } /** * Update */ bool update () { checkWaitingUnregistrationServices (); CallbackServer->update (); return true; } void release() { if (CallbackServer != NULL) delete CallbackServer; CallbackServer = NULL; } private: /// Service instance manager singleton CServiceInstanceManager _ServiceInstances; }; static const char* getCompleteServiceName(const IService* theService) { static std::string s; s= "naming_service"; if (theService->haveLongArg("nsname")) { s+= "_"+theService->getLongArg("nsname"); } if (theService->haveLongArg("fullnsname")) { s= theService->getLongArg("fullnsname"); } return s.c_str(); } static const char* getShortServiceName(const IService* theService) { static std::string s; s= "NS"; if (theService->haveLongArg("shortnsname")) { s= theService->getLongArg("shortnsname"); } return s.c_str(); } // /// Naming Service // NLNET_SERVICE_MAIN( CNamingService, getShortServiceName(scn), getCompleteServiceName(scn), 0, EmptyCallbackArray, "", "") // // Commands // NLMISC_COMMAND (nsServices, "displays the list of all registered services", "") { if(args.size() != 0) return false; displayRegisteredServices (&log); return true; } NLMISC_COMMAND (kill, "kill a service and send an unregister broadcast to other service", "|") { if(args.size() != 1) return false; // try with number uint16 serviceId; NLMISC::fromString(args[0], serviceId); TServiceId sid(serviceId); if(sid.get() == 0) { // not a number, try a name list::iterator it; for (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { if ((*it).Name == args[0]) { sid = (*it).SId; break; } } if (it == RegisteredServices.end()) { log.displayNL ("Bad service name or id '%s'", args[0].c_str()); return false; } } doUnregisterService (sid); return true; } NLMISC_DYNVARIABLE(uint32, NbRegisteredServices, "display the number of service that are registered in naming service") { if (get) *pointer = (uint32)RegisteredServices.size(); } NLMISC_COMMAND( displayServiceInstances, "SIM: Display info on service instances", "" ) { SIMInstance->displayInfo( &log ); return true; } NLMISC_COMMAND( killAllServices, "SIM: Make all the controlled services quit", "" ) { SIMInstance->killAllServices(); return true; } ================================================ FILE: code/EVA/server/naming_service.cfg ================================================ // link the common configuration file #include "common.cfg" DisplayedVariables += { "", "@Services|nsServices" }; SId = 69; DontUseNS = 1; AESAliasName = "rns"; NegFiltersDebug = { "NETL" }; NegFiltersInfo = { "NETL" }; UniqueOnShardServices = {}; UniqueByMachineServices = {}; ================================================ FILE: code/EVA/server/player_logic_service/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp *.h) ADD_EXECUTABLE(player_logic_service WIN32 ${SRC}) INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR}) TARGET_LINK_LIBRARIES( player_logic_service #eva_adminmodules servershare ) NL_DEFAULT_PROPS(player_logic_service "Base, Services: Player Logic Service (PLS)") NL_ADD_RUNTIME_FLAGS(player_logic_service) #ADD_DEFINITIONS(${LIBXML2_DEFINITIONS}) IF(WITH_PCH AND NOT MINGW) # FIXME: PCH too large (> 130MB), crashes cc1plus under MinGW ADD_NATIVE_PRECOMPILED_HEADER(player_logic_service ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.h ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.cpp) ENDIF(WITH_PCH AND NOT MINGW) INSTALL(TARGETS player_logic_service RUNTIME DESTINATION sbin COMPONENT services) ================================================ FILE: code/EVA/server/player_logic_service/player_logic_service.cpp ================================================ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include using namespace NLMISC; using namespace NLNET; using namespace std; CFileDisplayer *Fd = NULL; CStdDisplayer Sd; //extern void admin_modules_forceLink(); //void foo() //{ // admin_modules_forceLink(); //} void displayInfo () { ICommand::execute ("info", *NLMISC::InfoLog); } class CPlayerLogicService : public NLNET::IService { public: /// Init the service, load the universal time. void init () { TimerManager->init(); LuaNetworkMgr.Init(); ScriptMgr.init(); LuaThreadMgr.Init(); } bool update () { NLMISC::TTicks curr_ticks = CTime::getLocalTime(); LocalTime.SetCurrTime(curr_ticks); TimerManager->tickUpdate(); ScriptMgr.update(); LuaNetworkMgr.Update(); LuaThreadMgr.Update(); return true; } void release () { TimerManager->release(); ScriptMgr.release(); LuaNetworkMgr.Release(); LuaThreadMgr.Release(); google::protobuf::ShutdownProtobufLibrary(); } }; // Service instantiation NLNET_SERVICE_MAIN (CPlayerLogicService, LogicService.c_str(), "player_logic_service", 0, EmptyCallbackArray, "", ""); ================================================ FILE: code/EVA/server/player_logic_service/player_logic_service.h ================================================ #ifndef PLAYER_LOGIC_SERVICE_H #define PLAYER_LOGIC_SERVICE_H // we have to include windows.h because mysql.h uses it but not include it #ifdef NL_OS_WINDOWS # define NOMINMAX # include #endif #include "nel/misc/types_nl.h" #include "nel/misc/debug.h" #include "nel/misc/config_file.h" #include "nel/misc/displayer.h" #include "nel/misc/log.h" #include "nel/net/service.h" #endif // PLAYER_LOGIC_SERVICE_H /* End of player_logic_service.h */ ================================================ FILE: code/EVA/server/player_logic_service/stdpch.cpp ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" ================================================ FILE: code/EVA/server/player_logic_service/stdpch.h ================================================ #include "nel/misc/types_nl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef NL_OS_WINDOWS # ifndef NL_COMP_MINGW # define NOMINMAX # endif # include # include #endif ================================================ FILE: code/EVA/server/player_logic_service.cfg ================================================ RootConfigFilename = "common.cfg"; AESAliasName = "lgc_0"; SId = 1; DisplayedVariables += { "", "@Info|info", "@LoadConfig|loadconfig", "@Hotfix|hotfix" }; StartLuaScript = "_PLSMain.lua"; Paths = { "./script/_PLS/", // for lua root script }; ================================================ FILE: code/EVA/server/save_shard/rrd_graphs/hold_dir ================================================ ================================================ FILE: code/EVA/server/schedule_service/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp *.h) ADD_EXECUTABLE(schedule_service WIN32 ${SRC}) INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR}) TARGET_LINK_LIBRARIES( schedule_service #eva_adminmodules servershare) NL_DEFAULT_PROPS(schedule_service "Base, Services: Schedule Service (SCH)") NL_ADD_RUNTIME_FLAGS(schedule_service) INSTALL(TARGETS schedule_service RUNTIME DESTINATION sbin COMPONENT services) ================================================ FILE: code/EVA/server/schedule_service/schedule_service.cpp ================================================ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #ifdef NL_OS_WINDOWS #include #endif using namespace std; using namespace NLMISC; using namespace NLNET; using namespace DEF; //extern void admin_modules_forceLink(); //void foo() { admin_modules_forceLink(); } class CScheduleService : public NLNET::IService { public: void init(); bool update(); void release(); }; void CScheduleService::init() { LocalTime.SetCurrTime( CTime::getLocalTime() ); TimerManager->init(); LuaThreadMgr.Init(); LuaNetworkMgr.Init(); ScriptMgr.init(); } bool CScheduleService::update() { TimerManager->tickUpdate(); ScriptMgr.update(); LuaNetworkMgr.Update(); LuaThreadMgr.Update(); return true; } void CScheduleService::release() { TimerManager->release(); ScriptMgr.release(); LuaNetworkMgr.Release(); LuaThreadMgr.Release(); google::protobuf::ShutdownProtobufLibrary(); } /**************************************************************************** * SCHEDULE SERVICE MAIN Function * * This call create a main function for a service: * * - based on the "CScheduleService" class * - having the short name "SCH" * - having the long name "schedule_service" * - listening on the port "0" (dynamically determined) * - and shard callback set to "CallbackArray" * ****************************************************************************/ NLNET_SERVICE_MAIN (CScheduleService, "SCH", "schedule_service", 49971, EmptyCallbackArray, "", "") /* end of file */ ================================================ FILE: code/EVA/server/schedule_service.cfg ================================================ RootConfigFilename = "common.cfg"; AESAliasName = "egs"; SId = 65; NegFiltersDebug = { "NET" }; StartLuaScript = "_SCHMain.lua"; Paths = { "./script/_SCH/", // for lua root script }; DisplayedVariables += { "", "@Info|info" }; ================================================ FILE: code/EVA/server/script/.vs/ProjectSettings.json ================================================ { "CurrentProjectSetting": null } ================================================ FILE: code/EVA/server/script/.vs/VSWorkspaceState.json ================================================ { "ExpandedNodes": [ "", "\\Framework", "\\Framework\\Net", "\\_PLS", "\\_PLS\\Games", "\\_PLS\\Room" ], "PreviewInSolutionExplorer": false } ================================================ FILE: code/EVA/server/script/BaseService.luaprj ================================================  ================================================ FILE: code/EVA/server/script/DataTable/RoomConfig.json ================================================ { "RM_DDZ": { "room_type": "RM_DDZ", "game_type": "GM_DDZ", "app_name": "APP_DDZ", "min_ver": 1.16, "match": "private", "room_name": "斗地主", "enter_level": 0, "enter_score": 0, "room_max": 3, "room_min": 3, "viewer_max": 5, "is_goback": 1, "auto_return": 1, "room_time": 28800, "room_icon": "icon_yule", "room_bg": "Texture/BackGround/nj_mahjong_room_logo_4", "game_icon": "Texture/BackGround/hall_game_icon_4", "game_bg": "Texture/BackGround/hall_game_bg", "enter_game_scene": "BlackJackScene", "enter_room_scene": "jiuguan" } } ================================================ FILE: code/EVA/server/script/DataTable/RoomCreateCost.json ================================================ { "1001": { "cost_id": 1001, "room_type": "RM_DDZ", "game_cnt": 4, "item_id": 5001, "cost_num": 2 }, "1002": { "cost_id": 1002, "room_type": "RM_DDZ", "game_cnt": 8, "item_id": 5001, "cost_num": 3 }, "1003": { "cost_id": 1003, "room_type": "RM_DDZ", "game_cnt": 16, "item_id": 5001, "cost_num": 6 } } ================================================ FILE: code/EVA/server/script/DataTable/SpecialConfig.json ================================================ { "RM_DDZ": { "multi_boom": 3, "multi_ct": 3, "add_times": 2, "game_type": "GM_DDZ" } } ================================================ FILE: code/EVA/server/script/DataTable/proto/define_attrib.proto ================================================ syntax = "proto2"; package PB; enum TAttribType { INVALID_ATTRIB = 0; ID = 2001001 ; LEVEL_UP_EXP_INT = 2001002 ; NAME_STRING = 2001003 ; LIFE_INT = 2001004 ; LIFE_CURR_INT = 2001005 ; }; ================================================ FILE: code/EVA/server/script/DataTable/proto/define_pro.proto ================================================ syntax = "proto2"; package PB; enum TEvent { EventInvalid = 0; // 无效事件 EventPlayerUp = 2; // 玩家升级 EventCostMoney = 40; // 消费金钱 EventLogin = 46; // 玩家登录 }; /// 标识占据第几位 0-63 enum TPlayerFlagBit { PLAYER_FLAG_TEST_0 = 0; // 玩家第一次做xx事的标识位 PLAYER_FLAG_FIRST_CARD_ONE = 1; // PLAYER_FLAG_FIRST_CARD_TEN = 2; // }; enum TErrorType { INVALID_TYPE = 0; ACCOUNT_LOGGED = 1; SERVER_FULL = 2; SERVER_NOT_OPEN = 3; TEXT_SUCESS = 4; TEXT_FAIL = 5; PWD_ERROR = 6; PLAYER_ONLINE_TO_FES = 7; PLAYER_EXISTS = 8; PLAYER_RELOAD = 9; SUCESS = 23; NO_AUTH_TYPE = 24; CONFIG_NOT_FOUND = 33; // 配置未找到 NOT_ENOUGH_MONEY = 37; // 金币不足 PLAYER_BASE_ERROR = 128; // 玩家基本数据不正确 }; enum TGender { MALE = 0; // 男性 FEMALE = 1; // 女性 }; // 房间付费方式 enum TGameConsumePay { TGC_GOLD = 0; TGC_SILVER = 1; } //房间付费机制 enum TPaymentMechanism { ROOM_OWNER_OPTION = 0; // 房主; AA_SYSTEM_OPTION = 1; // AA制; BIG_OWNER_OPTION = 2; // 大赢家; VIP_TISSUE_OPTION = 3; // 消耗高级牌友圈房卡; } enum TRoomCmdRecord { RC_ACTION_NULL = 0; // 用户过牌; RC_ACTION_START_GAME = 1; // 游戏开始; ( MsgRecordNodeList 中的 card_value[0] 为 会儿皮 ) RC_ACTION_OPERATE_RESULT = 2; // 用户选择权限结果; RC_ACTION_SEND_CARD = 3; // 用户发牌; RC_ACTION_OUT_CARD = 4; // 用户出牌; RC_ACTION_SHOWDOWN_DIANPAO = 5; // 用户点炮胡牌; 有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card ) RC_ACTION_SHOWDOWN_ZIMO = 6; // 用户自摸胡牌; 有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card ) RC_ACTION_SHOWDOWN_QIANGGANGHU = 7; // 用户抢杠胡牌; 有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card ) RC_ACTION_SHOWDOWN_LIUJU = 8; // 用户流局胡牌; 有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card ) RC_ACTION_SHOWDOWN = 9; // 进入结算 RC_ACTION_CONTRACT = 10; // 户承包关系; ( MsgRecordNodeList 中的 TarGetID 为承包id 、 ActionID为被承包id ) RC_ACTION_SEND_FLOWER_CARD = 11; // 用户抓牌花牌; ( MsgRecordNodeList 中的 card_index 为 flower_num ) RC_ACTION_START_FLOWER_CARD = 12; // 用户手牌补花; ( MsgRecordNodeList 中的 card_index 为 flower_num ) RC_ACTION_OPERATE_CHOICE = 13; // 用户选择权限; RC_ACTION_MINGLOU = 14; // 用户明楼; RC_ACTION_SEND_HAND_CARD = 15; // 用户发送手牌; RC_ACTION_CATHECTIC = 16; // 用户下注; RC_ACTION_HUNYOU = 17; // 用户混悠; RC_ACTION_TRUST_STATE = 18; // 用户托管状态; } enum TShowDownEvent { EVENT_XIAOHU = 1; // 小胡; EVENT_MEIHUI = 2; // 没会; EVENT_HUIGUIWEI = 3; // 会归位; EVENT_GANGKAIHUA = 4; // 杠开花; EVENT_TIANHU = 5; // 天胡; EVENT_DIHU = 6; // 地胡; EVENT_SIGEHUI = 7; // 四个会; EVENT_QIDUI = 8; // 七对; EVENT_QINGQIDUI = 9; // 清七对; EVENT_HAOHUAQIDUI = 10; // 豪华七对; EVENT_CHAOHUAQIDUI = 11; // 超豪华七对; EVENT_CHAOCHAOHAOHUAQIDUI = 12; // 超超豪华七对; EVENT_ZHUANGJIA = 13; // 庄家; EVENT_MINGGANG = 14; // 明杠; EVENT_ANGANG = 15; // 暗杠; EVENT_SIXIFENG = 16; // 四喜风; EVENT_SANZHIJIAN = 17; // 三支箭; EVENT_HUIMINGGANG = 18; // 会明杠; EVENT_HUIANGANG = 19; // 会暗杠; EVENT_MENG = 20; // 梦; EVENT_GENZHUANG = 21; // 跟庄(罚款); EVENT_SHISANYAO = 22; // 十三幺; EVENT_LONG = 23; // 一条龙; EVENT_QINGYISE = 24; // 清一色; EVENT_HUNYISE = 25; // 混一色; EVENT_PENGPENGHU = 26; // 碰碰胡; EVENT_JIANGYISE = 27; // 将一色; EVENT_HAIDILAOYUE = 28; // 海底捞月; EVENT_HUGANGFANG = 29; // 胡杠放; EVENT_WUHUAGUO = 30; // 无花果; EVENT_TING = 31; // 听牌; EVENT_PFFLOWER = 32; // 碰风花; EVENT_KOU_PAI = 33; // 扣牌; EVENT_THREE_ZUAN = 34; // 三钻; EVENT_FOUR_ZUAN = 35; // 四钻; EVENT_DIAOWUWAN = 36; // 吊五万; EVENT_ZHUOWUKUI = 37; // 捉五魁; EVENT_ZHI_GANG = 38; // 直杠; EVENT_DIANPAO = 39; // 点炮; EVENT_ZIMO = 40; // 自摸; EVENT_QIANGGANGHU = 41; // 抢杠胡; EVENT_BASESCORE = 42; // 底分; EVENT_JIAPINGHU = 43; // 夹平胡; EVENT_SHISANBUKAO = 44; // 十三不靠; EVENT_PAOPEIPINGHU = 45; // 跑配平胡; EVENT_PAOPEIQIDUI = 46; // 跑配七对; EVENT_KANHUI = 47; // 砍会 EVENT_MINGLOU = 48; // 明楼 EVENT_XIAOGANGKAIHUA = 49; // 小杠开花; EVENT_HUANGZHUANG = 50; // 荒庄; EVENT_HAOHUAQQIDUI = 51; // 豪华清七对; EVENT_CHAOHUAQQIDUI = 52; // 超豪华清七对; EVENT_CHAOCHAOHAOHUAQQIDUI = 53; // 超超豪华清七对; EVENT_PIAOCAI = 54; // 飘财; EVENT_BAOTOU = 55; // 爆头; EVENT_LAOZHUANG = 56; // 老庄; EVENT_DASANYUAN = 57; // 大三元 EVENT_DIAOYU = 58; // 钓鱼 EVENT_SUIJIYISE = 59; // 随机清一色 EVENT_LANPAI = 60; // 烂牌 EVENT_QIXINGLANPAI = 61; // 七星烂牌 EVENT_SANCAISHEN = 62; // 三财神 EVENT_QIFENGDAO = 63; // 七风倒 EVENT_QIFENGBAIDA = 64; // 七风百搭 EVENT_SHISANBAIDA = 65; // 十三白搭 EVENT_QUANFENGZI = 66; // 全风子 EVENT_DANDIAO = 67; // 单吊 EVENT_WUCAI = 68; // 无财 EVENT_QUANFENGZIPENGPENGHU = 69; // 全风子大碰胡 EVENT_QUANFENGZIQIDUI = 70; // 全风子七对子 EVENT_DIANPAOFEN = 71; // 点炮分 EVENT_QIANGGANGHUFEN = 72; // 抢杠胡分 EVENT_ZIMOFEN = 73; // 自摸分 EVENT_DUIDUIHU = 74; // 对对胡 EVENT_MEIBAIDA = 75; // 没百搭 EVENT_SANBAIDA = 76; // 三百搭 EVENT_DADIAOCHE = 77; // 大吊车 EVENT_SHUANGPIAO = 78; // 双飘财 EVENT_SANPIAO = 79; // 三飘财 EVENT_LANBAIDA = 80; // 烂百搭 EVENT_FENGZIBAIDA = 81; // 风字百搭 EVENT_SIHUA = 82; // 四花牌 EVENT_CHUNHUA = 83; // 纯花 EVENT_PENGFENGHUA = 84; // 碰风花 EVENT_GANGHUA = 85; // 杠花 EVENT_HUNPENG = 86; // 混碰 EVENT_QINGPENG = 87; // 清碰 EVENT_HUNQIDUI = 88; // 混七对 EVENT_HUAPAI = 89; // 花牌 EVENT_GUODAN = 90; // 过蛋儿 EVENT_MENQING = 91; // 闭门(门前清) EVENT_SANJIABIMEN = 92; // 三家闭门 EVENT_SHOWBAYI = 93; // 手把一 EVENT_SIGUIYI = 94; // 四归一 EVENT_XUANFENGGANG = 95; // 旋风杠 EVENT_JIEGANG = 96; // 借杠 EVENT_ZIYISE = 97; // 随机字一色 EVENT_TESHUYISE = 98; // 特殊清一色 EVENT_19LAOTOUBAIDA = 99; // 19老头百搭 EVENT_QIANGANGXIAOHU = 100; // 强杠小胡 EVENT_BUQIUREN = 101; // 不求人清一色 EVENT_CONTRACT = 102; // 承包 EVENT_ZHAMA = 103; // 扎码 EVENT_HUNBAZHANG = 104; // 胡八张 EVENT_QUEYIMEN = 105; // 缺一门 EVENT_HUIDIAO = 106; // 会吊 EVENT_QINGHU = 107; // 清胡 EVENT_HUIDIAOHUI = 108; // 会吊会 EVENT_PIAOHU = 109; // 飘胡 EVENT_THREEBIAN = 110; // 三边 EVENT_FOURBIAN = 111; // 四边 EVENT_SUHU = 112; // 素胡 EVENT_HUNDIAOHUN = 113; // 会吊会 EVENT_DAIZHUANG = 114; // 带庄 EVENT_JIA1FEN = 115; // 加1分 EVENT_JIA2FEN = 116; // 加2分 EVENT_WUZI = 117; // 无字; EVENT_KANZHANG = 118; // 坎张; EVENT_BIANZHANG = 119; // 边张; EVENT_SBALUOHAN = 120; // 十八罗汉 EVENT_HONGZGBAO = 121; // 红中宝 EVENT_QUEYI = 122; // 缺一 EVENT_LUANYAO = 123; // 乱幺; EVENT_BAO3QIANGGANGHU = 124; // 包三抢杠胡 EVENT_ERWUBAJIANG = 125; // 258将 EVENT_GUJIANG = 126; // 孤将 EVENT_DUANYAOJIU = 127; // 断幺九 EVENT_YIBIANGAO = 128; // 一边高 EVENT_GULIANLIU = 129; // 孤连六 EVENT_DAXIAOWU = 130; // 大小五 EVENT_GOUSHAN = 131; // 够扇 EVENT_ZHONGFABAI = 132; // 中发白 EVENT_THREEZA = 133; // 三砸 EVENT_FOURZA = 134; // 四砸 EVENT_KAWUKUI = 135; // 卡五魁 EVENT_ANXIAO = 136; // 暗潇 EVENT_SANGEYI = 137; // 三个一 EVENT_SANGEJIU = 138; // 三个九 EVENT_SUQIDUI = 139; // 素七对 EVENT_HUIDIAOQIXIAODUI = 140; // 会吊七小对 EVENT_MANGUAN = 141; // 满贯 EVENT_HUIBENLONG = 142; // 本会儿龙 EVENT_DIAOWUKUI = 143; // 吊五魁 EVENT_LAZHUANG = 144; // 拉庄 EVENT_LIUGANG = 145; // 流杠 EVENT_SULONG = 146; // 素龙 EVENT_HUNLONG = 147; // 混龙 EVENT_HEIFENG = 148; // 黑风 EVENT_HONGFENG = 149; // 红风 EVENT_YIJIU = 150; // 一九 EVENT_ZMH_PH = 151; // 桥东自摸屁胡 EVENT_ZMH_MQ = 152; // 桥东自摸门清 EVENT_QGH_PH = 153; // 桥东抢杠胡屁胡 EVENT_QGH_MQ = 154; // 桥东抢杠胡门清 EVENT_DPH_PH = 155; // 桥东点炮胡屁胡 EVENT_DPH_MQ = 156; // 桥东点炮胡门清 EVENT_QYS_LONG = 157; // 清一色+一条龙 EVENT_LIANGXI = 158; // 亮喜 EVENT_BUXI = 159; // 补喜 EVENT_PENG = 160; // 碰 EVENT_DAJIANG = 161; // 大将 EVENT_FENGYISE = 162; // 风一色 EVENT_QIDUIHUIDIAO = 163; // 七对会调 EVENT_QIDUIHUIDIAOHUI = 164; // 七对会调会 EVENT_DASIXI = 165; // 大四喜 EVENT_XIAOSIXI = 166; // 小四喜 EVENT_XIAOSANYUAN = 167; // 小三元 EVENT_GANGGANGHU = 168; // 杠杠胡 EVENT_BUHUAHU = 169; // 花上 EVENT_LIANGTAIHUA = 170; // 两台花 EVENT_LIANGTAIHUAQUEYI = 171; // 两台花缺一 EVENT_HUAGANG = 172; // 花杠 EVENT_HUISCORE = 173; // 混儿加分 EVENT_HUWEI = 174; // 胡尾 EVENT_ANKAN = 175; // 暗坎 EVENT_HUNERDIAO = 176; // 混儿吊 EVENT_PINGHU = 177; // 平胡 EVENT_HUNERYOU = 178; // 混儿悠 EVENT_YITIAOZHENLONG = 179; // 一条真龙 EVENT_YITIAOJIALONG = 180; // 一条假龙 EVENT_HUANGJINGANG = 181; // 黄金杠 EVENT_ZMH_PH_PINGHU = 182; // 桥东自摸屁胡,平胡(上面是大胡) EVENT_ZMH_MQ_PINGHU = 183; // 桥东自摸门清,平胡 EVENT_QGH_PH_PINGHU = 184; // 桥东抢杠胡屁胡,平胡 EVENT_QGH_MQ_PINGHU = 185; // 桥东抢杠胡门清,平胡 EVENT_DPH_PH_PINGHU = 186; // 桥东点炮胡屁胡,平胡 EVENT_DPH_MQ_PINGHU = 187; // 桥东点炮胡门清,平胡 EVENT_PINGHU_MINGGANG = 188; // 平胡明杠(桥东用,相对于大胡) EVENT_PINGHU_ANGANG = 189; // 平胡暗杠(桥东) EVENT_DIANPAO_QIDUI = 190; // 点炮七对(桥东) EVENT_ZIMO_QIDUI = 191; // 自摸七对(桥东) EVENT_PINGHU_GENZHUANG = 192; // 平胡跟庄(罚款)(桥东用); EVENT_FAGANG = 193; // 满城罚杠; EVENT_ZIMOFENGKE = 194; // 自摸风刻(天台); EVENT_ZIMOFENGDIAO = 195; // 自摸风调(天台); EVENT_ZIMOKE = 196; // 自摸刻子(天台); EVENT_ZIMOJIA = 197; // 自摸夹子(天台); EVENT_ZIMODIAO = 198; // 自摸单调(天台); EVENT_DIANPAOKE = 199; // 点炮刻字(天台); EVENT_DIANPAODIAO = 200; // 点炮单调(天台); EVENT_DIANPAOJIA = 201; // 点炮夹子(天台); EVENT_FENGKEZI = 202; // 风刻子(天台); EVENT_NORMALKEZI = 203; // 正常刻子(天台); EVENT_ZIJIAHUA = 204; // 自家花(天台); EVENT_SIGEHUA = 205; // 四个花(天台); EVENT_BAGEHUA = 206; // 八个花(天台); EVENT_BIANKADIAOSANQI = 207; // 边卡吊三七; EVENT_ZIJIAPENG = 208; // 自家碰(天台); EVENT_ZIJIAKEZI = 209; // 自家刻(天台); EVENT_HONGZHONGPENG = 210; // 红中碰(天台); EVENT_HONGZHONGKEZI = 211; // 红中刻(天台); EVENT_FACAIPENG = 212; // 发财碰(天台); EVENT_FACAIKEZI = 213; // 发财刻(天台); EVENT_HUJUEZHANG = 214; // 胡绝张 EVENT_YIBANGAO = 215; // 一般高 EVENT_LIANLIU = 216; // 连六 EVENT_QUANLAOTOU = 217; // 全老头 EVENT_LUANLAOTOU = 218; // 乱老头 EVENT_SANBAIDAZUOKE = 219; // 三百搭作刻 EVENT_CHUBAIDA = 220; // 出百搭 EVENT_CHAOQIANGGANGHU = 221; // 超抢杠胡(东台); EVENT_DUISHANGGANG = 222; // 对上杠(东台); EVENT_DUITIANTING = 223; // 对天听(东台); EVENT_DUIDANDIAO = 224; // 对单钓(东台); EVENT_SHANGGANG = 225; // 上杠(东台); EVENT_TIANTING = 226; // 天听(东台); EVENT_GANGSHANGDIANPAO = 227; // 杠上点炮(东台); EVENT_BAIDADUIZUOTOU = 228; // 百搭对作头(嘉善硬自摸) EVENT_SHUANGGANKAN = 229; // 双干坎(嘉善硬自摸) EVENT_GANGKAIHUIDIAOHUI = 230; // 杠开会吊会儿 EVENT_HUIDIAOLONG = 231; // 会吊龙 EVENT_HUIDIAOBENHUILONG = 232; // 会吊本会龙 EVENT_ZHANGMAO = 233; // 长毛 EVENT_ZIJIAGANG = 234; // 自家杠(天台); EVENT_HONGZHONGGANG = 235; // 红中杠(天台); EVENT_FACAIGANG = 236; // 发财杠(天台); EVENT_ZIJIADUI = 237; // 自家对子(天台); EVENT_FACAIDUI = 238; // 发财对子(天台); EVENT_HONGZHONGDUI = 239; // 红中对子(天台); EVENT_YIJIUCARD = 240; // 1,9 组合(清河); EVENT_HUADUIZIJIA = 241; // 花墩子+ EVENT_HUADUIZIJIAN = 242; // 花墩子- EVENT_QYS_QIDUI = 243; // 清一色+七对 EVENT_ZHONGMA = 244; // 中马 (自由麻将) EVENT_PENGHOUGANG = 245; // 碰后杠(自由麻将) EVENT_QYS_HUIDIAO = 246; // 清一色混吊(易县麻将) EVENT_ZIMOWUHUN = 247; // 自摸无混(易县麻将) EVENT_HENGYIHENGJIU = 248; // 清河横一横九 ENENT_CAIFENG = 249; // 清河彩风组合 EVENT_DDZDIFEN = 250; // 斗地主底分 EVENT_ZHADAN = 251; // 斗地主炸弹翻倍 EVENT_CHUNTIAN = 252; // 斗地主春天翻倍 EVENT_MINGPAI = 253; // 斗地主明牌翻倍 EVENT_DIPAI = 254; // 斗地主底牌翻倍 EVENT_QIANGDIZHU = 255; // 斗地主抢地主翻倍 EVENT_JIABEI = 256; // 斗地主加倍翻倍 EVENT_JIAOFEN = 257; // 斗地主叫分翻倍 EVENT_XIAOWANG = 258; // 斗地主底牌小王翻倍 EVENT_DAWANG = 259; // 斗地主底牌大王翻倍 EVENT_DUIZI = 260; // 斗地主底牌对子翻倍 EVENT_TONGHUA = 261; // 斗地主底牌同花翻倍 EVENT_SHUNZI = 262; // 斗地主底牌顺子翻倍 EVENT_SANZHANG = 263; // 斗地主底牌三张翻倍 EVENT_TONGHUASHUN = 264; // 斗地主底牌同花顺翻倍 EVENT_DAIYIJIU = 265; // 带一九 EVENT_LONGQIDUI = 266; // 龙七对 EVENT_GEN = 267; // 根 EVENT_JINGOUHU = 268; // 金钩胡 EVENT_ZHONGZHANG = 269; // 中张 EVENT_GANGSHANGPAO = 270; // 杠上炮 EVENT_DIANPAOHU = 271; // 点炮胡 EVENT_BEIZIMO = 272; // 被自摸 EVENT_ZIMOHU = 273; // 自摸胡 EVENT_GUAFENG = 274; // 刮风 EVENT_BEIGUAFENG = 275; // 被刮风 EVENT_XIAYU = 276; // 下雨 EVENT_BEIXIAYU = 277; // 被下雨 EVENT_MIANXIAGANG = 278; // 面下杠(二次杠) EVENT_BEIMIANXIAGANG = 279; // 被面下杠(二次杠) EVENT_HUJIAOZHUANYI = 280; // 呼叫转移 EVENT_BEIHUJIAOZHUANYI = 281; // 被呼叫转移 EVENT_CHAHUAZHU = 282; // 查花猪 EVENT_CHAJIAO = 283; // 查叫 EVENT_BEICHAHUAZHU = 284; // 被查花猪 EVENT_BEICHAJIAO = 285; // 被查叫 } ================================================ FILE: code/EVA/server/script/DataTable/proto/msg_client.proto ================================================ syntax = "proto2"; package PB; import "define_pro.proto"; message MsgLogin { optional string Version = 1; optional string Channel = 2; optional string AppName = 3; optional string User = 4; optional string NonceStr = 5; optional string Token = 6; optional uint64 Timestamp = 7; optional uint64 UID = 8; optional string RoomType = 9; } message MsgPlayerInfo { optional uint64 UID = 1; optional string Nickname = 2; optional uint32 Portrait = 3; optional uint64 Money = 4; optional uint64 RMB = 5; optional uint32 Main = 6; optional uint64 FlagBit = 7; } message MsgCreatePrivateRoom { optional uint32 consume_id = 1; optional TGameConsumePay consume_kind = 2; optional string room_type = 3; optional uint32 special_kind = 4; optional uint32 score = 5; optional uint32 game_versione = 6; optional TPaymentMechanism pay_ment = 7; optional uint32 player_number = 8; optional uint64 tissue_id = 9; } message MsgEnterPrivateRoom { optional uint64 room_id = 1; optional string room_type = 2; optional string app_name = 3; optional uint32 game_version = 4; } message MsgCard { optional uint32 card = 1; } message MsgCards { optional uint32 type = 1; repeated uint32 cards = 2; } message MsgInt { optional int64 value = 1; } message MsgBool { optional bool value = 1; } message MsgString { optional string str = 1; } message MsgError { optional uint32 errno = 1; optional uint64 value = 2; } //////////////////////////////// Record Start ////////////////////// message MsgRecordRoleInfo { optional uint64 id = 1; optional uint32 seat = 2; optional string usename = 3; optional int64 score = 4; repeated uint32 hand_card = 5; optional string nick_name = 6; optional uint32 game_state = 7; optional uint32 series = 8; optional int64 current_score = 9; } message MsgRecordRoomInfo { optional uint32 special_kind = 1; optional uint64 banker = 2; optional uint32 score = 3; optional uint32 game_count = 4; repeated uint32 bottom_cards = 5; } message MsgRecordEvent { optional uint32 event_id = 1; optional uint32 count = 2; repeated int32 score = 3; repeated uint32 score_count = 4; } message MsgRecordWeaveCard { optional uint32 card = 1; optional uint32 wik = 2; optional uint32 barkind = 3; repeated uint32 mix_card = 4; // 组合牌; } message MsgRecordShowDown { optional uint64 id = 1; optional int64 score = 2; optional int64 fixedscore = 3; optional int64 param1 = 4; optional int64 param2 = 5; optional uint32 hucard = 6; repeated MsgRecordEvent event = 7; optional int64 money = 8; optional int64 param3 = 9; optional int64 param4 = 10; optional int64 param5 = 11; optional int64 play_id = 12; repeated uint32 hand_card = 13; repeated MsgRecordWeaveCard weave_card = 14; repeated uint32 hucard_list = 15; } message MsgGDShowDownRole { optional uint64 role_id = 1; optional uint32 game_count = 2; optional uint32 series = 3; optional int32 score = 4; optional int32 current_score = 5; } message MsgGDRankInfo { repeated uint64 rank_list = 1; } message MsgRecordNodeList { optional uint32 cmd_id = 1; repeated uint32 card_value = 2; optional uint32 card_index = 3; optional uint64 action_id = 4; optional uint32 action_wik = 5; optional uint64 target_id = 6; optional uint32 node_size = 7; repeated MsgRecordRoleInfo role_data = 8; optional MsgRecordRoomInfo room_data = 9; repeated MsgRecordShowDown showdown_list = 10; repeated MsgRecordNodeList next_node = 11; repeated MsgGDShowDownRole win_role = 12; repeated MsgGDShowDownRole lost_role = 13; optional MsgGDRankInfo room_ranking = 14; } //////////////////////////////// Record End //////////////////////////// ================================================ FILE: code/EVA/server/script/DataTable/proto/msg_doudizhu.proto ================================================ syntax = "proto2"; package PB; import "msg_client.proto"; enum TDDZPlayerWik // 玩家权限 { ASK_DDZ_NULL = 1; // 空 ASK_DDZ_TISHI = 2; // 提示 ASK_DDZ_BUCHU = 3; // 不出 ASK_DDZ_CHUPAI = 4; // 出牌 ASK_DDZ_DIZHU_MINGPAI = 5; // 地主明牌 }; enum TDDZPlayerState // 玩家状态 { STATE_DDZ_READY = 1; // 准备 STATE_DDZ_GUOPAI = 2; // 过牌 STATE_DDZ_CHUNTIAN = 3; // 春天 STATE_DDZ_NEWROLE = 4; // 新玩家 STATE_DDZ_ROOM_OWNER = 5; // 房主 STATE_DDZ_RELIEVE = 6; // 解除房间状态; STATE_DDZ_LEAVE = 7; // 离开状态 STATE_DDZ_LIMIT = 8; // 限制状态 STATE_DDZ_OFFLINE = 9; // 脱机状态; STATE_DDZ_MINGPAI = 10; // 明牌 状态; STATE_DDZ_DIZHU = 11; // 地主状态; STATE_DDZ_NONGMING = 12; // 农民状态; STATE_DDZ_JIABEI = 13; // 加倍状态 STATE_DDZ_QIANGDIZHU = 14; // 抢地主状态 STATE_DDZ_SELECT_JIABEI = 15; // 选择加倍状态 STATE_DDZ_SELECT_MINGPAISTART = 16; // 选择明牌开始状态 STATE_DDZ_FENGDING = 17; // 封顶状态 STATE_DDZ_CONTINUE_GAME = 18; // 继续游戏状态 }; enum TDDZState // 游戏房间状态 { TDDZStateWait = 0; // 等待开始 TDDZStateCheckStartGame = 1; // 检查是否可以开始游戏 TDDZStateSelectMingCardStart = 2; // 选择明牌开始阶段 TDDZStateStartGame = 3; // 开始游戏 TDDZStateSendCard = 4; // 发送手牌 TDDZStateQiangDiZhu = 5; // 抢地主阶段 TDDZStateSelectAddTimes = 6; // 选择加倍阶段 TDDZStateAction = 7; // 玩家自由活动 TDDZStateOutCard = 8; // 出牌状态 TDDZStateShowDown = 9; // 游戏结算 TDDZStateRelieveRoom = 10; // 解散房间 }; enum TDDZCT // 牌型 { CT_DDZ_ERROR = 0; // 错误类型 CT_DDZ_SINGLE = 1; // 单牌类型 CT_DDZ_DOUBLE = 2; // 对子类型 CT_DDZ_THREE_TIAO = 3; // 三条类型 CT_DDZ_THREE_TIAO_WITH_ONE = 4; // 三带一单类型 CT_DDZ_THREE_TIAO_WITH_YIDUI = 5; // 三带一对类型 CT_DDZ_SHUN_ZI = 6; // 顺子类型 CT_DDZ_LIAN_DUI = 7; // 连对类型 CT_DDZ_FEIJI_WITH_NULL = 8; // 飞机不带类型 CT_DDZ_FEIJI_WITH_ONE = 9; // 飞机带单类型 CT_DDZ_FEIJI_WITH_YIDUI = 10; // 飞机带对类型 CT_DDZ_FOUR_WITHDOUBLE = 11; // 四带二类型 CT_DDZ_FOUR_LIANGDUI = 12; // 四带二对类型 CT_DDZ_ZHADAN_SIZHANG = 13; // 炸弹 CT_DDZ_HUOJIAN = 14; // 火箭 }; enum TDDZBottomType // 底牌牌型 { DDZ_BT_NULL = 0; // 无类型 DDZ_BT_XIAO_KING = 1; // 小王类型 DDZ_BT_DA_KING = 2; // 大王类型 DDZ_BT_DUIZI = 3; // 对子类型 DDZ_BT_TONGHUA = 4; // 同花类型 DDZ_BT_SHUNZI = 5; // 顺子类型 DDZ_BT_SANZHANG = 6; // 三张类型 DDZ_BT_TONGHUASHUN = 7; // 同花顺类型 }; enum TDDZQiangDiZhu // 抢地主权限 { DDZ_QDZ_JIAODIZHU = 1; // 叫地主 DDZ_QDZ_BUJIAO = 2; // 不叫 DDZ_QDZ_QIANGDIZHU = 3; // 抢地主 DDZ_QDZ_BUQIANG = 4; // 不抢 }; enum TDDZJiaoFen // 叫分权限 { DDZ_JF_BUJIAO = 1; // 不叫 DDZ_JF_JIAO_ONE = 2; // 叫一分 DDZ_JF_JIAO_TWO = 3; // 叫二分 DDZ_JF_JIAO_THREE = 4; // 叫三分 }; enum TDDZAddTimes // 加倍选择 { DDZ_AT_NULL = 0; DDZ_AT_BUJIABIE = 1; // 不加倍 DDZ_AT_JIABIE = 2; // 加倍 }; enum TDDZMingPaiType // 明牌选择 { DDZ_MP_NULL = 0; DDZ_MP_NORMALSTART = 1; // 普通开始 DDZ_MP_MINGPAISTART = 2; // 明牌开始 }; enum TGameSpecialKindDouDiZhu // 斗地主房间玩法 { TSK_DDZ_NULL = 0; TSK_DDZ_QDZ = 1; // 抢地主 TSK_DDZ_JF = 2; // 叫分 TSK_DDZ_BFD = 3; // 不封顶 TSK_DDZ_16 = 4; // 16封顶 TSK_DDZ_32 = 5; // 32封顶 TSK_DDZ_64 = 6; // 64封顶 TSK_DDZ_DIPAI = 7; // 底牌翻倍 TSK_DDZ_JIABEI = 8; // 加倍 TSK_DDZ_MINGPAI = 9; // 明牌 } message MsgQiangDiZhu // 抢地主信息(服务器发给客户端的) { optional uint64 playid = 1; // 玩家id optional uint64 qingdizhu_wiki = 2; // 玩家可操作的权限 } message MsgQiangDiZhuResult // 抢地主结果(客户端发给服务器的,服务器广播的) { optional uint64 playid = 1; // 玩家id optional uint64 result = 2; // 玩家选择的结果 optional uint64 state = 3; // 状态 repeated uint32 dizhu_cards = 4; // 刷新地主的手牌 optional uint64 cardcount = 5; // 手牌数量 optional uint64 multiple = 6; // 房间倍数 } message MsgBRQiangDiZhuResult // 抢地主最终结果(服务器广播的) { repeated MsgQiangDiZhuResult player_list = 1; optional uint64 multiple = 2; // 房间倍数 repeated MsgDiPaiMutiple dipai_multi_list = 3; // 底牌翻倍列表 } message MsgDiPaiMutiple // 底牌翻倍的类型事件 { optional uint32 event_id = 1; optional uint32 count = 2; } message MsgMingPaiResult // 选择明牌结果(客户端发给服务器的,服务器广播的) { optional uint64 playid = 1; // 玩家id optional uint64 result = 2; // 玩家选择的结果 optional uint64 state = 3; // 状态 repeated uint32 dizhu_cards = 4; // 地主明牌时刷新手牌 optional uint64 multiple = 5; // 房间倍数 } message MsgJiaBeiResult // 选择加倍结果(客户端发给服务器的,服务器广播的) { optional uint64 playid = 1; // 玩家id optional uint64 result = 2; // 玩家选择的结果 optional uint64 state = 3; // 状态 } message MsgDDZPlayer // 玩家信息 { optional MsgPlayerInfo player_base = 1; // 玩家信息(房间信息填充) optional uint32 state = 2; // 玩家状态 optional uint32 hand_count = 3; // 手牌数量 repeated uint32 card_list = 4; // 手牌列表(房间信息、showdown填充) optional uint32 seats = 5; // 座位(房间信息填充) optional int64 score = 6; // 玩家当前的积分 optional int64 show_down_score = 7; // 玩家该局游戏的加减分 optional uint32 qingdizhu_wiki = 8; // 玩家抢地主的权限 optional uint32 qingdizhu_value = 9; // 玩家抢地主的结果 optional uint32 multiple = 10; // 玩家倍数,(结算时使用) optional uint32 integral_num = 11; // 加券数 repeated uint32 out_cards = 12; // 上把玩家出的牌信息 optional uint32 out_type = 13; // 上把玩家的出牌种类 } message MsgDDZActon { optional uint64 new_actionid = 1; // 当前活动玩家 optional uint64 old_actionid = 2; // 上把的活动玩家 repeated uint32 last_out_cards = 3; // 上把玩家出的牌信息 optional uint32 last_out_type = 4; // 上把玩家的出牌种类 optional uint32 wik = 5; // 当前活动玩家的权限 TDDZPlayerWik repeated MsgDDZPlayer player_list = 6; // 玩家信息 } message MsgDDZUserOutCard { optional uint64 old_actionid = 1; // 旧玩家ID optional uint32 out_type = 2; // 出牌种类 optional uint32 hand_count = 3; // 玩家手牌数量 repeated uint32 out_cards = 4; // 出牌列表 optional uint64 multiple = 5; // 房间倍数 repeated uint32 hand_cards = 6; // 明牌玩家剩余的手牌,客户端刷新使用 } message MsgDDZRoom // 房间信息 { optional uint32 room_state = 1; // 房间当前状态 TDDZState optional uint32 state_time = 2; // 状态运行时间 repeated MsgDDZPlayer player_list = 3; // 玩家信息 optional uint64 action_id = 4; // 当前活动玩家 optional uint64 room_id = 5; // 房间ID optional uint32 game_count = 6; // 当前是该房间的第几局 optional MsgCreatePrivateRoom private_room = 7; // 私房信息; optional MsgDDZUserOutCard last_outcard = 8; // 房间上家牌的信息 optional uint32 wik = 9; // 当前活动玩家的权限 TDDZPlayerWik optional uint32 bottom_cards = 10; // 底牌列表 optional uint64 multiple = 11; // 房间倍数 repeated MsgDiPaiMutiple dipai_multi_list = 12; // 底牌翻倍列表 optional uint32 room_pay_type = 13; // 付费类型 } message MsgDDZRoomShowDown // 结算房间信息 { optional uint32 room_state = 1; // 房间当前状态 TDDZState optional uint32 state_time = 2; // 状态运行时间 repeated MsgDDZPlayer player_list = 3; // 玩家信息 optional uint64 room_id = 4; // 房间ID optional uint32 game_count = 5; // 当前是该房间的第几局 optional uint32 time = 6; // 时间 optional bool game_over = 8; // 是否结束 repeated MsgDDZShowDownEvent event_count = 9; // 结算事件; repeated MsgDDZIntegralCount integral_list = 10; // 积分卷; } // 积分卷 message MsgDDZIntegralCount { optional uint64 roleid = 1; optional uint32 count = 2; } message MsgDDZShowDownEvent // 结算事件; { optional uint32 event_id = 1; optional uint32 count = 2; } ================================================ FILE: code/EVA/server/script/DataTable/proto/msg_service.proto ================================================ syntax = "proto2"; package PB; message MsgGameType { optional string Type = 1; optional uint32 Max = 2; optional uint32 Curr = 3; } message MsgServiceInfo { repeated MsgGameType RoomList = 1; optional uint32 MaxPlayer = 2; optional uint32 CurrPlayer = 3; optional uint32 ServiceID = 4; optional string ServiceName = 5; } ================================================ FILE: code/EVA/server/script/DataTable/ssl/1_root_bundle.crt ================================================ -----BEGIN CERTIFICATE----- MIIErjCCA5agAwIBAgIQBYAmfwbylVM0jhwYWl7uLjANBgkqhkiG9w0BAQsFADBh MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD QTAeFw0xNzEyMDgxMjI4MjZaFw0yNzEyMDgxMjI4MjZaMHIxCzAJBgNVBAYTAkNO MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQL ExREb21haW4gVmFsaWRhdGVkIFNTTDEdMBsGA1UEAxMUVHJ1c3RBc2lhIFRMUyBS U0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgWa9X+ph+wAm8 Yh1Fk1MjKbQ5QwBOOKVaZR/OfCh+F6f93u7vZHGcUU/lvVGgUQnbzJhR1UV2epJa e+m7cxnXIKdD0/VS9btAgwJszGFvwoqXeaCqFoP71wPmXjjUwLT70+qvX4hdyYfO JcjeTz5QKtg8zQwxaK9x4JT9CoOmoVdVhEBAiD3DwR5fFgOHDwwGxdJWVBvktnoA zjdTLXDdbSVC5jZ0u8oq9BiTDv7jAlsB5F8aZgvSZDOQeFrwaOTbKWSEInEhnchK ZTD1dz6aBlk1xGEI5PZWAnVAba/ofH33ktymaTDsE6xRDnW97pDkimCRak6CEbfe 3dXw6OV5AgMBAAGjggFPMIIBSzAdBgNVHQ4EFgQUf9OZ86BHDjEAVlYijrfMnt3K AYowHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG AQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au ZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwTAYDVR0gBEUwQzA3Bglg hkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t L0NQUzAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAK3dVOj5dlv4MzK2i233 lDYvyJ3slFY2X2HKTYGte8nbK6i5/fsDImMYihAkp6VaNY/en8WZ5qcrQPVLuJrJ DSXT04NnMeZOQDUoj/NHAmdfCBB/h1bZ5OGK6Sf1h5Yx/5wR4f3TUoPgGlnU7EuP ISLNdMRiDrXntcImDAiRvkh5GJuH4YCVE6XEntqaNIgGkRwxKSgnU3Id3iuFbW9F UQ9Qqtb1GX91AJ7i4153TikGgYCdwYkBURD8gSVe8OAco6IfZOYt/TEwii1Ivi1C qnuUlWpsF1LdQNIdfbW3TSe0BhQa7ifbVIfvPWHYOu3rkg1ZeMo6XRU9B4n5VyJY RmE= -----END CERTIFICATE----- ================================================ FILE: code/EVA/server/script/DataTable/ssl/2_ssl.ranatune.com.crt ================================================ -----BEGIN CERTIFICATE----- MIIFjDCCBHSgAwIBAgIQCY9Me/5efgsfOXOdKT7DGDANBgkqhkiG9w0BAQsFADBy MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg SW5jLjEdMBsGA1UECxMURG9tYWluIFZhbGlkYXRlZCBTU0wxHTAbBgNVBAMTFFRy dXN0QXNpYSBUTFMgUlNBIENBMB4XDTE4MDUwOTAwMDAwMFoXDTE5MDUwOTEyMDAw MFowGzEZMBcGA1UEAxMQc3NsLnJhbmF0dW5lLmNvbTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAL2AfBI702GiX1ig5O0ZLQSUoEqr8JZacdvh2m+H3xCb maC6wmoi7ZT6VSGRz3dEdIVOL002YkrLE5Yd0qsenJK6QK/tWqpXYBkk+EOz0AlJ GH5mUGuen8qTtnypkHXjeji+NiNF1yPGXU0wdugYUVJSeqe/Py1PxozMSL+QOZUl xxSi9taF2G1wM3Hm3D4isfRZyqfwD0c+ftv60Ss4C81qLNBcPaeK+1gSnUtd5fz1 G6y0zI/XRDc1Cwoz7A7LodCN0Qh1WjUA0X+q89AwrwjWUMGHeumMAjrIiypdGhZN /hS86ZXfhWWwIKJcF9VtcqkytnOL26fkT1TH4CiMl0ECAwEAAaOCAnMwggJvMB8G A1UdIwQYMBaAFH/TmfOgRw4xAFZWIo63zJ7dygGKMB0GA1UdDgQWBBSJyxcHZxbj c5C81VnsS+EYu4HfiDAbBgNVHREEFDASghBzc2wucmFuYXR1bmUuY29tMA4GA1Ud DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTAYDVR0g BEUwQzA3BglghkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGln aWNlcnQuY29tL0NQUzAIBgZngQwBAgEwgYEGCCsGAQUFBwEBBHUwczAlBggrBgEF BQcwAYYZaHR0cDovL29jc3AyLmRpZ2ljZXJ0LmNvbTBKBggrBgEFBQcwAoY+aHR0 cDovL2NhY2VydHMuZGlnaXRhbGNlcnR2YWxpZGF0aW9uLmNvbS9UcnVzdEFzaWFU TFNSU0FDQS5jcnQwCQYDVR0TBAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB2 AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABY0RokEYAAAQDAEcw RQIhAJt/LQ3PTVXKIgfxD6HRqrbhEoGBJZFR31yyXKIUguJ5AiAR45vJDn59PREN VhO+bL19jch96oxJJmekkuVdOVMZIwB0AG9Tdqwx8DEZ2JkApFEV/3cVHBHZAsEA KQaNsgiaN9kTAAABY0RokpgAAAQDAEUwQwIfVMA85Y5vSPWK6wFZ+uo9jxQnpgnf 239Zy8fJDQoyOAIgNIkGET33PAVPQm/yBUW5AT3kDH99FqqLBwso7WQA7oUwDQYJ KoZIhvcNAQELBQADggEBAALuI5sUT8o92kah2IBDCdb5P5O2T34mP/+3v9E+4YrG R+gElUfeMTbfLcx6U+7KunhgTLzsqANUJ206mELG9xwfycB2qup4RSD66t3+ZYyM w3TlUIPE8fDWyyWeq2ZNNL+QM7KuyD2FtDfnpLdiqgw8BapXQU6jtsRPrv+GE7Cf Ap7PrSKzGr5fvCgd7PPcIaWGH6oWD/HGGl6NHL9XK0afKvZHl6A6l09EtrRQqtP3 PORhvx87GleEsu/B+QLpdHj+SLXvTV2sU05m1PIFntcyaQmBlrLqhPvUv2pSJnNT ZYTVB5V6RLM363foeGvqHcN0bVlkv1MgRZLVPyh/cFg= -----END CERTIFICATE----- ================================================ FILE: code/EVA/server/script/DataTable/ssl/3_ssl.ranatune.com.key ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAvYB8EjvTYaJfWKDk7RktBJSgSqvwllpx2+Hab4ffEJuZoLrC aiLtlPpVIZHPd0R0hU4vTTZiSssTlh3Sqx6ckrpAr+1aqldgGST4Q7PQCUkYfmZQ a56fypO2fKmQdeN6OL42I0XXI8ZdTTB26BhRUlJ6p78/LU/GjMxIv5A5lSXHFKL2 1oXYbXAzcebcPiKx9FnKp/APRz5+2/rRKzgLzWos0Fw9p4r7WBKdS13l/PUbrLTM j9dENzULCjPsDsuh0I3RCHVaNQDRf6rz0DCvCNZQwYd66YwCOsiLKl0aFk3+FLzp ld+FZbAgolwX1W1yqTK2c4vbp+RPVMfgKIyXQQIDAQABAoIBAANJsDVkh3UKYzk7 XudwdDIP9lU/VRL1viOakD62wrdz/KsPzHVZFmpLGtikkg77n4Ir1mkiejt6GSSV z0C37O9khwBqZ8QcdJrRE/PgQfn0REYWpjrsx1DVZeFVM5ABDq7++VtcsAgzTg17 m5eIqvoIu28vQ7RIfd1V4sX8lYwtckiX+tBXLS5CSRYa87pxxXOI/WkcXCb9bvI4 bKoGO99xDe92la8c42SL5B1fzZJ34l5xNHavimFwANdqfiAN5to+JFUxH5AZ3zES y3hQh4yB2L0q0pOcb/pwrM+WY4nzBba2I+h0nEsJmletAHmsvss9QOJL6MTHfoAC gr8ssLECgYEA4yAwZ+axap1moIy0xUzMOd31WWfbNNadTNaaTkrGTTVkhpimpGBU J+uW387pkvXsu1eUl2qIWxOdzuIThbludlFg9Nb5ISFWWYi0JM4ekyXKiNEyGp45 5GnmeCY2CQNvekKQrxDCcDwnr1xvnoU5fbfciN61HLiMfQtWqMYXuVECgYEA1ZfT r38FobVPODdLFvOzrEslHpYt7OvY49y9bBQfiOLer24szmGU59eH0b7VWCFtIrmb Uy893pON8P3hJ2G6AWetZiFBvcoZ/Qy8SkppYcyVYrTXDx4UBxN59c0hghpiMzlV pE0FYwcjS+hB9yt7veYq2k9b384si6I+fNdcgvECgYAEJtx7qb3ogwQTPz82tBav oB0SC1H4f0vU0b90Wu2RD77MrxGsw44GRMo3QSMH6rLvIcS3l9zyPUOPOpa8xQz9 4LLzBtL7Bg78CAGzAomQiwpOwfQ2hFnukPkDjT9Dnup0w669ZIMJZjAbhocL0Mei QrAnWFrbMYxv5LsqzqQ0YQKBgQCujijimIVKtXjrcUy9kiZ5HORWDde0cr5K4eAw DnYDEZ15cynM9DSUEDEgObvzDUY6hcMphUcjuiTbGTBDVfuEIG22NGGcsCjzA9Bx SkS7N02yYCYNZcBqVAFs3tqOj+9G+4lA/+zyFChFZadbTz8OX6cPyKFF0yHWb55v ujURkQKBgErctBLWdL5v8JE5Vn56j46c8zChlEuhmjQ6XaWEDE/8jWLLsXn/Opq1 7L5w4zdp/4iFWYgm57Lc7+iRU/MraEe1ugpRoQIrohVR2zi52kBNNBcUlUtv6r65 DyQgrNxSPxKcLRnoZRtFiyNzk5IW+qalrfKKg8LFR0Q8145xIMD0 -----END RSA PRIVATE KEY----- ================================================ FILE: code/EVA/server/script/Framework/CJsonUtil.lua ================================================ local json = require "cjson" -- Various common routines used by the Lua CJSON package -- -- Mark Pulford -- Determine with a Lua table can be treated as an array. -- Explicitly returns "not an array" for very sparse arrays. -- Returns: -- -1 Not an array -- 0 Empty table -- >0 Highest index in the array local function is_array(table) local max = 0 local count = 0 for k, v in pairs(table) do if type(k) == "number" then if k > max then max = k end count = count + 1 else return -1 end end if max > count * 2 then return -1 end return max end local serialise_value local function serialise_table(value, indent, depth) local spacing, spacing2, indent2 if indent then spacing = "\n" .. indent spacing2 = spacing .. " " indent2 = indent .. " " else spacing, spacing2, indent2 = " ", " ", false end depth = depth + 1 if depth > 50 then return "Cannot serialise any further: too many nested tables" end local max = is_array(value) local comma = false local fragment = { "{" .. spacing2 } if max > 0 then -- Serialise array for i = 1, max do if comma then table.insert(fragment, "," .. spacing2) end table.insert(fragment, serialise_value(value[i], indent2, depth)) comma = true end elseif max < 0 then -- Serialise table for k, v in pairs(value) do if k ~= "class" then if comma then table.insert(fragment, "," .. spacing2) end table.insert(fragment, --("[%s] = %s"):format(serialise_value(k, indent2, depth), ("%s : %s"):format(serialise_value(k, indent2, depth), serialise_value(v, indent2, depth))) comma = true end end end table.insert(fragment, spacing .. "}") return table.concat(fragment) end function serialise_value(value, indent, depth) if indent == nil then indent = "" end if depth == nil then depth = 0 end if value == json.null then return "json.null" elseif type(value) == "string" then return ("%q"):format(value) elseif type(value) == "nil" or type(value) == "number" or type(value) == "boolean" then return tostring(value) elseif type(value) == "table" then return serialise_table(value, indent, depth) else return "\"<" .. type(value) .. ">\"" end end local function file_load(filename) local file if filename == nil then file = io.stdin else local err file, err = io.open(filename, "rb") if file == nil then error(("Unable to read '%s': %s"):format(filename, err)) end end local data = file:read("*a") if filename ~= nil then file:close() end if data == nil then error("Failed to read " .. filename) end return data end local function file_save(filename, data) local file if filename == nil then file = io.stdout else local err file, err = io.open(filename, "wb") if file == nil then error(("Unable to write '%s': %s"):format(filename, err)) end end file:write(data) if filename ~= nil then file:close() end end local function compare_values(val1, val2) local type1 = type(val1) local type2 = type(val2) if type1 ~= type2 then return false end -- Check for NaN if type1 == "number" and val1 ~= val1 and val2 ~= val2 then return true end if type1 ~= "table" then return val1 == val2 end -- check_keys stores all the keys that must be checked in val2 local check_keys = {} for k, _ in pairs(val1) do check_keys[k] = true end for k, v in pairs(val2) do if not check_keys[k] then return false end if not compare_values(val1[k], val2[k]) then return false end check_keys[k] = nil end for k, _ in pairs(check_keys) do -- Not the same if any keys from val1 were not found in val2 return false end return true end local test_count_pass = 0 local test_count_total = 0 local function run_test_summary() return test_count_pass, test_count_total end local function run_test(testname, func, input, should_work, output) local function status_line(name, status, value) local statusmap = { [true] = ":success", [false] = ":error" } if status ~= nil then name = name .. statusmap[status] end nlinfo(("[%s] %s"):format(name, serialise_value(value, false))) end local result = {} local tmp = { pcall(func, unpack(input)) } local success = tmp[1] for i = 2, table.maxn(tmp) do result[i - 1] = tmp[i] end local correct = false if success == should_work and compare_values(result, output) then correct = true test_count_pass = test_count_pass + 1 end test_count_total = test_count_total + 1 local teststatus = { [true] = "PASS", [false] = "FAIL" } nlinfo(("==> Test [%d] %s: %s"):format(test_count_total, testname, teststatus[correct])) status_line("Input", nil, input) if not correct then status_line("Expected", should_work, output) end status_line("Received", success, result) nlinfo() return correct, result end local function run_test_group(tests) local function run_helper(name, func, input) if type(name) == "string" and #name > 0 then nlinfo("==> " .. name) end -- Not a protected call, these functions should never generate errors. func(unpack(input or {})) nlinfo() end for _, v in ipairs(tests) do -- Run the helper if "should_work" is missing if v[4] == nil then run_helper(unpack(v)) else run_test(unpack(v)) end end end -- Run a Lua script in a separate environment local function run_script(script, env) local env = env or {} local func -- Use setfenv() if it exists, otherwise assume Lua 5.2 load() exists if _G.setfenv then func = loadstring(script) if func then setfenv(func, env) end else func = load(script, nil, nil, env) end if func == nil then error("Invalid syntax.") end func() return env end -- Export functions return { serialise_value = serialise_value, file_load = file_load, file_save = file_save, compare_values = compare_values, run_test_summary = run_test_summary, run_test = run_test, run_test_group = run_test_group, run_script = run_script } -- vi:ai et sw=4 ts=4: ================================================ FILE: code/EVA/server/script/Framework/Class.lua ================================================ function class(classname, super) local superType = type(super) local cls if superType ~= "function" and superType ~= "table" then superType = nil super = nil end if superType == "function" or (super and super.__ctype == 1) then -- inherited from native C++ Object cls = {} if superType == "table" then -- copy fields from super for k,v in pairs(super) do cls[k] = v end cls.__create = super.__create cls.super = super else cls.__create = super cls.ctor = function() end end cls.__cname = classname cls.__ctype = 1 function cls.new(...) local instance = cls.__create(...) -- copy fields from class to native object for k,v in pairs(cls) do instance[k] = v end instance.class = cls instance:ctor(...) return instance end else -- inherited from Lua Object if super then cls = {} setmetatable(cls, {__index = super}) cls.super = super else cls = {ctor = function() end} end cls.__cname = classname cls.__ctype = 2 -- lua cls.__index = cls function cls.new(...) local instance = setmetatable({}, cls) instance.class = cls instance:ctor(...) return instance end end return cls end ================================================ FILE: code/EVA/server/script/Framework/Event/EventController.lua ================================================ --========================================================= -- 消息派发 --========================================================= EventController = singleton("EventController"); function EventController:Init() self._MessageQue = {}; end function EventController:RegisterEvent(messageType, callback) --if EventName[messageType] == nil or type(callback) ~= "function" then -- return --end if (messageType == nil) then logError("EventController.RegisterEvent messageType == nil"); return; end if (callback == nil) then local sError = "EventController.RegisterEvent callback == nil "; if (nil ~= messageType) then sError = sError .. "messageType = "..messageType; end logError(sError); return; end if self._MessageQue[messageType] == nil then self._MessageQue[messageType] = {} end local index = #self._MessageQue[messageType]; -- table.getn => # lua5.3 self._MessageQue[messageType][index+1] = callback end function EventController:TriggerEvent( msg_type, ... ) if self._MessageQue[msg_type] == nil then return end for i,v in pairs(self._MessageQue[msg_type]) do if (v ~= nil)then v(...) else end end end function EventController:RemoveEvent(messageType,callback) --if EventName[messageType] == nil or type(callback) ~= "function" then -- return --end for i,v in pairs(self._MessageQue[messageType]) do if callback == v then table.remove(self._MessageQue[messageType],i) return end end end return EventController ================================================ FILE: code/EVA/server/script/Framework/Event/EventRegister.lua ================================================ --========================================================= -- 消息注册管理 --========================================================= local EventRegister = class("EventRegister"); -- 构造函数 function EventRegister:ctor() self._EventCallBackTable = {}; -- 事件回调表 end -- 注册某个事件 function EventRegister:RegisterEvent(Name, Obj, Func) if (nil == Name) then logError("RegisterEvent Name == nil!") return; end local Handler = handler(Obj, Func); local EventTable = self:GetEventRegisterTable(Name); if (nil ~= EventTable) then local idx = #EventTable; EventTable[idx + 1] = Handler; else local v = {}; v[1] = Handler; self._EventCallBackTable[Name] = v; end EventController.Instance():RegisterEvent(Name, Handler); end -- 获取事件注册表 function EventRegister:GetEventRegisterTable(Name) for k,v in pairs(self._EventCallBackTable) do if(k == Name) then return v; end end return nil; end -- 删除所有事件 function EventRegister:UnRegisterAllEvent() for k,v in pairs(self._EventCallBackTable) do for i = 1, #v do EventController.Instance():RemoveEvent(k, v[i]); end end self._EventCallBackTable = {}; end return EventRegister; ================================================ FILE: code/EVA/server/script/Framework/Event/EventTrigger.lua ================================================ EventTrigger = {}; local this = EventTrigger; function EventTrigger.OnEvent( msg_type, ... ) EventController.Instance():TriggerEvent( msg_type, ... ); end ================================================ FILE: code/EVA/server/script/Framework/Hotfix/HotfixHelper.lua ================================================ --- Hotfix helper which hotfixes modified modules. local M = class("HotfixHelper") local hotfix = require("Hotfix/hotfix") -- global_objects which must not hotfix. local global_objects = { arg, assert, bit32, collectgarbage, coroutine, debug, dofile, error, getmetatable, io, ipairs, load, loadfile, loadstring, math, module, next, os, package, pairs, pcall, print, rawequal, rawget, rawlen, rawset, require, select, setmetatable, string, table, tonumber, tostring, type, unpack, utf8, xpcall, } function M:Init() --hotfix.log_debug = function(s) print(s) end hotfix.log_debug = nlinfo hotfix.add_protect(global_objects) self.uptick = 0; -- Map file path to file time to detect modification. self.path_to_time = { }; end --- Check modules and hotfix. function M:Update( curr_tick ) if curr_tick~=nil then if curr_tick - self.uptick < 2000 then return; end self.uptick = curr_tick; end local MOD_NAME = "hotfix_module_names" if not package.searchpath(MOD_NAME, package.path) then return end package.loaded[MOD_NAME] = nil -- always reload it local module_names = require(MOD_NAME) for _, module_name in pairs(module_names) do local path, err = package.searchpath(module_name, package.path) -- Skip non-exist module. if not path then nlwarning(string.format("No such module: %s. %s", module_name, err)) goto continue end --local file_time = lfs.attributes (path, "modification") local file_time = Misc.GetFileModificationDate(path) if file_time == self.path_to_time[path] then goto continue end nlinfo(string.format("Hot fix module %s (%s)", module_name, path)) self.path_to_time[path] = file_time hotfix.hotfix_module(module_name) ::continue:: end -- for end -- check() return M ================================================ FILE: code/EVA/server/script/Framework/Hotfix/hotfix.lua ================================================ --[[ Lua 5.2/5.3 hotfix. Hot update functions and keep old data. Author: Jin Qing ( http://blog.csdn.net/jq0123 ) --]] local M = {} local module_updater = require("Hotfix/internal/module_updater") local functions_replacer = require("Hotfix/internal/functions_replacer") -- Do not update and replace protected objects. local protected = {} -- To protect self. local function add_self_to_protect() M.add_protect{ M, M.hotfix_module, M.log_error, M.log_info, M.log_debug, M.add_protect, M.remove_protect, module_updater, module_updater.log_debug, module_updater.update_loaded_module, functions_replacer, functions_replacer.replace_all, } end -- add_self_to_protect -- Hotfix module with new module object. -- Update package.loaded[module_name] and replace all functions. -- module_obj is the newly loaded module object. local function hotfix_module_with_obj(module_name, module_obj) assert("string" == type(module_name)) add_self_to_protect() module_updater.log_debug = M.log_debug -- Step 1: Update package.loaded[module_name], recording updated functions. local updated_function_map = module_updater.update_loaded_module( module_name, protected, module_obj) -- Step 2: Replace old functions with new ones in module_obj, _G and registry. functions_replacer.replace_all(protected, updated_function_map, module_obj) end -- hotfix_module_with_obj() -- Hotfix module. -- Skip unloaded module. -- Usage: hotfix_module("mymodule.sub_module") -- Returns package.loaded[module_name]. function M.hotfix_module(module_name) assert("string" == type(module_name)) if not package.loaded[module_name] then M.log_debug("Skip unloaded module: " .. module_name) return package.loaded[module_name] end M.log_debug("Hot fix module: " .. module_name) local file_path = assert(package.searchpath(module_name, package.path)) local fp = assert(io.open(file_path)) local chunk = fp:read("*all") fp:close() -- Load chunk. local func = assert(load(chunk, '@'..file_path)) local ok, obj = assert(pcall(func)) if nil == obj then obj = true end -- obj may be false hotfix_module_with_obj(module_name, obj) return package.loaded[module_name] end -- User can set log functions. Default is no log. -- Like: require("hotfix").log_info = function(s) mylog:info(s) end function M.log_error(msg_str) end function M.log_info(msg_str) end function M.log_debug(msg_str) end -- Add objects to protect. -- Example: add_protect({table, math, print}) function M.add_protect(object_array) for _, obj in pairs(object_array) do protected[obj] = true end end -- add_protect() -- Remove objects in protected set. -- Example: remove_protect({table, math, print}) function M.remove_protect(object_array) for _, obj in pairs(object_array) do protected[obj] = nil end end -- remove_protect() return M ================================================ FILE: code/EVA/server/script/Framework/Hotfix/internal/functions_replacer.lua ================================================ --- Replace functions of table or upvalue. -- Search for the old functions and replace them with new ones. local M = {} -- Objects whose functions have been replaced already. -- Each objects need to be replaced once. local replaced_obj = {} -- Map old functions to new functions. -- Used to replace functions finally. -- Set to hotfix.updated_func_map. local updated_func_map = {} -- Do not update and replace protected objects. -- Set to hotfix.protected. local protected = {} local replace_functions -- forward declare -- Replace all updated functions in upvalues of function object. local function replace_functions_in_upvalues(function_object) local obj = function_object assert("function" == type(obj)) assert(not protected[obj]) assert(obj ~= updated_func_map) for i = 1, math.huge do local name, value = debug.getupvalue(obj, i) if not name then return end local new_func = updated_func_map[value] if new_func then assert("function" == type(value)) debug.setupvalue(obj, i, new_func) else replace_functions(value) end end -- for assert(false, "Can not reach here!") end -- replace_functions_in_upvalues() -- Replace all updated functions in the table. local function replace_functions_in_table(table_object) local obj = table_object assert("table" == type(obj)) assert(not protected[obj]) assert(obj ~= updated_func_map) replace_functions(debug.getmetatable(obj)) local new = {} -- to assign new fields for k, v in pairs(obj) do local new_k = updated_func_map[k] local new_v = updated_func_map[v] if new_k then obj[k] = nil -- delete field new[new_k] = new_v or v else obj[k] = new_v or v replace_functions(k) end if not new_v then replace_functions(v) end end -- for k, v for k, v in pairs(new) do obj[k] = v end end -- replace_functions_in_table() -- Replace all updated functions. -- Record all replaced objects in replaced_obj. function replace_functions(obj) if protected[obj] then return end local obj_type = type(obj) if "function" ~= obj_type and "table" ~= obj_type then return end if replaced_obj[obj] then return end replaced_obj[obj] = true assert(obj ~= updated_func_map) if "function" == obj_type then replace_functions_in_upvalues(obj) else -- table replace_functions_in_table(obj) end end -- replace_functions(obj) --- Replace all old functions with new ones. -- Replace in new_obj, _G and debug.getregistry(). -- a_protected is a list of protected object. -- an_updated_func_map is a map from old function to new function. -- new_obj is the newly loaded module. function M.replace_all(a_protected, an_updated_func_map, new_obj) protected = a_protected updated_func_map = an_updated_func_map assert(type(protected) == "table") assert(type(updated_func_map) == "table") if nil == next(updated_func_map) then return end replaced_obj = {} replace_functions(new_obj) -- new_obj may be not in _G replace_functions(_G) replace_functions(debug.getregistry()) replaced_obj = {} end -- M.replace_all() return M ================================================ FILE: code/EVA/server/script/Framework/Hotfix/internal/module_updater.lua ================================================ --- Updater to update loaded module. -- Updating a table is to update metatable and sub-table of the old table, -- and to update functions of the old table, keeping value fields. -- Updating a function is to copy upvalues of old function to new function. -- Functions will be replaced later after updating. local M = {} local update_table local update_func -- Updated signature set to prevent self-reference dead loop. local updated_sig = {} -- Map old function to new functions. local updated_func_map = {} -- Do not update and replace protected objects. -- Set to hotfix.protected. local protected = {} -- Set to hotfix.log_debug. function M.log_debug(msg_str) end -- Check if function or table has been updated. Return true if updated. local function check_updated(new_obj, old_obj, name, deep) local signature = string.format("new(%s) old(%s)", tostring(new_obj), tostring(old_obj)) M.log_debug(string.format("%sUpdate %s: %s", deep, name, signature)) if new_obj == old_obj then M.log_debug(deep .. " Same") return true end if updated_sig[signature] then M.log_debug(deep .. " Already updated") return true end updated_sig[signature] = true return false end -- Update new function with upvalues of old function. -- Parameter name and deep are only for log. function update_func(new_func, old_func, name, deep) assert("function" == type(new_func)) assert("function" == type(old_func)) if protected[old_func] then return end if check_updated(new_func, old_func, name, deep) then return end deep = deep .. " " updated_func_map[old_func] = new_func -- Get upvalues of old function. local old_upvalue_map = {} for i = 1, math.huge do local name, value = debug.getupvalue(old_func, i) if not name then break end old_upvalue_map[name] = value end local function log_dbg(name, from, to) M.log_debug(string.format("%ssetupvalue %s: (%s) -> (%s)", deep, name, tostring(from), tostring(to))) end -- Update new upvalues with old. for i = 1, math.huge do local name, value = debug.getupvalue(new_func, i) if not name then break end local old_value = old_upvalue_map[name] if old_value then local type_old_value = type(old_value) if type_old_value ~= type(value) then debug.setupvalue(new_func, i, old_value) log_dbg(name, value, old_value) elseif type_old_value == "function" then update_func(value, old_value, name, deep) elseif type_old_value == "table" then update_table(value, old_value, name, deep) debug.setupvalue(new_func, i, old_value) else debug.setupvalue(new_func, i, old_value) log_dbg(name, value, old_value) end end -- if old_value end -- for i end -- update_func() -- Compare 2 tables and update the old table. Keep the old data. function update_table(new_table, old_table, name, deep) assert("table" == type(new_table)) assert("table" == type(old_table)) if protected[old_table] then return end if check_updated(new_table, old_table, name, deep) then return end deep = deep .. " " -- Compare 2 tables, and update old table. for key, value in pairs(new_table) do local old_value = old_table[key] local type_value = type(value) if type_value ~= type(old_value) then old_table[key] = value M.log_debug(string.format("%sUpdate field %s: (%s) -> (%s)", deep, key, tostring(old_value), tostring(value))) elseif type_value == "function" then update_func(value, old_value, key, deep) elseif type_value == "table" then update_table(value, old_value, key, deep) end end -- for -- Update metatable. local old_meta = debug.getmetatable(old_table) local new_meta = debug.getmetatable(new_table) if type(old_meta) == "table" and type(new_meta) == "table" then update_table(new_meta, old_meta, name.."'s Meta", deep) end end -- update_table() -- Update new loaded object with package.loaded[module_name]. local function update_loaded_module2(module_name, new_obj) assert(nil ~= new_obj) assert("string" == type(module_name)) local old_obj = package.loaded[module_name] local new_type = type(new_obj) local old_type = type(old_obj) if new_type == old_type then if "table" == new_type then update_table(new_obj, old_obj, module_name, "") return end if "function" == new_type then update_func(new_obj, old_obj, module_name, "") return; end end -- if new_type == old_type M.log_debug(string.format("Directly replace module: old(%s) -> new(%s)", tostring(old_obj), tostring(new_obj))) package.loaded[module_name] = new_obj end -- update_loaded_module2() -- Update new loaded object with package.loaded[module_name]. -- Return an updated function map (updated_func_map). -- new_module_obj is the newly loaded module object. function M.update_loaded_module(module_name, protected_objects, new_module_obj) assert(type(module_name) == "string") assert(type(protected_objects) == "table") protected = protected_objects updated_func_map = {} updated_sig = {} update_loaded_module2(module_name, new_module_obj) updated_sig = {} return updated_func_map end -- update_loaded_module() return M ================================================ FILE: code/EVA/server/script/Framework/InitFramework.lua ================================================ --========================================================= -- 初始化基础通用工具 --========================================================= local BasePath = Misc.GetBasePath() .. "/script/"; package.path = package.path .. BasePath .. "Framework/?.lua;"; package.path = package.path .. BasePath .. "Framework/Event/?.lua;"; package.path = package.path .. BasePath .. "Framework/Net/?.lua;"; protobuf = require "protobuf" Json = require "cjson" JsonUtil = require "CJsonUtil" -- 工具库 require("Class") require("functions") require("Map") require("MapMap") --require ("bit") require("Net/NetWorkHandler") require("Net/BaseService") require("TimerMgr"); require("Event/EventTrigger"); --List = require("Common/List") --Queue = require("Common/Queue") --Map = require("Common/Map") -- protobuf --require ("Common/ProtoBuffer/define_attrib_pb") -- LuaFramework -- IDGenerate = bin_types.IDGenerate; MysqlStmt = bin_types.MysqlStmt; MysqlConn = bin_types.MysqlConn; MysqlResult = bin_types.MysqlResult; CMessage = bin_types.LuaMessage.NewInstance; --[[ Util = LuaFramework.Util; NativeUtil = LuaFramework.NativeUtil; AppConst = LuaFramework.AppConst; LuaHelper = LuaFramework.LuaHelper; NetMessage = LuaFramework.NetMessage; RecordNodeTable = LuaFramework.RecordNodeTable; -- LuaHelper -- NetWorkHelper = LuaHelper.GetNetManager(); GameManager = LuaHelper.GetGameManager(); PoolManager = LuaHelper.GetPoolManager(); LuaManager = LuaHelper.GetLuaManger(); --]] -- 表 --require("Event/EventType") -- 工具 --LSModule = require("SDK/LService/LSModule") --WebModule = require("SDK/Web/WebModule") --HttpClient = require("Common/Net/HttpClient") MemoryRefInfo = require("MemoryReferenceInfo") EventController = require("Event/EventController") --ServerManager = require("Net/ServerManager") EventRegister = require("Event/EventRegister") CallbackServer = require("Net/CallbackServer"); StateMachine = require("SimpleStateMachine"); HotfixHelper = require("Hotfix/HotfixHelper"); enum = {} -- 初始化单例 function OnInitFramework() addr = io.open( BasePath.."DataTable/ProtoMsg.pb", "rb") buffer = addr:read "*a" addr:close() protobuf.register(buffer) local decode = protobuf.decode("google.protobuf.FileDescriptorSet", buffer) for _,v in ipairs(decode.file) do if v.enum_type ~= nil then for _,etp in ipairs(v.enum_type) do local enum_val = etp.value; for _,eval in ipairs(enum_val) do --nlinfo( " " .. eval.name .. " " .. eval.number ); enum[eval.name] = eval.number; end end end end --math.randomseed(tostring(os.time()):reverse():sub(1, 7)) local seed = os.time() + (Misc.GetLocalTime()*100000); math.randomseed(seed) EventController.Instance():Init() TimerMgr:Init( Misc.GetLocalTime() ); Hotfix = HotfixHelper:new(); Hotfix:Init(); end OnInitFramework(); ================================================ FILE: code/EVA/server/script/Framework/List.lua ================================================ local List = class("List"); -- 构造函数 function List:ctor() -- body -- 元素列表 self._list = {}; -- nlinfo(self._list); end -- 添加一个元素 function List:Push(value) -- body table.insert(self._list, value); end -- 插入一个元素 function List:Insert(idx, value) table.insert(self._list, idx, value); end -- 获取一个元素 function List:Get(index) -- body if self:Count() <= 0 or index == nil or type(index) ~= "number" then --todo return nil; end return self._list[index]; end -- 获取最后一个元素 function List:GetLast() return self:Get(self:Count()); end -- 获取第一个元素 function List:GetFirst() return self:Get(1); end -- 删除对象 function List:Remove(value) if value == nil then return end -- body for i=1,self:Count() do local nValue = self._list[i]; if nValue == value then --todo table.remove(self._list, i); i = i - 1; end end end --删除单个对象 function List:RemoveOne(value) if value == nil then return end for i=1,self:Count() do local nValue = self._list[i]; if nValue == value then --todo table.remove(self._list, i); break; end end end -- 根据索引删除对象 function List:RemoveByIndex(idx) if (idx < 1 or idx > self:Count()) then return; end table.remove(self._list, idx); end -- 自定义函数删除 -- 注意会把nil一起删除掉,如果不需要可以改下 function List:RemoveIf(fun, ...) local m = 1; while m <= self:Count() do local nValue = self._list[m]; if (nil ~= nValue) then if fun(nValue, ...) then table.remove(self._list, m); else m = m + 1; end else table.remove(self._list, m); end end end -- 删除所有对象 function List:RemoveAll(Value) local m = 1; while m <= self:Count() do local nValue = self._list[m]; if (nValue == Value) then table.remove(self._list, m); else m = m + 1; end end end -- 是否有某个元素 function List:Contain(value) for i=1,self:Count() do local nValue = self._list[i]; if nValue == value then return true; end end return false; end -- 替换列表中的元素 -- 下标为空替换失败 function List:ReplaceValue( index , value ) local nValue = self._list[index]; if nil ~= nValue then self._list[index] = value; end end --获取列表中元素的个数 function List:GetValueCount(value) local Count = 0; for i=1,self:Count() do local nValue = self._list[i]; if nValue == value then Count = Count + 1; end end return Count; end -- 获取元素的索引 -- 找不到返回-1 function List:IndexOf(value) for i = 1,self:Count() do local nValue = self._list[i]; if nValue == value then return i; end end return -1; end -- 遍历所有成员 function List:ForEach(fun, ...) -- body for k,v in pairs(self._list) do fun(v, ...) end end -- 数量 function List:Count() -- body return #self._list; end -- 克隆一个 function List:Clone() local t = List:new() for i, v in pairs(self._list) do t:Push(v) end return t end -- list赋值 function List:Assign(InList) self._list = {}; for i = 1, InList:Count() do self._list[i] = InList:Get(i); end end -- 追加 function List:Append(InList) local CurCount = self:Count(); for i = 1, InList:Count() do self._list[i + CurCount] = InList:Get(i); end end -- 清除 function List:Clear() -- body self._list={}; end -- 排序 function List:Sort( Action ) table.sort( self._list, Action ); end -- 反序 function List:Reverse() local TmpTab = {}; local k = 1; for i = #self._list, 1, -1 do TmpTab[k] = self._list[i]; k = k + 1; end for i = 1, #TmpTab do self._list[i] = TmpTab[i]; end TmpTab = nil; end -- 求包含的元素个数 function List:NumsOf(inValue) local Nums = 0; for i = 1,self:Count() do local nValue = self._list[i]; if nValue == inValue then Nums = Nums + 1; end end return Nums; end -- 返回符合条件的项 function List:GetIf(fun, ...) for i = 1, self:Count() do local Value = self:Get(i); if (nil ~= Value) then if fun(Value, ...) then return Value; end end end return nil; end -- 返回符合条件项的数量 function List:NumsIf(fun, ...) local Nums = 0; for i = 1, self:Count() do local Value = self:Get(i); if (nil ~= Value) then if fun(Value, ...) then Nums = Nums + 1; end end end return Nums; end -- 返回所有符合条件的所有项 function List:GetIfAll(fun, ...) local ret = {}; for i = 1, self:Count() do local Value = self:Get(i); if (nil ~= Value) then if fun(Value, ...) then table.insert(ret, Value); end end end return ret; end return List; ================================================ FILE: code/EVA/server/script/Framework/Map.lua ================================================ Map = class("Map") local this = Map function this:ctor() self.map = {}; self.count = 0 end -- Map 插入新值 function this:Insert(k,v) if nil == self.map[k] then self.map[k] = v self.count = self.count + 1 end end -- Map 插入新值并且切换旧值 function this:Replace(k,v) if nil == self.map[k] then self.map[k] = v; self.count = self.count + 1; else self.map[k] = v; end end function this:Remove(k) if nil ~= self.map[k] then self.map[k] = nil if self.count >0 then self.count = self.count - 1 end end end function this:ForEachRemove(field, value) local newT = {} for k,v in pairs(self.map) do if v[field]~=value then newT[k] = v; end end self.map = newT; end function this:Find(k) return self.map[k] end function this:Clear() self.map = {}; self.count = 0 end -- 遍历所有成员 function this:ForEach(fun, ...) -- body for k,v in pairs(self.map) do fun(k, v, ...) end end -- Map 获取字典的count function this:Count() return self.count; end return Map; --local characters = Map:new() --characters:Insert("name1"," this Name:123") --characters:Replace("name1"," this Name:2" ) --local name2 = characters:Find("name1") --nlinfo(name2) --nlinfo(characters.count) --for k,v in pairs(characters) do --nlinfo(k,v) --end ================================================ FILE: code/EVA/server/script/Framework/MapMap.lua ================================================ MapMap = class("MapMap") local this = MapMap function this:ctor() self._map = {}; self._count = 0 end -- MapMap ֵ function this:Insert(k1, k2, v) if nil == self._map[k1] then local maptmp = Map:new(); maptmp:Insert(k2,v); self._map[k1] = maptmp; self._count = self._count + 1 else self._map[k1]:Insert(k2,v); end end -- MapMap ֵлֵ function this:Replace(k1,k2,v) if nil == self._map[k1] then local maptmp = Map:new(); maptmp:Insert(k2,v); self._map[k1] = maptmp; self._count = self._count + 1; else self._map[k1]:Replace(k2,v); end end function this:Remove(k1, k2) if nil ~= self._map[k1] then if k2==nil then self._map[k1] = nil self._count = self._count - 1 else self._map[k1]:Remove(k2); end end end function this:Find(k1, k2) local value = nil if nil ~= self._map[k1] then value = self._map[k1]:Find(k2); end return value end function this:Clear() for k,_ in pairs(self.List) do if nil ~= self.List[k] then self.List[k] = nil end end self._count = 0 end -- гԱ function this:ForEach(fun, ...) -- body for k,v in pairs(self._map) do fun(k, v, ...) end end -- MapMap ȡֵcount function this:Count() return self._count; end return Map; --local characters = Map:new() --characters:Insert("name1"," this Name:123") --characters:Replace("name1"," this Name:2" ) --local name2 = characters:Find("name1") --nlinfo(name2) --nlinfo(characters._count) --for k,v in pairs(characters) do --nlinfo(k,v) --end ================================================ FILE: code/EVA/server/script/Framework/MemoryReferenceInfo.lua ================================================ -- -- Collect memory reference info. -- -- @filename MemoryReferenceInfo.lua -- @author WangYaoqi -- @date 2016-02-03 -- The global config of the mri. local cConfig = { m_bAllMemoryRefFileAddTime = true, m_bSingleMemoryRefFileAddTime = true, m_bComparedMemoryRefFileAddTime = true } -- Get the format string of date time. local function FormatDateTimeNow() local cDateTime = os.date("*t") local strDateTime = string.format("%04d%02d%02d-%02d%02d%02d", tostring(cDateTime.year), tostring(cDateTime.month), tostring(cDateTime.day), tostring(cDateTime.hour), tostring(cDateTime.min), tostring(cDateTime.sec)) return strDateTime end -- Get the string result without overrided __tostring. local function GetOriginalToStringResult(cObject) if not cObject then return "" end local cMt = getmetatable(cObject) if not cMt then return tostring(cObject) end -- Check tostring override. local strName = "" local cToString = rawget(cMt, "__tostring") if cToString then rawset(cMt, "__tostring", nil) strName = tostring(cObject) rawset(cMt, "__tostring", cToString) else strName = tostring(cObject) end return strName end -- Create a container to collect the mem ref info results. local function CreateObjectReferenceInfoContainer() -- Create new container. local cContainer = {} -- Contain [table/function] - [reference count] info. local cObjectReferenceCount = {} setmetatable(cObjectReferenceCount, {__mode = "k"}) -- Contain [table/function] - [name] info. local cObjectAddressToName = {} setmetatable(cObjectAddressToName, {__mode = "k"}) -- Set members. cContainer.m_cObjectReferenceCount = cObjectReferenceCount cContainer.m_cObjectAddressToName = cObjectAddressToName -- For stack info. cContainer.m_nStackLevel = -1 cContainer.m_strShortSrc = "None" cContainer.m_nCurrentLine = -1 return cContainer end -- Create a container to collect the mem ref info results from a dumped file. -- strFilePath - The file path. local function CreateObjectReferenceInfoContainerFromFile(strFilePath) -- Create a empty container. local cContainer = CreateObjectReferenceInfoContainer() cContainer.m_strShortSrc = strFilePath -- Cache ref info. local cRefInfo = cContainer.m_cObjectReferenceCount local cNameInfo = cContainer.m_cObjectAddressToName -- Read each line from file. local cFile = assert(io.open(strFilePath, "rb")) for strLine in cFile:lines() do local strHeader = string.sub(strLine, 1, 2) if "--" ~= strHeader then local _, _, strAddr, strName, strRefCount= string.find(strLine, "(.+)\t(.*)\t(%d+)") if strAddr then cRefInfo[strAddr] = strRefCount cNameInfo[strAddr] = strName end end end -- Close and clear file handler. io.close(cFile) cFile = nil return cContainer end -- Create a container to collect the mem ref info results from a dumped file. -- strObjectName - The object name you need to collect info. -- cObject - The object you need to collect info. local function CreateSingleObjectReferenceInfoContainer(strObjectName, cObject) -- Create new container. local cContainer = {} -- Contain [address] - [true] info. local cObjectExistTag = {} setmetatable(cObjectExistTag, {__mode = "k"}) -- Contain [name] - [true] info. local cObjectAliasName = {} -- Contain [access] - [true] info. local cObjectAccessTag = {} setmetatable(cObjectAccessTag, {__mode = "k"}) -- Set members. cContainer.m_cObjectExistTag = cObjectExistTag cContainer.m_cObjectAliasName = cObjectAliasName cContainer.m_cObjectAccessTag = cObjectAccessTag -- For stack info. cContainer.m_nStackLevel = -1 cContainer.m_strShortSrc = "None" cContainer.m_nCurrentLine = -1 -- Init with object values. cContainer.m_strObjectName = strObjectName cContainer.m_strAddressName = (("string" == type(cObject)) and ("\"" .. tostring(cObject) .. "\"")) or GetOriginalToStringResult(cObject) cContainer.m_cObjectExistTag[cObject] = true return cContainer end -- Collect memory reference info from a root table or function. -- strName - The root object name that start to search, default is "_G" if leave this to nil. -- cObject - The root object that start to search, default is _G if leave this to nil. -- cDumpInfoContainer - The container of the dump result info. local function CollectObjectReferenceInMemory(strName, cObject, cDumpInfoContainer) if not cObject then return end if not strName then strName = "" end -- Check container. if (not cDumpInfoContainer) then cDumpInfoContainer = CreateObjectReferenceInfoContainer() end -- Check stack. if cDumpInfoContainer.m_nStackLevel > 0 then local cStackInfo = debug.getinfo(cDumpInfoContainer.m_nStackLevel, "Sl") if cStackInfo then cDumpInfoContainer.m_strShortSrc = cStackInfo.short_src cDumpInfoContainer.m_nCurrentLine = cStackInfo.currentline end cDumpInfoContainer.m_nStackLevel = -1 end -- Get ref and name info. local cRefInfoContainer = cDumpInfoContainer.m_cObjectReferenceCount local cNameInfoContainer = cDumpInfoContainer.m_cObjectAddressToName local strType = type(cObject) if "table" == strType then -- Check table with class name. if rawget(cObject, "__cname") then if "string" == type(cObject.__cname) then strName = strName .. "[class:" .. cObject.__cname .. "]" end elseif rawget(cObject, "class") then if "string" == type(cObject.class) then strName = strName .. "[class:" .. cObject.class .. "]" end elseif rawget(cObject, "_className") then if "string" == type(cObject._className) then strName = strName .. "[class:" .. cObject._className .. "]" end end -- Check if table is _G. if cObject == _G then strName = strName .. "[_G]" end -- Get metatable. local bWeakK = false local bWeakV = false local cMt = getmetatable(cObject) if cMt then -- Check mode. local strMode = rawget(cMt, "__mode") if strMode then if "k" == strMode then bWeakK = true elseif "v" == strMode then bWeakV = true elseif "kv" == strMode then bWeakK = true bWeakV = true end end end -- Add reference and name. cRefInfoContainer[cObject] = (cRefInfoContainer[cObject] and (cRefInfoContainer[cObject] + 1)) or 1 if cNameInfoContainer[cObject] then return end -- Set name. cNameInfoContainer[cObject] = strName -- Dump table key and value. for k, v in pairs(cObject) do -- Check key type. local strKeyType = type(k) if "table" == strKeyType then if not bWeakK then CollectObjectReferenceInMemory(strName .. ".[table:key.table]", k, cDumpInfoContainer) end if not bWeakV then CollectObjectReferenceInMemory(strName .. ".[table:value]", v, cDumpInfoContainer) end elseif "function" == strKeyType then if not bWeakK then CollectObjectReferenceInMemory(strName .. ".[table:key.function]", k, cDumpInfoContainer) end if not bWeakV then CollectObjectReferenceInMemory(strName .. ".[table:value]", v, cDumpInfoContainer) end elseif "thread" == strKeyType then if not bWeakK then CollectObjectReferenceInMemory(strName .. ".[table:key.thread]", k, cDumpInfoContainer) end if not bWeakV then CollectObjectReferenceInMemory(strName .. ".[table:value]", v, cDumpInfoContainer) end elseif "userdata" == strKeyType then if not bWeakK then CollectObjectReferenceInMemory(strName .. ".[table:key.userdata]", k, cDumpInfoContainer) end if not bWeakV then CollectObjectReferenceInMemory(strName .. ".[table:value]", v, cDumpInfoContainer) end else CollectObjectReferenceInMemory(strName .. "." .. k, v, cDumpInfoContainer) end end -- Dump metatable. if cMt then CollectObjectReferenceInMemory(strName ..".[metatable]", cMt, cDumpInfoContainer) end elseif "function" == strType then -- Get function info. local cDInfo = debug.getinfo(cObject, "Su") -- Write this info. cRefInfoContainer[cObject] = (cRefInfoContainer[cObject] and (cRefInfoContainer[cObject] + 1)) or 1 if cNameInfoContainer[cObject] then return end -- Set name. cNameInfoContainer[cObject] = strName .. "[line:" .. tostring(cDInfo.linedefined) .. "@file:" .. cDInfo.short_src .. "]" -- Get upvalues. local nUpsNum = cDInfo.nups for i = 1, nUpsNum do local strUpName, cUpValue = debug.getupvalue(cObject, i) local strUpValueType = type(cUpValue) --print(strUpName, cUpValue) if "table" == strUpValueType then CollectObjectReferenceInMemory(strName .. ".[ups:table:" .. strUpName .. "]", cUpValue, cDumpInfoContainer) elseif "function" == strUpValueType then CollectObjectReferenceInMemory(strName .. ".[ups:function:" .. strUpName .. "]", cUpValue, cDumpInfoContainer) elseif "thread" == strUpValueType then CollectObjectReferenceInMemory(strName .. ".[ups:thread:" .. strUpName .. "]", cUpValue, cDumpInfoContainer) elseif "userdata" == strUpValueType then CollectObjectReferenceInMemory(strName .. ".[ups:userdata:" .. strUpName .. "]", cUpValue, cDumpInfoContainer) end end -- Dump environment table. local getfenv = debug.getfenv if getfenv then local cEnv = getfenv(cObject) if cEnv then CollectObjectReferenceInMemory(strName ..".[function:environment]", cEnv, cDumpInfoContainer) end end elseif "thread" == strType then -- Add reference and name. cRefInfoContainer[cObject] = (cRefInfoContainer[cObject] and (cRefInfoContainer[cObject] + 1)) or 1 if cNameInfoContainer[cObject] then return end -- Set name. cNameInfoContainer[cObject] = strName -- Dump environment table. local getfenv = debug.getfenv if getfenv then local cEnv = getfenv(cObject) if cEnv then CollectObjectReferenceInMemory(strName ..".[thread:environment]", cEnv, cDumpInfoContainer) end end -- Dump metatable. local cMt = getmetatable(cObject) if cMt then CollectObjectReferenceInMemory(strName ..".[thread:metatable]", cMt, cDumpInfoContainer) end elseif "userdata" == strType then -- Add reference and name. cRefInfoContainer[cObject] = (cRefInfoContainer[cObject] and (cRefInfoContainer[cObject] + 1)) or 1 if cNameInfoContainer[cObject] then return end -- Set name. cNameInfoContainer[cObject] = strName -- Dump environment table. local getfenv = debug.getfenv if getfenv then local cEnv = getfenv(cObject) if cEnv then CollectObjectReferenceInMemory(strName ..".[userdata:environment]", cEnv, cDumpInfoContainer) end end -- Dump metatable. local cMt = getmetatable(cObject) if cMt then CollectObjectReferenceInMemory(strName ..".[userdata:metatable]", cMt, cDumpInfoContainer) end elseif "string" == strType then -- Add reference and name. cRefInfoContainer[cObject] = (cRefInfoContainer[cObject] and (cRefInfoContainer[cObject] + 1)) or 1 if cNameInfoContainer[cObject] then return end -- Set name. cNameInfoContainer[cObject] = strName .. "[" .. strType .. "]" else -- For "number" and "boolean". (If you want to dump them, uncomment the followed lines.) -- -- Add reference and name. -- cRefInfoContainer[cObject] = (cRefInfoContainer[cObject] and (cRefInfoContainer[cObject] + 1)) or 1 -- if cNameInfoContainer[cObject] then -- return -- end -- -- Set name. -- cNameInfoContainer[cObject] = strName .. "[" .. strType .. ":" .. tostring(cObject) .. "]" end end -- Collect memory reference info of a single object from a root table or function. -- strName - The root object name that start to search, can not be nil. -- cObject - The root object that start to search, can not be nil. -- cDumpInfoContainer - The container of the dump result info. local function CollectSingleObjectReferenceInMemory(strName, cObject, cDumpInfoContainer) if not cObject then return end if not strName then strName = "" end -- Check container. if (not cDumpInfoContainer) then cDumpInfoContainer = CreateObjectReferenceInfoContainer() end -- Check stack. if cDumpInfoContainer.m_nStackLevel > 0 then local cStackInfo = debug.getinfo(cDumpInfoContainer.m_nStackLevel, "Sl") if cStackInfo then cDumpInfoContainer.m_strShortSrc = cStackInfo.short_src cDumpInfoContainer.m_nCurrentLine = cStackInfo.currentline end cDumpInfoContainer.m_nStackLevel = -1 end local cExistTag = cDumpInfoContainer.m_cObjectExistTag local cNameAllAlias = cDumpInfoContainer.m_cObjectAliasName local cAccessTag = cDumpInfoContainer.m_cObjectAccessTag local strType = type(cObject) if "table" == strType then -- Check table with class name. if rawget(cObject, "__cname") then if "string" == type(cObject.__cname) then strName = strName .. "[class:" .. cObject.__cname .. "]" end elseif rawget(cObject, "class") then if "string" == type(cObject.class) then strName = strName .. "[class:" .. cObject.class .. "]" end elseif rawget(cObject, "_className") then if "string" == type(cObject._className) then strName = strName .. "[class:" .. cObject._className .. "]" end end -- Check if table is _G. if cObject == _G then strName = strName .. "[_G]" end -- Get metatable. local bWeakK = false local bWeakV = false local cMt = getmetatable(cObject) if cMt then -- Check mode. local strMode = rawget(cMt, "__mode") if strMode then if "k" == strMode then bWeakK = true elseif "v" == strMode then bWeakV = true elseif "kv" == strMode then bWeakK = true bWeakV = true end end end -- Check if the specified object. if cExistTag[cObject] and (not cNameAllAlias[strName]) then cNameAllAlias[strName] = true end -- Add reference and name. if cAccessTag[cObject] then return end -- Get this name. cAccessTag[cObject] = true -- Dump table key and value. for k, v in pairs(cObject) do -- Check key type. local strKeyType = type(k) if "table" == strKeyType then if not bWeakK then CollectSingleObjectReferenceInMemory(strName .. ".[table:key.table]", k, cDumpInfoContainer) end if not bWeakV then CollectSingleObjectReferenceInMemory(strName .. ".[table:value]", v, cDumpInfoContainer) end elseif "function" == strKeyType then if not bWeakK then CollectSingleObjectReferenceInMemory(strName .. ".[table:key.function]", k, cDumpInfoContainer) end if not bWeakV then CollectSingleObjectReferenceInMemory(strName .. ".[table:value]", v, cDumpInfoContainer) end elseif "thread" == strKeyType then if not bWeakK then CollectSingleObjectReferenceInMemory(strName .. ".[table:key.thread]", k, cDumpInfoContainer) end if not bWeakV then CollectSingleObjectReferenceInMemory(strName .. ".[table:value]", v, cDumpInfoContainer) end elseif "userdata" == strKeyType then if not bWeakK then CollectSingleObjectReferenceInMemory(strName .. ".[table:key.userdata]", k, cDumpInfoContainer) end if not bWeakV then CollectSingleObjectReferenceInMemory(strName .. ".[table:value]", v, cDumpInfoContainer) end else CollectSingleObjectReferenceInMemory(strName .. "." .. k, v, cDumpInfoContainer) end end -- Dump metatable. if cMt then CollectSingleObjectReferenceInMemory(strName ..".[metatable]", cMt, cDumpInfoContainer) end elseif "function" == strType then -- Get function info. local cDInfo = debug.getinfo(cObject, "Su") local cCombinedName = strName .. "[line:" .. tostring(cDInfo.linedefined) .. "@file:" .. cDInfo.short_src .. "]" -- Check if the specified object. if cExistTag[cObject] and (not cNameAllAlias[cCombinedName]) then cNameAllAlias[cCombinedName] = true end -- Write this info. if cAccessTag[cObject] then return end -- Set name. cAccessTag[cObject] = true -- Get upvalues. local nUpsNum = cDInfo.nups for i = 1, nUpsNum do local strUpName, cUpValue = debug.getupvalue(cObject, i) local strUpValueType = type(cUpValue) --print(strUpName, cUpValue) if "table" == strUpValueType then CollectSingleObjectReferenceInMemory(strName .. ".[ups:table:" .. strUpName .. "]", cUpValue, cDumpInfoContainer) elseif "function" == strUpValueType then CollectSingleObjectReferenceInMemory(strName .. ".[ups:function:" .. strUpName .. "]", cUpValue, cDumpInfoContainer) elseif "thread" == strUpValueType then CollectSingleObjectReferenceInMemory(strName .. ".[ups:thread:" .. strUpName .. "]", cUpValue, cDumpInfoContainer) elseif "userdata" == strUpValueType then CollectSingleObjectReferenceInMemory(strName .. ".[ups:userdata:" .. strUpName .. "]", cUpValue, cDumpInfoContainer) end end -- Dump environment table. local getfenv = debug.getfenv if getfenv then local cEnv = getfenv(cObject) if cEnv then CollectSingleObjectReferenceInMemory(strName ..".[function:environment]", cEnv, cDumpInfoContainer) end end elseif "thread" == strType then -- Check if the specified object. if cExistTag[cObject] and (not cNameAllAlias[strName]) then cNameAllAlias[strName] = true end -- Add reference and name. if cAccessTag[cObject] then return end -- Get this name. cAccessTag[cObject] = true -- Dump environment table. local getfenv = debug.getfenv if getfenv then local cEnv = getfenv(cObject) if cEnv then CollectSingleObjectReferenceInMemory(strName ..".[thread:environment]", cEnv, cDumpInfoContainer) end end -- Dump metatable. local cMt = getmetatable(cObject) if cMt then CollectSingleObjectReferenceInMemory(strName ..".[thread:metatable]", cMt, cDumpInfoContainer) end elseif "userdata" == strType then -- Check if the specified object. if cExistTag[cObject] and (not cNameAllAlias[strName]) then cNameAllAlias[strName] = true end -- Add reference and name. if cAccessTag[cObject] then return end -- Get this name. cAccessTag[cObject] = true -- Dump environment table. local getfenv = debug.getfenv if getfenv then local cEnv = getfenv(cObject) if cEnv then CollectSingleObjectReferenceInMemory(strName ..".[userdata:environment]", cEnv, cDumpInfoContainer) end end -- Dump metatable. local cMt = getmetatable(cObject) if cMt then CollectSingleObjectReferenceInMemory(strName ..".[userdata:metatable]", cMt, cDumpInfoContainer) end elseif "string" == strType then -- Check if the specified object. if cExistTag[cObject] and (not cNameAllAlias[strName]) then cNameAllAlias[strName] = true end -- Add reference and name. if cAccessTag[cObject] then return end -- Get this name. cAccessTag[cObject] = true else -- For "number" and "boolean" type, they are not object type, skip. end end -- The base method to dump a mem ref info result into a file. -- strSavePath - The save path of the file to store the result, must be a directory path, If nil or "" then the result will output to console as print does. -- strExtraFileName - If you want to add extra info append to the end of the result file, give a string, nothing will do if set to nil or "". -- nMaxRescords - How many rescords of the results in limit to save in the file or output to the console, -1 will give all the result. -- strRootObjectName - The header info to show the root object name, can be nil. -- cRootObject - The header info to show the root object address, can be nil. -- cDumpInfoResultsBase - The base dumped mem info result, nil means no compare and only output cDumpInfoResults, otherwise to compare with cDumpInfoResults. -- cDumpInfoResults - The compared dumped mem info result, dump itself only if cDumpInfoResultsBase is nil, otherwise dump compared results with cDumpInfoResultsBase. local function OutputMemorySnapshot(strSavePath, strExtraFileName, nMaxRescords, strRootObjectName, cRootObject, cDumpInfoResultsBase, cDumpInfoResults) -- Check results. if not cDumpInfoResults then return end -- Get time format string. local strDateTime = FormatDateTimeNow() -- Collect memory info. local cRefInfoBase = (cDumpInfoResultsBase and cDumpInfoResultsBase.m_cObjectReferenceCount) or nil local cNameInfoBase = (cDumpInfoResultsBase and cDumpInfoResultsBase.m_cObjectAddressToName) or nil local cRefInfo = cDumpInfoResults.m_cObjectReferenceCount local cNameInfo = cDumpInfoResults.m_cObjectAddressToName -- Create a cache result to sort by ref count. local cRes = {} local nIdx = 0 for k in pairs(cRefInfo) do nIdx = nIdx + 1 cRes[nIdx] = k end -- Sort result. table.sort(cRes, function (l, r) return cRefInfo[l] > cRefInfo[r] end) -- Save result to file. local bOutputFile = strSavePath and (string.len(strSavePath) > 0) local cOutputHandle = nil local cOutputEntry = print if bOutputFile then -- Check save path affix. local strAffix = string.sub(strSavePath, -1) if ("/" ~= strAffix) and ("\\" ~= strAffix) then strSavePath = strSavePath .. "/" end -- Combine file name. local strFileName = strSavePath .. "LuaMemRefInfo-All" if (not strExtraFileName) or (0 == string.len(strExtraFileName)) then if cDumpInfoResultsBase then if cConfig.m_bComparedMemoryRefFileAddTime then strFileName = strFileName .. "-[" .. strDateTime .. "].txt" else strFileName = strFileName .. ".txt" end else if cConfig.m_bAllMemoryRefFileAddTime then strFileName = strFileName .. "-[" .. strDateTime .. "].txt" else strFileName = strFileName .. ".txt" end end else if cDumpInfoResultsBase then if cConfig.m_bComparedMemoryRefFileAddTime then strFileName = strFileName .. "-[" .. strDateTime .. "]-[" .. strExtraFileName .. "].txt" else strFileName = strFileName .. "-[" .. strExtraFileName .. "].txt" end else if cConfig.m_bAllMemoryRefFileAddTime then strFileName = strFileName .. "-[" .. strDateTime .. "]-[" .. strExtraFileName .. "].txt" else strFileName = strFileName .. "-[" .. strExtraFileName .. "].txt" end end end local cFile = assert(io.open(strFileName, "w")) cOutputHandle = cFile cOutputEntry = cFile.write end local cOutputer = function (strContent) if cOutputHandle then cOutputEntry(cOutputHandle, strContent) else cOutputEntry(strContent) end end -- Write table header. if cDumpInfoResultsBase then cOutputer("--------------------------------------------------------\n") cOutputer("-- This is compared memory information.\n") cOutputer("--------------------------------------------------------\n") cOutputer("-- Collect base memory reference at line:" .. tostring(cDumpInfoResultsBase.m_nCurrentLine) .. "@file:" .. cDumpInfoResultsBase.m_strShortSrc .. "\n") cOutputer("-- Collect compared memory reference at line:" .. tostring(cDumpInfoResults.m_nCurrentLine) .. "@file:" .. cDumpInfoResults.m_strShortSrc .. "\n") else cOutputer("--------------------------------------------------------\n") cOutputer("-- Collect memory reference at line:" .. tostring(cDumpInfoResults.m_nCurrentLine) .. "@file:" .. cDumpInfoResults.m_strShortSrc .. "\n") end cOutputer("--------------------------------------------------------\n") cOutputer("-- [Table/Function/String Address/Name]\t[Reference Path]\t[Reference Count]\n") cOutputer("--------------------------------------------------------\n") if strRootObjectName and cRootObject then if "string" == type(cRootObject) then cOutputer("-- From Root Object: \"" .. tostring(cRootObject) .. "\" (" .. strRootObjectName .. ")\n") else cOutputer("-- From Root Object: " .. GetOriginalToStringResult(cRootObject) .. " (" .. strRootObjectName .. ")\n") end end -- Save each info. for i, v in ipairs(cRes) do if (not cDumpInfoResultsBase) or (not cRefInfoBase[v]) then if (nMaxRescords > 0) then if (i <= nMaxRescords) then if "string" == type(v) then local strOrgString = tostring(v) local nPattenBegin, nPattenEnd = string.find(strOrgString, "string: \".*\"") if ((not cDumpInfoResultsBase) and ((nil == nPattenBegin) or (nil == nPattenEnd))) then local strRepString = string.gsub(strOrgString, "([\n\r])", "\\n") cOutputer("string: \"" .. strRepString .. "\"\t" .. cNameInfo[v] .. "\t" .. tostring(cRefInfo[v]) .. "\n") else cOutputer(tostring(v) .. "\t" .. cNameInfo[v] .. "\t" .. tostring(cRefInfo[v]) .. "\n") end else cOutputer(GetOriginalToStringResult(v) .. "\t" .. cNameInfo[v] .. "\t" .. tostring(cRefInfo[v]) .. "\n") end end else if "string" == type(v) then local strOrgString = tostring(v) local nPattenBegin, nPattenEnd = string.find(strOrgString, "string: \".*\"") if ((not cDumpInfoResultsBase) and ((nil == nPattenBegin) or (nil == nPattenEnd))) then local strRepString = string.gsub(strOrgString, "([\n\r])", "\\n") cOutputer("string: \"" .. strRepString .. "\"\t" .. cNameInfo[v] .. "\t" .. tostring(cRefInfo[v]) .. "\n") else cOutputer(tostring(v) .. "\t" .. cNameInfo[v] .. "\t" .. tostring(cRefInfo[v]) .. "\n") end else cOutputer(GetOriginalToStringResult(v) .. "\t" .. cNameInfo[v] .. "\t" .. tostring(cRefInfo[v]) .. "\n") end end end end if bOutputFile then io.close(cOutputHandle) cOutputHandle = nil end end -- The base method to dump a mem ref info result of a single object into a file. -- strSavePath - The save path of the file to store the result, must be a directory path, If nil or "" then the result will output to console as print does. -- strExtraFileName - If you want to add extra info append to the end of the result file, give a string, nothing will do if set to nil or "". -- nMaxRescords - How many rescords of the results in limit to save in the file or output to the console, -1 will give all the result. -- cDumpInfoResults - The dumped results. local function OutputMemorySnapshotSingleObject(strSavePath, strExtraFileName, nMaxRescords, cDumpInfoResults) -- Check results. if not cDumpInfoResults then return end -- Get time format string. local strDateTime = FormatDateTimeNow() -- Collect memory info. local cObjectAliasName = cDumpInfoResults.m_cObjectAliasName -- Save result to file. local bOutputFile = strSavePath and (string.len(strSavePath) > 0) local cOutputHandle = nil local cOutputEntry = print if bOutputFile then -- Check save path affix. local strAffix = string.sub(strSavePath, -1) if ("/" ~= strAffix) and ("\\" ~= strAffix) then strSavePath = strSavePath .. "/" end -- Combine file name. local strFileName = strSavePath .. "LuaMemRefInfo-Single" if (not strExtraFileName) or (0 == string.len(strExtraFileName)) then if cConfig.m_bSingleMemoryRefFileAddTime then strFileName = strFileName .. "-[" .. strDateTime .. "].txt" else strFileName = strFileName .. ".txt" end else if cConfig.m_bSingleMemoryRefFileAddTime then strFileName = strFileName .. "-[" .. strDateTime .. "]-[" .. strExtraFileName .. "].txt" else strFileName = strFileName .. "-[" .. strExtraFileName .. "].txt" end end local cFile = assert(io.open(strFileName, "w")) cOutputHandle = cFile cOutputEntry = cFile.write end local cOutputer = function (strContent) if cOutputHandle then cOutputEntry(cOutputHandle, strContent) else cOutputEntry(strContent) end end -- Write table header. cOutputer("--------------------------------------------------------\n") cOutputer("-- Collect single object memory reference at line:" .. tostring(cDumpInfoResults.m_nCurrentLine) .. "@file:" .. cDumpInfoResults.m_strShortSrc .. "\n") cOutputer("--------------------------------------------------------\n") -- Calculate reference count. local nCount = 0 for k in pairs(cObjectAliasName) do nCount = nCount + 1 end -- Output reference count. cOutputer("-- For Object: " .. cDumpInfoResults.m_strAddressName .. " (" .. cDumpInfoResults.m_strObjectName .. "), have " .. tostring(nCount) .. " reference in total.\n") cOutputer("--------------------------------------------------------\n") -- Save each info. for k in pairs(cObjectAliasName) do if (nMaxRescords > 0) then if (i <= nMaxRescords) then cOutputer(k .. "\n") end else cOutputer(k .. "\n") end end if bOutputFile then io.close(cOutputHandle) cOutputHandle = nil end end -- Fileter an existing result file and output it. -- strFilePath - The existing result file. -- strFilter - The filter string. -- bIncludeFilter - Include(true) or exclude(false) the filter. -- bOutputFile - Output to file(true) or console(false). local function OutputFilteredResult(strFilePath, strFilter, bIncludeFilter, bOutputFile) if (not strFilePath) or (0 == string.len(strFilePath)) then print("You need to specify a file path.") return end if (not strFilter) or (0 == string.len(strFilter)) then print("You need to specify a filter string.") return end -- Read file. local cFilteredResult = {} local cReadFile = assert(io.open(strFilePath, "rb")) for strLine in cReadFile:lines() do local nBegin, nEnd = string.find(strLine, strFilter) if nBegin and nEnd then if bIncludeFilter then nBegin, nEnd = string.find(strLine, "[\r\n]") if nBegin and nEnd and (string.len(strLine) == nEnd) then table.insert(cFilteredResult, string.sub(strLine, 1, nBegin - 1)) else table.insert(cFilteredResult, strLine) end end else if not bIncludeFilter then nBegin, nEnd = string.find(strLine, "[\r\n]") if nBegin and nEnd and (string.len(strLine) == nEnd) then table.insert(cFilteredResult, string.sub(strLine, 1, nBegin - 1)) else table.insert(cFilteredResult, strLine) end end end end -- Close and clear read file handle. io.close(cReadFile) cReadFile = nil -- Write filtered result. local cOutputHandle = nil local cOutputEntry = print if bOutputFile then -- Combine file name. local _, _, strResFileName = string.find(strFilePath, "(.*)%.txt") strResFileName = strResFileName .. "-Filter-" .. ((bIncludeFilter and "I") or "E") .. "-[" .. strFilter .. "].txt" local cFile = assert(io.open(strResFileName, "w")) cOutputHandle = cFile cOutputEntry = cFile.write end local cOutputer = function (strContent) if cOutputHandle then cOutputEntry(cOutputHandle, strContent) else cOutputEntry(strContent) end end -- Output result. for i, v in ipairs(cFilteredResult) do cOutputer(v .. "\n") end if bOutputFile then io.close(cOutputHandle) cOutputHandle = nil end end -- Dump memory reference at current time. -- strSavePath - The save path of the file to store the result, must be a directory path, If nil or "" then the result will output to console as print does. -- strExtraFileName - If you want to add extra info append to the end of the result file, give a string, nothing will do if set to nil or "". -- nMaxRescords - How many rescords of the results in limit to save in the file or output to the console, -1 will give all the result. -- strRootObjectName - The root object name that start to search, default is "_G" if leave this to nil. -- cRootObject - The root object that start to search, default is _G if leave this to nil. local function DumpMemorySnapshot(strSavePath, strExtraFileName, nMaxRescords, strRootObjectName, cRootObject) -- Get time format string. local strDateTime = FormatDateTimeNow() -- Check root object. if cRootObject then if (not strRootObjectName) or (0 == string.len(strRootObjectName)) then strRootObjectName = tostring(cRootObject) end else cRootObject = debug.getregistry() strRootObjectName = "registry" end -- Create container. local cDumpInfoContainer = CreateObjectReferenceInfoContainer() local cStackInfo = debug.getinfo(2, "Sl") if cStackInfo then cDumpInfoContainer.m_strShortSrc = cStackInfo.short_src cDumpInfoContainer.m_nCurrentLine = cStackInfo.currentline end -- Collect memory info. CollectObjectReferenceInMemory(strRootObjectName, cRootObject, cDumpInfoContainer) -- Dump the result. OutputMemorySnapshot(strSavePath, strExtraFileName, nMaxRescords, strRootObjectName, cRootObject, nil, cDumpInfoContainer) end -- Dump compared memory reference results generated by DumpMemorySnapshot. -- strSavePath - The save path of the file to store the result, must be a directory path, If nil or "" then the result will output to console as print does. -- strExtraFileName - If you want to add extra info append to the end of the result file, give a string, nothing will do if set to nil or "". -- nMaxRescords - How many rescords of the results in limit to save in the file or output to the console, -1 will give all the result. -- cResultBefore - The base dumped results. -- cResultAfter - The compared dumped results. local function DumpMemorySnapshotCompared(strSavePath, strExtraFileName, nMaxRescords, cResultBefore, cResultAfter) -- Dump the result. OutputMemorySnapshot(strSavePath, strExtraFileName, nMaxRescords, nil, nil, cResultBefore, cResultAfter) end -- Dump compared memory reference file results generated by DumpMemorySnapshot. -- strSavePath - The save path of the file to store the result, must be a directory path, If nil or "" then the result will output to console as print does. -- strExtraFileName - If you want to add extra info append to the end of the result file, give a string, nothing will do if set to nil or "". -- nMaxRescords - How many rescords of the results in limit to save in the file or output to the console, -1 will give all the result. -- strResultFilePathBefore - The base dumped results file. -- strResultFilePathAfter - The compared dumped results file. local function DumpMemorySnapshotComparedFile(strSavePath, strExtraFileName, nMaxRescords, strResultFilePathBefore, strResultFilePathAfter) -- Read results from file. local cResultBefore = CreateObjectReferenceInfoContainerFromFile(strResultFilePathBefore) local cResultAfter = CreateObjectReferenceInfoContainerFromFile(strResultFilePathAfter) -- Dump the result. OutputMemorySnapshot(strSavePath, strExtraFileName, nMaxRescords, nil, nil, cResultBefore, cResultAfter) end -- Dump memory reference of a single object at current time. -- strSavePath - The save path of the file to store the result, must be a directory path, If nil or "" then the result will output to console as print does. -- strExtraFileName - If you want to add extra info append to the end of the result file, give a string, nothing will do if set to nil or "". -- nMaxRescords - How many rescords of the results in limit to save in the file or output to the console, -1 will give all the result. -- strObjectName - The object name reference you want to dump. -- cObject - The object reference you want to dump. local function DumpMemorySnapshotSingleObject(strSavePath, strExtraFileName, nMaxRescords, strObjectName, cObject) -- Check object. if not cObject then return end if (not strObjectName) or (0 == string.len(strObjectName)) then strObjectName = GetOriginalToStringResult(cObject) end -- Get time format string. local strDateTime = FormatDateTimeNow() -- Create container. local cDumpInfoContainer = CreateSingleObjectReferenceInfoContainer(strObjectName, cObject) local cStackInfo = debug.getinfo(2, "Sl") if cStackInfo then cDumpInfoContainer.m_strShortSrc = cStackInfo.short_src cDumpInfoContainer.m_nCurrentLine = cStackInfo.currentline end -- Collect memory info. CollectSingleObjectReferenceInMemory("registry", debug.getregistry(), cDumpInfoContainer) -- Dump the result. OutputMemorySnapshotSingleObject(strSavePath, strExtraFileName, nMaxRescords, cDumpInfoContainer) end -- Return methods. local cPublications = {m_cConfig = nil, m_cMethods = {}, m_cHelpers = {}, m_cBases = {}} cPublications.m_cConfig = cConfig cPublications.m_cMethods.DumpMemorySnapshot = DumpMemorySnapshot cPublications.m_cMethods.DumpMemorySnapshotCompared = DumpMemorySnapshotCompared cPublications.m_cMethods.DumpMemorySnapshotComparedFile = DumpMemorySnapshotComparedFile cPublications.m_cMethods.DumpMemorySnapshotSingleObject = DumpMemorySnapshotSingleObject cPublications.m_cHelpers.FormatDateTimeNow = FormatDateTimeNow cPublications.m_cHelpers.GetOriginalToStringResult = GetOriginalToStringResult cPublications.m_cBases.CreateObjectReferenceInfoContainer = CreateObjectReferenceInfoContainer cPublications.m_cBases.CreateObjectReferenceInfoContainerFromFile = CreateObjectReferenceInfoContainerFromFile cPublications.m_cBases.CreateSingleObjectReferenceInfoContainer = CreateSingleObjectReferenceInfoContainer cPublications.m_cBases.CollectObjectReferenceInMemory = CollectObjectReferenceInMemory cPublications.m_cBases.CollectSingleObjectReferenceInMemory = CollectSingleObjectReferenceInMemory cPublications.m_cBases.OutputMemorySnapshot = OutputMemorySnapshot cPublications.m_cBases.OutputMemorySnapshotSingleObject = OutputMemorySnapshotSingleObject cPublications.m_cBases.OutputFilteredResult = OutputFilteredResult return cPublications ================================================ FILE: code/EVA/server/script/Framework/MiddleClass.lua ================================================ -- Example -- local class = require 'middleclass' -- local Fruit = class('Fruit') -- 'Fruit' is the class' name -- function Fruit:initialize(sweetness) -- self.sweetness = sweetness -- end -- Fruit.static.sweetness_threshold = 5 -- class variable (also admits methods) -- function Fruit:isSweet() -- return self.sweetness > Fruit.sweetness_threshold -- end -- local Lemon = class('Lemon', Fruit) -- subclassing -- function Lemon:initialize() -- Fruit.initialize(self, 1) -- invoking the superclass' initializer -- end -- local lemon = Lemon:new() or Lemon() -- nlinfo(lemon:isSweet()) -- false -- local middleclass = {} local function _createIndexWrapper(aClass, f) if f == nil then return aClass.__instanceDict else return function(self, name) local value = aClass.__instanceDict[name] if value ~= nil then return value elseif type(f) == "function" then return (f(self, name)) else return f[name] end end end end local function _propagateInstanceMethod(aClass, name, f) f = name == "__index" and _createIndexWrapper(aClass, f) or f aClass.__instanceDict[name] = f for subclass in pairs(aClass.subclasses) do if rawget(subclass.__declaredMethods, name) == nil then _propagateInstanceMethod(subclass, name, f) end end end local function _declareInstanceMethod(aClass, name, f) aClass.__declaredMethods[name] = f if f == nil and aClass.super then f = aClass.super.__instanceDict[name] end _propagateInstanceMethod(aClass, name, f) end local function _tostring(self) return "class " .. self.name end local function _call(self, ...) return self:new(...) end local function _createClass(name, super) local dict = {} dict.__index = dict local aClass = {name = name, super = super, static = {}, __instanceDict = dict, __declaredMethods = {}, subclasses = setmetatable({}, {__mode = 'k'})} if super then setmetatable(aClass.static, {__index = function(_, k) return rawget(dict, k) or super.static[k] end}) else setmetatable(aClass.static, {__index = function(_, k) return rawget(dict, k) end}) end setmetatable(aClass, {__index = aClass.static, __tostring = _tostring, __call = _call, __newindex = _declareInstanceMethod}) return aClass end local function _includeMixin(aClass, mixin) assert(type(mixin) == 'table', "mixin must be a table") for name, method in pairs(mixin) do if name ~= "included" and name ~= "static" then aClass[name] = method end end for name, method in pairs(mixin.static or {}) do aClass.static[name] = method end if type(mixin.included) == "function" then mixin:included(aClass) end return aClass end local DefaultMixin = { __tostring = function(self) return "instance of " .. tostring(self.class) end, initialize = function(self, ...) end, isInstanceOf = function(self, aClass) return type(aClass) == 'table' and (aClass == self.class or self.class:isSubclassOf(aClass)) end, static = { allocate = function(self) assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'") return setmetatable({class = self}, self.__instanceDict) end, new = function(self, ...) assert(type(self) == 'table', "Make sure that you are using 'Class:new' instead of 'Class.new'") local instance = self:allocate() instance:initialize(...) return instance end, subclass = function(self, name) assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'") assert(type(name) == "string", "You must provide a name(string) for your class") local subclass = _createClass(name, self) for methodName, f in pairs(self.__instanceDict) do _propagateInstanceMethod(subclass, methodName, f) end subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end self.subclasses[subclass] = true self:subclassed(subclass) return subclass end, subclassed = function(self, other) end, isSubclassOf = function(self, other) return type(other) == 'table' and type(self.super) == 'table' and (self.super == other or self.super:isSubclassOf(other)) end, include = function(self, ...) assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'") for _, mixin in ipairs({...}) do _includeMixin(self, mixin) end return self end } } function middleclass.class(name, super) assert(type(name) == 'string', "A name (string) is needed for the new class") return super and super:subclass(name) or _includeMixin(_createClass(name), DefaultMixin) end setmetatable(middleclass, {__call = function(_, ...) return middleclass.class(...) end}) return middleclass ================================================ FILE: code/EVA/server/script/Framework/Net/BaseService.lua ================================================ BaseService = {} function BaseService:Send( service_id, cmsg_or_type, proto_type, proto_msg ) local param_type = type(cmsg_or_type) if param_type=="string" then local lua_msg = CMessage(cmsg_or_type); if type(proto_type)=="table" then -- send table => json str local json_str = Table2Json(proto_type); lua_msg:wstring(json_str); elseif type(proto_type)=="string" then -- send proto msg local proto_code = protobuf.encode(proto_type, proto_msg); lua_msg:wbuffer(proto_code, #proto_code); end Net.Send( service_id, lua_msg ); elseif param_type=="userdata" then -- send cmessage Net.Send( service_id, cmsg_or_type ); end end function BaseService:Broadcast( service_name, msg_out ) Net.Broadcast( service_name, msg_out ); end function BaseService:SendToClient( player, cmsg_or_type, proto_type, proto_msg ) if player==nil then return end if player.ConFES==nil then return end local send_info = { player.ConFES, player.UID }; local param_type = type(cmsg_or_type) if param_type=="string" then local lua_msg = CMessage(cmsg_or_type); if type(proto_type)=="table" then -- send table => json str local json_str = Table2Json(proto_type); lua_msg:wstring(json_str); nlwarning(json_str); elseif type(proto_type)=="string" then -- send proto msg local proto_code = protobuf.encode(proto_type, proto_msg); lua_msg:wbuffer(proto_code, #proto_code); -- nlinfo("Msg:"..cmsg_or_type.." Buffer Len : "..#proto_code); end Net.SendToClient( lua_msg, send_info ); elseif param_type=="userdata" then -- send cmessage Net.SendToClient( cmsg_or_type, send_info ); end end return BaseService ================================================ FILE: code/EVA/server/script/Framework/Net/CallbackServer.lua ================================================ local CallbackServer = class("CallbackServer") function CallbackServer:ctor() self.Service = nil; self.ConnectCallbackEvent = ""; self.DisConnectCallbackEvent = ""; end function CallbackServer:Init( name, protocal ) self.ConnectCallbackEvent = name .. "Con"; self.DisConnectCallbackEvent = name .. "Dis"; local listen_proc = string.lower(protocal); self.Service = bin_types.LuaCallbackServer.NewInstance( name, listen_proc ); end function CallbackServer:Listen( port ) self.Service:Listen(port); end function CallbackServer:LoadSslCA( ssl_ca ) self.Service:LoadSslCA(ssl_ca); end function CallbackServer:LoadSslCrt( ssl_crt ) self.Service:LoadSslCrt(ssl_crt); end function CallbackServer:LoadSslPrivateKey( ssl_prvkey ) self.Service:LoadSslPrivateKey(ssl_prvkey); end function CallbackServer:SetClientData( client_data ) self.Service:SetClientData( client_data ); end function CallbackServer:RemoveClientData( uid ) self.Service:RemoveClientData(uid); end function CallbackServer:DisConnect( sock_id ) self.Service:DisConnect(sock_id); end function CallbackServer:Send( sock_id, msg_or_type, proto_type, proto_msg ) local param_type = type(msg_or_type) if param_type=="string" then local lua_msg = CMessage(msg_or_type); if proto_type~=nil then local proto_code = protobuf.encode(proto_type, proto_msg); lua_msg:wbuffer(proto_code, #proto_code); end self.Service:Send( sock_id, lua_msg ); else self.Service:Send( sock_id, msg_or_type ); end end return CallbackServer ================================================ FILE: code/EVA/server/script/Framework/Net/NetWorkHandler.lua ================================================ NetWorkHandler = {}; local this = NetWorkHandler; -- 收到连接,断开事件 function NetWorkHandler.OnNetEvent( event_from, event_type, event_val ) EventController.Instance():TriggerEvent( event_type, event_from, event_val ); end -- 收到网络消息 function NetWorkHandler.OnMessage( msg_from, lua_msg ) --if lua_msg:name()~="SvrInfo" then -- nlinfo("recv msg:"..lua_msg:name()); --end EventController.Instance():TriggerEvent( lua_msg:name(), msg_from, lua_msg ); end function NetWorkHandler.OnError(state) end ================================================ FILE: code/EVA/server/script/Framework/Net/protobuf.lua ================================================ local c = require "protobuf.c" local setmetatable = setmetatable local type = type local table = table local assert = assert local pairs = pairs local ipairs = ipairs local string = string local print = print local io = io local tinsert = table.insert local rawget = rawget local rawset = rawset local M = {} local _pattern_cache = {} local P,GC P = debug.getregistry().PROTOBUF_ENV if P then GC = c._gc() else P= c._env_new() GC = c._gc(P) end M.GC = GC function M.lasterror() return c._last_error(P) end local decode_type_cache = {} local _R_meta = {} function _R_meta:__index(key) local v = decode_type_cache[self._CType][key](self, key) self[key] = v return v end local _reader = {} function _reader:real(key) return c._rmessage_real(self._CObj , key , 0) end function _reader:string(key) return c._rmessage_string(self._CObj , key , 0) end function _reader:bool(key) return c._rmessage_int(self._CObj , key , 0) ~= 0 end function _reader:message(key, message_type) local rmessage = c._rmessage_message(self._CObj , key , 0) if rmessage then local v = { _CObj = rmessage, _CType = message_type, _Parent = self, } return setmetatable( v , _R_meta ) end end function _reader:int(key) return c._rmessage_int(self._CObj , key , 0) end function _reader:real_repeated(key) local cobj = self._CObj local n = c._rmessage_size(cobj , key) local ret = {} for i=0,n-1 do tinsert(ret, c._rmessage_real(cobj , key , i)) end return ret end function _reader:string_repeated(key) local cobj = self._CObj local n = c._rmessage_size(cobj , key) local ret = {} for i=0,n-1 do tinsert(ret, c._rmessage_string(cobj , key , i)) end return ret end function _reader:bool_repeated(key) local cobj = self._CObj local n = c._rmessage_size(cobj , key) local ret = {} for i=0,n-1 do tinsert(ret, c._rmessage_int(cobj , key , i) ~= 0) end return ret end function _reader:message_repeated(key, message_type) local cobj = self._CObj local n = c._rmessage_size(cobj , key) local ret = {} for i=0,n-1 do local m = { _CObj = c._rmessage_message(cobj , key , i), _CType = message_type, _Parent = self, } tinsert(ret, setmetatable( m , _R_meta )) end return ret end function _reader:int_repeated(key) local cobj = self._CObj local n = c._rmessage_size(cobj , key) local ret = {} for i=0,n-1 do tinsert(ret, c._rmessage_int(cobj , key , i)) end return ret end --[[ #define PBC_INT 1 #define PBC_REAL 2 #define PBC_BOOL 3 #define PBC_ENUM 4 #define PBC_STRING 5 #define PBC_MESSAGE 6 #define PBC_FIXED64 7 #define PBC_FIXED32 8 #define PBC_BYTES 9 #define PBC_INT64 10 #define PBC_UINT 11 #define PBC_UNKNOWN 12 #define PBC_REPEATED 128 ]] _reader[1] = function(msg) return _reader.int end _reader[2] = function(msg) return _reader.real end _reader[3] = function(msg) return _reader.bool end _reader[4] = function(msg) return _reader.string end _reader[5] = function(msg) return _reader.string end _reader[6] = function(msg) local message = _reader.message return function(self,key) return message(self, key, msg) end end _reader[7] = _reader[1] _reader[8] = _reader[1] _reader[9] = _reader[5] _reader[10] = _reader[7] _reader[11] = _reader[7] _reader[128+1] = function(msg) return _reader.int_repeated end _reader[128+2] = function(msg) return _reader.real_repeated end _reader[128+3] = function(msg) return _reader.bool_repeated end _reader[128+4] = function(msg) return _reader.string_repeated end _reader[128+5] = function(msg) return _reader.string_repeated end _reader[128+6] = function(msg) local message = _reader.message_repeated return function(self,key) return message(self, key, msg) end end _reader[128+7] = _reader[128+1] _reader[128+8] = _reader[128+1] _reader[128+9] = _reader[128+5] _reader[128+10] = _reader[128+7] _reader[128+11] = _reader[128+7] local _decode_type_meta = {} function _decode_type_meta:__index(key) local t, msg = c._env_type(P, self._CType, key) local func = assert(_reader[t],key)(msg) self[key] = func return func end setmetatable(decode_type_cache , { __index = function(self, key) local v = setmetatable({ _CType = key } , _decode_type_meta) self[key] = v return v end }) local function decode_message( message , buffer, length) local rmessage = c._rmessage_new(P, message, buffer, length) if rmessage then local self = { _CObj = rmessage, _CType = message, } c._add_rmessage(GC,rmessage) return setmetatable( self , _R_meta ) end end ----------- encode ---------------- local encode_type_cache = {} local function encode_message(CObj, message_type, t) local type = encode_type_cache[message_type] for k,v in pairs(t) do local func = type[k] func(CObj, k , v) end end local _writer = { real = c._wmessage_real, enum = c._wmessage_string, string = c._wmessage_string, int = c._wmessage_int, } function _writer:bool(k,v) c._wmessage_int(self, k, v and 1 or 0) end function _writer:message(k, v , message_type) local submessage = c._wmessage_message(self, k) encode_message(submessage, message_type, v) end function _writer:real_repeated(k,v) for _,v in ipairs(v) do c._wmessage_real(self,k,v) end end function _writer:bool_repeated(k,v) for _,v in ipairs(v) do c._wmessage_int(self, k, v and 1 or 0) end end function _writer:string_repeated(k,v) for _,v in ipairs(v) do c._wmessage_string(self,k,v) end end function _writer:message_repeated(k,v, message_type) for _,v in ipairs(v) do local submessage = c._wmessage_message(self, k) encode_message(submessage, message_type, v) end end function _writer:int_repeated(k,v) for _,v in ipairs(v) do c._wmessage_int(self,k,v) end end _writer[1] = function(msg) return _writer.int end _writer[2] = function(msg) return _writer.real end _writer[3] = function(msg) return _writer.bool end _writer[4] = function(msg) return _writer.string end _writer[5] = function(msg) return _writer.string end _writer[6] = function(msg) local message = _writer.message return function(self,key , v) return message(self, key, v, msg) end end _writer[7] = _writer[1] _writer[8] = _writer[1] _writer[9] = _writer[5] _writer[10] = _writer[7] _writer[11] = _writer[7] _writer[128+1] = function(msg) return _writer.int_repeated end _writer[128+2] = function(msg) return _writer.real_repeated end _writer[128+3] = function(msg) return _writer.bool_repeated end _writer[128+4] = function(msg) return _writer.string_repeated end _writer[128+5] = function(msg) return _writer.string_repeated end _writer[128+6] = function(msg) local message = _writer.message_repeated return function(self,key, v) return message(self, key, v, msg) end end _writer[128+7] = _writer[128+1] _writer[128+8] = _writer[128+1] _writer[128+9] = _writer[128+5] _writer[128+10] = _writer[128+7] _writer[128+11] = _writer[128+7] local _encode_type_meta = {} function _encode_type_meta:__index(key) local t, msg = c._env_type(P, self._CType, key) local func = assert(_writer[t],key)(msg) self[key] = func return func end setmetatable(encode_type_cache , { __index = function(self, key) local v = setmetatable({ _CType = key } , _encode_type_meta) self[key] = v return v end }) function M.encode( message, t , func , ...) local encoder = c._wmessage_new(P, message) assert(encoder , message) encode_message(encoder, message, t) if func then local buffer, len = c._wmessage_buffer(encoder) local ret = func(buffer, len, ...) c._wmessage_delete(encoder) return ret else local s = c._wmessage_buffer_string(encoder) c._wmessage_delete(encoder) return s end end --------- unpack ---------- local _pattern_type = { [1] = {"%d","i"}, [2] = {"%F","r"}, [3] = {"%d","b"}, [5] = {"%s","s"}, [6] = {"%s","m"}, [7] = {"%D","d"}, [128+1] = {"%a","I"}, [128+2] = {"%a","R"}, [128+3] = {"%a","B"}, [128+5] = {"%a","S"}, [128+6] = {"%a","M"}, [128+7] = {"%a","D"}, } _pattern_type[4] = _pattern_type[1] _pattern_type[8] = _pattern_type[1] _pattern_type[9] = _pattern_type[5] _pattern_type[10] = _pattern_type[7] _pattern_type[11] = _pattern_type[7] _pattern_type[128+4] = _pattern_type[128+1] _pattern_type[128+8] = _pattern_type[128+1] _pattern_type[128+9] = _pattern_type[128+5] _pattern_type[128+10] = _pattern_type[128+7] _pattern_type[128+11] = _pattern_type[128+7] local function _pattern_create(pattern) local iter = string.gmatch(pattern,"[^ ]+") local message = iter() local cpat = {} local lua = {} for v in iter do local tidx = c._env_type(P, message, v) local t = _pattern_type[tidx] assert(t,tidx) tinsert(cpat,v .. " " .. t[1]) tinsert(lua,t[2]) end local cobj = c._pattern_new(P, message , "@" .. table.concat(cpat," ")) if cobj == nil then return end c._add_pattern(GC, cobj) local pat = { CObj = cobj, format = table.concat(lua), size = 0 } pat.size = c._pattern_size(pat.format) return pat end setmetatable(_pattern_cache, { __index = function(t, key) local v = _pattern_create(key) t[key] = v return v end }) function M.unpack(pattern, buffer, length) local pat = _pattern_cache[pattern] return c._pattern_unpack(pat.CObj , pat.format, pat.size, buffer, length) end function M.pack(pattern, ...) local pat = _pattern_cache[pattern] return c._pattern_pack(pat.CObj, pat.format, pat.size , ...) end function M.check(typename , field) if field == nil then return c._env_type(P,typename) else return c._env_type(P,typename,field) ~=0 end end -------------- local default_cache = {} -- todo : clear default_cache, v._CObj local function default_table(typename) local v = default_cache[typename] if v then return v end local default_inst = assert(decode_message(typename , "")) v = { __index = function(tb, key) local ret = default_inst[key] if 'table' ~= type(ret) then return ret end ret = setmetatable({}, { __index = ret }) rawset(tb, key, ret) return ret end } default_cache[typename] = v return v end local decode_message_mt = {} local function decode_message_cb(typename, buffer) return setmetatable ( { typename, buffer } , decode_message_mt) end function M.decode(typename, buffer, length) local ret = {} local ok = c._decode(P, decode_message_cb , ret , typename, buffer, length) if ok then return setmetatable(ret , default_table(typename)) else return false , c._last_error(P) end end local function expand(tbl) local typename = rawget(tbl , 1) local buffer = rawget(tbl , 2) tbl[1] , tbl[2] = nil , nil assert(c._decode(P, decode_message_cb , tbl , typename, buffer), typename) setmetatable(tbl , default_table(typename)) end function decode_message_mt.__index(tbl, key) expand(tbl) return tbl[key] end function decode_message_mt.__pairs(tbl) expand(tbl) return pairs(tbl) end local function set_default(typename, tbl) for k,v in pairs(tbl) do if type(v) == "table" then local t, msg = c._env_type(P, typename, k) if t == 6 then set_default(msg, v) elseif t == 128+6 then for _,v in ipairs(v) do set_default(msg, v) end end end end return setmetatable(tbl , default_table(typename)) end function M.register(buffer) c._env_register(P, buffer) end function M.register_file(filename) local f = assert(io.open(filename , "rb")) local buffer = f:read "*a" c._env_register(P, buffer) f:close() end function M.enum_id(enum_type, enum_name) return c._env_enum_id(P, enum_type, enum_name) end function M.extract(tbl) local typename = rawget(tbl , 1) local buffer = rawget(tbl , 2) if type(typename) == "string" and type(buffer) == "string" then if M.check(typename) then expand(tbl) end end for k, v in pairs(tbl) do if type(v) == "table" then M.extract(v) end end end M.default=set_default return M ================================================ FILE: code/EVA/server/script/Framework/Queue.lua ================================================ Queue = class("Queue") -- 构造函数 function Queue:ctor() -- body -- 元素列表 self._list = {}; end -- 添加一个元素 function Queue:Push(value) -- body if value ~= nil then --todo local nPos = #self._list + 1; table.insert(self._list, nPos, value); end end -- 弹出一个函数 function Queue:Pop() -- body if self:Count() <= 0 then --todo return nil; end local nValue = self._list[1]; table.remove(self._list, 1); return nValue; end -- 删除对象 function Queue:Remove(value) -- body for i=1,self:Count() do local nValue = self._list[i]; if v == value then --todo table.remove(self._list, i); i = i - 1; end end end -- 数量 function Queue:Count() -- body return #self._list; end -- 清除 function Queue:Clear() -- body self._list={}; end return Queue; ================================================ FILE: code/EVA/server/script/Framework/SimpleStateMachine.lua ================================================ -- region *.lua -- Date -- 此文件由[BabeLua]插件自动生成 --local class = require("MiddleClass") local simple_state_machine = class("SimpleStateMachine") simple_state_machine.VERSION = "2.2.0" -- the event transitioned successfully from one state to another simple_state_machine.SUCCEEDED = 1 -- the event was successfull but no state transition was necessary simple_state_machine.NOTRANSITION = 2 -- the event was cancelled by the caller in a beforeEvent callback simple_state_machine.CANCELLED = 3 -- the event is asynchronous and the caller is in control of when the transition occurs simple_state_machine.PENDING = 4 -- the event was failure simple_state_machine.FAILURE = 5 -- caller tried to fire an event that was innapropriate in the current state simple_state_machine.INVALID_TRANSITION_ERROR = "INVALID_TRANSITION_ERROR" -- caller tried to fire an event while an async transition was still pending simple_state_machine.PENDING_TRANSITION_ERROR = "PENDING_TRANSITION_ERROR" -- caller provided callback function threw an exception simple_state_machine.INVALID_CALLBACK_ERROR = "INVALID_CALLBACK_ERROR" simple_state_machine.WILDCARD = "*" simple_state_machine.ASYNC = "ASYNC" function simple_state_machine:initialize() end function simple_state_machine:setup_state(cfg) assert(type(cfg) == "table", "simple_state_machine:setup_state() - invalid config") -- cfg.initial allow for a simple string, -- or an table with { state = "foo", event = "setup", defer = true|false } if type(cfg.initial) == "string" then self._initial = {state = cfg.initial} else self._initial = cfg.initial end self._terminal = cfg.terminal or cfg.final self._events = cfg.events or {} self._callbacks = cfg.callbacks or {} self._map = {} self._current = "none" self._in_transition = false if self._initial then self._initial.event = self._initial.event or "startup" self:_add_event({name = self._initial.event, from = "none", to = self._initial.state}) end for _, event in ipairs(self._events) do self:_add_event(event) end if self._initial and not self._initial.defer then self:do_event(self._initial.event) end return self._target end function simple_state_machine:is_ready() return self._current ~= "none" end function simple_state_machine:get_state() return self._current end function simple_state_machine:is_state(state) if type(state) == "table" then for _, s in ipairs(state) do if s == self._current then return true end end return false else return self._current == state end end function simple_state_machine:can_do_event(event_name) return not self._in_transition and (self._map[event_name][self._current] ~= nil or self._map[event_name][simple_state_machine.WILDCARD] ~= nil) end function simple_state_machine:cannot_do_event(event_name) return not self:can_do_event(event_name) end function simple_state_machine:is_finished_state() return self:is_state(self._terminal) end function simple_state_machine:do_event_force(name, ...) local from = self._current local map = self._map[name] local to = (map[from] or map[simple_state_machine.WILDCARD]) or from local args = {...} local event = { name = name, from = from, to = to, args = args } if self._in_transition then self._in_transition = false end self:_before_event(event) if from == to then self:_after_event(event) return simple_state_machine.NOTRANSITION end self._current = to self:_enter_state(event) self:_change_state(event) self:_after_event(event) return simple_state_machine.SUCCEEDED end function simple_state_machine:do_event(name, ...) assert(self._map[name] ~= nil, string.format("simple_state_machine:DoEvent() - invalid event %s", tostring(name))) local from = self._current local map = self._map[name] local to = (map[from] or map[simple_state_machine.WILDCARD]) or from local args = {...} local event = { name = name, from = from, to = to, args = args, } if self._in_transition then self:_on_error(event, simple_state_machine.PENDING_TRANSITION_ERROR, "event " .. name .. " inappropriate because previous transition did not complete") return simple_state_machine.FAILURE end if self:cannot_do_event(name) then self:_on_error(event, simple_state_machine.INVALID_TRANSITION_ERROR, "event " .. name .. " inappropriate in current state " .. self._current) return simple_state_machine.FAILURE end if self:_before_event(event) == false then return simple_state_machine.CANCELLED end if from == to then self:_after_event(event) return simple_state_machine.NOTRANSITION end event.transition = function() self._in_transition = false self._current = to -- this method should only ever be called once self:_enter_state(event) self:_change_state(event) self:_after_event(event) return simple_state_machine.SUCCEEDED end event.cancel = function() -- provide a way for caller to cancel async transition if desired event.transition = nil self:_after_event(event) end self._in_transition = true local leave = self:_leave_state(event) if leave == false then event.transition = nil event.cancel = nil self._in_transition = false return simple_state_machine.CANCELLED elseif string.upper(tostring(leave)) == simple_state_machine.ASYNC then return simple_state_machine.PENDING else -- need to check in case user manually called transition() -- but forgot to return StateMachine.ASYNC if event.transition then return event.transition() else self._in_transition = false end end end function simple_state_machine:_add_event(event) local from = {} if type(event.from) == "table" then for _, name in ipairs(event.from) do from[name] = true end elseif event.from then from[event.from] = true else -- allow "wildcard" transition if "from" is not specified from[simple_state_machine.WILDCARD] = true end self._map[event.name] = self._map[event.name] or {} local map = self._map[event.name] for fromName, _ in pairs(from) do map[fromName] = event.to or fromName end end local function _do_callback(callback, event) if callback then return callback(event) end end function simple_state_machine:_before_any_event(event) return _do_callback(self._callbacks["onbeforeevent"], event) end function simple_state_machine:_after_any_event(event) return _do_callback(self._callbacks["onafterevent"], event) end function simple_state_machine:_leave_any_state(event) return _do_callback(self._callbacks["onleavestate"], event) end function simple_state_machine:_enter_any_state(event) return _do_callback(self._callbacks["onenterstate"] or self._callbacks["onstate"], event) end function simple_state_machine:_change_state(event) return _do_callback(self._callbacks["onchangestate"], event) end function simple_state_machine:_before_this_event(event) return _do_callback(self._callbacks["onbefore" .. event.name], event) end function simple_state_machine:_after_this_event(event) return _do_callback(self._callbacks["onafter" .. event.name] or self._callbacks["on" .. event.name], event) end function simple_state_machine:_leave_this_state(event) return _do_callback(self._callbacks["onleave" .. event.from], event) end function simple_state_machine:_enter_this_state(event) return _do_callback(self._callbacks["onenter" .. event.to] or self._callbacks["on" .. event.to], event) end function simple_state_machine:_before_event(event) if self:_before_this_event(event) == false or self:_before_any_event(event) == false then return false end end function simple_state_machine:_after_event(event) self:_after_this_event(event) self:_after_any_event(event) end function simple_state_machine:_leave_state(event, transition) local specific = self:_leave_this_state(event, transition) local general = self:_leave_any_state(event, transition) if specific == false or general == false then return false elseif string.upper(tostring(specific)) == simple_state_machine.ASYNC or string.upper(tostring(general)) == simple_state_machine.ASYNC then return simple_state_machine.ASYNC end end function simple_state_machine:_enter_state(event) self:_enter_this_state(event) self:_enter_any_state(event) end function simple_state_machine:_on_error(event, error, message) nlinfo("%s [simple_state_machine] ERROR: error %s, event %s, from %s to %s", tostring(self._target), tostring(error), event.name, event.from, event.to) nlinfo(message) end return simple_state_machine ================================================ FILE: code/EVA/server/script/Framework/Stack.lua ================================================ stack = { } function stack:create() local t = { } t._et = { } function t:push(...) if ... then local targs = { ...} for _, v in ipairs(targs) do table.insert(self._et, v) end end end function t:pop(num) local num = num or 1 local entries = { } for i = 1, num do if #self._et ~= 0 then table.insert(entries, self._et[#self._et]) table.remove(self._et) else break end end return unpack(entries) end function t:peek() if #self._et ~= 0 then return self._et[#self._et] end return nil end function t:clear() while #self._et ~= 0 do table.remove(self._et) end end function t:getn() return #self._et end function t:list() for i, v in pairs(self._et) do nlinfo(i, v) end end return t end ================================================ FILE: code/EVA/server/script/Framework/StateFul.lua ================================================ -- # Example -- ``` lua -- local class = require 'middleclass' -- local Stateful = require 'stateful' -- local Enemy = class('Enemy') -- Enemy:include(Stateful) -- function Enemy:initialize(health) -- self.health = health -- end -- function Enemy:speak() -- return 'My health is' .. tostring(self.health) -- end -- local Immortal = Enemy:addState('Immortal') -- -- overriden function -- function Immortal:speak() -- return 'I am UNBREAKABLE!!' -- end -- -- added function -- function Immortal:die() -- return 'I can not die now!' -- end -- local peter = Enemy:new(10) -- peter:speak() -- My health is 10 -- peter:gotoState('Immortal') -- peter:speak() -- I am UNBREAKABLE!! -- peter:die() -- I can not die now! -- peter:gotoState(nil) -- peter:speak() -- My health is 10 -- ``` local Stateful = {static = {}} local _callbacks = { enteredState = 1, exitedState = 1, pushedState = 1, poppedState = 1, pausedState = 1, continuedState = 1 } local _BaseState = {} local function _addStatesToClass(klass, superStates) klass.static.states = {} for stateName, state in pairs(superStates or {}) do klass:addState(stateName, state) end end local function _getStatefulMethod(instance, name) if not _callbacks[name] then local stack = rawget(instance, '__stateStack') if not stack then return end for i = #stack, 1, -1 do if stack[i][name] then return stack[i][name] end end end end local function _getNewInstanceIndex(prevIndex) if type(prevIndex) == 'function' then return function(instance, name) return _getStatefulMethod(instance, name) or prevIndex(instance, name) end end return function(instance, name) return _getStatefulMethod(instance, name) or prevIndex[name] end end local function _getNewAllocateMethod(oldAllocateMethod) return function(klass, ...) local instance = oldAllocateMethod(klass, ...) instance.__stateStack = {} return instance end end local function _modifyInstanceIndex(klass) klass.__instanceDict.__index = _getNewInstanceIndex(klass.__instanceDict.__index) end local function _getNewSubclassMethod(prevSubclass) return function(klass, name) local subclass = prevSubclass(klass, name) _addStatesToClass(subclass, klass.states) _modifyInstanceIndex(subclass) return subclass end end local function _modifySubclassMethod(klass) klass.static.subclass = _getNewSubclassMethod(klass.static.subclass) end local function _modifyAllocateMethod(klass) klass.static.allocate = _getNewAllocateMethod(klass.static.allocate) end local function _assertType(val, name, expected_type, type_to_s) assert(type(val) == expected_type, "Expected " .. name .. " to be of type " .. (type_to_s or expected_type) .. ". Was " .. tostring(val) .. "(" .. type(val) .. ")") end local function _assertInexistingState(klass, stateName) assert(klass.states[stateName] == nil, "State " .. tostring(stateName) .. " already exists on " .. tostring(klass)) end local function _assertExistingState(self, state, stateName) assert(state, "The state " .. stateName .. " was not found in " .. tostring(self.class)) end local function _invokeCallback(self, state, callbackName, ...) if state and state[callbackName] then state[callbackName](self, ...) end end local function _getCurrentState(self) return self.__stateStack[#self.__stateStack] end local function _getStateFromClassByName(self, stateName) local state = self.class.static.states[stateName] _assertExistingState(self, state, stateName) return state end local function _getStateIndexFromStackByName(self, stateName) if stateName == nil then return #self.__stateStack end local target = _getStateFromClassByName(self, stateName) for i = #self.__stateStack, 1, -1 do if self.__stateStack[i] == target then return i end end end local function _getStateName(self, target) for name, state in pairs(self.class.static.states) do if state == target then return name end end end function Stateful:included(klass) _addStatesToClass(klass) _modifyInstanceIndex(klass) _modifySubclassMethod(klass) _modifyAllocateMethod(klass) end function Stateful.static:addState(stateName, superState) superState = superState or _BaseState _assertType(stateName, 'stateName', 'string') _assertInexistingState(self, stateName) self.static.states[stateName] = setmetatable({}, {__index = superState}) return self.static.states[stateName] end function Stateful:gotoState(stateName, ...) self:popAllStates() if stateName == nil then self.__stateStack = {} else _assertType(stateName, 'stateName', 'string', 'string or nil') local newState = _getStateFromClassByName(self, stateName) self.__stateStack = {newState} _invokeCallback(self, newState, 'enteredState', ...) end end function Stateful:pushState(stateName) local oldState = _getCurrentState(self) _invokeCallback(self, oldState, 'pausedState') local newState = _getStateFromClassByName(self, stateName) table.insert(self.__stateStack, newState) _invokeCallback(self, newState, 'pushedState') _invokeCallback(self, newState, 'enteredState') end function Stateful:popState(stateName) local oldStateIndex = _getStateIndexFromStackByName(self, stateName) local oldState if oldStateIndex then oldState = self.__stateStack[oldStateIndex] _invokeCallback(self, oldState, 'poppedState') _invokeCallback(self, oldState, 'exitedState') table.remove(self.__stateStack, oldStateIndex) end local newState = _getCurrentState(self) if oldState ~= newState then _invokeCallback(self, newState, 'continuedState') end end function Stateful:popAllStates() local size = #self.__stateStack for i = 1, size do self:popState() end end function Stateful:getStateStackDebugInfo() local info, state = {}, nil for i = #self.__stateStack, 1, -1 do state = self.__stateStack[i] table.insert(info, _getStateName(self, state)) end return info end return Stateful ================================================ FILE: code/EVA/server/script/Framework/Test/FSMClass.lua ================================================ local FSMClass = class("FSMClass") -- 构造函数; function FSMClass:ctor() self._GameFSM = StateMachine:new(); self._GameFSM:setup_state({ events = { {name = "TChessStateWait" }, -- 等待游戏开始 {name = "TChessStateStartGame" }, -- 开始游戏 {name = "TChessStateAction" }, -- 玩家自由出牌状态 {name = "TChessStateShowDown" }, -- 玩家结算状态 {name = "TChessStateLeaveRoom" }, -- 离开 }, callbacks = { onTChessStateWait = handler(self, self.DoGameFSMWait), onTChessStateStartGame = handler(self, self.DoGameFSMStartGame), } }) end function FSMClass:SwitchState( event, ... ) if (self._GameFSM ~= nil) then self._GameFSM:do_event( event, ... ); end end function FSMClass:DoGameFSMWait( event ) nlinfo( "FSMClass:DoGameFSMWait" .. event.args[1] ); end function FSMClass:DoGameFSMStartGame( event ) nlinfo( "FSMClass:DoGameFSMStartGame".. event.args[1] ); end return FSMClass; ================================================ FILE: code/EVA/server/script/Framework/Test/MainTest.lua ================================================ local BasePath = "E:/BaseService/code/EVA/server/script/"; package.path = BasePath .. "Framework/Test/?.lua;" .. BasePath .. "Framework/?.lua;"; require("Class") require("functions") require("TimerMgr") StateMachine = require("SimpleStateMachine"); local FSMClass = require("FSMClass"); local TimerTest = require("TimerTest"); TimerMgr:Init( os.time()*1000 ); local test_timer = TimerTest:new(); while true do TimerMgr:Update( os.time()*1000 ); end ================================================ FILE: code/EVA/server/script/Framework/Test/TimerTest.lua ================================================ local TimerTest = class("TimerTest") function TimerTest:ctor() self.val = 0; TimerMgr:AddTimer(1000, self, self.CallBack); end function TimerTest:CallBack() local timerid = TimerMgr:AddTimer(1000, self, self.CallBack); self.val = self.val+1; print("======"..self.val.." id:"..timerid); end --释放函数 function TimerTest:Release() end return TimerTest; ================================================ FILE: code/EVA/server/script/Framework/TimerMgr.lua ================================================ utils = require("Utils") TimerMgr = {} local tbinsert = table.insert local ums2t = utils.ms2t function TimerMgr:Init(cycle) self.timerid = 1; self._removemap = {}; self._cycle = cycle self._slots = {} self._slots[1] = {} self._slots[2] = {} self._slots[3] = {} self._slots[4] = {} utils.tinsert_n(self._slots[1], {}, 24) utils.tinsert_n(self._slots[2], {}, 60) utils.tinsert_n(self._slots[3], {}, 60) utils.tinsert_n(self._slots[4], {}, 1000) --setmetatable(results,{__mode = "v"}) end function TimerMgr:GetTime() return self._cycle; end function TimerMgr:Update(cycle) local h1, m1, s1, ms1 = ums2t(self._cycle) self._cycle = cycle local h2, m2, s2, ms2 = ums2t(self._cycle) self:__UpdateT__(24, 1, h1, h2, handler(self, self.__UpdateH__)) self:__UpdateT__(60, 2, m1, m2, handler(self, self.__UpdateM__)) self:__UpdateT__(60, 3, s1, s2, handler(self, self.__UpdateS__)) self:__UpdateT__(1000, 4, ms1, ms2, handler(self, self.__UpdateMS__)) --[[ self:__UpdateT__(24, 1, h1, h2, utils.bind(self.__UpdateH__, self)) self:__UpdateT__(60, 2, m1, m2, utils.bind(self.__UpdateM__, self)) self:__UpdateT__(60, 3, s1, s2, utils.bind(self.__UpdateS__, self)) self:__UpdateT__(1000, 4, ms1, ms2, utils.bind(self.__UpdateMS__, self)) --]] end function TimerMgr:AddTimer(delay, obj, func) self.timerid = self.timerid + 1; local Handler = handler(obj, func); self:__Insert__(delay + 1, self.timerid, Handler ) return self.timerid; end function TimerMgr:RemoveTimer( timerid ) if timerid~=nil then self._removemap[timerid]=true; end end function TimerMgr:__Insert__(delay, timerid, func) if 0 == delay then if self._removemap[timerid]==nil then func() else self._removemap[timerid] = nil; end else local h1, m1, s1, ms1 = ums2t(delay) local h2, m2, s2, ms2 = ums2t(delay + self._cycle) local tick = { func = func, id = timerid, time = { h = h2, m = m2, s = s2, ms = ms2 } } if h1 ~= 0 then tbinsert(self._slots[1][h2 == 0 and 24 or h2], tick) elseif m1 ~= 0 then tbinsert(self._slots[2][m2 == 0 and 60 or m2], tick) elseif s1 ~= 0 then tbinsert(self._slots[3][s2 == 0 and 60 or s2], tick) elseif ms1 ~= 0 then tbinsert(self._slots[4][ms2 == 0 and 1000 or ms2], tick) end end end function TimerMgr:__UpdateT__(cycle, index, first, last, func) local slots = self._slots[index] while first ~= last do first = first + 1 local func_cnt = #slots[first]; if func_cnt>0 then for i = 1, func_cnt do func(slots[first][i]) end slots[first] = {} end first = first % cycle end end function TimerMgr:__UpdateH__(v) local delay = v.time.m * 60000 + v.time.s * 1000 + v.time.ms; self:__Insert__(delay, v.id, v.func) end function TimerMgr:__UpdateM__(v) local delay = v.time.s * 1000 + v.time.ms; self:__Insert__(delay, v.id, v.func) end function TimerMgr:__UpdateS__(v) self:__Insert__(v.time.ms, v.id, v.func) end function TimerMgr:__UpdateMS__(v) self:__Insert__(0, v.id, v.func) end return TimerMgr ================================================ FILE: code/EVA/server/script/Framework/Utils.lua ================================================ local _M = {} function _M.bind(func, ...) local args = {...} return function(...) func(table.unpack(args), ...) end end function _M.dump(value, dep) dep = dep or "" local ret = "" if type(value) == "table" then ret = ret .. "{\n" for k, v in pairs(value) do ret = string.format("%s%s\t[%s] = %s\n", ret, dep, k, dump(v, dep .. "\t")) end ret = ret .. dep .. "},\n" else ret = ret .. tostring(value) .. ", " end return ret end function _M.clone(src) local ret = {} if type(src) == "table" then for k, v in pairs(src) do ret[k] = _M.clone(v) end else ret = src end return ret end function _M.tinsert_n(src, val, n) for i = 1, n do table.insert(src, _M.clone(val)) end end function _M.ms2t(cycle) local s = math.floor(cycle / 1000) local m = math.floor(cycle / 60000) local h = math.floor(cycle / 3600000) local ms = cycle - h * 3600000 - m * 60000 - s * 1000 return math.floor(h % 24), math.floor(m % 60), math.floor(s % 60), math.floor(ms % 1000) end function _M.t2ms(h, m, s, ms) return h * 3600000 + m * 60000 + s * 1000 + ms end return _M ================================================ FILE: code/EVA/server/script/Framework/functions.lua ================================================ --[[ 实际上,除了 C++ 回调 Lua 函数之外,在其他所有需要回调的地方都可以使用 handler()。 @param mixed obj Lua 对象 @param function method 对象方法 @return function ]]-- function handler(obj, method) if (nil == obj or nil == method) then logError("handler param == nil"); return nil; end return function(...) return method(obj, ...) end end function checktable(value) if type(value) ~= "table" then value = {} end return value end function md5(value) return Misc.MD5( value, string.len(value) ); end function nldebug( str ) Debug.Debug(str,2); end function nlinfo( str ) Debug.Info(str,2); end function nlwarning( str ) Debug.Warning(str,2); end function nlstop( str ) Debug.Stop(str,2); end function shuffle(tbl) local tbl_count = #tbl; for i=1,tbl_count do local ridx = math.random(1, tbl_count); if i~=ridx then local temp = tbl[i]; tbl[i] = tbl[ridx]; tbl[ridx] = temp; end end end function GetServiceID() return Net.GetServiceID(); end function PrintTable( tbl, indent, depth ) Debug.Info(JsonUtil.serialise_value(tbl, indent, depth), 2); --[[ if tbl==nil then return; end local msg = "" depth = depth or 1 local indent_str = "" for i = 2, depth do indent_str = indent_str.." " end nlinfo(indent_str .. "{") for k,v in pairs(tbl) do if k ~= "class" then local item_str = string.format("%s%s = %s", indent_str .. " ",tostring(k), tostring(v)) nlinfo(item_str) if type(v) == "table" then PrintTable(v, depth + 1) end end end nlinfo(indent_str .. "}") --]] end function Table2Json( tbl ) return JsonUtil.serialise_value(tbl); end function Json2Table( str ) return Json.decode(str); end -- start -- -------------------------------- -- 从表格中删除指定值,返回删除的值的个数 -- @function [parent=#table] removebyvalue -- @param table array 表格 -- @param mixed value 要删除的值 -- @param boolean removeall 是否删除所有相同的值 -- @return integer#integer --[[-- 从表格中删除指定值,返回删除的值的个数 ~~~ lua local array = {"a", "b", "c", "c"} nlinfo(table.removebyvalue(array, "c", true)) -- 输出 2 ~~~ ]] -- end -- function table.removebyvalue(array, value, removeall) local c, i, max = 0, 1, #array while i <= max do if array[i] == value then table.remove(array, i) c = c + 1 i = i - 1 max = max - 1 if not removeall then break end end i = i + 1 end return c end function get_data_by_sec(sec) sec = sec < 0 and 0 or sec local data = { day = math.floor(sec / 3600 / 24), hour = math.floor(sec / 3600) % 24, min = math.floor(sec % 3600 / 60), sec = sec % 60, } return data end -- 单例模式 function singleton(classname, super) local cls = {} if super then for k,v in pairs(super) do cls[k] = v end cls.super = super else cls.ctor = function() end end cls.__cname = classname cls.__index = cls local Instance = setmetatable({class = cls}, cls) function cls.Instance() return Instance end return cls end -- 分割字符串 function SplitStr(str, reps) local resultStrList = {} string.gsub(str,'[^'..reps..']+',function ( w ) table.insert(resultStrList,w) end) return resultStrList end function urlEncode(s) s = string.gsub(s, "([^%w%.%- ])", function(c) return string.format("%%%02X", string.byte(c)) end) return string.gsub(s, " ", "+") end function urlDecode(s) s = string.gsub(s, '%%(%x%x)', function(h) return string.char(tonumber(h, 16)) end) return s end -- 检查表中是否存在 function IsInTable(value, tbl) if nil == tbl then return false; end for k,v in pairs(tbl) do if v == value then return true; end end return false; end function ReverseTable(tab) local tmp = {} for i = 1, #tab do local key = #tab tmp[i] = table.remove(tab) end return tmp end -- 位标识符操作 Start function GetBit( curr, enum_val ) return (curr & (1< 0; end function SetBit( curr, enum_val ) return curr | (1< 0 then curr = curr ~ (1< 0 then curr = curr ~ (1< ================================================ FILE: code/EVA/server/script/SharedLib/Event/EventType.lua ================================================ --========================================================= -- 事件类型 --========================================================= EventType = { -- 内部事件 格式:[EVENT_XXXXX] EVENT_LOGIN = "EVENT_LOGIN"; -- 执行登录状态切换 } ================================================ FILE: code/EVA/server/script/SharedLib/InitSharedLib.lua ================================================ --========================================================= -- 初始化游戏内共享工具,游戏逻辑相关。 --========================================================= local BasePath = Misc.GetBasePath() .. "/script/"; package.path = package.path .. BasePath .. "Framework/?.lua;"; require("InitFramework") require("StaticTableMgr"); require("Event/EventType"); -- 初始化单例 function OnInitSharedLib() StaticTableMgr:Init(); end OnInitSharedLib(); ================================================ FILE: code/EVA/server/script/SharedLib/StaticTableMgr.lua ================================================ StaticTableMgr = {} function StaticTableMgr:Init() local ConfigPath = Misc.GetBasePath() .. "/script/DataTable/"; local json_text = JsonUtil.file_load(ConfigPath.."RoomConfig.json") self._RoomConfig = Json.decode(json_text) json_text = JsonUtil.file_load(ConfigPath.."RoomCreateCost.json") self._CreateCost = Json.decode(json_text) json_text = JsonUtil.file_load(ConfigPath.."SpecialConfig.json") self._SpecialCfg = Json.decode(json_text) end function StaticTableMgr:GetRoomConfig( room_type ) return self._RoomConfig[tostring(room_type)]; end function StaticTableMgr:GetCreateCost( cost_id ) return self._CreateCost[tostring(cost_id)]; end function StaticTableMgr:GetSpecialCfg( room_type ) return self._SpecialCfg[tostring(room_type)]; end return StaticTableMgr; ================================================ FILE: code/EVA/server/script/_FES/Client/Client.lua ================================================ local Client = class("Client") -- 构造函数; function Client:ctor() self.SockID = nil; self.ConPLS = nil; self.UID = nil; self._LastHeartbeat = TimerMgr:GetTime(); self._TimerHandle = TimerMgr:AddTimer(7000, self, self.CheckTimeout); end function Client:ResetHeartbeat() self._LastHeartbeat = TimerMgr:GetTime(); end function Client:CheckTimeout() if TimerMgr:GetTime() - self._LastHeartbeat > 1500000 then ClientService:DisConnect(self.SockID); -- nlinfo("CheckTimeout:DisConnect "..self.SockID); else self._TimerHandle = TimerMgr:AddTimer(7000, self, self.CheckTimeout); nlinfo("CheckTimeout"); end end -- 通知逻辑服务器,客户端网络断开。 function Client:_NotifyClientOffline() if self.ConPLS ~= nil then local msg = CMessage("ClientOffline"); msg:wint(self.UID) BaseService:Send( self.ConPLS, msg ) end end function Client:Release() nlinfo("Client:Release UID:" .. self.UID); self:_NotifyClientOffline(); TimerMgr:RemoveTimer(self._TimerHandle); end return Client; ================================================ FILE: code/EVA/server/script/_FES/Client/ClientMgr.lua ================================================ ClientMgr = {} -- 初始化函数 function ClientMgr:Init() self.ClientMap = {}; self.SocketMap = {}; end function ClientMgr:GetClient( _uid ) return self.ClientMap[_uid]; end function ClientMgr:SetClient( _uid, _sock_id ) if self.ClientMap[_uid] == nil then local client = Client:new(); client.SockID = _sock_id; client.UID = _uid; self.ClientMap[_uid] = client; self.SocketMap[_sock_id] = client; else local client = self.ClientMap[_uid]; self.SocketMap[client.SockID] = nil; ClientService:RemoveClientData(_uid); ClientService:DisConnect(client.SockID); client.ConPLS = nil; client.SockID = _sock_id; self.SocketMap[_sock_id] = client; end end -- 客户端逻辑层心跳,刷新心跳时间。 function ClientMgr:ResetHeartbeat( _uid ) local client = self.ClientMap[_uid]; if client ~= nil then client:ResetHeartbeat(); end end function ClientMgr:RemoveClient( _uid ) if self.ClientMap[_uid] ~= nil then local old_client = self.ClientMap[_uid]; self.SocketMap[old_client.SockID] = nil; self.ClientMap[_uid] = nil; ClientService:RemoveClientData(_uid); old_client:Release(); end end function ClientMgr:RemoveSockID( _sockid ) if self.SocketMap[_sockid] ~= nil then local old_client = self.SocketMap[_sockid]; nlinfo("ClientMgr:RemoveSockID:".._sockid.." UID:"..old_client.UID); ClientService:RemoveClientData(old_client.UID); self.ClientMap[old_client.UID] = nil; self.SocketMap[_sockid] = nil; old_client:Release(); end end return ClientMgr ================================================ FILE: code/EVA/server/script/_FES/FrontEndService.lua ================================================ FrontEndService = {} function FrontEndService:Init() self._EventRegister = EventRegister.new(); self._EventRegister:RegisterEvent( "FESCon", self, self.Connection ); self._EventRegister:RegisterEvent( "FESDis", self, self.DisConnection ); self._EventRegister:RegisterEvent( "PLSCon", self, self.Connection ); self._EventRegister:RegisterEvent( "PLSDis", self, self.DisConnection ); -- 注册其它服务器启动的回调 Net.SetConnectionCallback("FES"); Net.SetDisConnectionCallback("FES"); Net.SetConnectionCallback("PLS"); Net.SetDisConnectionCallback("PLS"); end function FrontEndService:Connection( service_id, service_name ) nlinfo("FrontEndService:Connection:"..service_name.." sid:"..service_id); end function FrontEndService:DisConnection( service_id, service_name ) nlinfo("FrontEndService:DisConnection"..service_name.." sid:"..service_id); end -- 释放函数 function FrontEndService:Release() self._EventRegister:UnRegisterAllEvent(); end return FrontEndService ================================================ FILE: code/EVA/server/script/_FES/Msg/MsgLogin.lua ================================================ MsgLogin = {} function MsgLogin:Init() self._EventRegister = EventRegister.new(); self._EventRegister:RegisterEvent( ClientService.ConnectCallbackEvent, self, self.Connect ); self._EventRegister:RegisterEvent( ClientService.DisConnectCallbackEvent, self, self.DisConnect ); -- 客户端消息 self._EventRegister:RegisterEvent( "LOGIN", self, self.CBLogin ); self._EventRegister:RegisterEvent( "HB", self, self.CBHeartBeat ); -- 服务器间消息 self._EventRegister:RegisterEvent( "AuthOk", self, self.CBAuthOk ); -- 有客户端在其它FES上登录成功。RemoveClient self._EventRegister:RegisterEvent( "SyncData", self, self.CBLoginPLS ); -- 在PLS上登录成功。 end function MsgLogin:CBLogin( sock_id, msg_login ) local tbl_login = msg_login:rpb("PB.MsgLogin"); PrintTable(tbl_login); -- 验证签名 local sign_str = tbl_login.UID .. tbl_login.Channel .. tbl_login.RoomType .. tbl_login.AppName; sign_str = sign_str .. tbl_login.User .. tbl_login.NonceStr .. tbl_login.Timestamp; sign_str = sign_str .. "BLACKSHEEPWALL"; local sign = string.upper( md5(sign_str) ); nlinfo("sign_str:"..sign_str); nlinfo("sign:"..sign); -------------- 账号认证通过 local msg_authok = CMessage("AuthOk"); msg_authok:wint64(tbl_login.UID); BaseService:Broadcast( "FES", msg_authok ) -- 通知其它网关有玩家登录成功。 msg_authok:wstring(tbl_login.RoomType); BaseService:Broadcast( "SCH", msg_authok ) -- 玩家认证通过,请求发送数据。 -- 保存客户端连接 ClientMgr:SetClient(tbl_login.UID, sock_id); -- 通知客户端 账号认证通过. ClientService:Send( sock_id, "AuthOk" ); end function MsgLogin:CBHeartBeat( sock_id, msgin ) local uid = msgin:rint64(); nlinfo("MsgLogin:CBHeartBeat"..uid); ClientMgr:ResetHeartbeat(uid); end -- 有客户端在其它FES上登录成功。RemoveClient function MsgLogin:CBAuthOk( sock_id, msg_authok ) local uid = msg_authok:rint64(); nlinfo("MsgLogin:AuthOk"..uid); ClientMgr:RemoveClient(uid); end function MsgLogin:CBLoginPLS( pls_id, msg_sdata_2 ) local uid = msg_sdata_2:rint64(); local client = ClientMgr:GetClient(uid); if( client ~= nil ) then client.ConPLS = pls_id; -- 设置UID相关信息,用于底层转发消息。 msg.xml ClientService:SetClientData( {client.UID, client.SockID, pls_id} ); end end function MsgLogin:Connect( sock_id ) nlinfo("CallbackClient:Connect"..sock_id); end function MsgLogin:DisConnect( sock_id ) nlinfo("CallbackClient:DisConnect"..sock_id); ClientMgr:RemoveSockID(sock_id); end ================================================ FILE: code/EVA/server/script/_FES/Player/PlayerInfo.lua ================================================ -- Player PLS Info local PlayerInfo = class("PlayerInfo") -- 构造函数; function PlayerInfo:ctor() self.PLSID = nil; self.UID = nil; end return PlayerInfo; ================================================ FILE: code/EVA/server/script/_FES/Player/PlayerInfoMgr.lua ================================================ PlayerInfoMgr = {} -- 初始化函数 function PlayerInfoMgr:Init() self.PlayerInfoMap = Map:new(); end function PlayerInfoMgr:GetPlayerInfo( _uid ) return self.PlayerInfoMap:Find(_uid); end function PlayerInfoMgr:SetPlayerInfo( _uid, _playerinfo ) if _uid ~= _playerinfo.UID then assert() end; self.PlayerInfoMap:Insert(_uid, _playerinfo); end function PlayerInfoMgr:RemovePlayerInfo( _uid ) self.PlayerInfoMap:Remove(_uid); end function PlayerInfoMgr:RemovePLS( pls_sid ) self.PlayerInfoMap:ForEachRemove("PLSID", pls_sid); end return PlayerInfoMgr ================================================ FILE: code/EVA/server/script/_FES/_FESMain.lua ================================================ --========================================================= -- 加载常用模块 --========================================================= local BasePath = Misc.GetBasePath() .. "/script/"; package.path = BasePath .. "_FES/?.lua;" .. BasePath .. "SharedLib/?.lua;"; require("InitSharedLib") require("FrontEndService"); require("Client/ClientMgr"); require("Msg/MsgLogin"); -- Class Client = require("Client/Client"); ClientService = CallbackServer:new(); RobotCallback = CallbackServer:new(); -- 主入口函数。从这里开始lua逻辑 function ServiceInit() nlinfo(" =========FES Main Start============ "); ClientMgr:Init(); FrontEndService:Init(); ClientService:Init( "ClientService", "tcp" ); --ClientService:Init( "ClientService", "ws" ); --ClientService:Init( "ClientService", "wss" ); --ClientService:LoadSslCA(BasePath.."DataTable/ssl/1_root_bundle.crt"); --ClientService:LoadSslCrt(BasePath.."DataTable/ssl/2_ssl.ranatune.com.crt"); --ClientService:LoadSslPrivateKey(BasePath.."DataTable/ssl/3_ssl.ranatune.com.key"); ClientService:Listen( 9999 ); MsgLogin:Init(); end -- 游戏循环 function ServiceUpdate() -- TimerMgr:Update( Misc.GetLocalTime() ); TimerMgr:Update(math.floor(os.clock() * 1000)) end function ServiceRelease() nlinfo("Lua Release."); end function ServiceInfo() end --[[ --bash_path = "E:\\BaseService\\code\\EVA\\server\\script\\"; --package.path = bash_path .. "Framework\\?.lua;" .. bash_path .. "Framework\\Net\\?.lua;"; nlinfo(package.path); local protobuf = require "protobuf" addr = io.open( bash_path.."DataTable\\proto_msg.pb", "rb") buffer = addr:read "*a" addr:close() protobuf.register(buffer) t = protobuf.decode("google.protobuf.FileDescriptorSet", buffer) player_info = { name = "Alice", pid = 12345, view_player_list = { { pid = 17712345678, head_portrait = 1 }, { pid = 17712345679, head_portrait = 2 }, }, level = 2 } code = protobuf.encode("MsgPlayerInfo", player_info) decode = protobuf.decode("MsgPlayerInfo" , code) nlinfo(decode.name) nlinfo(decode.pid) for _,v in ipairs(decode.view_player_list) do nlinfo("\t"..v.pid, v.head_portrait) end ]] ================================================ FILE: code/EVA/server/script/_FES.luaprj ================================================  ================================================ FILE: code/EVA/server/script/_PLS/DB/DBMgr.lua ================================================ DBMgr = {} function DBMgr:Init() self.ConnPlayerInfo = MysqlConn.NewInstance(); local conn_info = { "localhost", "root", "", "d_mt_player", 3306 }; self.ConnPlayerInfo:Connect( conn_info ); self.StmtGetPlayerInfo = MysqlStmt.NewInstance("CALL _t_mt_select_playerinfo(?)"); self.StmtCreatePlayer = MysqlStmt.NewInstance("CALL _t_mt_insert_playerinfo(?)"); self.MysqlResult = MysqlResult.NewInstance(); self.ItemIDGen = IDGenerate.NewInstance(1020); end function DBMgr:LoadPlayerInfo(_uid) self.MysqlResult:Clear(); self.StmtGetPlayerInfo:Clear(); self.StmtGetPlayerInfo:SetUint64(_uid); if self.ConnPlayerInfo:Query( self.StmtGetPlayerInfo, self.MysqlResult ) > 0 then local tb_player_info = PlayerDataHelper:new(); tb_player_info.f_uid = self.MysqlResult:GetUint64(); tb_player_info.f_nickname = self.MysqlResult:GetString(); tb_player_info.f_portrait = self.MysqlResult:GetUint32(); tb_player_info.f_money = self.MysqlResult:GetUint64(); tb_player_info.f_rmb = self.MysqlResult:GetUint64(); tb_player_info.f_main = self.MysqlResult:GetUint32(); tb_player_info.f_flag_bit = self.MysqlResult:GetUint64(); return tb_player_info; end return nil; end function DBMgr:CreatePlayer(_uid) self.StmtCreatePlayer:Clear(); self.StmtCreatePlayer:SetUint64(_uid); if self.ConnPlayerInfo:Exec( self.StmtCreatePlayer ) > 0 then return true; end return false; end --释放函数 function DBMgr:Release() end return DBMgr; ================================================ FILE: code/EVA/server/script/_PLS/DB/DBProc.lua ================================================ local DBProc = class("DBProc") -- 构造函数; function DBProc:ctor( Data ) self:Init(); end function DBProc:LuaTest() nlinfo("DBProc LuaTest "); msg_session = { check = 13, session = 4611686020574871551, index = 21 } PostSub( "thd_player", "EVT_DB_SUB", "MsgSession", msg_session, 0xffff ); end function DBProc:LuaTestCB( from, proto_buf ) local msg_session = protobuf.decode("MsgSession" , proto_buf) nlinfo("Main Thread DBProc Callback " .. from); nlinfo(msg_session.check); nlinfo(msg_session.session); nlinfo(msg_session.index); code = protobuf.encode("MsgSession", msg_session) len = string.len(code); end function DBProc:Init() self._EventRegister = EventRegister.new(); self._EventRegister:RegisterEvent( "EVT_DB_MAIN", self, self.LuaTestCB ); end --释放函数 function DBProc:Release() self._EventRegister:UnRegisterAllEvent(); end return DBProc; ================================================ FILE: code/EVA/server/script/_PLS/DB/DBSubProc.lua ================================================ local DBSubProc = class("DBSubProc") -- 构造函数; function DBSubProc:ctor( Data ) self:Init(); end function DBSubProc:LuaTestCB( from, proto_buf ) local msg_session = protobuf.decode("MsgSession" , proto_buf) nlinfo("Sub Thread DBSubProc Callback " .. from); nlinfo(msg_session.check); nlinfo(msg_session.session); nlinfo(msg_session.index); PostMain( "thd_player", "EVT_DB_MAIN", "MsgSession", msg_session, from ); end function DBSubProc:Init() self._EventRegister = EventRegister.new(); self._EventRegister:RegisterEvent( "EVT_DB_SUB", self, self.LuaTestCB ); end --释放函数 function DBSubProc:Release() self._EventRegister:UnRegisterAllEvent(); end return DBSubProc; ================================================ FILE: code/EVA/server/script/_PLS/DB/DBSubStart.lua ================================================ local BasePath = Misc.GetBasePath() .. "/script/"; package.path = BasePath .. "_PLS/?.lua;" .. BasePath .. "Framework/?.lua;"; require("InitFramework") nlinfo("-=======DBSubStart==========-"); DBSubProc = require("DBSubProc"); sub_proc = DBSubProc:new(); --DBProc = require("DBProc"); --db_proc = DBProc:new(); --db_proc:LuaTest(); ================================================ FILE: code/EVA/server/script/_PLS/Games/Common/CardsAnalyseRes.lua ================================================ local CardsAnalyseRes = class("CardsAnalyseRes") --[[ 牌型分析结构,表示每张相同牌的信息。 Analyse必须是排序后的。 --]] function CardsAnalyseRes:ctor() self:Reset(); end function CardsAnalyseRes:Reset() self.CardCount = { 0, 0, 0, 0 }; self.CardData = { {}, {}, {}, {} }; end function CardsAnalyseRes:GetCount( num ) if self.CardCount[num]~=nil then return self.CardCount[num]; end return 0; end function CardsAnalyseRes:GetDatas( num ) return self.CardData[num]; end -- 牌的逻辑值是否是连续的 function CardsAnalyseRes:IsLink( num ) local is_link = false; local cnt = self:GetCount(num); if cnt>=2 then local val_1 = GetPokerLogicValue(self.CardData[num][1]); -- 如果第一张牌不是2或王,继续判断。 if val_1<15 then is_link = true; for i=2,cnt do local val_next = GetPokerLogicValue(self.CardData[num][i])+i-1; if val_1 ~= val_next then is_link = false; break; end end end end return is_link; end -- 统计牌张数 function CardsAnalyseRes:Analyse( hand_cards ) local hand_cnt = #hand_cards; if hand_cnt==0 then return; end local i=1; while i<=hand_cnt do local card = hand_cards[i]; local same_cnt = 1; local logic_val = GetPokerLogicValue(card); -- 向后遍历同牌 for j=i+1,hand_cnt do if( GetPokerLogicValue(hand_cards[j]) == logic_val ) then same_cnt = same_cnt + 1; else break; end end -- 保存结果 self.CardCount[same_cnt] = self.CardCount[same_cnt] + 1; table.insert( self.CardData[same_cnt], logic_val ); i = i+same_cnt; end end return CardsAnalyseRes; ================================================ FILE: code/EVA/server/script/_PLS/Games/Common/CommonDef.lua ================================================ function CardColor( card ) return card & 0xF0; end function CardValue( card ) return card & 0x0F; end ================================================ FILE: code/EVA/server/script/_PLS/Games/Common/PokerDef.lua ================================================ ConstCardsPoker = { 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D, -- 方块; 0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D, -- 梅花; 0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D, -- 红桃; 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D, -- 黑桃; 0x41,0x42, -- 大小王; } -- 获得牌的逻辑数值,牌值大小。 function GetPokerLogicValue( card ) local value = CardValue(card); -- 大小王 if card >= 0x40 then return value+15; end if value==1 then return 14; end if value==2 then return 15; end return value end function GetPokerCount( card_list, card ) local value = GetPokerLogicValue(card); local count = 0; for _,v in ipairs(card_list) do if value==GetPokerLogicValue(v) then count = count + 1; end end return count; end -- 按牌的逻辑值从大到小排序 function SortPokerLogicValue( cards ) local cnt = #cards; if cnt<=1 then return; end local logic_cards = {}; for i,card in ipairs(cards) do logic_cards[i] = GetPokerLogicValue(card); end local is_sorted = false; local last_n = cnt - 1; while ( not is_sorted ) do is_sorted = true; for i=1,last_n do local ccurr = logic_cards[i]; local cnext = logic_cards[i+1]; if ( ccurr0x40 and out_cards[2]>0x40 then -- return enum.CT_DDZ_HUOJIAN, val_1; elseif val_1==GetPokerLogicValue(out_cards[2]) then -- return enum.CT_DDZ_DOUBLE, val_1; end return enum.CT_DDZ_ERROR; end -- Ʒ local ddz_anly = self.TempAnalyse; ddz_anly:Reset(); ddz_anly:Analyse( out_cards ); local cnt_4 = ddz_anly:GetCount(4); if cnt_4>0 then local anly_datas = ddz_anly:GetDatas(4); local first_val = anly_datas[1]; if cnt_4==1 and out_cnt==4 then -- ը return enum.CT_DDZ_ZHADAN_SIZHANG, first_val; elseif cnt_4==1 and out_cnt==6 then -- Ĵ return enum.CT_DDZ_FOUR_WITHDOUBLE, first_val; elseif cnt_4==1 and out_cnt==8 and ddz_anly:GetCount(2)==2 then -- Ĵ return enum.CT_DDZ_FOUR_LIANGDUI, first_val; elseif cnt_4==2 and out_cnt==8 then if first_type==enum.CT_DDZ_FOUR_LIANGDUI then -- Ĵ return enum.CT_DDZ_FOUR_LIANGDUI, first_val; end local second_val = anly_datas[2]; if (first_val+1)==second_val then -- ɻ return enum.CT_DDZ_FEIJI_WITH_ONE, first_val; end return enum.CT_DDZ_FOUR_LIANGDUI, first_val; end end local cnt_3 = ddz_anly:GetCount(3); local cnt_2 = ddz_anly:GetCount(2); local cnt_1 = ddz_anly:GetCount(1); if cnt_3>0 then local anly_datas = ddz_anly:GetDatas(3); local first_val = anly_datas[1]; if out_cnt==3 then -- return enum.CT_DDZ_THREE_TIAO, first_val; elseif cnt_3==1 and out_cnt==4 then -- һ return enum.CT_DDZ_THREE_TIAO_WITH_ONE, first_val; elseif cnt_3==1 and out_cnt==5 and cnt_2==1 then -- return enum.CT_DDZ_THREE_TIAO_WITH_YIDUI, first_val; elseif cnt_3==2 then -- ɻ if out_cnt==6 then -- ɻ return enum.CT_DDZ_FEIJI_WITH_NULL, first_val; else if ddz_anly:IsLink(3) then if out_cnt==8 then if cnt_2==1 or cnt_1==2 then -- ɻ return enum.CT_DDZ_FEIJI_WITH_ONE, first_val; end elseif out_cnt==10 and cnt_2==2 then -- ɻ return enum.CT_DDZ_FEIJI_WITH_YIDUI, first_val; end end end end elseif cnt_2>=3 and cnt_2*2==out_cnt and ddz_anly:IsLink(2) then -- local anly_datas = ddz_anly:GetDatas(2); return enum.CT_DDZ_LIAN_DUI, anly_datas[1]; elseif cnt_1>=5 and cnt_1==out_cnt and ddz_anly:IsLink(1) then -- ˳ local anly_datas = ddz_anly:GetDatas(1); return enum.CT_DDZ_SHUN_ZI, anly_datas[1]; end return enum.CT_DDZ_ERROR; end -- curr_out 󣬷true function DdzCardtypes:CompareCards( curr_out, last_out ) if curr_out.Type==enum.CT_DDZ_HUOJIAN or last_out.Type==enum.CT_DDZ_ERROR or curr_out.UID==last_out.UID then return true; end if curr_out.Type==enum.CT_DDZ_ERROR or last_out.Type==enum.CT_DDZ_HUOJIAN then return false; end -- Ƚը if curr_out.Type==enum.CT_DDZ_ZHADAN_SIZHANG or last_out.Type==enum.CT_DDZ_ZHADAN_SIZHANG then local curr_isbomb = curr_out.Type==enum.CT_DDZ_ZHADAN_SIZHANG; local last_isbomb = last_out.Type==enum.CT_DDZ_ZHADAN_SIZHANG; if last_isbomb and not curr_isbomb then -- ϼҳըԼIJը return false; elseif not last_isbomb and curr_isbomb then -- ϼҳIJըԼը return true; elseif last_isbomb and curr_isbomb then -- ըȽըС return curr_out.CompVal > last_out.CompVal; end end -- ж: 1.Ͳͬʱֱӷش 2.Ƶͬ if curr_out.Type ~= last_out.Type or #curr_out.Cards ~= #curr_out.Cards then return false; end --[[ local ctype = curr_out.Type; -- Ա if ctype==enum.CT_DDZ_SINGLE or ctype==enum.CT_DDZ_DOUBLE or ctype==enum.CT_DDZ_LIAN_DUI or ctype==enum.CT_DDZ_SHUN_ZI then return curr_out.CompVal > last_out.CompVal; elseif ctype==enum.CT_DDZ_FEIJI_WITH_YIDUI or ctype==enum.CT_DDZ_FEIJI_WITH_ONE then elseif ctype==enum.CT_DDZ_FEIJI_WITH_NULL then elseif ctype==enum.CT_DDZ_FOUR_WITHDOUBLE or ctype==enum.CT_DDZ_FOUR_LIANGDUI then elseif ctype==enum.CT_DDZ_THREE_TIAO or ctype==enum.CT_DDZ_THREE_TIAO_WITH_ONE or ctype==enum.CT_DDZ_THREE_TIAO_WITH_YIDUI then end ]] return curr_out.CompVal > last_out.CompVal; end -- Ƿܴ last_out . function DdzCardtypes:CheckCanOutCards( last_out, hand_cards ) local lastype = last_out.Type; if last_out.CompVal==0 or lastype==enum.CT_DDZ_ERROR then return true; end if lastype==enum.CT_DDZ_SINGLE then return self:__GetSingleCards(last_out.CompVal, hand_cards); elseif lastype==enum.CT_DDZ_DOUBLE then return self:__CheckHaveCards(last_out.CompVal, hand_cards, 2); elseif lastype==enum.CT_DDZ_THREE_TIAO then return self:__CheckHaveCards(last_out.CompVal, hand_cards, 3); elseif lastype==enum.CT_DDZ_THREE_TIAO_WITH_ONE then return self:__CheckHaveThreeOne(last_out.CompVal, hand_cards); elseif lastype==enum.CT_DDZ_THREE_TIAO_WITH_YIDUI then return self:__CheckHaveThreeDouble(last_out.CompVal, hand_cards); elseif lastype==enum.CT_DDZ_LIAN_DUI then return self:__CheckHaveDoubleLink(last_out.CompVal, hand_cards); elseif lastype==enum.CT_DDZ_SHUN_ZI then return self:__CheckHaveLinkCards(last_out.CompVal, hand_cards); elseif lastype==enum.CT_DDZ_FEIJI_WITH_NULL then return self:__CheckHaveFeiJiNull(last_out.CompVal, hand_cards); elseif lastype==enum.CT_DDZ_FEIJI_WITH_ONE then return self:__CheckHaveFeiJiOne(last_out.CompVal, hand_cards); elseif lastype==enum.CT_DDZ_FEIJI_WITH_YIDUI then return self:__CheckHaveFeiJiDouble(last_out.CompVal, hand_cards); elseif lastype==enum.CT_DDZ_FOUR_WITHDOUBLE then return self:__CheckHaveFourTwo(last_out.CompVal, hand_cards); elseif lastype==enum.CT_DDZ_FOUR_LIANGDUI then return self:__CheckHaveFourDouble(last_out.CompVal, hand_cards); elseif lastype==enum.CT_DDZ_ZHADAN_SIZHANG then return self:__CheckCanOutBomb(lastype, last_out.CompVal, hand_cards); elseif lastype==enum.CT_DDZ_HUOJIAN then return false; end return false; end function DdzCardtypes:__CheckCanOutBomb( last_type, last_compval, hand_cards ) if last_type==enum.CT_DDZ_HUOJIAN or #hand_cards<2 then return false; end local group = self:__GetCardValueGroup( hand_cards, 4 ); local has_hj = self:__HasHuoJian(hand_cards); if #group<1 and not has_hj then return false; end -- ϼҳը if last_type==enum.CT_DDZ_ZHADAN_SIZHANG and last_compval>0 then if group[1]>last_compval or has_hj then return true; end return false; end return true; end function DdzCardtypes:__GetSingleCards( last_compval, hand_cards ) if #hand_cards >= 1 then if GetPokerLogicValue(hand_cards[1]) > last_compval then return true; end end return self:__CheckCanOutBomb( 0, last_cards, hand_cards ); end function DdzCardtypes:__CheckHaveLinkCards( last_compval, hand_cards ) local hand_cnt = #hand_cards; -- ˳ if hand_cnt>=5 then local first_val = GetPokerLogicValue(hand_cards[1]); local group_1 = { first_val }; for i=2,hand_cnt do local curr = GetPokerLogicValue(hand_cards[i]); if first_val ~= curr then table.insert( group_1, curr ); first_val = curr; end end local max_val = self:__CheckHaveLink( group_1, 5 ); if max_val>last_compval then return true; end end return self:__CheckCanOutBomb( 0, last_cards, hand_cards ); end function DdzCardtypes:__CheckHaveFeiJiNull( last_compval, hand_cards ) if #hand_cards>=6 then local group_3 = self:__GetCardValueGroup( hand_cards, 3 ); local max_val = self:__CheckHaveLink( group_3, 2 ); if max_val>last_compval then return true; end end return self:__CheckCanOutBomb( 0, last_cards, hand_cards ); end function DdzCardtypes:__CheckHaveFeiJiOne( last_compval, hand_cards ) if #hand_cards>=8 then local group_3 = self:__GetCardValueGroup( hand_cards, 3 ); local max_val = self:__CheckHaveLink( group_3, 2 ); if max_val>last_compval then return true; end end return self:__CheckCanOutBomb( 0, last_cards, hand_cards ); end function DdzCardtypes:__CheckHaveFeiJiDouble( last_compval, hand_cards ) if #hand_cards>=10 then local group_3 = self:__GetCardValueGroup( hand_cards, 3 ); local max_val = self:__CheckHaveLink( group_3, 2 ); if max_val>last_compval then local lk_group = self:__GetLinkGroup( group_3, 2 ); local group_2 = self:__GetCardValueGroup( hand_cards, 2 ); local count = 0; for _,gp in ipairs(lk_group) do -- е 2 if gp[1]>last_compval then -- ׸ֵϼҵķɻ local double_cnt = 0; for _,v2 in ipairs(group_2) do if gp[1]~=v2 and gp[2]~=v2 then double_cnt = double_cnt+1; end end if double_cnt>=2 then return true; end end end end end return self:__CheckCanOutBomb( 0, last_cards, hand_cards ); end function DdzCardtypes:__CheckHaveThreeOne( last_compval, hand_cards ) if #hand_cards>=4 then local group_3 = self:__GetCardValueGroup( hand_cards, 3 ); if #group_3>0 and group_3[1]>last_compval then return true; end end return self:__CheckCanOutBomb( 0, last_cards, hand_cards ); end function DdzCardtypes:__CheckHaveThreeDouble( last_compval, hand_cards ) if #hand_cards>=5 then local group_3 = self:__GetCardValueGroup( hand_cards, 3 ); local group_2 = self:__GetCardValueGroup( hand_cards, 2 ); if #group_3>0 and #group_2>0 then for _,v3 in ipairs(group_3) do if v3>last_compval then for _,v2 in ipairs(group_2) do if v3~=v2 then return true; end end end end end end -- ûдģը return self:__CheckCanOutBomb( 0, last_cards, hand_cards ); end -- Ĵ function DdzCardtypes:__CheckHaveFourTwo( last_compval, hand_cards ) if #hand_cards>=6 then local group_4 = self:__GetCardValueGroup( hand_cards, 4 ); if #group_4>0 and group_4[1]>last_compval then return true; end end return self:__CheckCanOutBomb( 0, last_cards, hand_cards ); end -- Ĵ function DdzCardtypes:__CheckHaveFourDouble( last_compval, hand_cards ) if #hand_cards>=8 then local group_4 = self:__GetCardValueGroup( hand_cards, 4 ); local group_2 = self:__GetCardValueGroup( hand_cards, 2 ); if #group_4>0 and #group_2>0 then for _,v4 in ipairs(group_4) do if v4>last_compval then local double_cnt = 0; for _,v2 in ipairs(group_2) do if v4~=v2 then double_cnt = double_cnt+1; end end if double_cnt>=2 then return true; end end end end end return self:__CheckCanOutBomb( 0, last_cards, hand_cards ); end function DdzCardtypes:__CheckHaveCards( last_compval, hand_cards, same_cnt ) if #hand_cards < same_cnt then return false; end local group = self:__GetCardValueGroup( hand_cards, same_cnt ); if #group>0 and group[1]>last_compval then return true; end -- ûдģը return self:__CheckCanOutBomb( 0, last_cards, hand_cards ); end -- cardsѴӴС,˳ӣ˳ӵ򷵻0. function DdzCardtypes:__CheckHaveLink( cvs, link_num ) if #cvs < link_num then return 0; end local cont = 1; -- ͬͳ local card_val = cvs[1]; local max_val = card_val; for i=2,#cvs do local curr = cvs[i]; if curr+1==card_val then cont = cont + 1; end if cont==link_num then return max_val; end if curr+1~=card_val then cont = 1; max_val = curr; end card_val = curr; end return 0; end -- ÷ local cvs={ 5, 3, 2, 1 } __GetLinkGroup(cvs, 2) => { {3,2}, {2,1} } -- card_vals ȥ list function DdzCardtypes:__GetLinkGroup( card_vals, link_num ) local res = {}; local vals_len = #card_vals; if vals_len < link_num then return res; end local x = 1; local find = true; while find do local cont = 1; -- ͬͳ local card_val = card_vals[x]; find = false; for i=x+1,vals_len do local curr = card_vals[i]; if curr+1==card_val then cont = cont + 1; end if cont==link_num then local group = {}; for gi=i-link_num+1,i do table.insert( group, card_vals[gi] ); end table.insert( res, group ); if i==vals_len then return res; else x = i - link_num + 2; find = true; break; end end if curr+1~=card_val then cont = 1; end card_val = curr; end end return res; end -- tblȥ function DdzCardtypes:__UniqueList(tbl) local res = {}; if #tbl<1 then return res; end res[1] = tbl[1]; local value = tbl[1]; for i=2,#tbl do if value~=tbl[i]then table.insert(res, tbl[i]) end value = tbl[i]; end return res; end -- cards ѴӴС ͳcardsͬ -- local cards={4,4,4,4,5,5} __GetCardValueGroup( cards, 2 ) => {4,4,5} -- local cards={4,4,4,4,5,5} __GetCardValueGroup( cards, 3 ) => {4} function DdzCardtypes:__GetCardValueGroup( cards, same_cnt ) local res_group = {}; if #cards<1 then return res_group; end local cont = 1; -- ͬͳ local card = GetPokerLogicValue(cards[1]); for i=2,#cards do local curr = GetPokerLogicValue(cards[i]); if curr==card then cont = cont + 1; end if cont==same_cnt then cont = 0; table.insert(res_group, card) end if curr~=card then cont = 1; card = curr; end end return res_group; end function DdzCardtypes:__HasHuoJian( cards ) if #cards<2 then return false; end local cont = 0; -- Сͳ for i=1,#cards do if cards[i]>0x40 then cont = cont + 1; if cont == 2 then return true; end end end return false; end ================================================ FILE: code/EVA/server/script/_PLS/Games/PokerDdz/DdzFSM.lua ================================================ local FSMDouDiZhu = class("FSMDouDiZhu") --[[ ߼״̬ --]] function FSMDouDiZhu:ctor() self._GameFSM = StateMachine:new(); self._StateEnterTime = 0; self._CurrState = "TDDZStateWait"; self.RoomDdz = nil; end function FSMDouDiZhu:Init( room_ddz ) self._GameFSM:setup_state({ events = { {name = "TDDZStateWait" }, -- ȴʼ {name = "TDDZStateCheckStartGame" }, -- ǷԿʼϷ {name = "TDDZStateSelectMingCardStart" }, -- ѡƿʼ׶ {name = "TDDZStateStartGame" }, -- ʼϷ {name = "TDDZStateSendCard" }, -- {name = "TDDZStateQiangDiZhu" }, -- ׶ {name = "TDDZStateSelectAddTimes" }, -- ѡӱ׶ {name = "TDDZStateAction" }, -- ɻ {name = "TDDZStateOutCard" }, -- ״̬ {name = "TDDZStateShowDown" }, -- Ϸ {name = "TDDZStateRelieveRoom" }, -- ɢ }, callbacks = { onTDDZStateWait = handler(self, self.DoWait), onTDDZStateCheckStartGame = handler(self, self.DoCheckStartGame), onTDDZStateSelectMingCardStart = handler(self, self.DoSelectMingCardStart), onTDDZStateStartGame = handler(self, self.DoStartGame), onTDDZStateSendCard = handler(self, self.DoSendCard), onTDDZStateQiangDiZhu = handler(self, self.DoQiangDiZhu), onTDDZStateSelectAddTimes = handler(self, self.DoSelectAddTimes), onTDDZStateAction = handler(self, self.DoAction), onTDDZStateOutCard = handler(self, self.DoOutCard), onTDDZStateShowDown = handler(self, self.DoShowDown), onTDDZStateRelieveRoom = handler(self, self.DoRelieveRoom), } }) self.RoomDdz = room_ddz; self:SwitchState( self._CurrState ); end function FSMDouDiZhu:__GetRunStateTime() return TimerMgr:GetTime() - self._StateEnterTime; end function FSMDouDiZhu:TickUpdate() self._GameFSM:do_event( self._CurrState, false ); end function FSMDouDiZhu:SwitchState( event, ... ) self._CurrState = event; self._StateEnterTime = TimerMgr:GetTime(); self._GameFSM:do_event( event, true, ... ); end function FSMDouDiZhu:GetState() return self._CurrState; end function FSMDouDiZhu:IsState( state ) if self._CurrState == state then return true; end return false; end function FSMDouDiZhu:DoWait( event ) if not event.args[1] then -- ͨʼת״̬ if self.RoomDdz:GameStartWait() then self:SwitchState("TDDZStateCheckStartGame"); end end end -- ǷԿʼ,ݲ飬ֱһ״̬ function FSMDouDiZhu:DoCheckStartGame( event ) self:SwitchState("TDDZStateStartGame"); end -- ѡƿʼ function FSMDouDiZhu:DoSelectMingCardStart( event ) if event.args[1] then self.RoomDdz:ResetGameData(); self.RoomDdz:BroadcastGameInfo(); self.RoomDdz:SendQiangDiZhuWik(); end end function FSMDouDiZhu:DoStartGame( event ) if event.args[1] then self.RoomDdz.IsGameStart = true; self.RoomDdz:ResetGameData(); self.RoomDdz:BroadcastGameInfo(); else if self:__GetRunStateTime()<3000 then return; end -- self:SwitchState("TDDZStateSelectMingCardStart"); self:SwitchState("TDDZStateSendCard"); end end function FSMDouDiZhu:DoSendCard( event ) if event.args[1] then self.RoomDdz:SendHandCard(); self.RoomDdz:BroadcastGameInfo(); else if self:__GetRunStateTime()<3000 then return; end self:SwitchState("TDDZStateQiangDiZhu"); end end function FSMDouDiZhu:DoQiangDiZhu( event ) if event.args[1] then self.RoomDdz:SendQiangDiZhuWik(); end end function FSMDouDiZhu:DoSelectAddTimes( event ) --if self:__GetRunStateTime()<10000 then -- return; --end end function FSMDouDiZhu:DoAction( event ) if event.args[1] then self.RoomDdz:BroadGameActionPlayer(); end end function FSMDouDiZhu:DoOutCard( event ) if self:__GetRunStateTime()>3000 then self:SwitchState("TDDZStateAction"); end end function FSMDouDiZhu:DoShowDown( event ) if event.args[1] then self.RoomDdz:GameShowDown(); self.RoomDdz:BroadcastShowDownInfo(); self.RoomDdz:AfterShowDown(); else if self:__GetRunStateTime() > 5000 then self:SwitchState("TDDZStateWait"); end end end function FSMDouDiZhu:DoRelieveRoom( event ) nlinfo( "FSMClass:DoRelieveRoom" ); end return FSMDouDiZhu; ================================================ FILE: code/EVA/server/script/_PLS/Games/PokerDdz/DdzPlayerInfo.lua ================================================ local DdzPlayerInfo = class("DdzPlayerInfo", RoomPlayerBase) --[[ --]] function DdzPlayerInfo:ctor() self.super:ctor(); self.QiangDiZhu = 0; -- ѡ TDDZQiangDiZhu TDDZJiaoFen self._TempCards = {}; self._OutCount = 0; -- ҳƴʱʹ self.Multi = 1; self.StartScore = 0; -- ÿֿʼʱҵϷ end function DdzPlayerInfo:AddOutCount() self._OutCount = self._OutCount + 1; end function DdzPlayerInfo:GetOutCount() return self._OutCount; end function DdzPlayerInfo:AddHandCards( tbl, start_idx, end_idx ) if start_idx ~=nil then for idx=start_idx, end_idx do table.insert( self.HandCards, tbl[idx] ); end else for _,v in ipairs(tbl) do table.insert( self.HandCards, v ); end end end function DdzPlayerInfo:RemoveCards( cards ) self._TempCards = {}; for i,c in ipairs(self.HandCards) do self._TempCards[i] = c; end for i,c in ipairs(cards) do for ih,ch in ipairs(self._TempCards) do if ch==c then table.remove(self._TempCards, ih); break; end end end if #self._TempCards + #cards == #self.HandCards then self.HandCards = {}; for i,c in ipairs(self._TempCards) do self.HandCards[i] = c; end return true; end return false; end -- ÿʱ function DdzPlayerInfo:ClearOneGameData() self:ClearOneGameState(); self.StartScore = self._Score; end function DdzPlayerInfo:GetCardCount() return #self.HandCards; end --------- function DdzPlayerInfo:Auto() end return DdzPlayerInfo; ================================================ FILE: code/EVA/server/script/_PLS/Games/PokerDdz/MsgRoomDdz.lua ================================================ MsgRoomDdz = {} --[[ 斗地主消息处理。 --]] function MsgRoomDdz:Init() self._EventRegister = EventRegister.new(); self._EventRegister:RegisterEvent( "DDZ_SR", self, self.cbStartReady ); -- 斗地主开始准备 self._EventRegister:RegisterEvent( "DDZ_CR", self, self.cbCancleReady ); -- 斗地主取消准备 self._EventRegister:RegisterEvent( "DDZ_JB", self, self.cbDouDiZhuAddTimes ); -- 加倍选择 self._EventRegister:RegisterEvent( "DDZ_QDZ", self, self.cbDouDiZhuQiangDiZhu ); -- 抢地主选择 self._EventRegister:RegisterEvent( "DDZ_OC", self, self.cbDouDiZhuOutCard ); -- 斗地主出牌 self._EventRegister:RegisterEvent( "DDZ_PS", self, self.cbDouDiZhuPassCards ); -- 斗地主过牌 self._EventRegister:RegisterEvent( "DDZ_SMPS", self, self.cbPreStartMingPai ); -- 游戏开始前选择是否明牌 self._EventRegister:RegisterEvent( "DDZ_DZMP", self, self.cbPreMingPai ); -- 出牌前地主选择是否明牌 end function MsgRoomDdz:cbStartReady( fes_sid, msgin ) local uid = msgin:rint64(); local room = RoomMgr:GetRoomFromPID(uid); if room~=nil then room:UserStartReady(uid); end end function MsgRoomDdz:cbCancleReady( fes_sid, msgin ) local uid = msgin:rint64(); local room = RoomMgr:GetRoomFromPID(uid); if room~=nil then room:UserCancelReady(uid); end end function MsgRoomDdz:cbDouDiZhuAddTimes( fes_sid, msgin ) local uid = msgin:rint64(); local room = RoomMgr:GetRoomFromPID(uid); if room~=nil then local msg_jbr = msgin:rpb("PB.MsgJiaBeiResult"); room:RefreshSelectJiaBei(uid, msg_jbr); end end function MsgRoomDdz:cbDouDiZhuQiangDiZhu( fes_sid, msgin ) local uid = msgin:rint64(); local room = RoomMgr:GetRoomFromPID(uid); if room~=nil then local msg_qdz = msgin:rpb("PB.MsgQiangDiZhuResult"); room:RefrshRoleQiangDiZhu(uid, msg_qdz); end end function MsgRoomDdz:cbPreStartMingPai( fes_sid, msgin ) local uid = msgin:rint64(); local room = RoomMgr:GetRoomFromPID(uid); if room~=nil then end end function MsgRoomDdz:cbPreMingPai( fes_sid, msgin ) local uid = msgin:rint64(); local room = RoomMgr:GetRoomFromPID(uid); if room~=nil then end end function MsgRoomDdz:cbDouDiZhuOutCard( fes_sid, msgin ) local uid = msgin:rint64(); local room = RoomMgr:GetRoomFromPID(uid); if room~=nil then local msg_oc = msgin:rpb("PB.MsgDDZUserOutCard"); room:UserOutCard( uid, msg_oc ); end end function MsgRoomDdz:cbDouDiZhuPassCards( fes_sid, msgin ) local uid = msgin:rint64(); local room = RoomMgr:GetRoomFromPID(uid); if room~=nil then room:UserPassOutCard( uid ); end end --释放函数 function MsgRoomDdz:Release() self._EventRegister:UnRegisterAllEvent(); end return MsgRoomDdz; ================================================ FILE: code/EVA/server/script/_PLS/Games/PokerDdz/RoomDdz.lua ================================================ local RoomDdz = class("RoomDdz", RoomBase) DdzFSM = require("Games/PokerDdz/DdzFSM") DdzPlayerInfo = require("Games/PokerDdz/DdzPlayerInfo") DdzOutCardData = require("Games/PokerDdz/DDZOutCardData") --[[ 斗地主房间内游戏逻辑。 --]] local tbinsert = table.insert function RoomDdz:ctor() self.super:ctor(); self.CFG_HAND_COUNT = 17; -- 每个玩家的初始手牌个数 self.CFG_TOTAL_CARD = 54; -- 牌池 self.CFG_BASE_SCORE = 1; -- 底分 self.CFG_DIPAI_COUNT = 3; -- 底牌个数 self.CFG_HANDCOUNT_MAX = 20; -- 手牌最大个数 self.CFG_TRUSTMAX = 3; -- 最大托管次数 self.CFG_FENGDING_16 = 16; -- 16封顶 self.CFG_FENGDING_32 = 32; -- 32封顶 self.CFG_FENGDING_64 = 64; -- 64封顶 self._GameCount = 1; -- 当前是第几局 self.Fsm = DdzFSM:new(); self.Fsm:Init(self); self._LastOutCardData = DdzOutCardData:new(); self._TempOutCardData = DdzOutCardData:new(); -- 战绩回放 self._RecordNodeList = {}; -- 战绩回放的节点 self._RecordGames = {}; -- 记录房间中的每局战绩 list[_RecordNodeList] self:ResetGameData(); end -- 每局清除数据 function RoomDdz:ResetGameData() self._CardsPool = {}; self._CardsBottom = {}; -- 剩下的三张底牌 self._ActionID = 0; -- 当前活动的玩家 self._ActionUserWik = 0; -- 当前活动玩家权限 self._Multiple = 1; -- 房间翻倍数 self._QiangDiZhuWiki = 0; -- 抢地主权限 self._QiangDiZhu = true; -- 是否是叫地主抢地主模式 self._DiZhuID = 0; -- 地主 uid self._CanOutCard = {}; -- 当前可以出的牌,托管时使用 self.ShowDownEvent = {}; -- 结算事件 self._LastOutCardData:ClearData(); self._TempOutCardData:ClearData(); -- 清空玩家临时数据 for _,v in ipairs(self.SeatPlayers) do if v~=0 then local room_player = self.RoomPlayerData:Find(v); if room_player~=nil then room_player:ClearOneGameData(); end end end -- 发牌洗牌 for i,v in pairs(ConstCardsPoker) do self._CardsPool[i] = v; end shuffle(self._CardsPool); end -- 判断游戏是否可以开始 function RoomDdz:GameStartWait() -- 人数是否足够 if self.RoomPlayerData:Count()0 then self.Fsm:SwitchState("TDDZStateOutCard"); return true; end -- 手牌数为零,已出完牌。 self._ActionID = uid; self:__CheckIsChunTian(); -- 检查春天 self.Fsm:SwitchState("TDDZStateShowDown"); -- 跳结算 end function RoomDdz:UserPassOutCard( uid, is_auto ) if self._ActionID~=uid or (not self:__GetFsmState(enum.TDDZStateAction)) or (not GetBit(self._ActionUserWik, enum.ASK_DDZ_CHUPAI)) then return; end local room_player = self.RoomPlayerData:Find(uid); if room_player==nil then return false; end -- 客户端自动过牌时,检查下玩家手里有没有大于上家的牌 --if is_auto~=nil and is_auto then -- if self:__CheckCanOutCards(room_player) then -- return; -- end --end -- 查找下个玩家出牌 self._ActionID = self:GetNextUID(self._ActionID); if self._ActionID > 0 then -- 刷新过牌的玩家 self:__ClearPlayerState(enum.STATE_DDZ_GUOPAI); room_player:SetState( enum.STATE_DDZ_GUOPAI ); self._ActionUserWik = enum.ASK_DDZ_NULL; local MsgDDZActon = { old_actionid = uid }; self:BroadcastMsg( "DDZ_PS", "PB.MsgDDZActon", MsgDDZActon ); self:__RecordGameShowCardPass( uid ); self.Fsm:SwitchState("TDDZStateOutCard"); else nlwarning("self._ActionID==0"); end end function RoomDdz:BroadcastGameInfo( ) for _,v in ipairs(self.SeatPlayers) do if v~=0 then local msg_gameinfo = {}; self:SendGameInfo( v, "DDZ_GI", msg_gameinfo ); end end end function RoomDdz:RefreshRoomInfo( uid ) local msg_gameinfo = {}; self:SendGameInfo( uid, "DDZ_BLC", msg_gameinfo ); end function RoomDdz:SendGameInfo( uid, msg_name, msg_ddz_room ) msg_ddz_room.room_id = self.PrvRoomID; self:__FillRoomInfoMsg(msg_ddz_room, uid); local cur_state = self:__GetFsmState(); if uid==self._ActionID and ( cur_state==enum.TDDZStateAction or cur_state==enum.TDDZStateOutCard or cur_state==enum.TDDZStateRelieveRoom ) then msg_ddz_room.wik = self._ActionUserWik; else msg_ddz_room.wik = enum.ASK_DDZ_NULL; end local player = PlayerMgr:GetPlayer(uid); BaseService:SendToClient( player, msg_name, "PB.MsgDDZRoom", msg_ddz_room ) end -- 游戏结算 function RoomDdz:GameShowDown() self._GameCount = self._GameCount + 1; self:__AddShowDownEvent(enum.EVENT_DDZDIFEN, 1); local room_player = self.RoomPlayerData:Find( self._DiZhuID ); if room_player==nil then return; end -- 计算玩家的翻倍数,设置地主翻倍数. local dizhu_jb = room_player:GetState( enum.STATE_DDZ_JIABEI ); local total_multi, jiabei_cnt = self:__CalcJiaBei( dizhu_jb ); room_player.Mulit = total_multi; -- 封顶加减分 if self:CheckRoomSpecialKind(enum.TSK_DDZ_BFD) then self:__NormalCalcScore(total_multi); elseif self:CheckRoomSpecialKind(enum.TSK_DDZ_16) then self:__CalcScore( total_multi, 16, jiabei_cnt ); elseif self:CheckRoomSpecialKind(enum.TSK_DDZ_32) then self:__CalcScore( total_multi, 32, jiabei_cnt ); elseif self:CheckRoomSpecialKind(enum.TSK_DDZ_64) then self:__CalcScore( total_multi, 64, jiabei_cnt ); else self:__NormalCalcScore(total_multi); end end function RoomDdz:AfterShowDown() local COST_CFG = StaticTableMgr:GetCreateCost( self.CreateInfo.consume_id ); if COST_CFG~=nil then if self._GameCount > COST_CFG.game_cnt then self.IsGameStart = false; self:__GameOverRecordLog(); self:Release(); end end end function RoomDdz:BroadcastShowDownInfo() local COST_CFG = StaticTableMgr:GetCreateCost( self.CreateInfo.consume_id ); if COST_CFG==nil then return; end local MsgDDZRoomShowDown = { room_id = self.PrvRoomID, room_state = enum[self:__GetFsmState()], state_time = 0, game_count = self._GameCount, time = os.time(), game_over = self._GameCount>=COST_CFG.game_cnt, event_count = {}, player_list = {} }; for eid,cnt in pairs(self.ShowDownEvent) do local MsgDDZShowDownEvent = { event_id=eid, count=cnt }; tbinsert( MsgDDZRoomShowDown.event_count, MsgDDZShowDownEvent ); end for uid,room_player in pairs(self.RoomPlayerData.map) do local MsgDDZPlayer = { player_base = { UID = uid }, }; self:__FillPlayerRoomInfoMsg( uid, MsgDDZPlayer, uid ); tbinsert( MsgDDZRoomShowDown.player_list, MsgDDZPlayer ); end if MsgDDZRoomShowDown.game_over then -- 游戏结算积分 --self:__AddPlayerIntegral( ); end self:BroadcastMsg( "DDZ_SD", "PB.MsgDDZRoomShowDown", MsgDDZRoomShowDown ); self:__RecordGameShowDown( MsgDDZRoomShowDown ); end function RoomDdz:RelieveRequestRoom( uid, is_relieve ) if is_relieve then self:__AddPlayerState( enum.STATE_DDZ_RELIEVE, uid ); else self:__ClearPlayerState( enum.STATE_DDZ_RELIEVE ); end --local relv_cnt = self:__GetPlayerState( enum.STATE_DDZ_RELIEVE ); -- 用户取消解散房间 --local MsgInt = { value = uid }; --self:__ClearPlayerState( enum.STATE_DDZ_RELIEVE ); --self:BroadcastMsg( "DDZ_NRE", "PB.MsgInt", MsgInt ); if true then self:RelieveAutoRoom() return; end local MsgRoleStateCount = {}; self:__RefreshPlayerState( MsgRoleStateCount ); self:BroadcastMsg( "DDZ_ORE", "PB.MsgRoleStateCount", MsgRoleStateCount ); end function RoomDdz:RelieveAutoRoom( ) self._GameCount = 9999; --self.Fsm:SwitchState("TDDZStateShowDown"); -- 跳结算 self:BroadcastShowDownInfo(); self:AfterShowDown(); end -- 普通算分 function RoomDdz:__NormalCalcScore( total_multi ) for uid,room_player in pairs(self.RoomPlayerData.map) do if uid==self._DiZhuID then room_player:ChangeScore( total_multi, self._ActionID==self._DiZhuID ) else room_player:ChangeScore( room_player.Mulit, self._ActionID~=self._DiZhuID ) end end end -- 计算玩家的积分 function RoomDdz:__CalcScore( total_multi, limit_score, jiabei_cnt ) if total_multi>limit_score then for uid,room_player in pairs(self.RoomPlayerData.map) do -- 两个都没有加倍或者两个都加倍,在封顶时输赢的分相同 if jiabei_cnt==0 or jiabei_cnt==2 then if uid==self._DiZhuID then room_player:ChangeScore( limit_score, self._ActionID==self._DiZhuID ); else room_player:ChangeScore( limit_score//2, self._ActionID~=self._DiZhuID ); end else -- 农民中一个加倍一个不加倍,封顶时要按照比例进行加减分 if uid~=self._DiZhuID then if room_player:GetState(enum.STATE_DDZ_JIABEI) then if limit_score==16 then room_player:ChangeScore( 11, self._ActionID~=self._DiZhuID ); elseif limit_score==32 then room_player:ChangeScore( 22, self._ActionID~=self._DiZhuID ); elseif limit_score==64 then room_player:ChangeScore( 43, self._ActionID~=self._DiZhuID ); end else if limit_score==16 then room_player:ChangeScore( 5, self._ActionID~=self._DiZhuID ); elseif limit_score==32 then room_player:ChangeScore( 10, self._ActionID~=self._DiZhuID ); elseif limit_score==64 then room_player:ChangeScore( 21, self._ActionID~=self._DiZhuID ); end end else room_player:ChangeScore( limit_score, self._ActionID==self._DiZhuID ); end end end else self:__NormalCalcScore( total_multi ); end end -- 计算玩家加倍 function RoomDdz:__CalcJiaBei( is_dizhu ) local total_multi = 0; local jiabei_cnt = 0; local add_times = self:__GetSpecialCfg("add_times"); for uid,room_player in pairs(self.RoomPlayerData.map) do if uid~=self._DiZhuID then -- 如果没有加倍玩法,直接设置房间的加倍数 if not self:CheckRoomSpecialKind(enum.TSK_DDZ_JIABEI) then room_player.Mulit = self._Multiple; total_multi = total_multi + room_player.Mulit; else if room_player:GetState(enum.STATE_DDZ_JIABEI) then if is_dizhu then room_player.Mulit = self._Multiple * add_times * 2; else room_player.Mulit = self._Multiple * add_times; end jiabei_cnt = jiabei_cnt + 1; else if is_dizhu then room_player.Mulit = self._Multiple * add_times; else room_player.Mulit = self._Multiple; end end total_multi = total_multi + room_player.Mulit; end end end return total_multi, jiabei_cnt; end -- 战绩保存 function RoomDdz:__GameOverRecordLog() nlinfo("===== GameOverRecordLog "); end function RoomDdz:__FillRoomInfoMsg( msg_ddz_room, current_uid ) msg_ddz_room.room_id = self.PrvRoomID; msg_ddz_room.room_state = self:__GetFsmState(); msg_ddz_room.state_time = 0; -- 当前房间状态的运行时间 msg_ddz_room.action_id = self._ActionID; msg_ddz_room.game_count = self._GameCount; msg_ddz_room.multiple = self._Multiple; -- 房间的翻倍数 msg_ddz_room.bottom_cards = self._CardsBottom; -- 底牌 -- 上把牌信息 if self._LastOutCardData.UID>0 then msg_ddz_room.last_outcard = { old_actionid = self._LastOutCardData.UID, out_type = self._LastOutCardData.Type, out_cards = self._LastOutCardData.Cards }; end -- 创建房间的信息 msg_ddz_room.private_room = self.CreateInfo; for _,v in ipairs(self.SeatPlayers) do if v>0 then self:__FillPlayerBaseInfoMsg( v, msg_ddz_room, current_uid ); end end end function RoomDdz:__FillPlayerBaseInfoMsg( uid, msg_ddz_room, current_uid ) local room_player = {}; local player = PlayerMgr:GetPlayer(uid); if player~=nil then room_player.player_base = { UID = uid, Nickname = player.PlayerDataHelper.f_nickname; Portrait = player.PlayerDataHelper.f_portrait; } end self:__FillPlayerRoomInfoMsg(uid, room_player, current_uid ) if msg_ddz_room.player_list==nil then msg_ddz_room.player_list = {}; end tbinsert( msg_ddz_room.player_list, room_player ); end function RoomDdz:__FillPlayerRoomInfoMsg( uid, msg_room_player, current_uid ) local room_player = self.RoomPlayerData:Find(uid); if room_player~=nil then msg_room_player.state = room_player:GetState(); -- 玩家的当前状态 msg_room_player.hand_count = room_player:GetHandCount(); -- 玩家手中的牌数 msg_room_player.seats = self:GetPlayerSeatIdx(uid); -- 玩家的座位 msg_room_player.score = room_player:GetScore(); -- 玩家当前的积分 msg_room_player.multiple = room_player.Multi; msg_room_player.show_down_score = room_player:GetScore() - room_player.StartScore; -- 填充玩家的输赢积分 msg_room_player.qingdizhu_value = room_player.QiangDiZhu; if self:__GetFsmState(enum.TDDZStateQiangDiZhu) and room_player:GetState(enum.STATE_DDZ_QIANGDIZHU) then msg_room_player.qingdizhu_wiki = self._QiangDiZhuWiki; end if uid==current_uid or room_player:GetState(enum.STATE_DDZ_MINGPAI) then msg_room_player.card_list = room_player.HandCards; end end end function RoomDdz:__CheckCanOutCards( room_player ) --self._CanOutCard = {}; -- 上次出牌的玩家也是自己,或刚开局。 if self._ActionID==self._LastOutCardData.UID or self._LastOutCardData:GetCardCount()==0 then return true; end return DdzCardtypes:CheckCanOutCards( self._LastOutCardData, room_player.HandCards ); end -- 检查除了uid外,有没有玩家抢过地主 function RoomDdz:__CheckQiangDiDiZhu(uid) for k,v in pairs(self.RoomPlayerData.map) do if k~=uid and v.QiangDiZhu==enum.DDZ_QDZ_QIANGDIZHU then return true; end end return false; end function RoomDdz:__RefreshPlayerQDZState( uid ) self.RoomPlayerData:ForEach( function(k,v) if k==uid then v:SetState( enum.STATE_DDZ_QIANGDIZHU ); else v:ClearState( enum.STATE_DDZ_QIANGDIZHU ); end end ) end -- 玩家状态数据 function RoomDdz:__RefreshPlayerState( MsgRoleStateCount ) self.RoomPlayerData:ForEach( function(k,v) local MsgRoleState = { role_id=k, state=v:GetState() }; tbinsert( MsgRoleStateCount, MsgRoleState ); end ) end -- 叫地主的玩家选择不抢地主后,选择最后一次抢地主的玩家做地主 function RoomDdz:__SelectDZ(uid) for i=1,i<4 do local next_uid = self:GetNextUID(uid); if next_uid~=self._ActionID then local room_player = self:GetRoomPlayer(next_uid); if room_player==nil then return 0; end if room_player.QiangDiZhu == enum.DDZ_QDZ_QIANGDIZHU then return next_uid; end end uid = next_uid; end return 0; end -- 获取当前活动玩家操作权限 function RoomDdz:__GetActionWik() self._CanOutCard = {}; local WIK = enum.ASK_DDZ_NULL; local room_player = self.RoomPlayerData:Find(self._ActionID); if room_player==nil then return WIK; end -- 地主第一次出牌,没有选择明牌时可以有选择明牌的选项 if self:CheckRoomSpecialKind(enum.TSK_DDZ_MINGPAI) and self._ActionID==self._DiZhuID and room_player:GetState(enum.STATE_DDZ_MINGPAI) and room_player:GetHandCount()==self.CFG_HANDCOUNT_MAX then WIK = SetBit( WIK, enum.ASK_DDZ_DIZHU_MINGPAI ); end local is_can_out = self:__CheckCanOutCards(room_player); if is_can_out then if self._ActionID==self._LastOutCardData.UID or self._LastOutCardData:GetCardCount()==0 then WIK = SetBits( WIK, { enum.ASK_DDZ_TISHI, enum.ASK_DDZ_CHUPAI } ); else WIK = SetBits( WIK, { enum.ASK_DDZ_TISHI, enum.ASK_DDZ_CHUPAI, enum.ASK_DDZ_BUCHU } ); end else WIK = SetBit( WIK, enum.ASK_DDZ_BUCHU ); end return WIK; end -- 检查用户可否出牌 function RoomDdz:__UserOutCardLimit( room_player, out_cards ) if not self:__GetFsmState(enum.TDDZStateAction) then return false; end -- 排序要出的牌,分析用。 SortPokerLogicValue(out_cards); -- 获取牌型 local card_type, comp_val = DdzCardtypes:GetCardType( out_cards, self._LastOutCardData.Type ); if card_type == enum.CT_DDZ_ERROR then return false; end -- local temp_data = self._TempOutCardData; temp_data:SetCards(out_cards); temp_data.Type = card_type; temp_data.UID = self._ActionID; temp_data.CompVal = comp_val; -- 比较大小 if not DdzCardtypes:CompareCards( temp_data, self._LastOutCardData ) then return false; end -- 检查手牌中是否有这些要出的牌,如果可以出牌,从手牌中删除玩家需要出的牌。 if not room_player:RemoveCards(temp_data.Cards) then self:RefreshRoomInfo(self._ActionID); return false; end self._ActionID = self:GetNextUID( self._ActionID ); self._LastOutCardData:Copy( temp_data ); local MsgDDZUserOutCard = { old_actionid = temp_data.UID, out_type = card_type, hand_count = room_player:GetCardCount(), hand_cards = room_player.HandCards, out_cards = out_cards } -- 出炸弹时需要瞬间翻倍,同步到客户端 if card_type==enum.CT_DDZ_ZHADAN_SIZHANG or card_type==enum.CT_DDZ_HUOJIAN then local multi_boom = self:__GetSpecialCfg("multi_boom"); if multi_boom~=nil then self._Multiple = self._Multiple * multi_boom; self:__AddShowDownEvent( enum.EVENT_ZHADAN, 1 ); MsgDDZUserOutCard.multiple = self._Multiple; end end -- 广播出牌信息 self:BroadcastMsg( "DDZ_OC", "PB.MsgDDZUserOutCard", MsgDDZUserOutCard ); -- 添加玩家出牌次数,地主被春天时使用 room_player:AddOutCount(); -- 记录出的牌 self:__RecordGameOutCard( MsgDDZUserOutCard ); -- 清除上把的过牌状态 self:__ClearPlayerState(enum.STATE_DDZ_GUOPAI); return true; end -- 添加玩家状态 function RoomDdz:__AddPlayerState( state, uid ) for id,v in pairs(self.RoomPlayerData.map) do if not (uid~=nil and id~=uid) then v:SetState( state ); end end end -- DelRoleState function RoomDdz:__ClearPlayerState( state, uid ) for id,v in pairs(self.RoomPlayerData.map) do if not (uid~=nil and id~=uid) then v:ClearState( state ); end end end function RoomDdz:__GetFsmState( state ) if state~=nil then if enum[self.Fsm:GetState()]==state then return true; end return false; else return enum[self.Fsm:GetState()]; end end function RoomDdz:__CheckIsChunTian() local is_ct = false; for uid,v in pairs(self.RoomPlayerData.map) do -- 检查地主有没有被春天 if uid==self._DiZhuID and self._DiZhuID~=self._ActionID and v:GetOutCount()==1 then is_ct = true; break; end -- 地主获胜需要检查两个农民有没有被春天 if self._ActionID==self._DiZhuID and uid~=self._ActionID then if v:GetCardCount()==self.CFG_HAND_COUNT then is_ct = true; else is_ct = false; break; end end end if is_ct then local multi_ct = self:__GetSpecialCfg("multi_ct"); if multi_ct~=nil then self._Multiple = self._Multiple * multi_ct; self:__AddShowDownEvent(enum.EVENT_CHUNTIAN, 1); end end end -- -------------------------- 战绩回放 Start -- 记录游戏开始 function RoomDdz:__RecordGameStart() self._RecordNodeList = { cmd_id = enum.RC_ACTION_START_GAME, -- 房间数据 room_data = { special_kind = self.CreateInfo.special_kind, banker = self.CreateInfo.consume_id, bottom_cards = self._CardsBottom, game_count = self._GameCount, score = self._Multiple }, -- 玩家信息 role_data = {}, next_node = {} }; for i,uid in ipairs(self.SeatPlayers) do local MsgRecordRoleInfo = { id = uid, seat = i }; local player = PlayerMgr:GetPlayer(uid); if player~=nil then MsgRecordRoleInfo.usename = player.PlayerDataHelper.f_username; MsgRecordRoleInfo.nick_name = player.PlayerDataHelper.f_nickname; end local room_player = self.RoomPlayerData:Find(uid); if room_player~=nil then MsgRecordRoleInfo.score = room_player:GetScore(); MsgRecordRoleInfo.team_type = room_player:GetState(); MsgRecordRoleInfo.hand_card = room_player.HandCards; end tbinsert( self._RecordNodeList.role_data, MsgRecordRoleInfo ); end end function RoomDdz:__RecordGameOutCard( out_msg ) local MsgRecordNodeList = { cmd_id = enum.RC_ACTION_OUT_CARD, target_id = out_msg.old_actionid, card_index = out_msg.out_type, -- 玩家出牌类型 action_id = out_msg.hand_count, card_value = out_msg.out_cards, -- 出牌列表 node_size = out_msg.multiple, -- 房间倍数 next_node = {} }; tbinsert( self._RecordNodeList.next_node, MsgRecordNodeList ); end function RoomDdz:__RecordGameActionState( MsgDDZActon ) local MsgRecordNodeList = { cmd_id = enum.RC_ACTION_OPERATE_RESULT, action_id = MsgDDZActon.new_actionid, showdown_list = {}, next_node = {} }; for _,MsgDDZPlayer in pairs(MsgDDZActon.player_list) do local MsgRecordShowDown = { id = MsgDDZPlayer.seats, score = MsgDDZPlayer.score, param1 = MsgDDZPlayer.hand_count, param2 = MsgDDZPlayer.state }; tbinsert( MsgRecordNodeList.showdown_list, MsgRecordShowDown ); end tbinsert( self._RecordNodeList.next_node, MsgRecordNodeList ); end function RoomDdz:__RecordGameShowCardPass( uid ) local MsgRecordNodeList = { cmd_id = enum.RC_ACTION_OPERATE_CHOICE, action_id = uid, next_node = {} }; tbinsert( self._RecordNodeList.next_node, MsgRecordNodeList ); end function RoomDdz:__RecordGameShowDown( MsgDDZRoomShowDown ) local MsgRecordNodeList = { cmd_id = enum.RC_ACTION_SHOWDOWN, showdown_list = {}, next_node = {} }; local MsgRecordShowDown = { event = MsgDDZRoomShowDown.event_count }; tbinsert( MsgRecordNodeList.showdown_list, MsgRecordShowDown ); for _,MsgDDZPlayer in pairs(MsgDDZRoomShowDown.player_list) do local MsgRecordShowDown = { id = MsgDDZPlayer.seats, play_id = MsgDDZPlayer.player_base.UID, money = MsgDDZPlayer.show_down_score, score = MsgDDZPlayer.score, hucard = MsgDDZPlayer.multiple, param1 = MsgDDZPlayer.hand_count, param2 = MsgDDZPlayer.state }; tbinsert( MsgRecordNodeList.showdown_list, MsgRecordShowDown ); end tbinsert( self._RecordNodeList.next_node, MsgRecordNodeList ); end function RoomDdz:__RecordGameShowDownEvent( MsgRecordShowDown, MsgDDZRoomShowDown ) for _,evt in pairs(MsgDDZRoomShowDown.event_count) do local MsgRecordEvent = { event_id = evt.event_id, count = evt.count }; tbinsert( MsgRecordShowDown.event, MsgRecordEvent ); end -- MsgRecordShowDown.event = MsgDDZRoomShowDown.event_count; end -- -------------------------- 战绩回放 End --释放函数 function RoomDdz:Release() self:BaseRelease(); end return RoomDdz; ================================================ FILE: code/EVA/server/script/_PLS/Msg/MsgLogin.lua ================================================ MsgLogin = {} function MsgLogin:Init() self._EventRegister = EventRegister.new(); self._EventRegister:RegisterEvent( "SyncData", self, self.cbSyncData ); self._EventRegister:RegisterEvent( "ClientOffline", self, self.cbClientOffline ); end function MsgLogin:cbSyncData( schid, msg_sdata_1 ) local uid = msg_sdata_1:rint64(); local fesid = msg_sdata_1:rint32(); local player = PlayerMgr:GetPlayer(uid); if player == nil then player = PlayerMgr:LoadDBPlayer(uid); end if player~=nil then player.ConFES = fesid; PrintTable(player); -- 通知FES保存玩家在哪个PLS msg_sdata_1:invert(); BaseService:Send( fesid, msg_sdata_1); -- 发送玩家数据给客户端 BaseService:SendToClient( player, "SyncPlayerInfo", "PB.MsgPlayerInfo", player.PlayerDataHelper:ToMsg() ) end end function MsgLogin:cbClientOffline( fesid, msgin ) local uid = msgin:rint(); local player = PlayerMgr:GetPlayer(uid); if player~=nil then player:Offline(); nlinfo("MsgLogin:cbClientOffline UID:"..uid); end end --释放函数 function MsgLogin:Release() self._EventRegister:UnRegisterAllEvent(); end return MsgLogin; ================================================ FILE: code/EVA/server/script/_PLS/Msg/MsgRoom.lua ================================================ MsgRoom = {} -- 构造函数; function MsgRoom:Init() self._EventRegister = EventRegister.new(); self._EventRegister:RegisterEvent( "ER", self, self.cbEnterRoom ); self._EventRegister:RegisterEvent( "LR", self, self.cbLeaveRoom ); self._EventRegister:RegisterEvent( "RRM", self, self.cbReleasePrvRoom ); self._EventRegister:RegisterEvent( "DDZ_RE", self, self.cbDDZReliveRoom ); self._EventRegister:RegisterEvent( "CPRM=>PLS", self, self.cbCreatePrivateRoom ); self._EventRegister:RegisterEvent( "EPRM=>PLS", self, self.cbEnterPrivateRoom ); end function MsgRoom:cbEnterRoom( fes_sid, msg_enter_room ) nlinfo("MsgRoom:cbEnterRoom"); end function MsgRoom:cbLeaveRoom( fes_sid, msgin ) local uid = msgin:rint64(); local player = PlayerMgr:GetPlayer(uid); if player~=nil then local room = RoomMgr:GetRoom(player.RoomID); if room~=nil then room:LeaveRoom(uid); end end nlinfo("MsgRoom:cbLeaveRoom"); end function MsgRoom:cbCreatePrivateRoom( sch_sid, msgin ) local uid = msgin:rint(); local prv_room_id = msgin:rint(); local pls_sid = msgin:rint(); local msg_cpr = msgin:rtable(); -- local room_type = msgin:rstring(); nlwarning("MsgRoom:cbCreatePrivateRoom"); nlinfo(uid); nlinfo(prv_room_id); nlinfo(pls_sid); PrintTable(msg_cpr); RoomMgr:CreatePrivateRoom(uid, prv_room_id, msg_cpr); end function MsgRoom:cbEnterPrivateRoom( sch_sid, msgin ) local uid = msgin:rint(); local pls_sid = msgin:rint(); local prv_room_id = msgin:rint(); local room_type = msgin:rstring(); nlinfo("MsgRoom:cbEnterPrivateRoom"); nlinfo(uid); nlinfo(prv_room_id); nlinfo(pls_sid); nlinfo(room_type); if GetServiceID()~=pls_sid then nlwarning("GetServiceID()~=pls_sid"); else RoomMgr:EnterPrivateRoom(uid, prv_room_id, room_type); end end function MsgRoom:cbReleasePrvRoom( fes_sid, msgin ) local uid = msgin:rint64(); local player = PlayerMgr:GetPlayer(uid); if player~=nil then local room = RoomMgr:GetRoom(player.RoomID); if room~=nil then room:RelieveForceRoom(uid); end end end function MsgRoom:cbDDZReliveRoom( fes_sid, msgin ) local uid = msgin:rint64(); local player = PlayerMgr:GetPlayer(uid); if player~=nil then local room = RoomMgr:GetRoom(player.RoomID); if room~=nil then local msg_bool = msgin:rpb("PB.MsgBool"); room:RelieveRequestRoom(uid, msg_bool.value); end end end --释放函数 function MsgRoom:Release() self._EventRegister:UnRegisterAllEvent(); end return MsgRoom; ================================================ FILE: code/EVA/server/script/_PLS/Player/PlayerDataHelper.lua ================================================ local PlayerDataHelper = class("PlayerDataHelper") -- 构造函数; function PlayerDataHelper:ctor() self.f_uid = nil; self.f_username = nil; self.f_nickname = nil; self.f_portrait = nil; self.f_money = nil; self.f_rmb = nil; self.f_main = nil; self.f_flag_bit = nil; end function PlayerDataHelper:ToMsg() local MsgPlayerInfo = {}; MsgPlayerInfo["UID"] = self.f_uid; MsgPlayerInfo["Nickname"] = self.f_nickname; MsgPlayerInfo["Portrait"] = self.f_portrait; MsgPlayerInfo["Money"] = self.f_money; MsgPlayerInfo["RMB"] = self.f_rmb; MsgPlayerInfo["Main"] = self.f_main; MsgPlayerInfo["FlagBit"] = self.f_flag_bit; return MsgPlayerInfo; end return PlayerDataHelper; ================================================ FILE: code/EVA/server/script/_PLS/Player/PlayerHelper.lua ================================================ local PlayerHelper = class("PlayerHelper") -- 构造函数; function PlayerHelper:ctor() self.PlayerDataHelper = nil; self.UID = 0; self.ConFES = nil; self.IsRobot = false; self.RoomID = 0; self.JoinRoomTime = 0; self.OfflineTime = 0; self.LogoutTime = nil; self.PlayerState = nil; self.LastUpdateTime = TimerMgr:GetTime(); self._TimerHandle = TimerMgr:AddTimer( 30000, self, self.TickUpdate ); end function PlayerHelper:TickUpdate() local curr_time = TimerMgr:GetTime(); if curr_time - self.LastUpdateTime > 7*24*60*60*1000 then self._TimerHandle = nil; -- Release 时不再删除定时器 PlayerMgr:RemovePlayer(self.UID); else self._TimerHandle = TimerMgr:AddTimer( 10*60*1000, self, self.TickUpdate ); end end -- 从缓存中移除玩家,由PlayerMgr调用。 function PlayerHelper:Release() local msg = CMessage("RemovePlayer"); msg:wint(self.UID); BaseService:Broadcast("SCH", msg); if self._TimerHandle ~= nil then TimerMgr:RemoveTimer(self._TimerHandle); end end function PlayerHelper:Offline() self.OfflineTime = TimerMgr:GetTime(); self.ConFES = nil; if self.RoomID>0 then local room = RoomMgr:GetRoom(self.RoomID); if room~=nil then room:PlayerOffline( self.UID ); else nlwarning("room==nil"); end end nlwarning("Offline================"); end function PlayerHelper:Online() self.OfflineTime = 0; end return PlayerHelper; ================================================ FILE: code/EVA/server/script/_PLS/Player/PlayerMgr.lua ================================================ PlayerMgr = {} -- 初始化函数 function PlayerMgr:Init() self.playerMap = Map:new(); self.RobotPool = {}; self.RobotIdx = 1; self.RobotMax = 500; self.RobotIDStart = 1002; self.RobotIDEnd = 1003; for id=self.RobotIDStart,self.RobotIDEnd do local player_helper = self:LoadDBPlayer( id ); end end function PlayerMgr:Count() return self.playerMap:Count(); end function PlayerMgr:GetPlayer( _uid ) local player = self.playerMap:Find(_uid); if player~=nil then player.LastUpdateTime = TimerMgr:GetTime(); end return player end function PlayerMgr:LoadDBPlayer( _uid ) local tb_playerinfo = DBMgr:LoadPlayerInfo(_uid); if tb_playerinfo==nil then if DBMgr:CreatePlayer(_uid)==true then tb_playerinfo = DBMgr:LoadPlayerInfo(_uid); end end if tb_playerinfo~=nil then local player_helper = PlayerHelper:new(); player_helper.UID = _uid; player_helper.PlayerDataHelper = tb_playerinfo; self.playerMap:Insert(_uid, player_helper); return player_helper; end return nil; end -- 从缓存中移除玩家 function PlayerMgr:RemovePlayer( _uid ) local player = self.playerMap:Find(_uid); if player~=nil then if player.RoomID > 0 then player:Release(); self.playerMap:Remove(_uid); end end end function PlayerMgr:MakeRobot() return nil; end return PlayerMgr ================================================ FILE: code/EVA/server/script/_PLS/PlayerLogicService.lua ================================================ PlayerLogicService = {} function PlayerLogicService:Init() -- 注册其它服务器启动的回调 Net.SetConnectionCallback("SCH"); Net.SetDisConnectionCallback("SCH"); self._EventRegister = EventRegister.new(); self._EventRegister:RegisterEvent( "SCHCon", self, self.SCHConnection ); self._EventRegister:RegisterEvent( "SCHDis", self, self.SCHDisConnection ); self.TimerID = 0; self.sch_sid = 0; end function PlayerLogicService:UpdatePLSInfo( service_id ) local MsgServiceInfo = {}; MsgServiceInfo.MaxPlayer = PlayerConfig.MaxPlayer; MsgServiceInfo.CurrPlayer = PlayerMgr:Count(); MsgServiceInfo.ServiceID = Net.GetServiceID(); MsgServiceInfo.ServiceName = Net.GetServiceName(); MsgServiceInfo.RoomList = {}; for k, v in pairs(PLSConfig.GameConfig) do local MsgRoomType = {}; MsgRoomType.Type = k; MsgRoomType.Max = v.Max; MsgRoomType.Curr = PlayerMgr:Count(); table.insert( MsgServiceInfo.RoomList, MsgRoomType ); end BaseService:Send( service_id, "SvrInfo", "PB.MsgServiceInfo", MsgServiceInfo ) end function PlayerLogicService:SCHConnection( service_id, service_name ) nlinfo("PlayerLogicService:SCHConnection:"..service_name.." sid:"..service_id); self.sch_sid = service_id; self:UpdatePLSInfo(service_id); self.TimerID = TimerMgr:AddTimer(7000, self, self.UpdatePLSInfoTimer); end function PlayerLogicService:SCHDisConnection( service_id, service_name ) nlinfo("PlayerLogicService:SCHDisConnection"..service_name.." sid:"..service_id); self.sch_sid = nil; TimerMgr:RemoveTimer(self.TimerID); end function PlayerLogicService:UpdatePLSInfoTimer() self:UpdatePLSInfo(self.sch_sid); self.TimerID = TimerMgr:AddTimer(7000, self, self.UpdatePLSInfoTimer); end -- 释放函数 function PlayerLogicService:Release() self._EventRegister:UnRegisterAllEvent(); end return PlayerLogicService ================================================ FILE: code/EVA/server/script/_PLS/Room/RoomBase.lua ================================================ local RoomBase = class("RoomBase") -- 构造函数; function RoomBase:ctor() self.RoomID = RoomMgr:GenerateRoomID(); self.PrvRoomID = 0; self.RoomType = ""; self.IsGameStart = false; self.CreatorID = 0; -- 房间归属 self.CreateInfo = nil; -- 创建房间选项信息。 self.RoomPlayerData = Map:new(); self.SeatPlayers = {}; self.ViewPlayers = {}; self.ShowDownEvent = {}; self._TimerHandle = 0; self._TimerTick = 1000; self._CreateTime = os.time(); self.CFG_RM_MIN = 9999; self.CFG_LIMIT_TIME = 28800; end function RoomBase:PrintInfo() nlinfo("============== RoomID:"..self.RoomID .. " PrvID:"..self.PrvRoomID.." Creator:"..self.CreatorID); nlinfo("==>SeatPlayers:") PrintTable(self.SeatPlayers); nlinfo("==>RoomPlayers:") PrintTable(self.RoomPlayerData.map); end function RoomBase:Init( room_type, update_tick ) end function RoomBase:BaseInit( room_type, update_tick ) if update_tick~=nil then self._TimerTick = update_tick; end local ROOM_CFG = StaticTableMgr:GetRoomConfig(room_type); if ROOM_CFG~=nil then self.RoomType = room_type; self.CFG_RM_MIN = ROOM_CFG.room_min; self.CFG_LIMIT_TIME = ROOM_CFG.room_time; for i=1,ROOM_CFG.room_max do table.insert(self.SeatPlayers, 0); end self._TimerHandle = TimerMgr:AddTimer(self._TimerTick, self, self.BaseTickUpdate); self:Init(); end end function RoomBase:TickUpdate() nlinfo("RoomBase:TickUpdate "..self._TimerHandle); end function RoomBase:PlayerOffline(uid) if not self.IsGameStart then self:LeaveRoom(uid); end end function RoomBase:BaseTickUpdate() if os.time()-self._CreateTime > self.CFG_LIMIT_TIME then RoomMgr:ReleaseRoom( self.RoomID ); return; end if self._TimerHandle > 0 then -- BaseInit 之后才继续timer self._TimerHandle = TimerMgr:AddTimer(self._TimerTick, self, self.BaseTickUpdate); end self:TickUpdate(); end -- 玩家加入房间 function RoomBase:BaseJoinRoom( player ) player.RoomID = self.RoomID; self:__AddRoomPlayer(player.UID); end -- 玩家离开房间,子类可重写 function RoomBase:LeaveRoom( uid ) self:BrLeaveRoom(uid); if not self.IsGameStart and uid~=self.CreatorID then self:ReleaseRoomPlayer(uid); end end -- 广播玩家离开房间 function RoomBase:BrLeaveRoom( uid ) local msg_int = { value = uid }; self:BroadcastMsg( "LR", "PB.MsgInt", msg_int ); end function RoomBase:ReleaseRoomPlayer( uid ) -- 通知其它服务器离开房间 self:__NotifyOtherServiceLeave(uid); self:__RemoveSeatPlayer(uid); local player = PlayerMgr:GetPlayer(uid); if player~=nil then player.RoomID = 0; end self.RoomPlayerData:Remove(uid); if self:GetRoomPlayerNum()==0 then RoomMgr:ReleaseRoom( self.RoomID ); end end function RoomBase:IsRoomPlayer( uid ) for _,v in ipairs(self.SeatPlayers) do if v==uid then return true; end end return false; end function RoomBase:GetRoomPlayer( uid ) for _,v in ipairs(self.SeatPlayers) do if v==uid then return PlayerMgr:GetPlayer(uid); end end return nil; end function RoomBase:GetPlayerSeatIdx( uid ) for k,v in ipairs(self.SeatPlayers) do if v==uid then return k; end end return 0; end function RoomBase:GetRoomPlayerNum() local count = 0; for _,v in ipairs(self.SeatPlayers) do if v~=0 then count = count + 1; end end return count; end function RoomBase:GetNextUID( curr_id ) local curr_seat = self:GetPlayerSeatIdx(curr_id); if curr_seat>0 then -- 当前位置向后找 for i=curr_seat+1, #self.SeatPlayers do local next_uid = self.SeatPlayers[i]; if next_uid>0 then return next_uid; end end -- 后面没有了,从头开始找 for i=1, #self.SeatPlayers do local next_uid = self.SeatPlayers[i]; if next_uid>0 then return next_uid; end end end return 0; end function RoomBase:RelieveRequestRoom( uid, is_relieve ) end function RoomBase:RelieveAutoRoom() end function RoomBase:RelieveForceRoom( uid ) if self.CreatorID == uid then RoomMgr:ReleaseRoom( self.RoomID ) end end -- 新房间特殊玩法都用此方法判断 function RoomBase:CheckRoomSpecialKind( special_kind ) if self.CreateInfo~=nil and self.CreateInfo.special_kind~=nil then return GetBit(self.CreateInfo.special_kind, special_kind); end return false; end function RoomBase:IsFull() local ROOM_CFG = StaticTableMgr:GetRoomConfig(self.RoomType); if ROOM_CFG~=nil then if self:GetRoomPlayerNum()0 then self:ReleaseRoomPlayer(uid); end end self.Fsm = nil; TimerMgr:RemoveTimer(self._TimerHandle); end -- 广播消息给房间内桌上所有玩家 如有except_id,那么广播给除except_id的其它玩家。 function RoomBase:BroadcastMsg( msg_name, proto_name, proto_stru, except_id ) for _,v in ipairs(self.SeatPlayers) do if v~=0 then if except_id~=v then local player = PlayerMgr:GetPlayer(v); if player~=nil then BaseService:SendToClient( player, msg_name, proto_name, proto_stru ) end end end end end -- 广播消息给房间内观战所有玩家 如有except_id,那么广播给除except_id的其它玩家。 function RoomBase:BroadcastViewer( msg_name, msg_stru, except_id ) end -- 添加结算事件 function RoomBase:__AddShowDownEvent( TShowDownEvent, count ) local event_cnt = self.ShowDownEvent[TShowDownEvent]; if event_cnt==nil then self.ShowDownEvent[TShowDownEvent] = count; else event_cnt = event_cnt + count; end end function RoomBase:__GetSpecialCfg( field ) local ROOM_CFG = StaticTableMgr:GetSpecialCfg(self.RoomType); if ROOM_CFG~=nil then if field~=nil then return ROOM_CFG[field]; end return ROOM_CFG; end return nil; end function RoomBase:__NotifyOtherServiceLeave( uid ) local msgout = CMessage("PLS=>LURT"); msgout:wint(uid); msgout:wstring(self.RoomType); msgout:wint(self.PrvRoomID); BaseService:Broadcast( "SCH", msgout ); end function RoomBase:__AddRoomPlayer( uid ) local seat_idx = self:GetPlayerSeatIdx(uid); if seat_idx==0 then for k,v in ipairs(self.SeatPlayers) do if v==0 then self.SeatPlayers[k] = uid; seat_idx = k; break; end end end return seat_idx; end function RoomBase:__RemoveSeatPlayer( uid ) for k,v in ipairs(self.SeatPlayers) do if v==uid then self.SeatPlayers[k] = 0; end end end function RoomBase:__GetViewPlayerNum() return #self.ViewPlayers; end function RoomBase:__IsViewPlayer( playerid ) if self.ViewPlayers[playerid]~=nil then return true; end return false; end return RoomBase; ================================================ FILE: code/EVA/server/script/_PLS/Room/RoomFactory.lua ================================================ RoomFactory = {} function RoomFactory:Init() self.RoomTypes = {}; self.RoomTypes["RM_DDZ"] = require("Games/PokerDdz/RoomDdz"); end function RoomFactory:CreateRoom( room_type ) local room_class = self.RoomTypes[room_type]; if room_class~=nil then local room_ins = room_class:new(room_type); room_ins:BaseInit(room_type, 1000); return room_ins; end return nil; end ================================================ FILE: code/EVA/server/script/_PLS/Room/RoomMgr.lua ================================================ RoomMgr = {} function RoomMgr:Init() self.GameRooms = Map:new(); -- {roomid, room_ins} --self.RoomTypes = {}; -- {roomtype, {roomids, room_ins} } self.PrvRoomTypes = MapMap:new(); -- {roomtype, {prv_roomids, room_ins} } self.RoomIDGen = IDGenerate.NewInstance(1020); end function RoomMgr:PrintInfo() nlinfo("============== Rooms ============="); self.GameRooms:ForEach( function(_,v) v:PrintInfo(); end ); end function RoomMgr:CreatePrivateRoom( uid, prv_room_id, msg_cpr ) local room_type = msg_cpr.room_type; local player = PlayerMgr:GetPlayer(uid); local ROOM_CFG = StaticTableMgr:GetRoomConfig(room_type); if ROOM_CFG~=nil and player~=nil then if player.RoomID >0 then -- 已经创建过房间了 nlwarning("already create room. PlayerID:".. uid.." RoomInfo:"); local room = self.GameRooms:Find(player.RoomID); if room~=nil then PrintTable(room); end else local room_base = RoomFactory:CreateRoom(room_type); if room_base~=nil then room_base.PrvRoomID = prv_room_id; room_base.CreatorID = uid; room_base.CreateInfo = msg_cpr; if room_base:JoinRoom(player) then self.GameRooms:Insert(room_base.RoomID, room_base); self.PrvRoomTypes:Insert(room_type, prv_room_id, room_base); else room_base:Release(); nlwarning("player join room fail. uid:"..uid) end end end end return nil; end function RoomMgr:EnterPrivateRoom( uid, prv_room_id, room_type ) local player = PlayerMgr:GetPlayer(uid); local ROOM_CFG = StaticTableMgr:GetRoomConfig(room_type); if ROOM_CFG~=nil and player~=nil then if player.RoomID >0 then -- 已经在房间,自动返回 local room = self.GameRooms:Find(player.RoomID); if room~=nil then room:JoinRoom(player); end else local room = self.PrvRoomTypes:Find(room_type, prv_room_id); if room~=nil then room:JoinRoom(player); end end end return nil; end function RoomMgr:GetRoom( room_id ) return self.GameRooms:Find(room_id); end function RoomMgr:ReleaseRoom( room_id ) local room = self.GameRooms:Find(room_id); if room~=nil then if room.PrvRoomID > 0 then self.PrvRoomTypes:Remove( room.RoomType, room.PrvRoomID ); end self.GameRooms:Remove(room_id); room:Release(); end end function RoomMgr:GetRoomFromPID( uid ) local player = PlayerMgr:GetPlayer(uid); if player~=nil then return RoomMgr:GetRoom(player.RoomID); end return nil; end function RoomMgr:GenerateRoomID() return self.RoomIDGen:Generate(); end --释放函数 function RoomMgr:Release() end return RoomMgr; ================================================ FILE: code/EVA/server/script/_PLS/Room/RoomPlayerBase.lua ================================================ local RoomPlayerBase = class("RoomPlayerBase") function RoomPlayerBase:ctor() self._State = 0; self._Score = 0; -- self.HandCards = {}; end function RoomPlayerBase:GetHandCount() return #self.HandCards; end function RoomPlayerBase:ClearOneGameState() local clear_states = { enum.STATE_DDZ_NEWROLE, enum.STATE_DDZ_RELIEVE, enum.STATE_DDZ_GUOPAI, enum.STATE_DDZ_NONGMING, enum.STATE_DDZ_DIZHU, enum.STATE_DDZ_JIABEI, enum.STATE_DDZ_SELECT_JIABEI, enum.STATE_DDZ_MINGPAI,enum.STATE_DDZ_SELECT_MINGPAISTART, enum.STATE_DDZ_CONTINUE_GAME }; self._State = ClearBits( self._State, clear_states ); self.HandCards = {}; end function RoomPlayerBase:GetState( enum_val ) if enum_val==nil then return self._State; end return GetBit(self._State, enum_val); end function RoomPlayerBase:SetState( enum_val ) self._State = SetBit( self._State, enum_val ); end function RoomPlayerBase:ClearState( enum_val ) self._State = ClearBit(self._State, enum_val); end function RoomPlayerBase:AddHandCard( card ) table.insert(self.HandCards, card); end function RoomPlayerBase:RemoveHandCard( card ) for i,v in ipairs(self.HandCards) do if v==card then table.remove(self.HandCards, i); return; end end end function RoomPlayerBase:GetHandCardMsgList( msg_cards ) for i,v in ipairs(self.HandCards) do table.insert(msg_cards, v); end end function RoomPlayerBase:SetScore( score ) self._Score = score; end function RoomPlayerBase:GetScore() return self._Score; end function RoomPlayerBase:ChangeScore( score, is_add ) if is_add then self._Score = self._Score + score; else self._Score = self._Score - score; end return self._Score; end function RoomPlayerBase:AddScore( score ) self._Score = self._Score + score; return self._Score; end function RoomPlayerBase:SubScore( score ) self._Score = self._Score - score; return self._Score; end return RoomPlayerBase; ================================================ FILE: code/EVA/server/script/_PLS/_PLSConfig.lua ================================================ PLSConfig = {} PLSConfig["GameConfig"] = {}; PLSConfig.GameConfig["RM_DDZ"] = { Max = 5000 }; PlayerConfig = { MaxPlayer = 3000, -- DeleteTimeOut = 8*60*60*1000, -- ʱ䡣 λ DeleteTimeCheck = 10*60*1000, -- ʱ } ================================================ FILE: code/EVA/server/script/_PLS/_PLSMain.lua ================================================ --========================================================= -- 加载常用模块 --========================================================= local BasePath = Misc.GetBasePath() .. "/script/"; package.path = BasePath .. "_PLS/?.lua;" .. BasePath .. "SharedLib/?.lua;"; require("InitSharedLib") require("_PLSConfig") require("PlayerLogicService") require("Player/PlayerMgr") require("DB/DBMgr") require("Room/RoomMgr") require("Room/RoomFactory") require("Msg/MsgLogin") require("Msg/MsgRoom") require("Games/PokerDdz/MsgRoomDdz") require("Games/PokerDdz/DdzCardTypes") require("Games/Common/PokerDef"); require("Games/Common/CommonDef"); PlayerDataHelper = require("Player/PlayerDataHelper"); PlayerHelper = require("Player/PlayerHelper"); RoomPlayerBase = require("Room/RoomPlayerBase") RoomBase = require("Room/RoomBase") CardsAnalyseRes = require("Games/Common/CardsAnalyseRes") -- 主入口函数。从这里开始lua逻辑 function ServiceInit() nlinfo("Lua PLSConfig:"); PrintTable(PLSConfig) MsgLogin:Init(); MsgRoom:Init(); MsgRoomDdz:Init(); RoomFactory:Init(); RoomMgr:Init(); DBMgr:Init(); PlayerMgr:Init(); PlayerLogicService:Init(); DdzCardtypes:Init(); --local room = RoomFactory:CreateRoom("RM_DDZ"); -- local msg_ddz = {}; -- room:__FillRoomInfoMsg(msg_ddz, 0); --PrintTable(msg_ddz); end -- 游戏循环 function ServiceUpdate() local curr_tick = Misc.GetLocalTime(); TimerMgr:Update( curr_tick ); end function ServiceRelease() MsgLogin:Release(); MsgRoom:Release(); RoomMgr:Release(); DBMgr:Release(); PlayerLogicService:Release(); nlinfo("Lua Release."); end function ServiceInfo() nlinfo("PlayerNum:"..PlayerMgr:Count()); nlinfo("========= Players ============="); PrintTable(PlayerMgr.playerMap.map) RoomMgr:PrintInfo(); end --[[ --bash_path = "E:\\BaseService\\code\\EVA\\server\\script\\"; --package.path = bash_path .. "Framework\\?.lua;" .. bash_path .. "Framework\\Net\\?.lua;"; nlinfo(package.path); local protobuf = require "protobuf" addr = io.open( bash_path.."DataTable\\proto_msg.pb", "rb") buffer = addr:read "*a" addr:close() protobuf.register(buffer) t = protobuf.decode("google.protobuf.FileDescriptorSet", buffer) player_info = { name = "Alice", pid = 12345, view_player_list = { { pid = 17712345678, head_portrait = 1 }, { pid = 17712345679, head_portrait = 2 }, }, level = 2 } code = protobuf.encode("MsgPlayerInfo", player_info) decode = protobuf.decode("MsgPlayerInfo" , code) nlinfo(decode.name) nlinfo(decode.pid) for _,v in ipairs(decode.view_player_list) do nlinfo("\t"..v.pid, v.head_portrait) end ]] ================================================ FILE: code/EVA/server/script/_PLS/hotfix_module_names.lua ================================================ -- Module names need hotfix. -- hotfix_helper.lua will reload this module in check(). -- So it can be changed dynamically. local hotfix_module_names = { "Games/PokerDdz/RoomDdz", } return hotfix_module_names ================================================ FILE: code/EVA/server/script/_PLS.luaprj ================================================  ================================================ FILE: code/EVA/server/script/_SCH/Msg/MsgLogin.lua ================================================ --========================================================= -- SCH 负责分配到一个PLS --========================================================= MsgLogin = {} function MsgLogin:Init() self._EventRegister = EventRegister.new(); -- 服务器间消息 self._EventRegister:RegisterEvent( "AuthOk", self, self.DispatchPLS ); -- PLS 删除缓存中的玩家 self._EventRegister:RegisterEvent( "RemovePlayer", self, self.cbRemovePlayer ); end -- 分配PLS function MsgLogin:DispatchPLS( fes_id, msg_authok ) local uid = msg_authok:rint64(); local room_type = msg_authok:rstring(); local msg_sdata_0 = CMessage("SyncData"); msg_sdata_0:wint64(uid); msg_sdata_0:wint32(fes_id); local player = PlayerInfoMgr:GetPlayerInfo(uid); if player~=nil then player.ConFES = fes_id; if player.ConPLS~=nil then BaseService:Send( player.ConPLS, msg_sdata_0 ) else local pls_sid = PLSInfoMgr:AllocPLS(player.RoomType); if pls_sid~=nil then player.ConPLS = pls_sid; BaseService:Send( player.ConPLS, msg_sdata_0 ) else nlwarning(player.RoomType.." not in pls config."); end end else local pls_sid = PLSInfoMgr:AllocPLS(room_type); if pls_sid~=nil then player = PlayerInfoMgr:CreatePlayerInfo(uid); player.ConFES = fes_id; player.ConPLS = pls_sid; player.RoomType = room_type; BaseService:Send( player.ConPLS, msg_sdata_0 ) else nlwarning(room_type.." not in pls config."); end end end function MsgLogin:cbRemovePlayer( fesid, msgin ) local uid = msgin:rint(); end return MsgLogin; ================================================ FILE: code/EVA/server/script/_SCH/Msg/MsgRoom.lua ================================================ MsgRoom = {} function MsgRoom:Init() self._EventRegister = EventRegister.new(); self._EventRegister:RegisterEvent( "CPRM", self, self.cbCreatePrivateRoom ); self._EventRegister:RegisterEvent( "EPRM", self, self.cbEnterPrivateRoom ); self._EventRegister:RegisterEvent( "PLS=>LURT", self, self.cbLeaveRoomType ); end function MsgRoom:cbCreatePrivateRoom( sid, msgin ) local uid = msgin:rint64(); local msg_cpr = msgin:rpb("PB.MsgCreatePrivateRoom"); RoomMgr:CreatePrivateRoom(uid, msg_cpr) end function MsgRoom:cbEnterPrivateRoom( sid, msgin ) local uid = msgin:rint64(); local msg_epr = msgin:rpb("PB.MsgEnterPrivateRoom"); RoomMgr:EnterPrivateRoom(uid, msg_epr); end function MsgRoom:cbLeaveRoomType( sid, msgin ) local uid = msgin:rint(); local prv_rmtp = msgin:rstring(); local prv_rmid = msgin:rint(); RoomMgr:ResetPrivateRoom(uid, prv_rmtp, prv_rmid); end --释放函数 function MsgRoom:Release() self._EventRegister:UnRegisterAllEvent(); end return MsgRoom; ================================================ FILE: code/EVA/server/script/_SCH/PLSInfo/PLSGameInfo.lua ================================================ local PLSGameInfo = class("PLSGameInfo") -- 构造函数; function PLSGameInfo:ctor() self.Type = ""; self.Max = 0; self.Curr = 0; end function PLSGameInfo:IsFull() if( self.Curr > self.Max ) then return true; end return false; end return PLSGameInfo; ================================================ FILE: code/EVA/server/script/_SCH/PLSInfo/PLSInfo.lua ================================================ local PLSInfo = class("PLSInfo") -- 构造函数; function PLSInfo:ctor() self.ServiceID = 0; self.ServiceName = ""; self.MaxPlayer = 0; self.CurrPlayer = 0; self.RoomList = {}; end function PLSInfo:LoadData( _service_info ) self.ServiceID = _service_info.ServiceID; self.ServiceName = _service_info.ServiceName; self.MaxPlayer = _service_info.MaxPlayer; self.CurrPlayer = _service_info.CurrPlayer; self.RoomList = {}; if _service_info.RoomList~=nil then for _,v in ipairs(_service_info.RoomList) do local game_info = PLSGameInfo:new(); game_info.Type = v.Type; game_info.Max = v.Max; game_info.Curr = v.Curr; self.RoomList[game_info.Type] = game_info; end end end function PLSInfo:IsFull() if( self.CurrPlayer > self.MaxPlayer ) then return true; end return false; end return PLSInfo; ================================================ FILE: code/EVA/server/script/_SCH/PLSInfo/PLSInfoMgr.lua ================================================ PLSInfoMgr = {} -- 初始化函数 function PLSInfoMgr:Init() self.PLSMap = Map:new(); self._EventRegister = EventRegister.new(); self._EventRegister:RegisterEvent( "SvrInfo", self, self.SvrUpdateInfoCB ); nlinfo("PLSInfoMgr:Init"); end function PLSInfoMgr:SvrUpdateInfoCB( msg_from, msg_svrinfo ) local proto_buf = msg_svrinfo:rstring(); local pb_sinfo = protobuf.decode("PB.MsgServiceInfo" , proto_buf) local pls_info = PLSInfo:new(); pls_info:LoadData(pb_sinfo); if pb_sinfo.ServiceName=="PLS" then self.PLSMap:Replace(pls_info.ServiceID, pls_info); end end function PLSInfoMgr:AllocPLS( room_type ) for _,v in pairs(self.PLSMap.map) do if v.RoomList[room_type] ~= nil then local game_info = v.RoomList[room_type]; if not game_info:IsFull() then game_info.Curr = game_info.Curr + 1; return v.ServiceID; end; end; end; return -1; end function PLSInfoMgr:IsInPLS( room_type, pls_sid ) local pls_info = self.PLSMap:Find(pls_sid); if pls_info~=nil then if pls_info[room_type]~=nil then return true; end end return false; end --释放函数 function PLSInfoMgr:Release() self._EventRegister:UnRegisterAllEvent(); end return PLSInfoMgr ================================================ FILE: code/EVA/server/script/_SCH/Player/PlayerInfo.lua ================================================ -- Player SCH Info local PlayerInfo = class("PlayerInfo") -- 构造函数; function PlayerInfo:ctor() self.ConPLS = -1; self.ConFES = nil; self.UID = nil; --self.IsOffline = false; self.LogoutTime = nil; --self.TimerID = nil; self.RoomType = ""; self.PrvRoomID = 0; end function PlayerInfo:RemoveCachePlayerTimer() if self.LogoutTime then --self.TimerID = TimerMgr:AddTimer(7000, self, self.RemoveCachePlayerTimer); else --TimerMgr:RemoveTimer(self.TimerID); end end function PlayerInfo:Release() end --self.TimerID = TimerMgr:AddTimer(7000, self, self.UpdatePLSInfoTimer); return PlayerInfo; ================================================ FILE: code/EVA/server/script/_SCH/Player/PlayerInfoMgr.lua ================================================ PlayerInfoMgr = {} -- 初始化函数 function PlayerInfoMgr:Init() self.PlayerInfoMap = Map:new(); nlinfo("PlayerInfoMgr:Init"); end function PlayerInfoMgr:GetPlayerInfo( _uid ) return self.PlayerInfoMap:Find(_uid); end function PlayerInfoMgr:CreatePlayerInfo( _uid ) local player = self.PlayerInfoMap:Find(_uid); if player~= nil then return player; else player = PlayerInfo:new(); player.UID = _uid; self.PlayerInfoMap:Insert(_uid, player); end return player; end function PlayerInfoMgr:RemovePlayerInfo( _uid ) local player = self.PlayerInfoMap:Find(_uid); if player ~= nil then player:Release(); self.PlayerInfoMap:Remove(_uid); end end function PlayerInfoMgr:RemovePLS( pls_sid ) self.PlayerInfoMap:ForEachRemove("ConPLS", pls_sid); nlwarning("PlayerInfoMgr.RemovePLS:"..pls_sid); end function PlayerInfoMgr:Release() self.PlayerInfoMap:ForEach( function(_,v) v:Release(); end ); self.PlayerInfoMap = nil; end return PlayerInfoMgr ================================================ FILE: code/EVA/server/script/_SCH/Room/RoomIDAlloter.lua ================================================ local RoomIDAlloter = class("RoomIDAlloter") -- 构造函数; function RoomIDAlloter:ctor() self.IDPool = {}; self.RoomType = ""; self.IDMax = 999999; --999999; self.__AllocIdx = 1; self:Init(); end function RoomIDAlloter:Init() for i=1,self.IDMax do self.IDPool[i] = i; end for i=1,self.IDMax do local ridx = math.random(1, self.IDMax); if i~=ridx then local temp = self.IDPool[i]; self.IDPool[i] = self.IDPool[ridx]; self.IDPool[ridx] = temp; end end end function RoomIDAlloter:AllocID() if self.__AllocIdx == self.IDMax then self.__AllocIdx = 1; end local newid = self.IDPool[self.__AllocIdx]; self.__AllocIdx = self.__AllocIdx + 1; return newid; end return RoomIDAlloter; ================================================ FILE: code/EVA/server/script/_SCH/Room/RoomInfo.lua ================================================ local RoomInfo = class("RoomInfo") -- 构造函数; function RoomInfo:ctor() self.PLSID = -1; self.RoomType = ""; self.PrvRoomID = 0; self.PlayerID = 0; -- 创建者ID end return RoomInfo; ================================================ FILE: code/EVA/server/script/_SCH/Room/RoomMgr.lua ================================================ RoomMgr = {} function RoomMgr:Init() self._RoomIDPool = {}; self._RoomsInfo = MapMap:new(); -- { room_type, {prv_room_id, room_ins} } self:__InitRoomID(); end function RoomMgr:CreatePrivateRoom( uid, msg_cpr ) local player = PlayerInfoMgr:GetPlayerInfo(uid); if player~=nil then if player.PrvRoomID==0 then local room_type = msg_cpr.room_type; local new_room_id = self:__NewRoomID(room_type); if new_room_id>0 then local room_info = RoomInfo:new(); room_info.PlayerID = uid; room_info.PrvRoomID = new_room_id; room_info.RoomType = room_type; if PLSInfoMgr:IsInPLS(room_type, player.ConPLS) then room_info.PLSID = player.ConPLS; else room_info.PLSID = PLSInfoMgr:AllocPLS(room_type); end player.PrvRoomID = new_room_id; player.RoomType = room_type; self._RoomsInfo:Insert(room_type, new_room_id, room_info); local msgout = CMessage("CPRM=>PLS"); msgout:wint(uid); msgout:wint(new_room_id); msgout:wint(room_info.PLSID); msgout:wtable(msg_cpr); BaseService:Send( player.ConPLS, msgout ); end else local msgout = CMessage("EPRM=>PLS"); msgout:wint(uid); msgout:wint(player.ConPLS); msgout:wint(player.PrvRoomID); msgout:wstring(player.RoomType); BaseService:Send( player.ConPLS, msgout ); end end end function RoomMgr:EnterPrivateRoom( uid, msg_epr ) local player = PlayerInfoMgr:GetPlayerInfo(uid); if player~=nil then if player.PrvRoomID==0 then local room_type = msg_epr.room_type; local room_id = msg_epr.room_id; local room = self._RoomsInfo:Find(room_type, room_id); if room~=nil then player.PrvRoomID = room_id; player.RoomType = room_type; local msgout = CMessage("EPRM=>PLS"); msgout:wint(uid); msgout:wint(room.PLSID); msgout:wint(room_id); msgout:wstring(room_type); BaseService:Send( player.ConPLS, msgout ); end else local msgout = CMessage("EPRM=>PLS"); msgout:wint(uid); msgout:wint(player.ConPLS); msgout:wint(player.PrvRoomID); msgout:wstring(player.RoomType); BaseService:Send( player.ConPLS, msgout ); end end end function RoomMgr:ResetPrivateRoom( uid, prv_rmtp, prv_rmid ) local player = PlayerInfoMgr:GetPlayerInfo(uid); if player~=nil then if player.PrvRoomID~=prv_rmid or player.RoomType~=prv_rmtp then nlwarning(" player.PrvRoomID~=prv_rmid or player.RoomType~=prv_rmtp "); return; end player.PrvRoomID = 0; player.RoomType = ""; end end function RoomMgr:__NewRoomID( room_type ) local idpool = self._RoomIDPool[room_type]; local new_id = 0; if idpool~=nil then new_id = idpool:AllocID(); end return new_id; end function RoomMgr:__InitRoomID() for k, v in pairs(StaticTableMgr._RoomConfig) do if v.match == "private" then self._RoomIDPool[k] = RoomIDAlloter.new(); end end end return RoomMgr ================================================ FILE: code/EVA/server/script/_SCH/ScheduleService.lua ================================================ ScheduleService = {} function ScheduleService:Init() self._EventRegister = EventRegister.new(); self._EventRegister:RegisterEvent( "FESCon", self, self.CbConnection ); self._EventRegister:RegisterEvent( "FESDis", self, self.CbFESDisConnection ); self._EventRegister:RegisterEvent( "PLSCon", self, self.CbConnection ); self._EventRegister:RegisterEvent( "PLSDis", self, self.CbPLSDisConnection ); -- 注册其它服务器启动的回调 Net.SetConnectionCallback("FES"); Net.SetDisConnectionCallback("FES"); Net.SetConnectionCallback("PLS"); Net.SetDisConnectionCallback("PLS"); nlinfo("ScheduleService:Init"); end function ScheduleService:CbConnection( service_id, service_name ) nlinfo("ScheduleService:CbConnection:"..service_name.." sid:"..service_id); end function ScheduleService:CbFESDisConnection( service_id, service_name ) nlinfo("ScheduleService:CbFESDisConnection"..service_name.." sid:"..service_id); end function ScheduleService:CbPLSDisConnection( service_id, service_name ) PlayerInfoMgr.RemovePLS(service_id); end -- 释放函数 function ScheduleService:Release() self._EventRegister:UnRegisterAllEvent(); end return ScheduleService ================================================ FILE: code/EVA/server/script/_SCH/_SCHMain.lua ================================================ --========================================================= -- 加载常用模块 --========================================================= local BasePath = Misc.GetBasePath() .. "/script/"; package.path = BasePath .. "_SCH/?.lua;" .. BasePath .. "SharedLib/?.lua;"; require("InitSharedLib") require("ScheduleService") require("PLSInfo/PLSInfoMgr") require("Player/PlayerInfoMgr") MsgLogin = require("Msg/MsgLogin") MsgRoom = require("Msg/MsgRoom") PLSGameInfo = require("PLSInfo/PLSGameInfo") PLSInfo = require("PLSInfo/PLSInfo") PlayerInfo = require("Player/PlayerInfo") RoomInfo = require("Room/RoomInfo") RoomMgr = require("Room/RoomMgr") RoomIDAlloter = require("Room/RoomIDAlloter") --PHPService = CallbackServer:new(); -- 主入口函数。从这里开始lua逻辑 function ServiceInit() nlinfo("Lua Start."); MsgLogin:Init(); MsgRoom:Init(); RoomMgr:Init(); PLSInfoMgr:Init(); PlayerInfoMgr:Init(); ScheduleService:Init(); --PHPService:Init( "PHP", "tcp" ); --PHPService:Listen( 20458 ); end -- 游戏循环 function ServiceUpdate() TimerMgr:Update( Misc.GetLocalTime() ); end function ServiceRelease() PLSInfoMgr:Release(); PlayerInfoMgr:Release(); ScheduleService:Release(); nlinfo("Lua Release."); end function ServiceInfo() PrintTable(PlayerInfoMgr.PlayerInfoMap.map); end ================================================ FILE: code/EVA/server/script/_SCH.luaprj ================================================  ================================================ FILE: code/EVA/server/script/__Robot/RobotSub/FSMRobot.lua ================================================ local FSMRobot = class("FSMRobot") --[[ ߼״̬ --]] function FSMRobot:ctor() self._GameFSM = StateMachine:new(); self._StateEnterTime = 0; self._CurrState = "TIdle"; self.Robot = nil; end function FSMRobot:Init( robot ) self._GameFSM:setup_state({ events = { {name = "TIdle" }, {name = "TLogin" }, }, callbacks = { onTIdle = handler(self, self.DoIdle), onTLogin = handler(self, self.DoLogin), } }) self.Robot = robot; self:SwitchState( self._CurrState ); end function FSMRobot:__GetRunStateTime() return TimerMgr:GetTime() - self._StateEnterTime; end function FSMRobot:TickUpdate() self._GameFSM:do_event( self._CurrState, false ); end function FSMRobot:SwitchState( event, ... ) self._CurrState = event; self._StateEnterTime = TimerMgr:GetTime(); self._GameFSM:do_event( event, true, ... ); end function FSMRobot:GetState() return self._CurrState; end function FSMRobot:IsState( state ) if self._CurrState == state then return true; end return false; end function FSMRobot:DoIdle( event ) -- ǵһ֡һִ֡С if not event.args[1] then if not self.Robot:Connected() then self:SwitchState("TLogin"); end end end function FSMRobot:DoLogin( event ) --if event.args[1] then --nlinfo( "FSMClass:DoLogin SwitchState" ); --else --nlinfo( "FSMClass:DoLogin TickUpdate" ); --end if not event.args[1] then if self.Robot:Login() then self.Robot:StartGameTest(); self:SwitchState("TIdle"); end end end return FSMRobot; ================================================ FILE: code/EVA/server/script/__Robot/RobotSub/GameDdz/FSMDdz.lua ================================================ local FSMDdz = class("FSMDdz") --[[ Ϸ߼״̬ --]] function FSMDdz:ctor() self._GameFSM = StateMachine:new(); self._StateEnterTime = 0; self._CurrState = "TIdle"; self.Robot = nil; end function FSMDdz:Init( robot ) self._GameFSM:setup_state({ events = { {name = "TIdle" }, {name = "TCreatePrvRoom" }, {name = "TJoinPrvRoom" }, {name = "TInRoomIdlem" }, {name = "TAction" }, {name = "TShowDown" }, }, callbacks = { onTIdle = handler(self, self.DoIdle), onTCreatePrvRoom = handler(self, self.DoCreatePrvRoom), onTJoinPrvRoom = handler(self, self.DoJoinPrvRoom), onTInRoomIdlem = handler(self, self.DoInRoomIdlem), onTAction = handler(self, self.DoAction), TShowDown = handler(self, self.DoShowDown), } }) self.Robot = robot; self.GameDdz = robot.Game; self:SwitchState( self._CurrState ); self.CreateRoomWait = nil; end function FSMDdz:__GetRunStateTime() return TimerMgr:GetTime() - self._StateEnterTime; end function FSMDdz:TickUpdate() self._GameFSM:do_event( self._CurrState, false ); end function FSMDdz:SwitchState( event, ... ) self._CurrState = event; self._StateEnterTime = TimerMgr:GetTime(); self._GameFSM:do_event( event, true, ... ); end function FSMDdz:GetState() return self._CurrState; end function FSMDdz:IsState( state ) if self._CurrState == state then return true; end return false; end function FSMDdz:DoIdle( event ) -- ǵһ֡һִ֡С if not event.args[1] then if not (self.Robot.Data.UID > 0) then return; end if self.Robot.Game.RoomInfo == nil then local open_room = PublicRoomInfoMgr:GetOpenRoom("RM_DDZ"); if open_room ~= nil then -- robotķ䣬롣 self:SwitchState("TJoinPrvRoom", open_room); else -- ûйķ䣬һ if self.Robot.Data.UID==1007 then if self.CreateRoomWait == nil then self.CreateRoomWait = math.random(5000,10000); end if self:__GetRunStateTime() > self.CreateRoomWait then self.Robot:Print("request create room. UID:"..self.Robot.Data.UID .. " wait:"..self.CreateRoomWait); self.CreateRoomWait = math.random(5000,60000); self:SwitchState("TCreatePrvRoom"); end end end end end end function FSMDdz:DoCreatePrvRoom( event, open_room ) if event.args[1] then self.GameDdz:DoCreatePrvRoom() else if self:__GetRunStateTime() > 15*1000 then -- 䳬ʱ self:SwitchState("TIdle"); end end end function FSMDdz:DoJoinPrvRoom( event ) -- õִ֡ if event.args[1] then self.Robot:Print("DoJoinPrvRoom"); local open_room = event.args[2]; self.Robot:PrintTable(open_room); self.GameDdz:DoJoinPrvRoom(open_room) else if self:__GetRunStateTime() > 15*1000 then self:SwitchState("TIdle"); end end end function FSMDdz:DoInRoomIdlem( event ) if not event.args[1] then if not self.GameDdz:GetRobotState(enum.STATE_DDZ_READY) then self.GameDdz:DoReady(); end end end function FSMDdz:DoAction( event ) if not event.args[1] then self.GameDdz:DoAction(); end end function FSMDdz:DoShowDown( event ) end return FSMDdz; ================================================ FILE: code/EVA/server/script/__Robot/RobotSub/GameDdz/RobotGameDdz.lua ================================================ local RobotGameDdz = class("RobotGameDdz", RobotGameBase) function RobotGameDdz:ctor() self.super:ctor(); self.Robot = nil; self.RoomInfo = nil; self.SelfData = nil; -- player_listԼķ self.HandCards = {}; self.WIK = 0; end function RobotGameDdz:GetFsmState() return self.Robot.GameFsm:GetState(); end function RobotGameDdz:GetRobotState( enum_idx ) return GetBit( self.SelfData.state, enum_idx ); end function RobotGameDdz:__UID() return self.Robot.Data.UID; end function RobotGameDdz:DoCreatePrvRoom() local create_prvroom = { room_type="RM_DDZ", consume_id=1001, special_kind=0x1c5 }; self.Robot:Send( "CPRM", "PB.MsgCreatePrivateRoom", create_prvroom ); end function RobotGameDdz:DoJoinPrvRoom(open_room) local join_prvroom = { room_id=open_room.RoomID, room_type=open_room.RoomType }; self.Robot:Send( "EPRM", "PB.MsgEnterPrivateRoom", join_prvroom ); end function RobotGameDdz:DoReady() self.Robot:Send( "DDZ_SR" ); end -- ֵҳ function RobotGameDdz:DoAction() if #self.HandCards>0 and self.WIK ~= enum.ASK_DDZ_NULL then local flg_chupai = 1 << enum.ASK_DDZ_CHUPAI; local flg_buchu = 1 << enum.ASK_DDZ_BUCHU; local select_rnd = math.random( 1, 15 ); if self.WIK&flg_buchu and select_rnd==1 then self.Robot:Send( "DDZ_PS" ); elseif self.WIK&flg_chupai then local MsgDDZUserOutCard = { out_cards = {} }; local rnd_oc = math.random( 1, #self.HandCards ); table.insert( MsgDDZUserOutCard.out_cards, self.HandCards[rnd_oc] ); self.Robot:Send( "DDZ_OC", "PB.MsgDDZUserOutCard", MsgDDZUserOutCard ); self.Robot:Print( "out card:" .. self.HandCards[rnd_oc] ); end end end function RobotGameDdz:cbDdzGameInfo( msgin ) local ddz_gi = msgin:rpb("PB.MsgDDZRoom"); if ddz_gi==nil then nlwarning("ddz_gi==nil !!!!!!!!!!!!"); return end -- ˢ· self.RoomInfo = ddz_gi; -- ˢԼ for _,v in ipairs(ddz_gi.player_list) do if v.player_base.UID == self.Robot.Data.UID then self.SelfData = v; self.HandCards = v.card_list; end end self.Robot:PrintTable(ddz_gi); self.Robot:Print("=======> RobotGameDdz:cbDdzGameInfo UID:"..self.Robot.Data.UID); if self:GetFsmState()=="TCreatePrvRoom" then --if self:GetRobotState(enum.STATE_DDZ_ROOM_OWNER) then -- ԼģصǴɹ -- self.IsCreate = true; --end self.Robot:Print("=========>Create private room. UID:"..self.Robot.Data.UID); -- room_id뵽бУ˼롣 local pb_room_info = PublicRoomInfo:new(); pb_room_info.RoomType = ddz_gi.private_room.room_type; pb_room_info.RoomID = ddz_gi.room_id; pb_room_info.RoomRobots = ddz_gi.player_list; PublicRoomInfoMgr:PushOpenRoom(pb_room_info); self.Robot.GameFsm:SwitchState("TInRoomIdlem"); elseif self:GetFsmState()=="TJoinPrvRoom" then self.Robot:Print("=========>Join private room. UID:"..self.Robot.Data.UID); self.Robot.GameFsm:SwitchState("TInRoomIdlem"); else self.Robot:Print("=========>Refresh private room. UID:"..self.Robot.Data.UID); end end -- ҵ׼Լ͸״̬ function RobotGameDdz:cbDdzUserStartReady( msgin ) local ready_uid = msgin:rpb("PB.MsgInt"); if self.Robot.Data.UID==ready_uid then self.SelfData.state = SetBit( self.SelfData.state, enum.STATE_DDZ_READY ); self.Robot:Print("cbDdzUserStartReady"); end end function RobotGameDdz:cbDDZ_QDZ_QX( msg_qdz ) self.Robot:Print("SELF:"..self.Robot.Data.UID.." cbDDZ_QDZ_QX UID:"..msg_qdz.playid.." WIK:"..msg_qdz.qingdizhu_wiki); if self.Robot.Data.UID==msg_qdz.playid then if msg_qdz.qingdizhu_wiki > 0 then local select_wki_list = {}; for i=1,10 do if GetBit( msg_qdz.qingdizhu_wiki, i ) then table.insert(select_wki_list, i); end end if #select_wki_list==0 then nlwarning("#select_wki_list==0"); return; end local rnd = math.random(#select_wki_list); local select_wki = select_wki_list[rnd]; self.Robot:Print("Select WKI:"..select_wki); local MsgQiangDiZhuResult = { result=select_wki }; self.Robot:Send( "DDZ_QDZ", "PB.MsgQiangDiZhuResult", MsgQiangDiZhuResult ); end end end function RobotGameDdz:cbDDZ_QDZ_F( msg_qdz_res ) -- ǵˢ for _,v in ipairs(msg_qdz_res.player_list) do if v.playid==self.Robot.Data.UID and #v.dizhu_cards>0 then self.HandCards = v.dizhu_cards; self.Robot:Print("Refresh DiZhu HandCards"); break; end end local MsgJiaBeiResult = { result = math.random(2) }; self.Robot:Send( "DDZ_JB", "PB.MsgJiaBeiResult", MsgJiaBeiResult ); end -- ֵҳ function RobotGameDdz:cbDDZ_RA( msg_ddz_act ) self.Robot:PrintTable( msg_ddz_act ); if msg_ddz_act.new_actionid == self:__UID() then self.WIK = msg_ddz_act.wik; elseif msg_ddz_act.old_actionid == self:__UID() then self.WIK = msg_ddz_act.wik; -- ѳ for i,v in ipairs(self.HandCards) do if v==msg_ddz_act.last_out_cards[1] then table.remove( self.HandCards, i ); break; end end end if self:GetFsmState()~="TAction" then self.Robot.GameFsm:SwitchState("TAction"); end end function RobotGameDdz:cbDDZ_SD( msg_ddz_sd ) self.Robot:PrintTable( msg_ddz_sd ); self.Robot.GameFsm:SwitchState("TShowDown"); end return RobotGameDdz; ================================================ FILE: code/EVA/server/script/__Robot/RobotSub/PublicRoomInfo.lua ================================================ local PublicRoomInfo = class("PublicRoomInfo") function PublicRoomInfo:ctor() self.RoomType = ""; self.RoomID = -1; self.RoomRobots = {}; end return PublicRoomInfo; ================================================ FILE: code/EVA/server/script/__Robot/RobotSub/PublicRoomInfoMgr.lua ================================================ PublicRoomInfoMgr = {} -- Ϣrobot佻Ϣʹá function PublicRoomInfoMgr:Init() self.Rooms = {}; -- room_tyype, {room_prvid, room_ins} end function PublicRoomInfoMgr:PushOpenRoom( room_info ) if self.Rooms[room_info.RoomType] == nil then self.Rooms[room_info.RoomType] = {}; end self.Rooms[room_info.RoomType][room_info.RoomID] = room_info; end function PublicRoomInfoMgr:RemoveOpenRoom( room_type, room_prvid ) self.Rooms[room_prvid] = nil; end function PublicRoomInfoMgr:GetOpenRoom( room_type ) local rooms = self.Rooms[room_type]; if rooms~=nil then for _,v in pairs(rooms) do return v; end end return nil; end return PublicRoomInfoMgr; ================================================ FILE: code/EVA/server/script/__Robot/RobotSub/Robot.lua ================================================ local Robot = class("Robot") function Robot:ctor() self.Data = RobotData:new(); self.Fsm = FSMRobot:new(); self.Fsm:Init(self); self.Net = bin_types.LuaCallbackClient.NewInstance("tcp"); end function Robot:Init( net_handle ) self.Net:SetHandle(net_handle); end function Robot:Update() self.Net:Update(); self.Fsm:TickUpdate(); if self.GameFsm~=nil then self.GameFsm:TickUpdate(); self.Game:Update(); end end function Robot:GetHandle() return self.Net:GetHandle(); end function Robot:Connected() return self.Net:Connected(); end -- ʼϷ߼ function Robot:StartGameTest() if self.Data.Game == "RM_DDZ" then self.Game = RobotGameDdz:new(); self.Game.Robot = self; self.GameFsm = FSMDdz:new(); self.GameFsm:Init(self); end end function Robot:PrintTable( tbl ) RobotMgr:PrintTable(tbl, self.Data.UID); end function Robot:Print( str ) RobotMgr:Print(str, self.Data.UID); end function Robot:Login() local login_url = "http://127.0.0.1/www/login/login_test.php"; local login_params = "?Channel=REG&GameType="..self.Data.Game.."&User="..self.Data.User.."&AppName=WX_5E8A"; local http_res = Net.HttpGet(login_url..login_params); if http_res==nil or #http_res<20 then nlwarning("http login error") return end local http_tb = Json2Table(http_res); self:PrintTable(http_tb) self.Net:Connect("127.0.0.1:9999"); if self.Net:Connected() then local proto_msg = { UID = http_tb.UID, Channel = "REG", RoomType = "RM_DDZ", AppName = "WX_5E8A", User = self.Data.User, NonceStr = http_tb.NonceStr, Timestamp = http_tb.Timestamp, Token = http_tb.Token, } self:Send( "LOGIN", "PB.MsgLogin", proto_msg ) self:Print("Login :"..self.Data.User); return true; else nlwarning("Connect Error :"..self.Data.User); end return false; end function Robot:HeartBeat() local msgout = CMessage("HB"); self.Net:Send( msgout ); end function Robot:Send( msgname, proto_type, proto_msg ) local msg = CMessage(msgname); if proto_type~=nil then local code = protobuf.encode(proto_type, proto_msg); msg:wstring(code); end self.Net:Send( msg ); end function Robot:cbSyncPlayerInfo( msgin ) local player_info = msgin:rpb("PB.MsgPlayerInfo"); if player_info==nil then nlwarning("player_info==nil !!!!!!!!!"); return; end self:Print("Robot:cbSyncPlayerInfo"); self:PrintTable(player_info); self.Data.UID = player_info.UID; end return Robot; ================================================ FILE: code/EVA/server/script/__Robot/RobotSub/RobotData.lua ================================================ local RobotData = class("RobotData") function RobotData:ctor() self.UID = 0; self.User = ""; self._RoomState = 0; -- robot self.Game = ""; end function RobotData:ClearRoomState( enum_val ) if enum_val~=nil then self._RoomState = ClearBit(self._RoomState, enum_val); end end function RobotData:ClearRoomAllState() self._RoomState = 0; end function RobotData:GetRoomState( enum_val ) if enum_val==nil then return self._RoomState; end return GetBit(self._RoomState, enum_val); end function RobotData:SetRoomState( enum_val ) if enum_val~=nil then self._RoomState = SetBit(self._RoomState, enum_val); end end return RobotData; ================================================ FILE: code/EVA/server/script/__Robot/RobotSub/RobotGameBase.lua ================================================ local RobotGameBase = class("RobotGameBase") function RobotGameBase:ctor() end function RobotGameBase:Update() end return RobotGameBase; ================================================ FILE: code/EVA/server/script/__Robot/RobotSub/RobotMgr.lua ================================================ RobotMgr = {} function RobotMgr:Init() self._EventRegister = EventRegister.new(); -- ̼߳Ϣ self._EventRegister:RegisterEvent( "TestSubProc", self, self.LuaTestCB ); -- Ϣ self._EventRegister:RegisterEvent( "AuthOk", self, self.cbAuthOk ); self._EventRegister:RegisterEvent( "SyncPlayerInfo", self, self.cbSyncPlayerInfo ); -- Ϣ self._EventRegister:RegisterEvent( "DDZ_GI", self, self.cbDdzGameInfo ); self._EventRegister:RegisterEvent( "DDZ_SR", self, self.cbDdzUserStartReady ); self._EventRegister:RegisterEvent( "DDZ_QDZ_QX", self, self.cbDDZ_QDZ_QX ); self._EventRegister:RegisterEvent( "DDZ_QDZ_F", self, self.cbDDZ_QDZ_F ); self._EventRegister:RegisterEvent( "DDZ_RA", self, self.cbDDZ_RA ); self._EventRegister:RegisterEvent( "DDZ_SD", self, self.cbDDZ_SD ); self.TotalRobot = nil; self.RobotList = {}; self.PrintFilterWhite = {}; self.MsgNames = {}; end function RobotMgr:StartLogic( start_num, total_num ) --self.PrintFilterWhite[1007] = true; self.TotalRobot = total_num; for i=1,total_num do local robot = Robot:new(); robot.Data.User = "test_" .. start_num+i-1; robot.Data.Game = "RM_DDZ"; robot:Init(i); self.RobotList[robot:GetHandle()] = robot; end end function RobotMgr:RegisterMsg( msgname, callbackname ) if self.MsgNames[msgname]==nil then self._EventRegister:RegisterEvent( msgname, self, self.DispatchMsg ); self.MsgNames[msgname] = callbackname; end end function RobotMgr:DispatchMsg( from, msgin ) local robot = self.RobotList[from]; if robot~=nil then --robot.Game:cbXXX(msgin); end end function RobotMgr:Update() for _,v in pairs(self.RobotList) do v:Update(); end end function RobotMgr:Print( str, id ) if (#self.PrintFilterWhite)==0 then nlinfo("UID:"..id .. " "..str); else if self.PrintFilterWhite[id]~=nil then nlinfo("UID:"..id .. " "..str); end end end function RobotMgr:PrintTable( tbl, id ) if (#self.PrintFilterWhite)==0 then local str = JsonUtil.serialise_value(tbl, indent, depth); nlinfo("UID:"..id .. " "..str); else if self.PrintFilterWhite[id]~=nil then local str = JsonUtil.serialise_value(tbl, indent, depth); nlinfo("UID:"..id .. " "..str); end end end function RobotMgr:Release() end function RobotMgr:LuaTestCB( from, msgin ) local msgint = msgin:rint(); local msgstr = msgin:rstring(); nlinfo(from); nlinfo(msgint); nlinfo(msgstr); local msgout = CMessage("TestMainProc"); msgout:wstring("TestMainProc"); Misc.PostMain( G_ThreadHandle, msgout ); end function RobotMgr:cbAuthOk( from, msgin ) local robot = self.RobotList[from]; if robot~=nil then nlinfo("RobotMgr:cbAuthOk"); end end function RobotMgr:cbSyncPlayerInfo( from, msgin ) local robot = self.RobotList[from]; if robot~=nil then robot:cbSyncPlayerInfo(msgin); end end function RobotMgr:cbDdzGameInfo( from, msgin ) local robot = self.RobotList[from]; if robot~=nil then robot.Game:cbDdzGameInfo(msgin); end end function RobotMgr:cbDdzUserStartReady( from, msgin ) local robot = self.RobotList[from]; if robot~=nil then robot.Game:cbDdzUserStartReady(msgin); end end function RobotMgr:cbDDZ_QDZ_QX( from, msgin ) local robot = self.RobotList[from]; if robot~=nil then local msg_qdz = msgin:rpb("PB.MsgQiangDiZhu"); robot.Game:cbDDZ_QDZ_QX(msg_qdz); end end function RobotMgr:cbDDZ_QDZ_F( from, msgin ) local robot = self.RobotList[from]; if robot~=nil then local msg_qdz_res = msgin:rpb("PB.MsgBRQiangDiZhuResult"); robot.Game:cbDDZ_QDZ_F(msg_qdz_res); end end function RobotMgr:cbDDZ_RA( from, msgin ) local robot = self.RobotList[from]; if robot~=nil then local msg_ddz_act = msgin:rpb("PB.MsgDDZActon"); robot.Game:cbDDZ_RA(msg_ddz_act); end end function RobotMgr:cbDDZ_SD( from, msgin ) local robot = self.RobotList[from]; if robot~=nil then local msg_ddz_sd = msgin:rpb("PB.MsgDDZRoomShowDown"); robot.Game:cbDDZ_SD(msg_ddz_sd); end end return RobotMgr; ================================================ FILE: code/EVA/server/script/__Robot/RobotSub/RobotSubStart.lua ================================================ local BasePath = Misc.GetBasePath() .. "/script/"; package.path = BasePath .. "__Robot/RobotSub/?.lua;" .. BasePath .. "Framework/?.lua;"; require("InitFramework") require("RobotMgr") require("PublicRoomInfoMgr") FSMRobot = require("FSMRobot") RobotGameBase = require("RobotGameBase") RobotData = require("RobotData") Robot = require("Robot") PublicRoomInfo = require("PublicRoomInfo") FSMDdz = require("GameDdz/FSMDdz") RobotGameDdz = require("GameDdz/RobotGameDdz") nlinfo("-=======DBSubStart==========-"); G_ThreadHandle = 999; function ThreadInit( thread_handle, params ) nlinfo("Lua ThreadInit:".. thread_handle); nlinfo(params); G_ThreadHandle = thread_handle; PublicRoomInfoMgr:Init(); RobotMgr:Init(); RobotMgr:StartLogic(1, 3); end function ThreadUpdate() TimerMgr:Update( Misc.GetLocalTime() ); RobotMgr:Update(); end ================================================ FILE: code/EVA/server/script/__Robot/Test/CppTimerBase.lua ================================================ local CppTimerBase = class("CppTimerBase") function CppTimerBase:ctor() self.val = 0; self._TimerHandle = TimerMgr:AddTimer( 5000, self, self.TickUpdate); end function CppTimerBase:TickUpdate() --nlinfo("RoomBase:TickUpdate"); self:BaseTickUpdate(); end function CppTimerBase:BaseTickUpdate() --nlinfo("RoomBase:BaseTickUpdate"); self._TimerHandle = TimerMgr:AddTimer( 5000, self, self.TickUpdate); self.val = self.val+1; print("======"..self.val.." _TimerHandle:"..self._TimerHandle); end --释放函数 function CppTimerBase:Release() self.Timer = nil; end return CppTimerBase; ================================================ FILE: code/EVA/server/script/__Robot/Test/CppTimerTest.lua ================================================ local CppTimerTest = class("CppTimerTest", CppTimerBase) function CppTimerTest:ctor() self.super:ctor(); end return CppTimerTest; ================================================ FILE: code/EVA/server/script/__Robot/ThreadMgr.lua ================================================ ThreadMgr = {} function ThreadMgr:Init() self._EventRegister = EventRegister.new(); self._EventRegister:RegisterEvent( "TestMainProc", self, self.LuaTestCB ); self._ThreadMap = {}; end function ThreadMgr:Strat() local RobotSubPath = Misc.GetBasePath() .. "/script/__Robot/RobotSub/RobotSubStart.lua"; for i=1003,1003 do local sub_thread = bin_types.LuaThread.NewInstance("robot", 1000); local thread_handle = sub_thread:Start( RobotSubPath, Table2Json({uid=i, b=2}) ); self._ThreadMap[thread_handle] = sub_thread; nlinfo(thread_handle); end local msg = CMessage("TestSubProc"); msg:wint(111222); msg:wstring("string"); self._ThreadMap[0]:Post(msg); end function ThreadMgr:LuaTestCB( from, msgin ) local msgstr = msgin:rstring(); nlinfo(from); nlinfo(msgstr); end function ThreadMgr:LuaTestCB( from, msgin ) local msgstr = msgin:rstring(); nlinfo(from); nlinfo(msgstr); end --释放函数 function ThreadMgr:Release() self._EventRegister:UnRegisterAllEvent(); end return ThreadMgr; ================================================ FILE: code/EVA/server/script/__Robot/_ClientRobotMain.lua ================================================ --========================================================= -- 加载常用模块 --========================================================= local BasePath = Misc.GetBasePath() .. "/script/"; package.path = BasePath .. "__Robot/?.lua;" .. BasePath .. "SharedLib/?.lua;"; require("InitSharedLib") require("ThreadMgr"); --CppTimerBase = require("Test/CppTimerBase"); --CppTimerTest = require("Test/CppTimerTest"); -- 主入口函数。从这里开始lua逻辑 function ServiceInit() nlinfo("Lua Robot Init"); ThreadMgr:Init(); ThreadMgr:Strat(); end -- 主循环 function ServiceUpdate() local curr_tick = Misc.GetLocalTime(); TimerMgr:Update( curr_tick ); end function ServiceRelease() ThreadMgr:Release(); nlinfo("Lua Release."); end function ServiceInfo() end ================================================ FILE: code/EVA/server/server_share/CMakeLists.txt ================================================ FILE(GLOB SRC *.c *.cpp *.h) FILE(GLOB SRC_PROTO_MSG msg_proto/*.h msg_proto/*.cc) FILE(GLOB SRC_LUA lua/*.h lua/*.cpp) FILE(GLOB SRC_LUABIND bin_luabind/*.h bin_luabind/*.cpp) FILE(GLOB SRC_LUACJson cjson/*.h cjson/*.cpp) FILE(GLOB SRC_PBC pbc/*.h pbc/*.cpp) FILE(GLOB SRC_LUAMySQL lua_mysql/*.h lua_mysql/*.cpp) FILE(GLOB SRC_LUANET lua_net/*.h lua_net/*.cpp) SOURCE_GROUP("MessageProto" FILES ${SRC_PROTO_MSG}) SOURCE_GROUP("Lua" FILES ${SRC_LUA}) SOURCE_GROUP("LuaBind" FILES ${SRC_LUABIND}) SOURCE_GROUP("LuaCJson" FILES ${SRC_LUACJson}) SOURCE_GROUP("LuaPBC" FILES ${SRC_PBC}) SOURCE_GROUP("LuaMySQL" FILES ${SRC_LUAMySQL}) SOURCE_GROUP("LuaNet" FILES ${SRC_LUANET}) NL_TARGET_LIB(servershare ${SRC} ${SRC_PROTO_MSG} ${SRC_LUA} ${SRC_LUABIND} ${SRC_LUACJson} ${SRC_PBC} ${SRC_LUAMySQL} ${SRC_LUANET}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/server/src/server_share ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR} ${MYSQL_INCLUDE_DIR} ${LUA_INCLUDE_DIR} ${PROTOBUF_INCLUDE_DIR} ${PBC_INCLUDE_DIR} ${CURL_INCLUDE_DIR}) TARGET_LINK_LIBRARIES( servershare nelmisc nelnet ${OPENSSL_LIBRARIES} ${CURL_LIBRARY} ${LIBXML2_LIBRARIES} ${LUA_LIBRARIES} # ${PBC_LIBRARY} ${MYSQL_LIBRARIES} ${ZLIB_LIBRARIE_RELEASE} ) NL_DEFAULT_PROPS(servershare "Base, Library: Service Shared") NL_ADD_RUNTIME_FLAGS(servershare) NL_ADD_LIB_SUFFIX(servershare) ADD_DEFINITIONS(${LIBXML2_DEFINITIONS}) IF(WITH_PCH) ADD_NATIVE_PRECOMPILED_HEADER(servershare ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.h ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.cpp) ENDIF(WITH_PCH) #INSTALL(TARGETS servershare LIBRARY DESTINATION ${EVA_LIB_PREFIX} ARCHIVE DESTINATION ${EVA_LIB_PREFIX} COMPONENT libraries) IF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC) INSTALL(TARGETS servershare LIBRARY DESTINATION lib ARCHIVE DESTINATION lib COMPONENT libraries) ENDIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC) ================================================ FILE: code/EVA/server/server_share/base_object.h ================================================ #ifndef BASE_OBJECT_H #define BASE_OBJECT_H class CBaseObject { }; #endif ================================================ FILE: code/EVA/server/server_share/bin_luabind/Public.h ================================================ #ifndef SERVER_SHARD_LUA_PUBLIC_H #define SERVER_SHARD_LUA_PUBLIC_H #ifndef LUA_COMPAT_MODULE #define LUA_COMPAT_MODULE #endif #include "lua.hpp" #include #include #include #include #define LOG_MESSAGE nlwarning #endif ================================================ FILE: code/EVA/server/server_share/bin_luabind/Public.hpp ================================================ #pragma once #include "ScriptBase.h" #include "ScriptHandle.h" #include "ScriptProxy.h" #include "ScriptExporter.h" ================================================ FILE: code/EVA/server/server_share/bin_luabind/ScriptBase.cpp ================================================ #ifndef NL_OS_WINDOWS #include "ScriptBase.h" #include "ScriptExporter.h" #include "ScriptProxy.h" namespace bin { /* template // If a object, must be a proxy int TToLua::Make(O* o, lua_State* pL) { int nRet = 0; if (o) { if (o->GetScriptObject().IsExported()) { nRet = o->GetScriptObject().GetUserData(pL); } else { nRet = bin::ScriptExporterManager().AddScriptObject(o, pL); } } if (!nRet) { lua_pushnil(pL); nRet = 1; } return nRet; } template // If a object, must be a proxy int TFmLua::Make(lua_State* pL, int nIdx, O*& o) { o = NULL; if (!lua_isuserdata(pL, nIdx)) { return 0; } void* pUd = lua_touserdata(pL, nIdx); if (!pUd) { return 0; } SScriptProxy* pProxy = (SScriptProxy*)pUd; if (!(pProxy->ePT&SScriptProxy::EPT_OBJECT)) { return 0; } if (!pProxy->objRef.pObject) { return 0; } o = reinterpret_cast(pProxy->objRef.pObject->m_pThis); return 1; } */ }; #endif // !NL_OS_WINDOWS ================================================ FILE: code/EVA/server/server_share/bin_luabind/ScriptBase.h ================================================ #ifndef SERVER_SHARD_SCRIPT_BASE_H #define SERVER_SHARD_SCRIPT_BASE_H #include "Public.h" #include "ScriptProxy.h" namespace bin { static const char* SCRIPT_OWN_OBJECTS = "__bin_own_objects"; static const char* SCRIPT_USE_OBJECTS = "__bin_use_objects"; static const char* SCRIPT_REFS = "__bin_refs"; static const char* SCRIPT_TYPES = "__bin_types"; //extern void LOG_MESSAGE(const char* pszFmt, ...); class INonCopyable { public: INonCopyable(){} INonCopyable(INonCopyable&); INonCopyable& operator = (INonCopyable&); }; struct SCheckLuaStack { lua_State* pLua; int nTop; SCheckLuaStack(lua_State* pL) : pLua(pL) , nTop(-1) { if(pLua) { nTop = lua_gettop(pLua); } } ~SCheckLuaStack() { if(pLua) { lua_settop(pLua, nTop); pLua = NULL; nTop = -1; } } }; #define CHECK_LUA_STACK(l) SCheckLuaStack __checkStack(l) struct SGuardLuaGC { lua_State* pLua; SGuardLuaGC(lua_State* pL) : pLua(pL) { if(pLua) { lua_gc(pLua, LUA_GCSTOP, 0); } } ~SGuardLuaGC() { if(pLua) { lua_gc(pLua, LUA_GCRESTART, 0); pLua = NULL; } } }; #define GUARD_LUA_GC(l) SGuardLuaGC __guardGC(l) struct SVoidType { }; inline SVoidType __ret_void_tag() { return SVoidType();} #define RET_VOID bin::__ret_void_tag() template struct TRetType { typedef R return_type; }; template <> struct TRetType { typedef SVoidType return_type; }; template struct TToLua; template <> struct TToLua { static int Make(SVoidType v, lua_State* pL) { lua_pushnil(pL); return 1; } }; template <> struct TToLua { static int Make(bool a, lua_State* pL) { lua_pushboolean(pL, a); return 1; } }; //template <> //struct TToLua //{ // static int Make(int a, lua_State* pL) // { // lua_pushinteger(pL, (LUA_INTEGER)a); // return 1; // } //}; template <> struct TToLua { static int Make(double a, lua_State* pL) { lua_pushnumber(pL, a); return 1; } }; template <> struct TToLua { static int Make(sint64 a, lua_State* pL) { lua_pushinteger(pL, (LUA_INTEGER)a); return 1; } }; template <> struct TToLua { static int Make(sint32 a, lua_State* pL) { lua_pushinteger(pL, (LUA_INTEGER)a); return 1; } }; template <> struct TToLua { static int Make(char* a, lua_State* pL) { lua_pushstring(pL, a); return 1; } }; template <> struct TToLua { static int Make(const char* a, lua_State* pL) { lua_pushstring(pL, a); return 1; } }; template <> struct TToLua { static int Make(const std::string& a, lua_State* pL) { lua_pushlstring(pL, a.c_str(), a.size()); return 1; } }; template // If a object, must be a proxy struct TToLua { //#ifdef NL_OS_WINDOWS static int Make(O* o, lua_State* pL) { int nRet = 0; if(o) { if(o->GetScriptObject().IsExported()) { nRet = o->GetScriptObject().GetUserData(pL); } else { nRet = o->AddScriptObject(pL); //ScriptExporterManager().AddScriptObject(o, pL); } } if(!nRet) { lua_pushnil(pL); nRet = 1; } return nRet; } //#else // static int Make(O* o, lua_State* pL); //#endif }; template struct TFmLua; template <> struct TFmLua { static int Make(lua_State* pL, int nIdx, SVoidType& v) { return 1; } }; template <> struct TFmLua { static int Make(lua_State* pL, int nIdx, bool& b) { if(!lua_isboolean(pL, nIdx)) { return 0; } b = lua_toboolean(pL, nIdx)!=0; return 1; } }; template <> struct TFmLua { static int Make(lua_State* pL, int nIdx, sint32& a) { if(!lua_isnumber(pL, nIdx)) { return 0; } a = (sint32)lua_tointeger(pL, nIdx); return 1; } }; template <> struct TFmLua { static int Make(lua_State* pL, int nIdx, sint64& a) { if(!lua_isnumber(pL, nIdx)) { return 0; } a = (sint64)lua_tointeger(pL, nIdx); return 1; } }; template <> struct TFmLua { static int Make(lua_State* pL, int nIdx, double& d) { if(!lua_isnumber(pL, nIdx)) { return 0; } d = lua_tonumber(pL, nIdx); return 1; } }; template <> struct TFmLua { static int Make(lua_State* pL, int nIdx, std::string& str) { if(!lua_isstring(pL, nIdx)) { return 0; } str = lua_tostring(pL, nIdx); return 1; } }; template <> struct TFmLua { static int Make(lua_State* pL, int nIdx, const char*& cstr) { if(!lua_isstring(pL, nIdx)) { return 0; } cstr = lua_tostring(pL, nIdx); return 1; } }; // Partial specialization Not support by function, use class instead template // If a object, must be a proxy struct TFmLua { //#ifdef NL_OS_WINDOWS static int Make(lua_State* pL, int nIdx, O*& o) { o = NULL; if(!lua_isuserdata(pL, nIdx)) { return 0; } void* pUd = lua_touserdata(pL, nIdx); if(!pUd) { return 0; } SScriptProxy* pProxy = (SScriptProxy*)pUd; if(!(pProxy->ePT&SScriptProxy::EPT_OBJECT)) { return 0; } if(!pProxy->objRef.pObject) { return 0; } //o = reinterpret_cast(pProxy->objRef.pObject->m_pThis); o = reinterpret_cast(pProxy->objRef.GetScriptObj()); return 1; } //#else // static int Make(lua_State* pL, int nIdx, O*& o); //#endif }; template struct TArgumentType { typedef T value_type; typedef T& argument_type; typedef const T& c_argument_type; }; template struct TArgumentType { typedef T value_type; typedef T& argument_type; typedef const T& c_argument_type; }; template struct TArgumentType { typedef T value_type; typedef T& argument_type; typedef const T& c_argument_type; }; template struct TArgumentType { typedef T* value_type; typedef T* argument_type; typedef T* c_argument_type; }; template <> struct TArgumentType { typedef SVoidType value_type; typedef SVoidType argument_type; typedef SVoidType c_argument_type; }; template <> struct TArgumentType { typedef int value_type; typedef int argument_type; typedef int c_argument_type; }; template <> struct TArgumentType { typedef bool value_type; typedef bool argument_type; typedef bool c_argument_type; }; template <> struct TArgumentType { typedef double value_type; typedef double argument_type; typedef double c_argument_type; }; template <> struct TArgumentType { typedef long long value_type; typedef long long argument_type; typedef long long c_argument_type; }; template struct TLuaFuncCaller; template struct TLuaFuncCaller { F* pFun; lua_State* pLua; TLuaFuncCaller(lua_State* pL, F* pF) : pLua(pL), pFun(pF) { assert(pLua && pFun); } int MakeArgs() { return 1; } int MakeCArgs() { TFmLua::Make(pLua, 1, pFun->obj); if(!pFun->obj) { return 0; } return 1; } int Call() { return pFun->Exec(); } int MakeRet() { return TToLua::Make(pFun->r, pLua); } }; template struct TLuaFuncCaller { typedef typename TArgumentType::value_type Arg; Arg a; F* pFun; lua_State* pLua; TLuaFuncCaller(lua_State* pL, F* pF) : pLua(pL), pFun(pF) { assert(pLua && pFun); } int MakeArgs() { TFmLua::Make(pLua, 1, a); return 1; } int MakeCArgs() { TFmLua::Make(pLua, 1, pFun->obj); if(!pFun->obj) { return 0; } TFmLua::Make(pLua, 2, a); return 1; } int Call() { return pFun->Exec(a); } int MakeRet() { return TToLua::Make(pFun->r, pLua); } }; template struct TLuaFuncCaller { typedef typename TArgumentType::value_type Arg0; typedef typename TArgumentType::value_type Arg1; Arg0 a0; Arg1 a1; F* pFun; lua_State* pLua; TLuaFuncCaller(lua_State* pL, F* pF) : pLua(pL), pFun(pF) { assert(pLua && pFun); } int MakeArgs() { TFmLua::Make(pLua, 1, a0); TFmLua::Make(pLua, 2, a1); return 1; } int MakeCArgs() { TFmLua::Make(pLua, 1, pFun->obj); if(!pFun->obj) { return 0; } TFmLua::Make(pLua, 2, a0); TFmLua::Make(pLua, 3, a1); return 1; } int Call() { return pFun->Exec(a0, a1); } int MakeRet() { return TToLua::Make(pFun->r, pLua); } }; //! Define a script module(a lua table) //! \param modName the name of table #define BEGIN_SCRIPT_MODULE(modName)\ namespace __module_ ## modName\ {\ namespace __module = __module_ ## modName;\ static const char* __pszName = #modName;\ struct SModuleFunction_ ## modName;\ typedef SModuleFunction_ ## modName __mf_LinkNode;\ static __mf_LinkNode* __pHead = NULL;\ struct SModuleFunction_ ## modName : ModuleFunctionLinkNode\ {\ SModuleFunction_ ## modName(const char* pN, lua_CFunction pF)\ {\ pszName = pN;\ pFunc = pF;\ pNxt = __module::__pHead;\ __module::__pHead = this;\ }\ }; //! Define a module function(a function of the lua tabel) //! \param name name of function //! \param ret return type //! \param args the arguments //! for example : //! DEFINE_MODULE_FUNCTION(func, std::string, (int a0, int a1)) //! { //! int v = a0+a1; // a0 and a1 comes from lua //! r = "this is return value"; // The return value to lua //! return 1; // return 1 means succeed, not the return value to lua //! } #define DEFINE_MODULE_FUNCTION(name, ret, args)\ struct __mf_Impl_##name\ {\ typedef TRetType< ret >::return_type return_type;\ return_type r;\ bin::CScriptHandle lua;\ int Exec args;\ };\ static int __mf_lua_ ## name(lua_State* pL)\ {\ __mf_Impl_##name __mf_impl;\ __mf_impl.lua.Init(pL);\ TLuaFuncCaller<__mf_Impl_##name, ret args> caller(pL, &__mf_impl);\ if(!caller.MakeArgs() || !caller.Call() || !caller.MakeRet())\ {\ return 0;\ }\ return 1;\ }\ static __mf_LinkNode __mf_node_ ## name(#name, &__mf_lua_ ## name);\ int __mf_Impl_##name::Exec args //! End the definition of a module. #define END_SCRIPT_MODULE()\ static CModuleExporter __exporter(__module::__pszName, (ModuleFunctionLinkNode**)&__module::__pHead);\ }; //! Define a script class. //! \param clsName the name of this class. //! \param cppName the c++ class name #define BEGIN_SCRIPT_CLASS(clsName, cppName)\ namespace __class_ ## clsName\ {\ namespace __class = __class_ ## clsName;\ typedef cppName class_type;\ const char* __pszName = #clsName;\ const char* __pszSuper = NULL;\ struct SClassFunction_ ## clsName;\ typedef SClassFunction_ ## clsName __cf_LinkNode;\ static __cf_LinkNode* __pHead = NULL;\ struct SClassFunction_ ## clsName : ClassFunctionLinkNode\ {\ SClassFunction_ ## clsName(const char* pN, lua_CFunction pF)\ {\ pszName = pN;\ pFunc = pF;\ pNxt = __class::__pHead;\ __class::__pHead = this;\ }\ }; //! Indicates the super class name. //! \param clsName the lua class name. //! \param cppName the c++ class name. #define SUPER_CLASS(clsName, cppName)\ struct SSetSuper_ ## clsName\ {\ SSetSuper_ ## clsName()\ {\ __class::__pszSuper = #clsName;\ }\ };\ SSetSuper_ ## clsName __setSuper; //! Define a class member function. you can access the c++ object by obj and return the value by set value to r. //! If the userdata is invalid, obj is null. #define DEFINE_CLASS_FUNCTION(name, ret, args)\ struct __cf_Impl_##name\ {\ typedef TRetType< ret >::return_type return_type;\ typedef __class::class_type class_type;\ class_type* obj;\ return_type r;\ int Exec args;\ };\ static int __cf_lua_ ## name(lua_State* pL)\ {\ __cf_Impl_##name __cf_impl;\ TLuaFuncCaller<__cf_Impl_##name, ret args> caller(pL, &__cf_impl);\ if(!caller.MakeCArgs() || !caller.Call() || !caller.MakeRet())\ {\ return 0;\ }\ return 1;\ }\ static __cf_LinkNode __cf_node_ ## name(#name, &__cf_lua_ ## name);\ int __cf_Impl_##name::Exec args #define DEFINE_STATIC_FUNCTION(name, ret, args)\ struct __cf_Impl_##name\ {\ typedef TRetType< ret >::return_type return_type;\ typedef __class::class_type class_type;\ return_type r;\ int Exec args;\ };\ static int __cf_lua_ ## name(lua_State* pL)\ {\ __cf_Impl_##name __cf_impl;\ TLuaFuncCaller<__cf_Impl_##name, ret args> caller(pL, &__cf_impl);\ if(!caller.MakeArgs() || !caller.Call() || !caller.MakeRet())\ {\ return 0;\ }\ return 1;\ }\ static __cf_LinkNode __cf_node_ ## name(#name, &__cf_lua_ ## name);\ int __cf_Impl_##name::Exec args //! End the definition of a class. #define END_SCRIPT_CLASS()\ static CClassExporter __exporter(__class::__pszSuper, __class::__pszName, (ClassFunctionLinkNode**)&__class::__pHead);\ struct __cf_Record\ {\ __cf_Record()\ {\ __class::class_type::ClassExporter() = &__class::__exporter;\ }\ };\ static __cf_Record __recorder;\ }; //! Declare a class will be a script class. this declaration must be the base class, any sub-class of the class must be taged with DECLARE_SCRIPT_SUB_CLASS. #define DECLARE_SCRIPT_CLASS()\ public:\ bin::SScriptObject __m_scrObj;\ const bin::SScriptObject& GetScriptObject() const\ {\ return __m_scrObj;\ }\ bin::SScriptObject& GetScriptObject()\ {\ return __m_scrObj;\ }\ int AddScriptObject( lua_State* pL )\ {\ return bin::ScriptExporterManager().AddScriptObject(this, pL);\ }\ bin::CScriptHandle& GetScriptHandle()\ {\ return GetScriptObject().GetScriptHandle();\ }\ int GetScriptUserData(bin::CScriptUserData& scriptUserData)\ {\ return GetScriptObject().GetUserData(scriptUserData);\ }\ bool IsExported()\ {\ return GetScriptObject().IsExported();\ }\ virtual bin::CClassExporter* GetExporter() const\ {\ return ClassExporter();\ }\ static bin::CClassExporter*& ClassExporter()\ {\ static bin::CClassExporter* s_exporter = NULL;\ return s_exporter;\ }\ private: //! Taged a child class #define DECLARE_SCRIPT_SUB_CLASS(superCls)\ public:\ typedef superCls Super;\ virtual bin::CClassExporter* GetExporter() const\ {\ return ClassExporter();\ }\ static bin::CClassExporter*& ClassExporter()\ {\ static bin::CClassExporter* s_exporter = NULL;\ return s_exporter;\ }\ private: }; #endif ================================================ FILE: code/EVA/server/server_share/bin_luabind/ScriptExporter.cpp ================================================ // #include "Public.h" // #include "ScriptExporter.h" // #include "ScriptBase.h" // #include namespace bin { // void LOG_MESSAGE(const char* pszFmt, ...) // { // static char s_szBuffer[1024] = {0}; // // va_list ls; // va_start(ls, pszFmt); // // _vsnprintf(s_szBuffer, 1024, pszFmt, ls); // // va_end(ls); // // static std::ofstream ofstr; // if(!ofstr.is_open()) // { // ofstr.open("bin_script.log"); // } // // ofstr<< s_szBuffer<< std::endl; //#if defined _DEBUG // // To Console // std::cout<< s_szBuffer<< std::endl; //#endif // // } int CScriptExporterManager::ExportClass(const char* pszName, lua_State* pL, const char* pszNameSpace /*= NULL*/) { ExporterIterator pos = m_scriptExporters.find(pszName); if(pos != m_scriptExporters.end()) { SExporterInfo info = pos->second->GetInfo(); if(info.eET != SExporterInfo::EET_CLASS) { return 0; } CClassExporter* pClsExp = (CClassExporter*)(pos->second); return pClsExp->Export(pL, pszNameSpace); } return 0; } int CScriptExporterManager::ExportModule(const char* pszName, lua_State* pL) { ExporterIterator pos = m_scriptExporters.find(pszName); if(pos != m_scriptExporters.end()) { SExporterInfo info = pos->second->GetInfo(); if(info.eET != SExporterInfo::EET_MODULE) { return 0; } return pos->second->Export(pL); } return 0; } int CScriptExporterManager::ExportModuleTo(const char* pszName, lua_State* pL, CScriptTable& scriptTable) { assert(scriptTable.GetHandle() == pL); ExporterIterator pos = m_scriptExporters.find(pszName); if(pos != m_scriptExporters.end()) { SExporterInfo info = pos->second->GetInfo(); if(info.eET != SExporterInfo::EET_MODULE) { return 0; } CModuleExporter& exporter = (CModuleExporter&)*(pos->second); return exporter.ExportTo(pL, scriptTable); } return 0; } BEGIN_SCRIPT_MODULE(exporterManager) DEFINE_MODULE_FUNCTION(exportClass, bool, (const char* pszName, const std::string& strNameSpace)) { if(strNameSpace.empty()) { r = ScriptExporterManager().ExportClass(pszName, lua) != 0; } else { r = ScriptExporterManager().ExportClass(pszName, lua, strNameSpace.c_str()) != 0; } return 1; } DEFINE_MODULE_FUNCTION(exportModule, bool, (const char* pszName, CScriptTable& tbl)) { if(!tbl.IsReferd()) { r = ScriptExporterManager().ExportModule(pszName, lua) != 0; } else { r = ScriptExporterManager().ExportModuleTo(pszName, lua, tbl) != 0; } return 1; } END_SCRIPT_MODULE() }; ================================================ FILE: code/EVA/server/server_share/bin_luabind/ScriptExporter.h ================================================ #ifndef SERVER_SHARD_SCRIPT_EXPORTER_H #define SERVER_SHARD_SCRIPT_EXPORTER_H #include "ScriptBase.h" #include "ScriptProxy.h" #include "ScriptObject.h" namespace bin { struct SExporterInfo { enum EExporterType { EET_MODULE = 0, // A module, in lua just a table EET_FUNCTION, // Function EET_CLASS, // Class, in lua a userdata EET_SIZE, }; const char* pszName; EExporterType eET; SExporterInfo() : pszName(NULL) , eET(EET_SIZE) { } }; class IScriptExporter { public: virtual ~IScriptExporter(){} virtual int Export(lua_State* pL) = 0; virtual SExporterInfo GetInfo() const = 0; }; class CScriptExporterManager { public: typedef CHashMap ScriptExporters; typedef ScriptExporters::const_iterator ExporterIterator; public: CScriptExporterManager() { } // Internal used, the life of pExporter must be global int RegisterExporter(IScriptExporter* pExporter) { if(!pExporter) { return 0; } SExporterInfo info = pExporter->GetInfo(); std::pair ret = m_scriptExporters.insert(ScriptExporters::value_type(info.pszName, pExporter)); assert(ret.second && "ScriptBase.h [RegisterExporter] : Exporter conflict"); return 1; } // Internal used, The user data is on the top of stack template int AddScriptObject(T* pObj, lua_State* pL) { #if defined _DEBUG int nOldTop = lua_gettop(pL); #endif SScriptProxy* pProxy = (SScriptProxy*)lua_newuserdata(pL, sizeof(SScriptProxy)); if(!pProxy) { return 0; } new(pProxy) SScriptProxy; pProxy->ePT = SScriptProxy::EPT_OBJECT; pProxy->objRef.pObject = &pObj->GetScriptObject(); pProxy->objRef.pLua = pL; // Add property table for this object, this table will store the object field value lua_newtable(pL); lua_pushvalue(pL, -1); lua_setfield(pL, -2, "__newindex"); // Assign support lua_pushvalue(pL, -1); lua_setfield(pL, -2, "__index"); // Access support lua_pushstring(pL, "object"); lua_setfield(pL, -2, "type"); { lua_pushvalue(pL, -1); lua_setfield(pL, -2, "__bin_objtable"); // Setup object table, so we can set a new type on this object } // Set metatable to the new table, this metatable provides "class member functions" { SExporterInfo exporterInfo = pObj->GetExporter()->GetInfo(); assert(exporterInfo.eET == SExporterInfo::EET_CLASS); luaL_getmetatable(pL, exporterInfo.pszName); // Set __gc, __gc will be called when the userdata(or table) is destroyed lua_getfield(pL, -1, "__bin_gc"); lua_setfield(pL, -3, "__gc"); lua_setmetatable(pL, -2); } // Set the new table as the metatable of this userdata, now the object is on the stack // This metatable provides "class member fields and lua defined member functions" lua_setmetatable(pL, -2); // Add the object to objects table, objects table is on the stack CheckObjectsTable(pL, pObj->GetScriptObject().IsWeaked()); lua_pushvalue(pL, -2); // Set object to top pProxy->objRef.nRef = luaL_ref(pL, -2); lua_pop(pL, 1); // pop the objects table // Attach object to lua pObj->GetScriptObject().Attach(pObj, &pProxy->objRef); #if defined _DEBUG int nNewTop = lua_gettop(pL); assert(nNewTop == nOldTop+1); #endif return 1; } // Internal used, The user data is on the top of stack template T* NewScriptObject(lua_State* pL, bool bDelByScr = true) { T* pObj = new T(); pObj->GetScriptObject().SetDelByScr(bDelByScr); if(!AddScriptObject(pObj, pL)) { delete pObj; pObj = NULL; } return pObj; } // Internal used, The user data is on the top of stack template int AddScriptObject(const char* pszName, T* pObj, lua_State* pL) { if(!AddScriptObject(pObj, pL)) { return 0; } lua_pushvalue(pL, -1); lua_setglobal(pL, pszName); return 1; } // Internal used int CheckObjectsTable(lua_State* pL, bool bWeaked) { const char* pszName = bWeaked ? SCRIPT_OWN_OBJECTS : SCRIPT_USE_OBJECTS; lua_getfield(pL, LUA_REGISTRYINDEX, pszName); if(lua_isnil(pL, -1)) { lua_pop(pL, 1); // Pop the nil value lua_newtable(pL); //Set objects table as value weak table if(bWeaked) { lua_newtable(pL); lua_pushstring(pL, "v"); lua_setfield(pL, -2, "__mode"); lua_setmetatable(pL, -2); } lua_pushvalue(pL, -1); lua_setfield(pL, LUA_REGISTRYINDEX, pszName); } return 1; } // Internal used int CheckRefsTable(lua_State* pL) { lua_getfield(pL, LUA_REGISTRYINDEX, SCRIPT_REFS); if(lua_isnil(pL, -1)) { lua_pop(pL, 1); lua_newtable(pL); lua_pushvalue(pL, -1); lua_setfield(pL, LUA_REGISTRYINDEX, SCRIPT_REFS); } return 1; } // Internal used int CheckTypesTable(lua_State* pL) { lua_getfield(pL, LUA_REGISTRYINDEX, SCRIPT_TYPES); if(lua_isnil(pL, -1)) { lua_pop(pL, 1); lua_newtable(pL); lua_pushvalue(pL, -1); lua_setfield(pL, LUA_REGISTRYINDEX, SCRIPT_TYPES); lua_pushvalue(pL, -1); lua_setglobal(pL, "bin_types"); } return 1; } // Internal used int ExportClass(const char* pszName, lua_State* pL, const char* pszNameSpace = NULL); // Internal used int ExportModule(const char* pszName, lua_State* pL); // Internal used int ExportModuleTo(const char* pszName, lua_State* pL, CScriptTable& scriptTable); int ExportClass(const char* pszName, CScriptHandle& scriptHandle, const char* pszNameSpace = NULL) { if(scriptHandle.IsNull()) { return 0; } return ExportClass(pszName, scriptHandle.GetHandle(), pszNameSpace); } int ExportModule(const char* pszName, CScriptHandle& scriptHandle) { if(scriptHandle.IsNull()) { return 0; } return ExportModule(pszName, scriptHandle.GetHandle()); } int ExportModuleTo(const char* pszName, CScriptHandle& scriptHandle, const char* pszTableName) { // Get the table CScriptTable scriptTable; scriptHandle.Get(pszTableName, scriptTable); bool bNewed = !scriptTable.IsReferd(); int ret = ExportModuleTo(pszName, scriptHandle, scriptTable); if(ret && bNewed) // The table is a new table ? { scriptHandle.Set(pszTableName, scriptTable); } return ret; } int ExportModuleTo(const char* pszName, CScriptHandle& scriptHandle, CScriptTable& scriptTable) { if(scriptHandle.IsNull()) { return 0; } bool bNeedUnref = false; if(!scriptTable.IsReferd()) { scriptHandle.NewTable(scriptTable); bNeedUnref = true; } int ret = ExportModuleTo(pszName, scriptHandle.GetHandle(), scriptTable); if(!ret && bNeedUnref) { scriptTable.UnRef(); } return ret; } private: ScriptExporters m_scriptExporters; }; inline CScriptExporterManager& ScriptExporterManager() { static CScriptExporterManager s_scriptExpoterManager; return s_scriptExpoterManager; } struct SModuleFunction { const char* pszName; lua_CFunction pFunc; SModuleFunction(const char* pN = NULL, lua_CFunction pF = NULL) : pszName(pN), pFunc(pF) { } }; struct SClassFunction { const char* pszName; lua_CFunction pFunc; SClassFunction(const char* pN = NULL, lua_CFunction pF = NULL) : pszName(pN), pFunc(pF) { } }; template struct TLinkNode : T { TLinkNode* pNxt; TLinkNode() : pNxt(NULL) { } }; typedef TLinkNode ModuleFunctionLinkNode; typedef TLinkNode ClassFunctionLinkNode; class CModuleExporter : public IScriptExporter { public: CModuleExporter(const char* pszName, ModuleFunctionLinkNode** ppHead) : m_pszModuleName(pszName) , m_ppHead(ppHead) { assert(m_pszModuleName && m_ppHead); ScriptExporterManager().RegisterExporter(this); } virtual int Export(lua_State* pL) { CHECK_LUA_STACK(pL); const ModuleFunctionLinkNode* pNode = GetModuleFunctionList(); // Empty module if(!pNode) { return 1; } const int SIZE_HINT = 10; luaL_pushmodule(pL, GetModuleName(), SIZE_HINT); while(pNode) { lua_pushcfunction(pL, pNode->pFunc); lua_setfield(pL, -2, pNode->pszName); pNode = pNode->pNxt; } lua_pushstring(pL, GetModuleName()); lua_setfield(pL, -2, "name"); lua_pushstring(pL, "module"); lua_setfield(pL, -2, "type"); lua_pushcfunction(pL, &__Imported); lua_setfield(pL, -2, "imported"); return 1; } int ExportTo(lua_State* pL, CScriptTable& scriptTable) { assert(scriptTable.GetHandle() == pL); CHECK_LUA_STACK(pL); const ModuleFunctionLinkNode* pNode = GetModuleFunctionList(); // Empty module if(!pNode) { return 1; } scriptTable.PrepareStack(); // table while(pNode) { lua_pushcfunction(pL, pNode->pFunc); // table, func lua_setfield(pL, -2, pNode->pszName); // table pNode = pNode->pNxt; } return 1; } SExporterInfo GetInfo() const { SExporterInfo info; info.pszName = GetModuleName(); info.eET = SExporterInfo::EET_MODULE; return info; } const char* GetModuleName() const { return m_pszModuleName; } const ModuleFunctionLinkNode* GetModuleFunctionList() const { return *m_ppHead; } protected: static int __Imported(lua_State* pL) { lua_pushboolean(pL, true); return 1; } private: const char* m_pszModuleName; ModuleFunctionLinkNode** m_ppHead; }; class CClassExporter : public IScriptExporter { public: CClassExporter(const char* pszSuper, const char* pszName, ClassFunctionLinkNode** ppHead) : m_pszSuperName(pszSuper) , m_pszClassName(pszName) , m_ppHead(ppHead) { assert(m_pszClassName && m_ppHead); ScriptExporterManager().RegisterExporter(this); } int Export(lua_State* pL, const char* pszNameSpace) { CHECK_LUA_STACK(pL); if(luaL_newmetatable(pL, GetClassName()) != 0) // Has not been exported ? { lua_pushstring(pL, GetClassName()); lua_setfield(pL, -2, "name"); lua_pushstring(pL, "class"); lua_setfield(pL, -2, "type"); lua_pushvalue(pL, -1); lua_setfield(pL, -2, "__index"); lua_pushcfunction(pL, &__GC); lua_setfield(pL, -2, "__bin_gc"); lua_pushcfunction(pL, &__Imported); lua_setfield(pL, -2, "imported"); if(m_pszSuperName) // Export the super class { ScriptExporterManager().ExportClass(m_pszClassName, pL, pszNameSpace); luaL_getmetatable(pL, m_pszSuperName); // newClass, superClass lua_pushvalue(pL, -1); // newClass, superClass, superClass lua_setfield(pL, -3, "super"); // newClass, superClass lua_setmetatable(pL, -2); } const ClassFunctionLinkNode* pNode = GetClassFunctionList(); while(pNode) { lua_pushcfunction(pL, pNode->pFunc); lua_setfield(pL, -2, pNode->pszName); pNode = pNode->pNxt; } } // Now type is on the stack { int nTypeIdx = -2; CHECK_LUA_STACK(pL); ScriptExporterManager().CheckTypesTable(pL); if(pszNameSpace) { lua_getfield(pL, -1, pszNameSpace); // type, types, value if(lua_isnil(pL, -1)) { lua_pop(pL, 1); // type, types lua_newtable(pL); // type, types, namespace lua_pushvalue(pL, -1); // type, types, namespace, namespace lua_setfield(pL, -3, pszNameSpace);// type, types, namespace } else if(!lua_istable(pL, -1)) { luaL_error(pL, "namespace[%s] must be a table", pszNameSpace); } nTypeIdx = -3; } // Now the type table(or namespace) is on the stack lua_pushvalue(pL, nTypeIdx); // tbl, type lua_setfield(pL, -2, GetClassName()); } return 1; } virtual int Export(lua_State* pL) { return Export(pL, NULL); } SExporterInfo GetInfo() const { SExporterInfo info; info.pszName = GetClassName(); info.eET = SExporterInfo::EET_CLASS; return info; } const char* GetClassName() const { return m_pszClassName; } const ClassFunctionLinkNode* GetClassFunctionList() const { return *m_ppHead; } private: const char* m_pszSuperName; const char* m_pszClassName; ClassFunctionLinkNode** m_ppHead; // Static protected: static int __GC(lua_State* pL) { void* pUd = lua_touserdata(pL, 1); if(!pUd) { return 0; } SScriptProxy* pProxy = (SScriptProxy*)pUd; if(!(pProxy->ePT&SScriptProxy::EPT_OBJECT)) { return 0; } if(!pProxy->objRef.pObject) { return 0; } if(pProxy->objRef.pObject->GetDelByScr()) { pProxy->objRef.pObject->ReleaseByScr(); // Will call objRef.Unlink(); assert(!pProxy->objRef.pObject); } else { pProxy->objRef.Unlink(); } return 0; } // Check whether this lua object still reference to a c++ object static int __Imported(lua_State* pL) { bool bRet = false; SScriptProxy* pProxy = (SScriptProxy*)lua_touserdata(pL, 1); if(pProxy && (pProxy->ePT&SScriptProxy::EPT_OBJECT) && pProxy->objRef.pObject) { bRet = true; } lua_pushboolean(pL, bRet); return 1; } }; }; #endif ================================================ FILE: code/EVA/server/server_share/bin_luabind/ScriptHandle.cpp ================================================ // #include "Public.h" // #include "ScriptHandle.h" // #include "ScriptExporter.h" // namespace bin { //! Exec a lua file //! Initialize a CScriptHandle, NB. This CScriptHandle must be released state int CScriptHandle::Init() { assert(!m_pLua); m_pLua = luaL_newstate(); if(!m_pLua) { goto OPERATION_FAIL; } m_bOwn = true; { lua_State* L = m_pLua; const luaL_Reg loadedlibs[] = { {"_G", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_COLIBNAME, luaopen_coroutine}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, #if defined _DEBUG {LUA_DBLIBNAME, luaopen_debug}, #endif {NULL, NULL} }; const luaL_Reg* pos = loadedlibs; for(; pos->name; ++pos) { luaL_requiref(L, pos->name, pos->func, 1); lua_pop(L, 1); } } ScriptExporterManager().ExportModule("exporterManager", *this); return 1; OPERATION_FAIL: Release(); return 0; } int CScriptHandle::Exec(const char* pszFileName, CScriptTable& ret) { if(IsNull() || !pszFileName) { return 0; } CHECK_LUA_STACK(m_pLua); int nOldTop = lua_gettop(m_pLua); int nRet = luaL_dofile(m_pLua, pszFileName); if(nRet != LUA_OK) // Error, the error message is on the top { LOG_MESSAGE("[ERROR] Exec File[%s] : %s", pszFileName, lua_tostring(m_pLua, -1)); return 0; } else { int nCnt = lua_gettop(m_pLua)-nOldTop; if(nCnt != 0) { CHECK_LUA_STACK(m_pLua); if(!ret.IsReferd()) { NewTable(ret); } assert(ret.GetHandle() == GetHandle()); ret.PrepareStack(); // Set n lua_pushinteger(m_pLua, nCnt); lua_setfield(m_pLua, -2, "n"); for(int i=1; i<=nCnt; ++i) { lua_pushvalue(m_pLua, nOldTop+i); lua_rawseti(m_pLua, -2, i); } } else if(ret.IsReferd()) { ret.Set("n", nCnt); } } return 1; } //! Exec a lua string, ret contains the return value from string int CScriptHandle::ExecString(const char* pszString, CScriptTable& ret) { if(IsNull() || !pszString) { return 0; } CHECK_LUA_STACK(m_pLua); int nOldTop = lua_gettop(m_pLua); int nRet = luaL_dostring(m_pLua, pszString); if(nRet != LUA_OK) // Error, the error message is on the top { LOG_MESSAGE("[ERROR] Exec String : %s", lua_tostring(m_pLua, -1)); return 0; } else { int nCnt = lua_gettop(m_pLua)-nOldTop; if(nCnt != 0) { CHECK_LUA_STACK(m_pLua); if(!ret.IsReferd()) { NewTable(ret); } assert(ret.GetHandle() == GetHandle()); ret.PrepareStack(); // Set n lua_pushinteger(m_pLua, nCnt); lua_setfield(m_pLua, -2, "n"); for(int i=1; i<=nCnt; ++i) { lua_pushvalue(m_pLua, nOldTop+i); lua_rawseti(m_pLua, -2, i); } } else if(ret.IsReferd()) { ret.Set("n", nCnt); } } return 1; } int CScriptHandle::Get(const char* pszName, CScriptTable& tbl) { tbl.UnRef(); return PostFmLua(Get(pszName, tbl), tbl); } int CScriptHandle::Get(const char* pszName, CScriptUserData& ud) { ud.UnRef(); return PostFmLua(Get(pszName, ud), ud); } int CScriptHandle::PostFmLua(int nFmLuaRet, CScriptTable& tbl) { if(nFmLuaRet) { CScriptTable::RefNode& ref = tbl.m_ref; ref.LinkAfter(&m_head); } else { tbl.UnRef(); } return nFmLuaRet; } int CScriptHandle::PostFmLua(int nFmLuaRet, CScriptUserData& ud) { if(nFmLuaRet) { CScriptUserData::RefNode& ref = ud.m_ref; ref.LinkAfter(&m_head); } else { ud.UnRef(); } return nFmLuaRet; } void CScriptHandle::InvlRetVal(CScriptTable& tbl) { tbl.UnRef(); } void CScriptHandle::InvlRetVal(CScriptUserData& ud) { ud.UnRef(); } int CScriptHandle::NewTable(CScriptTable& tbl) { tbl.UnRef(); if(IsNull()) { return 0; } CHECK_LUA_STACK(m_pLua); lua_newtable(m_pLua); return PostFmLua(TFmLua::Make(m_pLua, -1, tbl), tbl); } int CScriptHandle::NewTable(const char* pszName, CScriptTable& tbl) { if(!NewTable(tbl)) { return 0; } if(!Set(pszName, tbl)) { tbl.UnRef(); } return tbl.IsReferd() ? 1 : 0; } int IScriptADBase::PrepareStack() { ScriptExporterManager().CheckRefsTable(m_ref.pLua); // __bin_refs lua_rawgeti(m_ref.pLua, -1, m_ref.nRef); // __bin_refs this_table return 1; } int IScriptADBase::PostFmLua(int nFmLuaRet, CScriptTable& tbl) { if(nFmLuaRet) { CScriptTable::RefNode& ref = tbl.m_ref; ref.LinkAfter(&m_ref); } else { tbl.UnRef(); } return nFmLuaRet; } int IScriptADBase::PostFmLua(int nFmLuaRet, CScriptUserData& ud) { if(nFmLuaRet) { CScriptUserData::RefNode& ref = ud.m_ref; ref.LinkAfter(&m_ref); } else { ud.UnRef(); } return nFmLuaRet; } void IScriptADBase::InvlRetVal(CScriptTable& tbl) { tbl.UnRef(); } void IScriptADBase::InvlRetVal(CScriptUserData& ud) { ud.UnRef(); } int IScriptADBase::Get(const char* pszName, CScriptTable& tbl) { tbl.UnRef(); return PostFmLua(Get(pszName, tbl), tbl); } int IScriptADBase::Get(const char* pszName, CScriptUserData& ud) { ud.UnRef(); return PostFmLua(Get(pszName, ud), ud); } int IScriptADBase::Get(int nIdx, CScriptTable& tbl) { tbl.UnRef(); return PostFmLua(Get(nIdx, tbl), tbl); } int IScriptADBase::Get(int nIdx, CScriptUserData& ud) { ud.UnRef(); return PostFmLua(Get(nIdx, ud), ud); } // Static void IScriptADBase::SRefNode::UnLinker(SScriptHandleRefNode* pT) { SRefNode* pThis = static_cast(pT); pThis->Unlink(); // UnLink to ref list if(pThis->pLua && pThis->nRef!=LUA_NOREF) { CHECK_LUA_STACK(pThis->pLua); ScriptExporterManager().CheckRefsTable(pThis->pLua); // Refs table is on the stack luaL_unref(pThis->pLua, -1, pThis->nRef); } pThis->pLua = NULL; pThis->nRef = LUA_NOREF; } int TFmLua::Make(lua_State* pL, int nIdx, CScriptTable& tbl) { tbl.UnRef(); if(!lua_istable(pL, nIdx)) { return 0; } CHECK_LUA_STACK(pL); nIdx = lua_absindex(pL, nIdx); // To absolute index, avoid negative index CScriptTable::RefNode& ref = tbl.m_ref; ScriptExporterManager().CheckRefsTable(pL); lua_pushvalue(pL, nIdx); ref.pLua = pL; ref.nRef = luaL_ref(pL, -2); return 1; } int TFmLua::Make(lua_State* pL, int nIdx, CScriptUserData& ud) { ud.UnRef(); if(!lua_isuserdata(pL, nIdx)) { return 0; } SScriptProxy* pProxy = (SScriptProxy*)lua_touserdata(pL, nIdx); if(!pProxy) { return 0; } // Check whether the proxy is associate with a valid object if(pProxy->ePT != SScriptProxy::EPT_OBJECT || !pProxy->objRef.pObject) { return 0; } CHECK_LUA_STACK(pL); nIdx = lua_absindex(pL, nIdx); // To absolute index, avoid negative index CScriptUserData::RefNode& ref = ud.m_ref; ScriptExporterManager().CheckRefsTable(pL); lua_pushvalue(pL, nIdx); ref.pLua = pL; ref.nRef = luaL_ref(pL, -2); return 1; } int TToLua::Make(CScriptTable& tbl, lua_State* pL) { if(!tbl.IsReferd()) { lua_pushnil(pL); return 1; } CScriptTable::RefNode& ref = tbl.m_ref; if(ref.pLua != pL) { return 0; } ScriptExporterManager().CheckRefsTable(pL); lua_rawgeti(pL, -1, ref.nRef); lua_replace(pL, -2); return 1; } int TToLua::Make(CScriptUserData& ud, lua_State* pL) { if(!ud.IsReferd()) { lua_pushnil(pL); return 1; } CScriptUserData::RefNode& ref = ud.m_ref; if(ref.pLua != pL) { return 0; } ScriptExporterManager().CheckRefsTable(pL); lua_rawgeti(pL, -1, ref.nRef); lua_replace(pL, -2); return 1; } } ================================================ FILE: code/EVA/server/server_share/bin_luabind/ScriptHandle.h ================================================ #ifndef SERVER_SHARD_SCRIPT_HANDLE_H #define SERVER_SHARD_SCRIPT_HANDLE_H #include "ScriptBase.h" namespace bin { struct SDBLinkNode { SDBLinkNode* pPre; SDBLinkNode* pNxt; SDBLinkNode() : pPre(NULL) , pNxt(NULL) { } void LinkAfter(SDBLinkNode* pNode) { pNxt = pNode->pNxt; pPre = pNode; pPre->pNxt = this; if(pNxt) { pNxt->pPre = this; } } void LinkBefore(SDBLinkNode* pNode) { pNxt = pNode; pPre = pNode->pPre; pNxt->pPre = this; if(pPre) { pPre->pNxt = this; } } void Unlink() { if(pPre) { pPre->pNxt = pNxt; } if(pNxt) { pNxt->pPre = pPre; } pPre = NULL; pNxt = NULL; } }; struct SScriptHandleRefNode : SDBLinkNode { typedef void (*UnLinker)(SScriptHandleRefNode*); UnLinker unLinker; SScriptHandleRefNode() : unLinker(NULL) { } }; class CScriptTable; class CScriptUserData; //! Encapsulate a lua_State, provide global setting and reading interface class CScriptHandle : INonCopyable { public: CScriptHandle() : m_bOwn(true) , m_pLua(NULL) { } ~CScriptHandle() { Release(); } //! Initialize a CScriptHandle, NB. This CScriptHandle must be released state int Init(); //! Initialize a CScriptHandle from file. int Init(const char* pszFileName) { if(!Init()) { return 0; } if(!Exec(pszFileName)) { goto OPERATION_FAIL; } return 1; OPERATION_FAIL: Release(); return 0; } //! Initialize a CScriptHandle from a exist lua_State. //! \param bOwn indicate whether CScriptHandle will own this pLua, if true, pLua will be closed while releasing this handle. int Init(lua_State* pLua, bool bOwn = false) { Release(); m_pLua = pLua; m_bOwn = bOwn; return 1; } //! Init from a lua string. int InitFmString(const char* pszString) { if(!Init()) { return 0; } if(!ExecString(pszString)) { goto OPERATION_FAIL; } return 1; OPERATION_FAIL: Release(); return 0; } //! Release this handle, if this handle owns lua_State, lua_State will be closed. //! All the tables and userdatas got from this handle will be unlinked( IsReferd() is false) void Release() { // Unlink all relations SScriptHandleRefNode* pNode = &m_head; SScriptHandleRefNode* pNxt = NULL; while(pNode) { pNxt = (SScriptHandleRefNode*)pNode->pNxt; if(pNode->unLinker) { pNode->unLinker(pNode); } pNode = pNxt; } if(m_pLua) { if(m_bOwn) { lua_close(m_pLua); } m_pLua = NULL; } assert(!m_head.pNxt && !m_head.pPre && !m_head.unLinker); } //! Exec a lua file int Exec(const char* pszFileName) { if(IsNull() || !pszFileName) { return 0; } CHECK_LUA_STACK(m_pLua); int nRet = luaL_dofile(m_pLua, pszFileName); if(nRet != LUA_OK) // Error, the error message is on the top { LOG_MESSAGE("[ERROR] Exec File[%s] : %s", pszFileName, lua_tostring(m_pLua, -1)); return 0; } return 1; } //! Exec a lua file int Exec(const char* pszFileName, CScriptTable& ret); //! Exec a lua string int ExecString(const char* pszString) { if(IsNull() || !pszString) { return 0; } CHECK_LUA_STACK(m_pLua); int nRet = luaL_dostring(m_pLua, pszString); if(nRet != LUA_OK) // Error, the error message is on the top { LOG_MESSAGE("[ERROR] Exec String : %s", lua_tostring(m_pLua, -1)); return 0; } return 1; } //! Exec a lua string, ret contains the return value from string int ExecString(const char* pszString, CScriptTable& ret); //! Check if this handle is Null. bool IsNull() const { return m_pLua == NULL; } //! Get the lua_State associated with this handle. lua_State* GetHandle() const { return m_pLua; } //! Get any thing from the global table in this handle. //! \param pszName the name of the variable. //! \param v the out value. //! \return 0-fail template int Get(const char* pszName, T& v) { if(IsNull()) { return 0; } CHECK_LUA_STACK(m_pLua); lua_getglobal(m_pLua, pszName); return TFmLua::value_type>::Make(m_pLua, -1, v); } //! Set anything in global table. //! \param pszName name of the variable. //! \param v input value. //! \return 0-fail template int Set(const char* pszName, T v) { if(IsNull()) { return 0; } CHECK_LUA_STACK(m_pLua); if(!TToLua::value_type>::Make(v, m_pLua)) { return 0; } lua_setglobal(m_pLua, pszName); return 1; } //! Set a table, template function must pass variable in value, so pass tbl in reference here. int Set(const char* pszName, CScriptTable& tbl) { return Set(pszName, tbl); } //! See int Set(const char* pszName, CScriptTable& tbl) int Set(const char* pszName, CScriptUserData& ud) { return Set(pszName, ud); } //! See int Set(const char* pszName, CScriptTable& tbl) int Set(const char* pszName, const std::string& str) { return Set(pszName, str); } //! Get a table from global table. if fail, tbl is invalid(IsRefered() is false). //! NB. tbl will be linked to this handle, so if handle is released, tbl will know this event. int Get(const char* pszName, CScriptTable& tbl); //! Get a userdata from global table. a userdata is a class you export to lua in fact. int Get(const char* pszName, CScriptUserData& ud); //! New a table, tbl will reference to it. int NewTable(CScriptTable& tbl); //! New a table, tbl will reference to it and this table will be set to global variable named pszName. int NewTable(const char* pszName, CScriptTable& tbl); #define ARGUMENT_TYPE(arg) typename TArgumentType::argument_type #define VALUE_TYPE(arg) typename TArgumentType::value_type #define FUNC_PREWORK() \ InvlRetVal(r);\ if(IsNull())\ {\ return 0;\ }\ CHECK_LUA_STACK(m_pLua);\ lua_getglobal(m_pLua, pszName);\ if(!lua_isfunction(m_pLua, -1))\ {\ return 0;\ } #define MAKE_ARG(type, vale)\ if(!TToLua::Make((vale), m_pLua))\ {\ return 0;\ } #define MAKE_RET()\ int __nFmRet = TFmLua::Make(m_pLua, -1, r) #define FUNC_POSWORK()\ return PostFmLua(__nFmRet, r); //! Call a global function named pszName, r is the returned value. //! \return 0-fail. template int CallFunc(const char* pszName, R& r) { FUNC_PREWORK(); if(lua_pcall(m_pLua, 0, 1, 0) != LUA_OK) // Error msg here { LOG_MESSAGE("[ERROR] Call Func[%s] : %s", pszName, lua_tostring(m_pLua, -1)); return 0; } MAKE_RET(); FUNC_POSWORK(); } //! Call a global function named pszName, r is the returned value, a0 is the only argument. //! NB. you must indicate the argument type explicitly like CallFunc(name, arg, ret) //! NB. the return type will be interpreted by compiler, there is no need to indicate it's type. //! \return 0-fail. template int CallFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, R& r) { FUNC_PREWORK(); MAKE_ARG(A0, a0); if(lua_pcall(m_pLua, 1, 1, 0) != LUA_OK) // Error msg here { LOG_MESSAGE("[ERROR] Call Func[%s] : %s", pszName, lua_tostring(m_pLua, -1)); return 0; } MAKE_RET(); FUNC_POSWORK(); } //! Two args version, see One args version. template int CallFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, ARGUMENT_TYPE(A1) a1, R& r) { FUNC_PREWORK(); MAKE_ARG(A0, a0); MAKE_ARG(A1, a1); if(lua_pcall(m_pLua, 2, 1, 0) != LUA_OK) // Error msg here { LOG_MESSAGE("[ERROR] Call Func[%s] : %s", pszName, lua_tostring(m_pLua, -1)); return 0; } MAKE_RET(); FUNC_POSWORK(); } //! Three args version, see One args version. template int CallFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, ARGUMENT_TYPE(A1) a1, ARGUMENT_TYPE(A2) a2, R& r) { FUNC_PREWORK(); MAKE_ARG(A0, a0); MAKE_ARG(A1, a1); MAKE_ARG(A2, a2); if (lua_pcall(m_pLua, 3, 1, 0) != LUA_OK) // Error msg here { LOG_MESSAGE("[ERROR] Call Func[%s] : %s", pszName, lua_tostring(m_pLua, -1)); return 0; } MAKE_RET(); FUNC_POSWORK(); } #undef ARGUMENT_TYPE #undef VALUE_TYPE #undef FUNC_PREWORK #undef MAKE_THIS #undef MAKE_ARG #undef MAKE_RET #undef FUNC_POSWORK protected: template int PostFmLua(int nFmLuaRet, T) { return nFmLuaRet; } int PostFmLua(int nFmLuaRet, CScriptTable& tbl); int PostFmLua(int nFmLuaRet, CScriptUserData& ud); template void InvlRetVal(T& ) { } void InvlRetVal(CScriptTable& tbl); void InvlRetVal(CScriptUserData& ud); private: bool m_bOwn; lua_State* m_pLua; SScriptHandleRefNode m_head; }; // Script abstract data base : abstract data means table and user data type // It's internal used, Never work with a table or userdata with this parent class class IScriptADBase : INonCopyable { protected: struct SRefNode : SScriptHandleRefNode { SRefNode() : pLua(NULL) , nRef(LUA_NOREF) { unLinker = &UnLinker; } lua_State* pLua; int nRef; bool IsReferd() const { return pLua && nRef != LUA_NOREF; } void UnRef() { if(unLinker) { unLinker(this); } } protected: // Static static void UnLinker(SScriptHandleRefNode* pT); }; typedef SRefNode RefNode; public: IScriptADBase() { } ~IScriptADBase() { UnRef(); } bool IsReferd() const { return m_ref.IsReferd(); } void UnRef() { m_ref.UnRef(); } //! Get value from the ad type(table or userdata) template int Get(const char* pszName, T& v) { if(!IsReferd()) { return 0; } lua_State* pLua = m_ref.pLua; CHECK_LUA_STACK(pLua); if(!PrepareStack()) // this_table is on the top { return 0; } lua_getfield(pLua, -1, pszName); // __bin_refs this_table value return TFmLua::value_type>::Make(pLua, -1, v); } template int Set(const char* pszName, T v) { if(!IsReferd()) { return 0; } lua_State* pLua = m_ref.pLua; CHECK_LUA_STACK(pLua); if(!PrepareStack()) { return 0; } if(!TToLua::value_type>::Make(v, pLua)) { return 0; } lua_setfield(pLua, -2, pszName); return 1; } int Set(const char* pszName, CScriptTable& tbl) { return Set(pszName, tbl); } int Set(const char* pszName, CScriptUserData& ud) { return Set(pszName, ud); } int Set(const char* pszName, const std::string& str) { return Set(pszName, str); } //! Get value from ad type(Call this method means you treat ad type as a array). //! NB. Array starts at 1 not 0 in lua. template int Get(int nIdx, T& v) { if(!IsReferd()) { return 0; } lua_State* pLua = m_ref.pLua; CHECK_LUA_STACK(pLua); if(!PrepareStack()) { return 0; } lua_rawgeti(pLua, -1, nIdx); return TFmLua::value_type>::Make(pLua, -1, v); } //! Set a array value. template int Set(int nIdx, T v) { if(!IsReferd()) { return 0; } lua_State* pLua = m_ref.pLua; CHECK_LUA_STACK(pLua); if(!PrepareStack()) { return 0; } if(!TToLua::value_type>::Make(v, pLua)) { return 0; } lua_rawseti(pLua, -2, nIdx); return 1; } int Set(int nIdx, CScriptTable& tbl) { return Set(nIdx, tbl); } int Set(int nIdx, CScriptUserData& ud) { return Set(nIdx, ud); } int Set(int nIdx, const std::string& str) { return Set(nIdx, str); } int Get(const char* pszName, CScriptTable& tbl); int Get(const char* pszName, CScriptUserData& ud); int Get(int nIdx, CScriptTable& tbl); int Get(int nIdx, CScriptUserData& ud); #define ARGUMENT_TYPE(arg) typename TArgumentType::argument_type #define VALUE_TYPE(arg) typename TArgumentType::value_type #define MEM_FUNC_PREWORK() \ InvlRetVal(r);\ if(!IsReferd())\ {\ return 0;\ }\ lua_State* pLua = m_ref.pLua;\ CHECK_LUA_STACK(pLua);\ if(!PrepareStack())\ {\ return 0;\ }\ lua_getfield(pLua, -1, pszName);\ if(!lua_isfunction(pLua, -1))\ {\ return 0;\ } #define MAKE_THIS()\ lua_pushvalue(pLua, -2) #define MAKE_ARG(type, vale)\ if(!TToLua::Make((vale), pLua))\ {\ return 0;\ } #define MAKE_RET()\ int __nFmRet = TFmLua::Make(pLua, -1, r) #define MEM_FUNC_POSWORK()\ return PostFmLua(__nFmRet, r); //! Call a member function of this ad type. //! Member function means the first argument is this object(table or userdata) //! \return 0-fail template int CallMemFunc(const char* pszName, R& r) { MEM_FUNC_PREWORK(); MAKE_THIS(); if(lua_pcall(pLua, 1, 1, 0) != LUA_OK) // Error msg here { LOG_MESSAGE("[ERROR] Call MemFunc[%s] : %s", pszName, lua_tostring(pLua, -1)); return 0; } MAKE_RET(); MEM_FUNC_POSWORK(); } //! One argument version, See the 0 argument version. template int CallMemFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, R& r) { MEM_FUNC_PREWORK(); MAKE_THIS(); MAKE_ARG(A0, a0); if(lua_pcall(pLua, 2, 1, 0) != LUA_OK) // Error msg here { LOG_MESSAGE("[ERROR] Call Func[%s] : %s", pszName, lua_tostring(pLua, -1)); return 0; } MAKE_RET(); MEM_FUNC_POSWORK(); } //! Two arguments version, see 0 argument version. template int CallMemFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, ARGUMENT_TYPE(A1) a1, R& r) { MEM_FUNC_PREWORK(); MAKE_THIS(); MAKE_ARG(A0, a0); MAKE_ARG(A1, a1); if(lua_pcall(pLua, 3, 1, 0) != LUA_OK) // Error msg here { LOG_MESSAGE("[ERROR] Call MemFunc[%s] : %s", pszName, lua_tostring(pLua, -1)); return 0; } MAKE_RET(); MEM_FUNC_POSWORK(); } #undef ARGUMENT_TYPE #undef VALUE_TYPE #undef MEM_FUNC_PREWORK #undef MAKE_THIS #undef MAKE_ARG #undef MAKE_RET #undef MEM_FUNC_POSWORK lua_State* GetHandle() const { return m_ref.pLua; } int PrepareStack(); protected: template int PostFmLua(int nFmLuaRet, T) { return nFmLuaRet; } int PostFmLua(int nFmLuaRet, CScriptTable& tbl); int PostFmLua(int nFmLuaRet, CScriptUserData& ud); template void InvlRetVal(T& ) { } void InvlRetVal(CScriptTable& tbl); void InvlRetVal(CScriptUserData& ud); SRefNode m_ref; friend class CScriptHandle; friend class CScriptUserData; }; //! Encapsulate a lua table. class CScriptTable : public IScriptADBase { public: CScriptTable() { } ~CScriptTable() { } #define ARGUMENT_TYPE(arg) typename TArgumentType::argument_type #define VALUE_TYPE(arg) typename TArgumentType::value_type #define FUNC_PREWORK() \ InvlRetVal(r);\ if(!IsReferd())\ {\ return 0;\ }\ lua_State* pLua = m_ref.pLua;\ CHECK_LUA_STACK(pLua);\ if(!PrepareStack())\ {\ return 0;\ }\ lua_getfield(pLua, -1, pszName);\ if(!lua_isfunction(pLua, -1))\ {\ return 0;\ } #define MAKE_ARG(type, vale)\ if(!TToLua::Make((vale), pLua))\ {\ return 0;\ } #define MAKE_RET()\ int __nFmRet = TFmLua::Make(pLua, -1, r) #define FUNC_POSWORK()\ return PostFmLua(__nFmRet, r); template int CallFunc(const char* pszName, R& r) { FUNC_PREWORK(); if(lua_pcall(pLua, 0, 1, 0) != LUA_OK) // Error msg here { LOG_MESSAGE("[ERROR] Call Func[%s] : %s", pszName, lua_tostring(pLua, -1)); return 0; } MAKE_RET(); FUNC_POSWORK(); } template int CallFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, R& r) { FUNC_PREWORK(); MAKE_ARG(A0, a0); if(lua_pcall(pLua, 1, 1, 0) != LUA_OK) // Error msg here { LOG_MESSAGE("[ERROR] Call Func[%s] : %s", pszName, lua_tostring(pLua, -1)); return 0; } MAKE_RET(); FUNC_POSWORK(); } template int CallFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, ARGUMENT_TYPE(A1) a1, R& r) { FUNC_PREWORK(); MAKE_ARG(A0, a0); MAKE_ARG(A1, a1); if(lua_pcall(pLua, 2, 1, 0) != LUA_OK) // Error msg here { LOG_MESSAGE("[ERROR] Call Func[%s] : %s", pszName, lua_tostring(pLua, -1)); return 0; } MAKE_RET(); FUNC_POSWORK(); } #undef ARGUMENT_TYPE #undef VALUE_TYPE #undef FUNC_PREWORK #undef MAKE_THIS #undef MAKE_ARG #undef MAKE_RET #undef FUNC_POSWORK template friend struct TFmLua; template friend struct TToLua; friend class CScriptHandle; friend class CScriptUserData; }; //! Encapsulate a lua userdata. class CScriptUserData : public IScriptADBase { public: CScriptUserData() { } ~CScriptUserData() { } template friend struct TFmLua; template friend struct TToLua; friend class CScriptHandle; friend class CScriptTable; }; //! Utilities template <> struct TFmLua { static int Make(lua_State* pL, int nIdx, CScriptTable& tbl); }; template <> struct TFmLua { static int Make(lua_State* pL, int nIdx, CScriptUserData& ud); }; template <> struct TToLua { static int Make(CScriptTable& tbl, lua_State* pL); }; template <> struct TToLua { static int Make(CScriptUserData& ud, lua_State* pL); }; }; #endif ================================================ FILE: code/EVA/server/server_share/bin_luabind/ScriptObject.h ================================================ #ifndef SERVER_SHARD_SCRIPT_OBJECT_H #define SERVER_SHARD_SCRIPT_OBJECT_H #include "ScriptHandle.h" namespace bin { struct SScriptObject { SScriptObject() : m_pObjRef(NULL) , m_pThis(NULL) , m_pExporter(NULL) , m_bDelByScr(false) , m_pReleaser(NULL) { } ~SScriptObject() { Unlink(); } // Copy constructor and assign operator should do nothing SScriptObject(const SScriptObject& r) : m_pObjRef(NULL) , m_pThis(NULL) , m_pExporter(NULL) , m_bDelByScr(false) // Should use the r.m_bDelByScr ? , m_pReleaser(NULL) { } SScriptObject& operator = (const SScriptObject& r) { // Copy nothing about script part } // Internal used, Attach this object to lua object template void Attach(T* pThis, SScriptObjectRef* pObjRef) { assert(!m_pObjRef && !m_pThis); m_pObjRef = pObjRef; m_pThis = pThis; m_pExporter = pThis->GetExporter(); assert(m_pExporter); m_pReleaser = &SScriptObject::ReleaseImpl; InitScript(); } // Internal used, unlink the reference to lua object, NB. lua object will still reference this c++ object void SideUnlink() { ReleaseScript(); m_pObjRef = NULL; m_pThis = NULL; m_pExporter = NULL; m_bDelByScr = false; } // Internal used, Unlink the connection between c++ object and lua object void Unlink() { if(m_pObjRef) { m_pObjRef->Unlink(); } assert(!m_pObjRef); } // Internal used, Release api for lua proxy, NB. this object will be deleted after calling this method void ReleaseByScr() { if(GetDelByScr()) { (this->*m_pReleaser)(); } // Never touch anything later, the object has been destroyed. } bool IsExported() const { return m_pObjRef != NULL; } // Internal used, Push userdata on top in pL's stack, nil if not exported int GetUserData(lua_State* pL) ; //! Get the lua_State handle. you can access lua machine from it. CScriptHandle& GetScriptHandle() { return m_scriptHandle; } //! Get the userdata (lua representation of this class), you can access lua script part from it. //! GetUserData is not like GetScriptHandle to return what we want. If do it like that, lua gc can't get the chance to collect a userdata because the reference in ref table. //! NB. if you store scriptUserData for later using, scriptUserData will be invalid if the object has been destroyed automatically. int GetUserData(CScriptUserData& scriptUserData); //! Set if the lua deletes this object(Means lua manages the life of this object). void SetDelByScr(bool bDelByScr) { if(IsExported()) { m_pObjRef->OnChangeWeakedTo(bDelByScr); } m_bDelByScr = bDelByScr; } //! Get the lua deleting tag. bool GetDelByScr() const { return m_bDelByScr; } bool IsWeaked() const { return GetDelByScr(); } public: // Internal used, don't touch these things void* m_pThis; class CClassExporter* m_pExporter; protected: template void ReleaseImpl() { T* pThis = reinterpret_cast(m_pThis); delete pThis; } // Initialize script handle and script userdata int InitScript(); // Release script handle and script userdata void ReleaseScript(); protected: bool m_bDelByScr; SScriptObjectRef* m_pObjRef; typedef void (SScriptObject::* Releaser)(); Releaser m_pReleaser; CScriptHandle m_scriptHandle; // NB : this reference will cause the gc can't clean the weak objects table if there is no reference in lua(except the ref table). //CScriptUserData m_scriptUserData; }; }; #endif ================================================ FILE: code/EVA/server/server_share/bin_luabind/ScriptProxy.cpp ================================================ // #include "Public.h" // #include "ScriptProxy.h" #include "ScriptObject.h" // #include "ScriptBase.h" #include "ScriptExporter.h" // namespace bin { void* SScriptObjectRef::GetScriptObj() { return pObject->m_pThis; } void SScriptObjectRef::Unlink() { SScriptObject* pObj = pObject; // Need pObj, So Unlink self first SideUnlink(); // Then obj if(pObj) { pObj->SideUnlink(); } } void SScriptObjectRef::SideUnlink() { // Remove the object from objects table if(pLua && nRef!=LUA_NOREF) { CHECK_LUA_STACK(pLua); ScriptExporterManager().CheckObjectsTable(pLua, pObject->IsWeaked()); // Avoid re-entrance by CheckObjectsTable if(pLua && nRef!=LUA_NOREF) { luaL_unref(pLua, -1, nRef); } } pObject = NULL; pLua = NULL; nRef = LUA_NOREF; } void SScriptObjectRef::OnChangeWeakedTo(bool bWeaked) { if(pObject && pObject->IsWeaked() != bWeaked) // Weak property is changed { assert(pLua && nRef!=LUA_NOREF); CHECK_LUA_STACK(pLua); ScriptExporterManager().CheckObjectsTable(pLua, pObject->IsWeaked()); // oldTbl lua_rawgeti(pLua, -1, nRef); // oldTbl, obj ScriptExporterManager().CheckObjectsTable(pLua, bWeaked); // oldTbl, obj, newTbl lua_pushvalue(pLua, -2); // oldTbl, obj, newTbl, obj int nNewRef = luaL_ref(pLua, -2); // oldTbl, obj, newTbl luaL_unref(pLua, -3, nRef); nRef = nNewRef; } } // Push userdata on top in pL's stack, nil if not exported int SScriptObject::GetUserData(lua_State* pL) { if(!IsExported() || m_pObjRef->pLua != pL) { lua_pushnil(pL); return 1; } // Stop gc, because CheckObjectsTable may call gc //GUARD_LUA_GC(pL); ScriptExporterManager().CheckObjectsTable(pL, IsWeaked()); lua_rawgeti(pL, -1, m_pObjRef->nRef); lua_replace(pL, -2); return 1; } int SScriptObject::GetUserData(CScriptUserData& scriptUserData) { scriptUserData.UnRef(); if(m_scriptHandle.IsNull()) { return 0; } lua_State* pLua = m_pObjRef->pLua; CHECK_LUA_STACK(pLua); // Stop gc, because CheckObjectsTable may call gc //GUARD_LUA_GC(pLua); ScriptExporterManager().CheckObjectsTable(pLua, IsWeaked()); lua_rawgeti(pLua, -1, m_pObjRef->nRef); const char* TEMP_REF = "__bin_temp"; lua_setglobal(pLua, TEMP_REF); m_scriptHandle.Get(TEMP_REF, scriptUserData); lua_pushnil(pLua); lua_setglobal(pLua, TEMP_REF); return 1; } int SScriptObject::InitScript() { ReleaseScript(); lua_State* pLua = m_pObjRef->pLua; if(!m_scriptHandle.Init(pLua)) { return 0; } return 1; } void SScriptObject::ReleaseScript() { m_scriptHandle.Release(); } }; ================================================ FILE: code/EVA/server/server_share/bin_luabind/ScriptProxy.h ================================================ #ifndef SERVER_SHARD_SCRIPT_PROXY_H #define SERVER_SHARD_SCRIPT_PROXY_H namespace bin { struct SScriptObject; struct SScriptObjectRef { struct SScriptObject* pObject; lua_State* pLua; int nRef; // INonCopyable SScriptObjectRef(SScriptObjectRef&); SScriptObjectRef& operator = (SScriptObjectRef&); SScriptObjectRef() : pObject(NULL) , pLua(NULL) , nRef(LUA_NOREF) { } ~SScriptObjectRef() { assert(!pObject); } void* GetScriptObj(); // Unlink the connection between c++ object and lua object void Unlink(); // Unlink the lua object reference to c++ object, NB. The c++ object still reference to lua object void SideUnlink(); void OnChangeWeakedTo(bool bWeaked); }; //! a c++ proxy to lua. this is the only way lua accesses to a c++ object. struct SScriptProxy { enum EProxyType { EPT_NULL = 0, EPT_OBJECT, }; EProxyType ePT; SScriptObjectRef objRef; // Valid only if Proxy takes a object SScriptProxy() : ePT(EPT_NULL) { } }; }; #endif ================================================ FILE: code/EVA/server/server_share/bit_set_ext2.h ================================================ #include #include class CBitSetExt2 { public: bool SetValue( uint32 idx, uint8 value ) { if ( idx!=0 && idx& bit_vct = m_BitSet.getVector(); m_ArrayStr.resize(bit_vct.size()*sizeof(uint32)); for ( uint i=0; i>1; } NLMISC::CSString toString() { NLMISC::CSString s; for ( uint32 i=0; i!=Size(); ++i ) { uint32 val = GetValue(i); s << "[" << i <<"]="; s << "" << val <<" "; if ( i%5==0 ) { s << "\n"; } } s << "\n"; return s; } enum { VALUE_USR_BIT = 2, MAX_INDEX = 512, INVALID_VAL = 0xff, }; private: std::string m_ArrayStr; NLMISC::CBitSet m_BitSet; }; ================================================ FILE: code/EVA/server/server_share/buf_fifo2.h ================================================ #ifndef NL_BUF_FIFO_DOUBLE_H #define NL_BUF_FIFO_DOUBLE_H #include #include namespace NLMISC { template class CBufFIFO2 { public: CBufFIFO2 ():_PosReadMax(0),_PosRead(0),_PosWrite(0),_pRead(NULL),_pWrite(NULL),_MaxSize(0){} ~CBufFIFO2 (){} void init( uint32 size ) { _MaxSize = size; _Data1.resize( _MaxSize ); _Data2.resize( _MaxSize ); _pRead = &_Data1; _pWrite = &_Data2; } bool push_back (T* data) { _WriteMutex.enter(); if( _PosWrite < _MaxSize ) // δ { (*_pWrite)[_PosWrite++] = data; _WriteMutex.leave(); return true; } _WriteMutex.leave(); return false; } // void swap() { _ReadMutex.enter(); _WriteMutex.enter(); _PosReadMax = _PosWrite; _PosWrite = 0; _PosRead = 0; std::vector* pTmp = _pRead; _pRead = _pWrite; _pWrite = pTmp; _WriteMutex.leave(); _ReadMutex.leave(); } T* pop_front() { T* pRet = NULL; _ReadMutex.enter(); if( _PosRead < _PosReadMax ) { pRet = (*_pRead)[_PosRead++]; } _ReadMutex.leave(); if ( pRet==NULL ) { swap(); } return pRet; } uint32 size() { return _PosWrite + _PosReadMax - _PosRead; } private: CMutex _WriteMutex; CMutex _ReadMutex; uint32 _PosRead; uint32 _PosReadMax; uint32 _PosWrite; uint32 _MaxSize; std::vector* _pRead; std::vector* _pWrite; std::vector _Data1; std::vector _Data2; }; } // NLMISC #endif // NL_BUF_FIFO_DOUBLE_H /* End of buf_fifo2.h */ ================================================ FILE: code/EVA/server/server_share/buf_fifo_ring.h ================================================ #ifndef NL_BUF_FIFO_RING_H #define NL_BUF_FIFO_RING_H #include #include namespace NLMISC { template class CBufFIFORing { public: CBufFIFORing ():_PosRead(0),_PosWrite(0),_MaxSize(1) { _Data.resize(1); } ~CBufFIFORing (){}; uint32 init( uint32 size ) // 扩展成2的倍数,<=2147483648。 { if( size < 0x80000000 ) { for( uint32 ndx = 0; ndx < 32; ndx++ ) { _MaxSize = ( _MaxSize << 1 ); if( _MaxSize >= size ) { break; } } } else { _MaxSize = 0x80000000; } _Mask = _MaxSize - 1; _Data.resize( _MaxSize ); return _MaxSize; } bool push_back (T* data) { bool res = false; if( _PosWrite - _PosRead < _MaxSize ) // 如果队列未满 { _mutex.enter(); uint32 write = _PosWrite++; _Data[write&_Mask] = data; _mutex.leave(); res = true; } return res; } T* pop_front() { T* res = NULL; if( _PosRead != _PosWrite ) // 如果队列不为空 { _mutex.enter(); uint32 read = _PosRead++; res = _Data[read&_Mask]; _mutex.leave(); } return res; } uint32 size() { return _PosWrite - _PosRead; } bool empty( void ) { return ( size() <= 0 ); } void clear() { _PosRead = 0; _PosWrite = 0; } private: CMutex _mutex; volatile uint32 _PosRead; volatile uint32 _PosWrite; uint32 _MaxSize; uint32 _Mask; std::vector _Data; }; } // NLMISC #endif // NL_BUF_FIFO_RING_H /* End of buf_fifo_ring.h */ ================================================ FILE: code/EVA/server/server_share/callback_adaptor.h ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef CALLBACK_ADAPTER_H #define CALLBACK_ADAPTER_H #include "nel/net/callback_client.h" #include "nel/net/callback_server.h" class ICallbackServerAdaptor { void *_ContainerClass; public: ICallbackServerAdaptor(void *containerClass) : _ContainerClass(containerClass) { } virtual ~ICallbackServerAdaptor() { } void *getContainerClass() { return _ContainerClass; } virtual void addCallbackArray(const NLNET::TCallbackItem *callbackarray, sint arraysize) =0; virtual void setConnectionCallback(NLNET::TNetCallback cb, void *arg) =0; virtual void setDisconnectionCallback(NLNET::TNetCallback cb, void *arg) =0; virtual void init(uint16 port) =0; virtual void disconnect( NLNET::TSockId hostid) =0; virtual void send(const NLNET::CMessage &buffer, NLNET::TSockId hostid, bool log = true) =0; virtual void update() =0; }; class ICallbackClientAdaptor { void *_ContainerClass; public: ICallbackClientAdaptor(void *containerClass) : _ContainerClass(containerClass) { } virtual ~ICallbackClientAdaptor() { } void *getContainerClass() { return _ContainerClass; } virtual void addCallbackArray(const NLNET::TCallbackItem *callbackarray, sint arraysize) =0; virtual void setDisconnectionCallback(NLNET::TNetCallback cb, void *arg) =0; virtual void connect( const NLNET::CInetAddress& addr ) =0; virtual bool connected( ) =0; virtual void send(const NLNET::CMessage &buffer, NLNET::TSockId hostid = NLNET::InvalidSockId, bool log = true) =0; virtual void update() =0; }; /** this is the default adaptor that make use of the NeL callback server */ class CNelCallbackServerAdaptor : public ICallbackServerAdaptor { protected: NLNET::CCallbackServer _CallbackServer; public: CNelCallbackServerAdaptor(void *containerClass) : ICallbackServerAdaptor(containerClass) { _CallbackServer.setUserData(this); } protected: virtual void addCallbackArray(const NLNET::TCallbackItem *callbackarray, sint arraysize) { _CallbackServer.addCallbackArray(callbackarray, arraysize); } virtual void setConnectionCallback(NLNET::TNetCallback cb, void *arg) { _CallbackServer.setConnectionCallback(cb, arg); } virtual void setDisconnectionCallback(NLNET::TNetCallback cb, void *arg) { _CallbackServer.setDisconnectionCallback(cb, arg); } virtual void init(uint16 port) { _CallbackServer.init(port); } virtual void disconnect( NLNET::TSockId hostid) { _CallbackServer.disconnect(hostid); } virtual void send(const NLNET::CMessage &buffer, NLNET::TSockId hostid, bool log = true) { _CallbackServer.send(buffer, hostid, log); } virtual void update() { _CallbackServer.update(); } }; /** this is the default adaptor that make use of the NeL callback client */ class CNelCallbackClientAdaptor : public ICallbackClientAdaptor { protected: NLNET::CCallbackClient _CallbackClient; public: CNelCallbackClientAdaptor(void *containerClass) : ICallbackClientAdaptor(containerClass) { _CallbackClient.setUserData(this); } protected: virtual void addCallbackArray(const NLNET::TCallbackItem *callbackarray, sint arraysize) { _CallbackClient.addCallbackArray(callbackarray, arraysize); } virtual void setDisconnectionCallback(NLNET::TNetCallback cb, void *arg) { _CallbackClient.setDisconnectionCallback(cb, arg); } virtual void connect( const NLNET::CInetAddress& addr ) { _CallbackClient.connect(addr); } virtual bool connected() { return _CallbackClient.connected(); } virtual void send(const NLNET::CMessage &buffer, NLNET::TSockId hostid = NLNET::InvalidSockId, bool log = true) { _CallbackClient.send(buffer, hostid, log); } virtual void update() { _CallbackClient.update(); } }; #endif // CALLBACK_ADAPTER_H ================================================ FILE: code/EVA/server/server_share/cjson/dtoa.cpp ================================================ /**************************************************************** * * The author of this software is David M. Gay. * * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. * ***************************************************************/ /* Please send bug reports to David M. Gay (dmg at acm dot org, * with " at " changed at "@" and " dot " changed to "."). */ /* On a machine with IEEE extended-precision registers, it is * necessary to specify double-precision (53-bit) rounding precision * before invoking strtod or dtoa. If the machine uses (the equivalent * of) Intel 80x87 arithmetic, the call * _control87(PC_53, MCW_PC); * does this with many compilers. Whether this or another call is * appropriate depends on the compiler; for this to work, it may be * necessary to #include "float.h" or another system-dependent header * file. */ /* strtod for IEEE-, VAX-, and IBM-arithmetic machines. * * This strtod returns a nearest machine number to the input decimal * string (or sets errno to ERANGE). With IEEE arithmetic, ties are * broken by the IEEE round-even rule. Otherwise ties are broken by * biased rounding (add half and chop). * * Inspired loosely by William D. Clinger's paper "How to Read Floating * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. * * Modifications: * * 1. We only require IEEE, IBM, or VAX double-precision * arithmetic (not IEEE double-extended). * 2. We get by with floating-point arithmetic in a case that * Clinger missed -- when we're computing d * 10^n * for a small integer d and the integer n is not too * much larger than 22 (the maximum integer k for which * we can represent 10^k exactly), we may be able to * compute (d*10^k) * 10^(e-k) with just one roundoff. * 3. Rather than a bit-at-a-time adjustment of the binary * result in the hard case, we use floating-point * arithmetic to determine the adjustment to within * one bit; only in really hard cases do we need to * compute a second residual. * 4. Because of 3., we don't need a large table of powers of 10 * for ten-to-e (just some small tables, e.g. of 10^k * for 0 <= k <= 22). */ /* * #define IEEE_8087 for IEEE-arithmetic machines where the least * significant byte has the lowest address. * #define IEEE_MC68k for IEEE-arithmetic machines where the most * significant byte has the lowest address. * #define Long int on machines with 32-bit ints and 64-bit longs. * #define IBM for IBM mainframe-style floating-point arithmetic. * #define VAX for VAX-style floating-point arithmetic (D_floating). * #define No_leftright to omit left-right logic in fast floating-point * computation of dtoa. This will cause dtoa modes 4 and 5 to be * treated the same as modes 2 and 3 for some inputs. * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 * and strtod and dtoa should round accordingly. Unless Trust_FLT_ROUNDS * is also #defined, fegetround() will be queried for the rounding mode. * Note that both FLT_ROUNDS and fegetround() are specified by the C99 * standard (and are specified to be consistent, with fesetround() * affecting the value of FLT_ROUNDS), but that some (Linux) systems * do not work correctly in this regard, so using fegetround() is more * portable than using FLT_ROUNDS directly. * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 * and Honor_FLT_ROUNDS is not #defined. * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines * that use extended-precision instructions to compute rounded * products and quotients) with IBM. * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic * that rounds toward +Infinity. * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased * rounding when the underlying floating-point arithmetic uses * unbiased rounding. This prevent using ordinary floating-point * arithmetic when the result could be computed with one rounding error. * #define Inaccurate_Divide for IEEE-format with correctly rounded * products but inaccurate quotients, e.g., for Intel i860. * #define NO_LONG_LONG on machines that do not have a "long long" * integer type (of >= 64 bits). On such machines, you can * #define Just_16 to store 16 bits per 32-bit Long when doing * high-precision integer arithmetic. Whether this speeds things * up or slows things down depends on the machine and the number * being converted. If long long is available and the name is * something other than "long long", #define Llong to be the name, * and if "unsigned Llong" does not work as an unsigned version of * Llong, #define #ULLong to be the corresponding unsigned type. * #define KR_headers for old-style C function headers. * #define Bad_float_h if your system lacks a float.h or if it does not * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) * if memory is available and otherwise does something you deem * appropriate. If MALLOC is undefined, malloc will be invoked * directly -- and assumed always to succeed. Similarly, if you * want something other than the system's free() to be called to * recycle memory acquired from MALLOC, #define FREE to be the * name of the alternate routine. (FREE or free is only called in * pathological cases, e.g., in a dtoa call after a dtoa return in * mode 3 with thousands of digits requested.) * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making * memory allocations from a private pool of memory when possible. * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, * unless #defined to be a different length. This default length * suffices to get rid of MALLOC calls except for unusual cases, * such as decimal-to-binary conversion of a very long string of * digits. The longest string dtoa can return is about 751 bytes * long. For conversions by strtod of strings of 800 digits and * all dtoa conversions in single-threaded executions with 8-byte * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte * pointers, PRIVATE_MEM >= 7112 appears adequate. * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK * #defined automatically on IEEE systems. On such systems, * when INFNAN_CHECK is #defined, strtod checks * for Infinity and NaN (case insensitively). On some systems * (e.g., some HP systems), it may be necessary to #define NAN_WORD0 * appropriately -- to the most significant word of a quiet NaN. * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, * strtod also accepts (case insensitively) strings of the form * NaN(x), where x is a string of hexadecimal digits and spaces; * if there is only one string of hexadecimal digits, it is taken * for the 52 fraction bits of the resulting NaN; if there are two * or more strings of hex digits, the first is for the high 20 bits, * the second and subsequent for the low 32 bits, with intervening * white space ignored; but if this results in none of the 52 * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 * and NAN_WORD1 are used instead. * #define MULTIPLE_THREADS if the system offers preemptively scheduled * multiple threads. In this case, you must provide (or suitably * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed * in pow5mult, ensures lazy evaluation of only one copy of high * powers of 5; omitting this lock would introduce a small * probability of wasting memory, but would otherwise be harmless.) * You must also invoke freedtoa(s) to free the value s returned by * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that * avoids underflows on inputs whose result does not underflow. * If you #define NO_IEEE_Scale on a machine that uses IEEE-format * floating-point numbers and flushes underflows to zero rather * than implementing gradual underflow, then you must also #define * Sudden_Underflow. * #define USE_LOCALE to use the current locale's decimal_point value. * #define SET_INEXACT if IEEE arithmetic is being used and extra * computation should be done to set the inexact flag when the * result is inexact and avoid setting inexact when the result * is exact. In this case, dtoa.c must be compiled in * an environment, perhaps provided by #include "dtoa.c" in a * suitable wrapper, that defines two functions, * int get_inexact(void); * void clear_inexact(void); * such that get_inexact() returns a nonzero value if the * inexact bit is already set, and clear_inexact() sets the * inexact bit to 0. When SET_INEXACT is #defined, strtod * also does extra computations to set the underflow and overflow * flags when appropriate (i.e., when the result is tiny and * inexact or when it is a numeric value rounded to +-infinity). * #define NO_ERRNO if strtod should not assign errno = ERANGE when * the result overflows to +-Infinity or underflows to 0. * #define NO_HEX_FP to omit recognition of hexadecimal floating-point * values by strtod. * #define NO_STRTOD_BIGCOMP (on IEEE-arithmetic systems only for now) * to disable logic for "fast" testing of very long input strings * to strtod. This testing proceeds by initially truncating the * input string, then if necessary comparing the whole string with * a decimal expansion to decide close cases. This logic is only * used for input more than STRTOD_DIGLIM digits long (default 40). */ #include "dtoa_config.h" #ifndef Long #define Long long #endif #ifndef ULong typedef unsigned Long ULong; #endif #ifdef DEBUG #include "stdio.h" #define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} #endif #include "stdlib.h" #include "string.h" #ifdef USE_LOCALE #include "locale.h" #endif #ifdef Honor_FLT_ROUNDS #ifndef Trust_FLT_ROUNDS #include #endif #endif #ifdef MALLOC #ifdef KR_headers extern char *MALLOC(); #else extern void *MALLOC(size_t); #endif #else #define MALLOC malloc #endif #ifndef Omit_Private_Memory #ifndef PRIVATE_MEM #define PRIVATE_MEM 2304 #endif #define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) static double private_mem[PRIVATE_mem], *pmem_next = private_mem; #endif #undef IEEE_Arith #undef Avoid_Underflow #ifdef IEEE_MC68k #define IEEE_Arith #endif #ifdef IEEE_8087 #define IEEE_Arith #endif #ifdef IEEE_Arith #ifndef NO_INFNAN_CHECK #undef INFNAN_CHECK #define INFNAN_CHECK #endif #else #undef INFNAN_CHECK #define NO_STRTOD_BIGCOMP #endif #include "errno.h" #ifdef Bad_float_h #ifdef IEEE_Arith #define DBL_DIG 15 #define DBL_MAX_10_EXP 308 #define DBL_MAX_EXP 1024 #define FLT_RADIX 2 #endif /*IEEE_Arith*/ #ifdef IBM #define DBL_DIG 16 #define DBL_MAX_10_EXP 75 #define DBL_MAX_EXP 63 #define FLT_RADIX 16 #define DBL_MAX 7.2370055773322621e+75 #endif #ifdef VAX #define DBL_DIG 16 #define DBL_MAX_10_EXP 38 #define DBL_MAX_EXP 127 #define FLT_RADIX 2 #define DBL_MAX 1.7014118346046923e+38 #endif #ifndef LONG_MAX #define LONG_MAX 2147483647 #endif #else /* ifndef Bad_float_h */ #include "float.h" #endif /* Bad_float_h */ #ifndef __MATH_H__ #include "math.h" #endif #ifdef __cplusplus extern "C" { #endif #ifndef CONST #ifdef KR_headers #define CONST /* blank */ #else #define CONST const #endif #endif #if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. #endif typedef union { double d; ULong L[2]; } U; #ifdef IEEE_8087 #define word0(x) (x)->L[1] #define word1(x) (x)->L[0] #else #define word0(x) (x)->L[0] #define word1(x) (x)->L[1] #endif #define dval(x) (x)->d #ifndef STRTOD_DIGLIM #define STRTOD_DIGLIM 40 #endif #ifdef DIGLIM_DEBUG extern int strtod_diglim; #else #define strtod_diglim STRTOD_DIGLIM #endif /* The following definition of Storeinc is appropriate for MIPS processors. * An alternative that might be better on some machines is * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) */ #if defined(IEEE_8087) + defined(VAX) #define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ ((unsigned short *)a)[0] = (unsigned short)c, a++) #else #define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ ((unsigned short *)a)[1] = (unsigned short)c, a++) #endif /* #define P DBL_MANT_DIG */ /* Ten_pmax = floor(P*log(2)/log(5)) */ /* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ /* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ /* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ #ifdef IEEE_Arith #define Exp_shift 20 #define Exp_shift1 20 #define Exp_msk1 0x100000 #define Exp_msk11 0x100000 #define Exp_mask 0x7ff00000 #define P 53 #define Nbits 53 #define Bias 1023 #define Emax 1023 #define Emin (-1022) #define Exp_1 0x3ff00000 #define Exp_11 0x3ff00000 #define Ebits 11 #define Frac_mask 0xfffff #define Frac_mask1 0xfffff #define Ten_pmax 22 #define Bletch 0x10 #define Bndry_mask 0xfffff #define Bndry_mask1 0xfffff #define LSB 1 #define Sign_bit 0x80000000 #define Log2P 1 #define Tiny0 0 #define Tiny1 1 #define Quick_max 14 #define Int_max 14 #ifndef NO_IEEE_Scale #define Avoid_Underflow #ifdef Flush_Denorm /* debugging option */ #undef Sudden_Underflow #endif #endif #ifndef Flt_Rounds #ifdef FLT_ROUNDS #define Flt_Rounds FLT_ROUNDS #else #define Flt_Rounds 1 #endif #endif /*Flt_Rounds*/ #ifdef Honor_FLT_ROUNDS #undef Check_FLT_ROUNDS #define Check_FLT_ROUNDS #else #define Rounding Flt_Rounds #endif #else /* ifndef IEEE_Arith */ #undef Check_FLT_ROUNDS #undef Honor_FLT_ROUNDS #undef SET_INEXACT #undef Sudden_Underflow #define Sudden_Underflow #ifdef IBM #undef Flt_Rounds #define Flt_Rounds 0 #define Exp_shift 24 #define Exp_shift1 24 #define Exp_msk1 0x1000000 #define Exp_msk11 0x1000000 #define Exp_mask 0x7f000000 #define P 14 #define Nbits 56 #define Bias 65 #define Emax 248 #define Emin (-260) #define Exp_1 0x41000000 #define Exp_11 0x41000000 #define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ #define Frac_mask 0xffffff #define Frac_mask1 0xffffff #define Bletch 4 #define Ten_pmax 22 #define Bndry_mask 0xefffff #define Bndry_mask1 0xffffff #define LSB 1 #define Sign_bit 0x80000000 #define Log2P 4 #define Tiny0 0x100000 #define Tiny1 0 #define Quick_max 14 #define Int_max 15 #else /* VAX */ #undef Flt_Rounds #define Flt_Rounds 1 #define Exp_shift 23 #define Exp_shift1 7 #define Exp_msk1 0x80 #define Exp_msk11 0x800000 #define Exp_mask 0x7f80 #define P 56 #define Nbits 56 #define Bias 129 #define Emax 126 #define Emin (-129) #define Exp_1 0x40800000 #define Exp_11 0x4080 #define Ebits 8 #define Frac_mask 0x7fffff #define Frac_mask1 0xffff007f #define Ten_pmax 24 #define Bletch 2 #define Bndry_mask 0xffff007f #define Bndry_mask1 0xffff007f #define LSB 0x10000 #define Sign_bit 0x8000 #define Log2P 1 #define Tiny0 0x80 #define Tiny1 0 #define Quick_max 15 #define Int_max 15 #endif /* IBM, VAX */ #endif /* IEEE_Arith */ #ifndef IEEE_Arith #define ROUND_BIASED #else #ifdef ROUND_BIASED_without_Round_Up #undef ROUND_BIASED #define ROUND_BIASED #endif #endif #ifdef RND_PRODQUOT #define rounded_product(a,b) a = rnd_prod(a, b) #define rounded_quotient(a,b) a = rnd_quot(a, b) #ifdef KR_headers extern double rnd_prod(), rnd_quot(); #else extern double rnd_prod(double, double), rnd_quot(double, double); #endif #else #define rounded_product(a,b) a *= b #define rounded_quotient(a,b) a /= b #endif #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) #define Big1 0xffffffff #ifndef Pack_32 #define Pack_32 #endif typedef struct BCinfo BCinfo; struct BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflchk; }; #ifdef KR_headers #define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff) #else #define FFFFFFFF 0xffffffffUL #endif #ifdef NO_LONG_LONG #undef ULLong #ifdef Just_16 #undef Pack_32 /* When Pack_32 is not defined, we store 16 bits per 32-bit Long. * This makes some inner loops simpler and sometimes saves work * during multiplications, but it often seems to make things slightly * slower. Hence the default is now to store 32 bits per Long. */ #endif #else /* long long available */ #ifndef Llong #define Llong long long #endif #ifndef ULLong #define ULLong unsigned Llong #endif #endif /* NO_LONG_LONG */ #ifndef MULTIPLE_THREADS #define ACQUIRE_DTOA_LOCK(n) /*nothing*/ #define FREE_DTOA_LOCK(n) /*nothing*/ #endif #define Kmax 7 #ifdef __cplusplus extern "C" double fpconv_strtod(const char *s00, char **se); extern "C" char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve); #endif struct Bigint { struct Bigint *next; int k, maxwds, sign, wds; ULong x[1]; }; typedef struct Bigint Bigint; static Bigint *freelist[Kmax+1]; static Bigint * Balloc #ifdef KR_headers (k) int k; #else (int k) #endif { int x; Bigint *rv; #ifndef Omit_Private_Memory unsigned int len; #endif ACQUIRE_DTOA_LOCK(0); /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ /* but this case seems very unlikely. */ if (k <= Kmax && (rv = freelist[k])) freelist[k] = rv->next; else { x = 1 << k; #ifdef Omit_Private_Memory rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); #else len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) /sizeof(double); if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) { rv = (Bigint*)pmem_next; pmem_next += len; } else rv = (Bigint*)MALLOC(len*sizeof(double)); #endif rv->k = k; rv->maxwds = x; } FREE_DTOA_LOCK(0); rv->sign = rv->wds = 0; return rv; } static void Bfree #ifdef KR_headers (v) Bigint *v; #else (Bigint *v) #endif { if (v) { if (v->k > Kmax) #ifdef FREE FREE((void*)v); #else free((void*)v); #endif else { ACQUIRE_DTOA_LOCK(0); v->next = freelist[v->k]; freelist[v->k] = v; FREE_DTOA_LOCK(0); } } } #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ y->wds*sizeof(Long) + 2*sizeof(int)) static Bigint * multadd #ifdef KR_headers (b, m, a) Bigint *b; int m, a; #else (Bigint *b, int m, int a) /* multiply by m and add a */ #endif { int i, wds; #ifdef ULLong ULong *x; ULLong carry, y; #else ULong carry, *x, y; #ifdef Pack_32 ULong xi, z; #endif #endif Bigint *b1; wds = b->wds; x = b->x; i = 0; carry = a; do { #ifdef ULLong y = *x * (ULLong)m + carry; carry = y >> 32; *x++ = y & FFFFFFFF; #else #ifdef Pack_32 xi = *x; y = (xi & 0xffff) * m + carry; z = (xi >> 16) * m + (y >> 16); carry = z >> 16; *x++ = (z << 16) + (y & 0xffff); #else y = *x * m + carry; carry = y >> 16; *x++ = y & 0xffff; #endif #endif } while(++i < wds); if (carry) { if (wds >= b->maxwds) { b1 = Balloc(b->k+1); Bcopy(b1, b); Bfree(b); b = b1; } b->x[wds++] = carry; b->wds = wds; } return b; } static Bigint * s2b #ifdef KR_headers (s, nd0, nd, y9, dplen) CONST char *s; int nd0, nd, dplen; ULong y9; #else (const char *s, int nd0, int nd, ULong y9, int dplen) #endif { Bigint *b; int i, k; Long x, y; x = (nd + 8) / 9; for(k = 0, y = 1; x > y; y <<= 1, k++) ; #ifdef Pack_32 b = Balloc(k); b->x[0] = y9; b->wds = 1; #else b = Balloc(k+1); b->x[0] = y9 & 0xffff; b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; #endif i = 9; if (9 < nd0) { s += 9; do b = multadd(b, 10, *s++ - '0'); while(++i < nd0); s += dplen; } else s += dplen + 9; for(; i < nd; i++) b = multadd(b, 10, *s++ - '0'); return b; } static int hi0bits #ifdef KR_headers (x) ULong x; #else (ULong x) #endif { int k = 0; if (!(x & 0xffff0000)) { k = 16; x <<= 16; } if (!(x & 0xff000000)) { k += 8; x <<= 8; } if (!(x & 0xf0000000)) { k += 4; x <<= 4; } if (!(x & 0xc0000000)) { k += 2; x <<= 2; } if (!(x & 0x80000000)) { k++; if (!(x & 0x40000000)) return 32; } return k; } static int lo0bits #ifdef KR_headers (y) ULong *y; #else (ULong *y) #endif { int k; ULong x = *y; if (x & 7) { if (x & 1) return 0; if (x & 2) { *y = x >> 1; return 1; } *y = x >> 2; return 2; } k = 0; if (!(x & 0xffff)) { k = 16; x >>= 16; } if (!(x & 0xff)) { k += 8; x >>= 8; } if (!(x & 0xf)) { k += 4; x >>= 4; } if (!(x & 0x3)) { k += 2; x >>= 2; } if (!(x & 1)) { k++; x >>= 1; if (!x) return 32; } *y = x; return k; } static Bigint * i2b #ifdef KR_headers (i) int i; #else (int i) #endif { Bigint *b; b = Balloc(1); b->x[0] = i; b->wds = 1; return b; } static Bigint * mult #ifdef KR_headers (a, b) Bigint *a, *b; #else (Bigint *a, Bigint *b) #endif { Bigint *c; int k, wa, wb, wc; ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; ULong y; #ifdef ULLong ULLong carry, z; #else ULong carry, z; #ifdef Pack_32 ULong z2; #endif #endif if (a->wds < b->wds) { c = a; a = b; b = c; } k = a->k; wa = a->wds; wb = b->wds; wc = wa + wb; if (wc > a->maxwds) k++; c = Balloc(k); for(x = c->x, xa = x + wc; x < xa; x++) *x = 0; xa = a->x; xae = xa + wa; xb = b->x; xbe = xb + wb; xc0 = c->x; #ifdef ULLong for(; xb < xbe; xc0++) { if ((y = *xb++)) { x = xa; xc = xc0; carry = 0; do { z = *x++ * (ULLong)y + *xc + carry; carry = z >> 32; *xc++ = z & FFFFFFFF; } while(x < xae); *xc = carry; } } #else #ifdef Pack_32 for(; xb < xbe; xb++, xc0++) { if (y = *xb & 0xffff) { x = xa; xc = xc0; carry = 0; do { z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; carry = z >> 16; z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; carry = z2 >> 16; Storeinc(xc, z2, z); } while(x < xae); *xc = carry; } if (y = *xb >> 16) { x = xa; xc = xc0; carry = 0; z2 = *xc; do { z = (*x & 0xffff) * y + (*xc >> 16) + carry; carry = z >> 16; Storeinc(xc, z, z2); z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; carry = z2 >> 16; } while(x < xae); *xc = z2; } } #else for(; xb < xbe; xc0++) { if (y = *xb++) { x = xa; xc = xc0; carry = 0; do { z = *x++ * y + *xc + carry; carry = z >> 16; *xc++ = z & 0xffff; } while(x < xae); *xc = carry; } } #endif #endif for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; c->wds = wc; return c; } static Bigint *p5s; static Bigint * pow5mult #ifdef KR_headers (b, k) Bigint *b; int k; #else (Bigint *b, int k) #endif { Bigint *b1, *p5, *p51; int i; static int p05[3] = { 5, 25, 125 }; if ((i = k & 3)) b = multadd(b, p05[i-1], 0); if (!(k >>= 2)) return b; if (!(p5 = p5s)) { /* first time */ #ifdef MULTIPLE_THREADS ACQUIRE_DTOA_LOCK(1); if (!(p5 = p5s)) { p5 = p5s = i2b(625); p5->next = 0; } FREE_DTOA_LOCK(1); #else p5 = p5s = i2b(625); p5->next = 0; #endif } for(;;) { if (k & 1) { b1 = mult(b, p5); Bfree(b); b = b1; } if (!(k >>= 1)) break; if (!(p51 = p5->next)) { #ifdef MULTIPLE_THREADS ACQUIRE_DTOA_LOCK(1); if (!(p51 = p5->next)) { p51 = p5->next = mult(p5,p5); p51->next = 0; } FREE_DTOA_LOCK(1); #else p51 = p5->next = mult(p5,p5); p51->next = 0; #endif } p5 = p51; } return b; } static Bigint * lshift #ifdef KR_headers (b, k) Bigint *b; int k; #else (Bigint *b, int k) #endif { int i, k1, n, n1; Bigint *b1; ULong *x, *x1, *xe, z; #ifdef Pack_32 n = k >> 5; #else n = k >> 4; #endif k1 = b->k; n1 = n + b->wds + 1; for(i = b->maxwds; n1 > i; i <<= 1) k1++; b1 = Balloc(k1); x1 = b1->x; for(i = 0; i < n; i++) *x1++ = 0; x = b->x; xe = x + b->wds; #ifdef Pack_32 if (k &= 0x1f) { k1 = 32 - k; z = 0; do { *x1++ = *x << k | z; z = *x++ >> k1; } while(x < xe); if ((*x1 = z)) ++n1; } #else if (k &= 0xf) { k1 = 16 - k; z = 0; do { *x1++ = *x << k & 0xffff | z; z = *x++ >> k1; } while(x < xe); if (*x1 = z) ++n1; } #endif else do *x1++ = *x++; while(x < xe); b1->wds = n1 - 1; Bfree(b); return b1; } static int cmp #ifdef KR_headers (a, b) Bigint *a, *b; #else (Bigint *a, Bigint *b) #endif { ULong *xa, *xa0, *xb, *xb0; int i, j; i = a->wds; j = b->wds; #ifdef DEBUG if (i > 1 && !a->x[i-1]) Bug("cmp called with a->x[a->wds-1] == 0"); if (j > 1 && !b->x[j-1]) Bug("cmp called with b->x[b->wds-1] == 0"); #endif if (i -= j) return i; xa0 = a->x; xa = xa0 + j; xb0 = b->x; xb = xb0 + j; for(;;) { if (*--xa != *--xb) return *xa < *xb ? -1 : 1; if (xa <= xa0) break; } return 0; } static Bigint * diff #ifdef KR_headers (a, b) Bigint *a, *b; #else (Bigint *a, Bigint *b) #endif { Bigint *c; int i, wa, wb; ULong *xa, *xae, *xb, *xbe, *xc; #ifdef ULLong ULLong borrow, y; #else ULong borrow, y; #ifdef Pack_32 ULong z; #endif #endif i = cmp(a,b); if (!i) { c = Balloc(0); c->wds = 1; c->x[0] = 0; return c; } if (i < 0) { c = a; a = b; b = c; i = 1; } else i = 0; c = Balloc(a->k); c->sign = i; wa = a->wds; xa = a->x; xae = xa + wa; wb = b->wds; xb = b->x; xbe = xb + wb; xc = c->x; borrow = 0; #ifdef ULLong do { y = (ULLong)*xa++ - *xb++ - borrow; borrow = y >> 32 & (ULong)1; *xc++ = y & FFFFFFFF; } while(xb < xbe); while(xa < xae) { y = *xa++ - borrow; borrow = y >> 32 & (ULong)1; *xc++ = y & FFFFFFFF; } #else #ifdef Pack_32 do { y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(xc, z, y); } while(xb < xbe); while(xa < xae) { y = (*xa & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*xa++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(xc, z, y); } #else do { y = *xa++ - *xb++ - borrow; borrow = (y & 0x10000) >> 16; *xc++ = y & 0xffff; } while(xb < xbe); while(xa < xae) { y = *xa++ - borrow; borrow = (y & 0x10000) >> 16; *xc++ = y & 0xffff; } #endif #endif while(!*--xc) wa--; c->wds = wa; return c; } static double ulp #ifdef KR_headers (x) U *x; #else (U *x) #endif { Long L; U u; L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; #ifndef Avoid_Underflow #ifndef Sudden_Underflow if (L > 0) { #endif #endif #ifdef IBM L |= Exp_msk1 >> 4; #endif word0(&u) = L; word1(&u) = 0; #ifndef Avoid_Underflow #ifndef Sudden_Underflow } else { L = -L >> Exp_shift; if (L < Exp_shift) { word0(&u) = 0x80000 >> L; word1(&u) = 0; } else { word0(&u) = 0; L -= Exp_shift; word1(&u) = L >= 31 ? 1 : 1 << 31 - L; } } #endif #endif return dval(&u); } static double b2d #ifdef KR_headers (a, e) Bigint *a; int *e; #else (Bigint *a, int *e) #endif { ULong *xa, *xa0, w, y, z; int k; U d; #ifdef VAX ULong d0, d1; #else #define d0 word0(&d) #define d1 word1(&d) #endif xa0 = a->x; xa = xa0 + a->wds; y = *--xa; #ifdef DEBUG if (!y) Bug("zero y in b2d"); #endif k = hi0bits(y); *e = 32 - k; #ifdef Pack_32 if (k < Ebits) { d0 = Exp_1 | y >> (Ebits - k); w = xa > xa0 ? *--xa : 0; d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); goto ret_d; } z = xa > xa0 ? *--xa : 0; if (k -= Ebits) { d0 = Exp_1 | y << k | z >> (32 - k); y = xa > xa0 ? *--xa : 0; d1 = z << k | y >> (32 - k); } else { d0 = Exp_1 | y; d1 = z; } #else if (k < Ebits + 16) { z = xa > xa0 ? *--xa : 0; d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; w = xa > xa0 ? *--xa : 0; y = xa > xa0 ? *--xa : 0; d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; goto ret_d; } z = xa > xa0 ? *--xa : 0; w = xa > xa0 ? *--xa : 0; k -= Ebits + 16; d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; y = xa > xa0 ? *--xa : 0; d1 = w << k + 16 | y << k; #endif ret_d: #ifdef VAX word0(&d) = d0 >> 16 | d0 << 16; word1(&d) = d1 >> 16 | d1 << 16; #else #undef d0 #undef d1 #endif return dval(&d); } static Bigint * d2b #ifdef KR_headers (d, e, bits) U *d; int *e, *bits; #else (U *d, int *e, int *bits) #endif { Bigint *b; int de, k; ULong *x, y, z; #ifndef Sudden_Underflow int i; #endif #ifdef VAX ULong d0, d1; d0 = word0(d) >> 16 | word0(d) << 16; d1 = word1(d) >> 16 | word1(d) << 16; #else #define d0 word0(d) #define d1 word1(d) #endif #ifdef Pack_32 b = Balloc(1); #else b = Balloc(2); #endif x = b->x; z = d0 & Frac_mask; d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ #ifdef Sudden_Underflow de = (int)(d0 >> Exp_shift); #ifndef IBM z |= Exp_msk11; #endif #else if ((de = (int)(d0 >> Exp_shift))) z |= Exp_msk1; #endif #ifdef Pack_32 if ((y = d1)) { if ((k = lo0bits(&y))) { x[0] = y | z << (32 - k); z >>= k; } else x[0] = y; #ifndef Sudden_Underflow i = #endif b->wds = (x[1] = z) ? 2 : 1; } else { k = lo0bits(&z); x[0] = z; #ifndef Sudden_Underflow i = #endif b->wds = 1; k += 32; } #else if (y = d1) { if (k = lo0bits(&y)) if (k >= 16) { x[0] = y | z << 32 - k & 0xffff; x[1] = z >> k - 16 & 0xffff; x[2] = z >> k; i = 2; } else { x[0] = y & 0xffff; x[1] = y >> 16 | z << 16 - k & 0xffff; x[2] = z >> k & 0xffff; x[3] = z >> k+16; i = 3; } else { x[0] = y & 0xffff; x[1] = y >> 16; x[2] = z & 0xffff; x[3] = z >> 16; i = 3; } } else { #ifdef DEBUG if (!z) Bug("Zero passed to d2b"); #endif k = lo0bits(&z); if (k >= 16) { x[0] = z; i = 0; } else { x[0] = z & 0xffff; x[1] = z >> 16; i = 1; } k += 32; } while(!x[i]) --i; b->wds = i + 1; #endif #ifndef Sudden_Underflow if (de) { #endif #ifdef IBM *e = (de - Bias - (P-1) << 2) + k; *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); #else *e = de - Bias - (P-1) + k; *bits = P - k; #endif #ifndef Sudden_Underflow } else { *e = de - Bias - (P-1) + 1 + k; #ifdef Pack_32 *bits = 32*i - hi0bits(x[i-1]); #else *bits = (i+2)*16 - hi0bits(x[i]); #endif } #endif return b; } #undef d0 #undef d1 static double ratio #ifdef KR_headers (a, b) Bigint *a, *b; #else (Bigint *a, Bigint *b) #endif { U da, db; int k, ka, kb; dval(&da) = b2d(a, &ka); dval(&db) = b2d(b, &kb); #ifdef Pack_32 k = ka - kb + 32*(a->wds - b->wds); #else k = ka - kb + 16*(a->wds - b->wds); #endif #ifdef IBM if (k > 0) { word0(&da) += (k >> 2)*Exp_msk1; if (k &= 3) dval(&da) *= 1 << k; } else { k = -k; word0(&db) += (k >> 2)*Exp_msk1; if (k &= 3) dval(&db) *= 1 << k; } #else if (k > 0) word0(&da) += k*Exp_msk1; else { k = -k; word0(&db) += k*Exp_msk1; } #endif return dval(&da) / dval(&db); } static CONST double tens[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 #ifdef VAX , 1e23, 1e24 #endif }; static CONST double #ifdef IEEE_Arith bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, #ifdef Avoid_Underflow 9007199254740992.*9007199254740992.e-256 /* = 2^106 * 1e-256 */ #else 1e-256 #endif }; /* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ /* flag unnecessarily. It leads to a song and dance at the end of strtod. */ #define Scale_Bit 0x10 #define n_bigtens 5 #else #ifdef IBM bigtens[] = { 1e16, 1e32, 1e64 }; static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; #define n_bigtens 3 #else bigtens[] = { 1e16, 1e32 }; static CONST double tinytens[] = { 1e-16, 1e-32 }; #define n_bigtens 2 #endif #endif #undef Need_Hexdig #ifdef INFNAN_CHECK #ifndef No_Hex_NaN #define Need_Hexdig #endif #endif #ifndef Need_Hexdig #ifndef NO_HEX_FP #define Need_Hexdig #endif #endif #ifdef Need_Hexdig /*{*/ static unsigned char hexdig[256]; static void #ifdef KR_headers htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc; #else htinit(unsigned char *h, unsigned char *s, int inc) #endif { int i, j; for(i = 0; (j = s[i]) !=0; i++) h[j] = i + inc; } static void #ifdef KR_headers hexdig_init() #else hexdig_init(void) #endif { #define USC (unsigned char *) htinit(hexdig, USC "0123456789", 0x10); htinit(hexdig, USC "abcdef", 0x10 + 10); htinit(hexdig, USC "ABCDEF", 0x10 + 10); } #endif /* } Need_Hexdig */ #ifdef INFNAN_CHECK #ifndef NAN_WORD0 #define NAN_WORD0 0x7ff80000 #endif #ifndef NAN_WORD1 #define NAN_WORD1 0 #endif static int match #ifdef KR_headers (sp, t) char **sp, *t; #else (const char **sp, const char *t) #endif { int c, d; CONST char *s = *sp; while((d = *t++)) { if ((c = *++s) >= 'A' && c <= 'Z') c += 'a' - 'A'; if (c != d) return 0; } *sp = s + 1; return 1; } #ifndef No_Hex_NaN static void hexnan #ifdef KR_headers (rvp, sp) U *rvp; CONST char **sp; #else (U *rvp, const char **sp) #endif { ULong c, x[2]; CONST char *s; int c1, havedig, udx0, xshift; if (!hexdig['0']) hexdig_init(); x[0] = x[1] = 0; havedig = xshift = 0; udx0 = 1; s = *sp; /* allow optional initial 0x or 0X */ while((c = *(CONST unsigned char*)(s+1)) && c <= ' ') ++s; if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X')) s += 2; while((c = *(CONST unsigned char*)++s)) { if ((c1 = hexdig[c])) c = c1 & 0xf; else if (c <= ' ') { if (udx0 && havedig) { udx0 = 0; xshift = 1; } continue; } #ifdef GDTOA_NON_PEDANTIC_NANCHECK else if (/*(*/ c == ')' && havedig) { *sp = s + 1; break; } else return; /* invalid form: don't change *sp */ #else else { do { if (/*(*/ c == ')') { *sp = s + 1; break; } } while((c = *++s)); break; } #endif havedig = 1; if (xshift) { xshift = 0; x[0] = x[1]; x[1] = 0; } if (udx0) x[0] = (x[0] << 4) | (x[1] >> 28); x[1] = (x[1] << 4) | c; } if ((x[0] &= 0xfffff) || x[1]) { word0(rvp) = Exp_mask | x[0]; word1(rvp) = x[1]; } } #endif /*No_Hex_NaN*/ #endif /* INFNAN_CHECK */ #ifdef Pack_32 #define ULbits 32 #define kshift 5 #define kmask 31 #else #define ULbits 16 #define kshift 4 #define kmask 15 #endif #if !defined(NO_HEX_FP) || defined(Honor_FLT_ROUNDS) /*{*/ static Bigint * #ifdef KR_headers increment(b) Bigint *b; #else increment(Bigint *b) #endif { ULong *x, *xe; Bigint *b1; x = b->x; xe = x + b->wds; do { if (*x < (ULong)0xffffffffL) { ++*x; return b; } *x++ = 0; } while(x < xe); { if (b->wds >= b->maxwds) { b1 = Balloc(b->k+1); Bcopy(b1,b); Bfree(b); b = b1; } b->x[b->wds++] = 1; } return b; } #endif /*}*/ #ifndef NO_HEX_FP /*{*/ static void #ifdef KR_headers rshift(b, k) Bigint *b; int k; #else rshift(Bigint *b, int k) #endif { ULong *x, *x1, *xe, y; int n; x = x1 = b->x; n = k >> kshift; if (n < b->wds) { xe = x + b->wds; x += n; if (k &= kmask) { n = 32 - k; y = *x++ >> k; while(x < xe) { *x1++ = (y | (*x << n)) & 0xffffffff; y = *x++ >> k; } if ((*x1 = y) !=0) x1++; } else while(x < xe) *x1++ = *x++; } if ((b->wds = x1 - b->x) == 0) b->x[0] = 0; } static ULong #ifdef KR_headers any_on(b, k) Bigint *b; int k; #else any_on(Bigint *b, int k) #endif { int n, nwds; ULong *x, *x0, x1, x2; x = b->x; nwds = b->wds; n = k >> kshift; if (n > nwds) n = nwds; else if (n < nwds && (k &= kmask)) { x1 = x2 = x[n]; x1 >>= k; x1 <<= k; if (x1 != x2) return 1; } x0 = x; x += n; while(x > x0) if (*--x) return 1; return 0; } enum { /* rounding values: same as FLT_ROUNDS */ Round_zero = 0, Round_near = 1, Round_up = 2, Round_down = 3 }; void #ifdef KR_headers gethex(sp, rvp, rounding, sign) CONST char **sp; U *rvp; int rounding, sign; #else gethex( CONST char **sp, U *rvp, int rounding, int sign) #endif { Bigint *b; CONST unsigned char *decpt, *s0, *s, *s1; Long e, e1; ULong L, lostbits, *x; int big, denorm, esign, havedig, k, n, nbits, up, zret; #ifdef IBM int j; #endif enum { #ifdef IEEE_Arith /*{{*/ emax = 0x7fe - Bias - P + 1, emin = Emin - P + 1 #else /*}{*/ emin = Emin - P, #ifdef VAX emax = 0x7ff - Bias - P + 1 #endif #ifdef IBM emax = 0x7f - Bias - P #endif #endif /*}}*/ }; #ifdef USE_LOCALE int i; #ifdef NO_LOCALE_CACHE const unsigned char *decimalpoint = (unsigned char*) localeconv()->decimal_point; #else const unsigned char *decimalpoint; static unsigned char *decimalpoint_cache; if (!(s0 = decimalpoint_cache)) { s0 = (unsigned char*)localeconv()->decimal_point; if ((decimalpoint_cache = (unsigned char*) MALLOC(strlen((CONST char*)s0) + 1))) { strcpy((char*)decimalpoint_cache, (CONST char*)s0); s0 = decimalpoint_cache; } } decimalpoint = s0; #endif #endif if (!hexdig['0']) hexdig_init(); havedig = 0; s0 = *(CONST unsigned char **)sp + 2; while(s0[havedig] == '0') havedig++; s0 += havedig; s = s0; decpt = 0; zret = 0; e = 0; if (hexdig[*s]) havedig++; else { zret = 1; #ifdef USE_LOCALE for(i = 0; decimalpoint[i]; ++i) { if (s[i] != decimalpoint[i]) goto pcheck; } decpt = s += i; #else if (*s != '.') goto pcheck; decpt = ++s; #endif if (!hexdig[*s]) goto pcheck; while(*s == '0') s++; if (hexdig[*s]) zret = 0; havedig = 1; s0 = s; } while(hexdig[*s]) s++; #ifdef USE_LOCALE if (*s == *decimalpoint && !decpt) { for(i = 1; decimalpoint[i]; ++i) { if (s[i] != decimalpoint[i]) goto pcheck; } decpt = s += i; #else if (*s == '.' && !decpt) { decpt = ++s; #endif while(hexdig[*s]) s++; }/*}*/ if (decpt) e = -(((Long)(s-decpt)) << 2); pcheck: s1 = s; big = esign = 0; switch(*s) { case 'p': case 'P': switch(*++s) { case '-': esign = 1; /* no break */ case '+': s++; } if ((n = hexdig[*s]) == 0 || n > 0x19) { s = s1; break; } e1 = n - 0x10; while((n = hexdig[*++s]) !=0 && n <= 0x19) { if (e1 & 0xf8000000) big = 1; e1 = 10*e1 + n - 0x10; } if (esign) e1 = -e1; e += e1; } *sp = (char*)s; if (!havedig) *sp = (char*)s0 - 1; if (zret) goto retz1; if (big) { if (esign) { #ifdef IEEE_Arith switch(rounding) { case Round_up: if (sign) break; goto ret_tiny; case Round_down: if (!sign) break; goto ret_tiny; } #endif goto retz; #ifdef IEEE_Arith ret_tiny: #ifndef NO_ERRNO errno = ERANGE; #endif word0(rvp) = 0; word1(rvp) = 1; return; #endif /* IEEE_Arith */ } switch(rounding) { case Round_near: goto ovfl1; case Round_up: if (!sign) goto ovfl1; goto ret_big; case Round_down: if (sign) goto ovfl1; goto ret_big; } ret_big: word0(rvp) = Big0; word1(rvp) = Big1; return; } n = s1 - s0 - 1; for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) k++; b = Balloc(k); x = b->x; n = 0; L = 0; #ifdef USE_LOCALE for(i = 0; decimalpoint[i+1]; ++i); #endif while(s1 > s0) { #ifdef USE_LOCALE if (*--s1 == decimalpoint[i]) { s1 -= i; continue; } #else if (*--s1 == '.') continue; #endif if (n == ULbits) { *x++ = L; L = 0; n = 0; } L |= (hexdig[*s1] & 0x0f) << n; n += 4; } *x++ = L; b->wds = n = x - b->x; n = ULbits*n - hi0bits(L); nbits = Nbits; lostbits = 0; x = b->x; if (n > nbits) { n -= nbits; if (any_on(b,n)) { lostbits = 1; k = n - 1; if (x[k>>kshift] & 1 << (k & kmask)) { lostbits = 2; if (k > 0 && any_on(b,k)) lostbits = 3; } } rshift(b, n); e += n; } else if (n < nbits) { n = nbits - n; b = lshift(b, n); e -= n; x = b->x; } if (e > Emax) { ovfl: Bfree(b); ovfl1: #ifndef NO_ERRNO errno = ERANGE; #endif word0(rvp) = Exp_mask; word1(rvp) = 0; return; } denorm = 0; if (e < emin) { denorm = 1; n = emin - e; if (n >= nbits) { #ifdef IEEE_Arith /*{*/ switch (rounding) { case Round_near: if (n == nbits && (n < 2 || any_on(b,n-1))) goto ret_tiny; break; case Round_up: if (!sign) goto ret_tiny; break; case Round_down: if (sign) goto ret_tiny; } #endif /* } IEEE_Arith */ Bfree(b); retz: #ifndef NO_ERRNO errno = ERANGE; #endif retz1: rvp->d = 0.; return; } k = n - 1; if (lostbits) lostbits = 1; else if (k > 0) lostbits = any_on(b,k); if (x[k>>kshift] & 1 << (k & kmask)) lostbits |= 2; nbits -= n; rshift(b,n); e = emin; } if (lostbits) { up = 0; switch(rounding) { case Round_zero: break; case Round_near: if (lostbits & 2 && (lostbits & 1) | (x[0] & 1)) up = 1; break; case Round_up: up = 1 - sign; break; case Round_down: up = sign; } if (up) { k = b->wds; b = increment(b); x = b->x; if (denorm) { #if 0 if (nbits == Nbits - 1 && x[nbits >> kshift] & 1 << (nbits & kmask)) denorm = 0; /* not currently used */ #endif } else if (b->wds > k || ((n = nbits & kmask) !=0 && hi0bits(x[k-1]) < 32-n)) { rshift(b,1); if (++e > Emax) goto ovfl; } } } #ifdef IEEE_Arith if (denorm) word0(rvp) = b->wds > 1 ? b->x[1] & ~0x100000 : 0; else word0(rvp) = (b->x[1] & ~0x100000) | ((e + 0x3ff + 52) << 20); word1(rvp) = b->x[0]; #endif #ifdef IBM if ((j = e & 3)) { k = b->x[0] & ((1 << j) - 1); rshift(b,j); if (k) { switch(rounding) { case Round_up: if (!sign) increment(b); break; case Round_down: if (sign) increment(b); break; case Round_near: j = 1 << (j-1); if (k & j && ((k & (j-1)) | lostbits)) increment(b); } } } e >>= 2; word0(rvp) = b->x[1] | ((e + 65 + 13) << 24); word1(rvp) = b->x[0]; #endif #ifdef VAX /* The next two lines ignore swap of low- and high-order 2 bytes. */ /* word0(rvp) = (b->x[1] & ~0x800000) | ((e + 129 + 55) << 23); */ /* word1(rvp) = b->x[0]; */ word0(rvp) = ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) | (b->x[1] << 16); word1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16); #endif Bfree(b); } #endif /*!NO_HEX_FP}*/ static int #ifdef KR_headers dshift(b, p2) Bigint *b; int p2; #else dshift(Bigint *b, int p2) #endif { int rv = hi0bits(b->x[b->wds-1]) - 4; if (p2 > 0) rv -= p2; return rv & kmask; } static int quorem #ifdef KR_headers (b, S) Bigint *b, *S; #else (Bigint *b, Bigint *S) #endif { int n; ULong *bx, *bxe, q, *sx, *sxe; #ifdef ULLong ULLong borrow, carry, y, ys; #else ULong borrow, carry, y, ys; #ifdef Pack_32 ULong si, z, zs; #endif #endif n = S->wds; #ifdef DEBUG /*debug*/ if (b->wds > n) /*debug*/ Bug("oversize b in quorem"); #endif if (b->wds < n) return 0; sx = S->x; sxe = sx + --n; bx = b->x; bxe = bx + n; q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ #ifdef DEBUG #ifdef NO_STRTOD_BIGCOMP /*debug*/ if (q > 9) #else /* An oversized q is possible when quorem is called from bigcomp and */ /* the input is near, e.g., twice the smallest denormalized number. */ /*debug*/ if (q > 15) #endif /*debug*/ Bug("oversized quotient in quorem"); #endif if (q) { borrow = 0; carry = 0; do { #ifdef ULLong ys = *sx++ * (ULLong)q + carry; carry = ys >> 32; y = *bx - (ys & FFFFFFFF) - borrow; borrow = y >> 32 & (ULong)1; *bx++ = y & FFFFFFFF; #else #ifdef Pack_32 si = *sx++; ys = (si & 0xffff) * q + carry; zs = (si >> 16) * q + (ys >> 16); carry = zs >> 16; y = (*bx & 0xffff) - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(bx, z, y); #else ys = *sx++ * q + carry; carry = ys >> 16; y = *bx - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; *bx++ = y & 0xffff; #endif #endif } while(sx <= sxe); if (!*bxe) { bx = b->x; while(--bxe > bx && !*bxe) --n; b->wds = n; } } if (cmp(b, S) >= 0) { q++; borrow = 0; carry = 0; bx = b->x; sx = S->x; do { #ifdef ULLong ys = *sx++ + carry; carry = ys >> 32; y = *bx - (ys & FFFFFFFF) - borrow; borrow = y >> 32 & (ULong)1; *bx++ = y & FFFFFFFF; #else #ifdef Pack_32 si = *sx++; ys = (si & 0xffff) + carry; zs = (si >> 16) + (ys >> 16); carry = zs >> 16; y = (*bx & 0xffff) - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(bx, z, y); #else ys = *sx++ + carry; carry = ys >> 16; y = *bx - (ys & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; *bx++ = y & 0xffff; #endif #endif } while(sx <= sxe); bx = b->x; bxe = bx + n; if (!*bxe) { while(--bxe > bx && !*bxe) --n; b->wds = n; } } return q; } #if defined(Avoid_Underflow) || !defined(NO_STRTOD_BIGCOMP) /*{*/ static double sulp #ifdef KR_headers (x, bc) U *x; BCinfo *bc; #else (U *x, BCinfo *bc) #endif { U u; double rv; int i; rv = ulp(x); if (!bc->scale || (i = 2*P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0) return rv; /* Is there an example where i <= 0 ? */ word0(&u) = Exp_1 + (i << Exp_shift); word1(&u) = 0; return rv * u.d; } #endif /*}*/ #ifndef NO_STRTOD_BIGCOMP static void bigcomp #ifdef KR_headers (rv, s0, bc) U *rv; CONST char *s0; BCinfo *bc; #else (U *rv, const char *s0, BCinfo *bc) #endif { Bigint *b, *d; int b2, bbits, d2, dd, dig, dsign, i, j, nd, nd0, p2, p5, speccase; dsign = bc->dsign; nd = bc->nd; nd0 = bc->nd0; p5 = nd + bc->e0 - 1; speccase = 0; #ifndef Sudden_Underflow if (rv->d == 0.) { /* special case: value near underflow-to-zero */ /* threshold was rounded to zero */ b = i2b(1); p2 = Emin - P + 1; bbits = 1; #ifdef Avoid_Underflow word0(rv) = (P+2) << Exp_shift; #else word1(rv) = 1; #endif i = 0; #ifdef Honor_FLT_ROUNDS if (bc->rounding == 1) #endif { speccase = 1; --p2; dsign = 0; goto have_i; } } else #endif b = d2b(rv, &p2, &bbits); #ifdef Avoid_Underflow p2 -= bc->scale; #endif /* floor(log2(rv)) == bbits - 1 + p2 */ /* Check for denormal case. */ i = P - bbits; if (i > (j = P - Emin - 1 + p2)) { #ifdef Sudden_Underflow Bfree(b); b = i2b(1); p2 = Emin; i = P - 1; #ifdef Avoid_Underflow word0(rv) = (1 + bc->scale) << Exp_shift; #else word0(rv) = Exp_msk1; #endif word1(rv) = 0; #else i = j; #endif } #ifdef Honor_FLT_ROUNDS if (bc->rounding != 1) { if (i > 0) b = lshift(b, i); if (dsign) b = increment(b); } else #endif { b = lshift(b, ++i); b->x[0] |= 1; } #ifndef Sudden_Underflow have_i: #endif p2 -= p5 + i; d = i2b(1); /* Arrange for convenient computation of quotients: * shift left if necessary so divisor has 4 leading 0 bits. */ if (p5 > 0) d = pow5mult(d, p5); else if (p5 < 0) b = pow5mult(b, -p5); if (p2 > 0) { b2 = p2; d2 = 0; } else { b2 = 0; d2 = -p2; } i = dshift(d, d2); if ((b2 += i) > 0) b = lshift(b, b2); if ((d2 += i) > 0) d = lshift(d, d2); /* Now b/d = exactly half-way between the two floating-point values */ /* on either side of the input string. Compute first digit of b/d. */ if (!(dig = quorem(b,d))) { b = multadd(b, 10, 0); /* very unlikely */ dig = quorem(b,d); } /* Compare b/d with s0 */ for(i = 0; i < nd0; ) { if ((dd = s0[i++] - '0' - dig)) goto ret; if (!b->x[0] && b->wds == 1) { if (i < nd) dd = 1; goto ret; } b = multadd(b, 10, 0); dig = quorem(b,d); } for(j = bc->dp1; i++ < nd;) { if ((dd = s0[j++] - '0' - dig)) goto ret; if (!b->x[0] && b->wds == 1) { if (i < nd) dd = 1; goto ret; } b = multadd(b, 10, 0); dig = quorem(b,d); } if (b->x[0] || b->wds > 1) dd = -1; ret: Bfree(b); Bfree(d); #ifdef Honor_FLT_ROUNDS if (bc->rounding != 1) { if (dd < 0) { if (bc->rounding == 0) { if (!dsign) goto retlow1; } else if (dsign) goto rethi1; } else if (dd > 0) { if (bc->rounding == 0) { if (dsign) goto rethi1; goto ret1; } if (!dsign) goto rethi1; dval(rv) += 2.*sulp(rv,bc); } else { bc->inexact = 0; if (dsign) goto rethi1; } } else #endif if (speccase) { if (dd <= 0) rv->d = 0.; } else if (dd < 0) { if (!dsign) /* does not happen for round-near */ retlow1: dval(rv) -= sulp(rv,bc); } else if (dd > 0) { if (dsign) { rethi1: dval(rv) += sulp(rv,bc); } } else { /* Exact half-way case: apply round-even rule. */ if ((j = ((word0(rv) & Exp_mask) >> Exp_shift) - bc->scale) <= 0) { i = 1 - j; if (i <= 31) { if (word1(rv) & (0x1 << i)) goto odd; } else if (word0(rv) & (0x1 << (i-32))) goto odd; } else if (word1(rv) & 1) { odd: if (dsign) goto rethi1; goto retlow1; } } #ifdef Honor_FLT_ROUNDS ret1: #endif return; } #endif /* NO_STRTOD_BIGCOMP */ double fpconv_strtod #ifdef KR_headers (s00, se) CONST char *s00; char **se; #else (const char *s00, char **se) #endif { int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1; int esign, i, j, k, nd, nd0, nf, nz, nz0, nz1, sign; CONST char *s, *s0, *s1; double aadj, aadj1; Long L; U aadj2, adj, rv, rv0; ULong y, z; BCinfo bc; Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; #ifdef Avoid_Underflow ULong Lsb, Lsb1; #endif #ifdef SET_INEXACT int oldinexact; #endif #ifndef NO_STRTOD_BIGCOMP int req_bigcomp = 0; #endif #ifdef Honor_FLT_ROUNDS /*{*/ #ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ bc.rounding = Flt_Rounds; #else /*}{*/ bc.rounding = 1; switch(fegetround()) { case FE_TOWARDZERO: bc.rounding = 0; break; case FE_UPWARD: bc.rounding = 2; break; case FE_DOWNWARD: bc.rounding = 3; } #endif /*}}*/ #endif /*}*/ #ifdef USE_LOCALE CONST char *s2; #endif sign = nz0 = nz1 = nz = bc.dplen = bc.uflchk = 0; dval(&rv) = 0.; for(s = s00;;s++) switch(*s) { case '-': sign = 1; /* no break */ case '+': if (*++s) goto break2; /* no break */ case 0: goto ret0; case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': continue; default: goto break2; } break2: if (*s == '0') { #ifndef NO_HEX_FP /*{*/ switch(s[1]) { case 'x': case 'X': #ifdef Honor_FLT_ROUNDS gethex(&s, &rv, bc.rounding, sign); #else gethex(&s, &rv, 1, sign); #endif goto ret; } #endif /*}*/ nz0 = 1; while(*++s == '0') ; if (!*s) goto ret; } s0 = s; y = z = 0; for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) if (nd < 9) y = 10*y + c - '0'; else if (nd < 16) z = 10*z + c - '0'; nd0 = nd; bc.dp0 = bc.dp1 = s - s0; for(s1 = s; s1 > s0 && *--s1 == '0'; ) ++nz1; #ifdef USE_LOCALE s1 = localeconv()->decimal_point; if (c == *s1) { c = '.'; if (*++s1) { s2 = s; for(;;) { if (*++s2 != *s1) { c = 0; break; } if (!*++s1) { s = s2; break; } } } } #endif if (c == '.') { c = *++s; bc.dp1 = s - s0; bc.dplen = bc.dp1 - bc.dp0; if (!nd) { for(; c == '0'; c = *++s) nz++; if (c > '0' && c <= '9') { bc.dp0 = s0 - s; bc.dp1 = bc.dp0 + bc.dplen; s0 = s; nf += nz; nz = 0; goto have_dig; } goto dig_done; } for(; c >= '0' && c <= '9'; c = *++s) { have_dig: nz++; if (c -= '0') { nf += nz; for(i = 1; i < nz; i++) if (nd++ < 9) y *= 10; else if (nd <= DBL_DIG + 1) z *= 10; if (nd++ < 9) y = 10*y + c; else if (nd <= DBL_DIG + 1) z = 10*z + c; nz = nz1 = 0; } } } dig_done: e = 0; if (c == 'e' || c == 'E') { if (!nd && !nz && !nz0) { goto ret0; } s00 = s; esign = 0; switch(c = *++s) { case '-': esign = 1; case '+': c = *++s; } if (c >= '0' && c <= '9') { while(c == '0') c = *++s; if (c > '0' && c <= '9') { L = c - '0'; s1 = s; while((c = *++s) >= '0' && c <= '9') L = 10*L + c - '0'; if (s - s1 > 8 || L > 19999) /* Avoid confusion from exponents * so large that e might overflow. */ e = 19999; /* safe for 16 bit ints */ else e = (int)L; if (esign) e = -e; } else e = 0; } else s = s00; } if (!nd) { if (!nz && !nz0) { #ifdef INFNAN_CHECK /* Check for Nan and Infinity */ if (!bc.dplen) switch(c) { case 'i': case 'I': if (match(&s,"nf")) { --s; if (!match(&s,"inity")) ++s; word0(&rv) = 0x7ff00000; word1(&rv) = 0; goto ret; } break; case 'n': case 'N': if (match(&s, "an")) { word0(&rv) = NAN_WORD0; word1(&rv) = NAN_WORD1; #ifndef No_Hex_NaN if (*s == '(') /*)*/ hexnan(&rv, &s); #endif goto ret; } } #endif /* INFNAN_CHECK */ ret0: s = s00; sign = 0; } goto ret; } bc.e0 = e1 = e -= nf; /* Now we have nd0 digits, starting at s0, followed by a * decimal point, followed by nd-nd0 digits. The number we're * after is the integer represented by those digits times * 10**e */ if (!nd0) nd0 = nd; k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; dval(&rv) = y; if (k > 9) { #ifdef SET_INEXACT if (k > DBL_DIG) oldinexact = get_inexact(); #endif dval(&rv) = tens[k - 9] * dval(&rv) + z; } bd0 = 0; if (nd <= DBL_DIG #ifndef RND_PRODQUOT #ifndef Honor_FLT_ROUNDS && Flt_Rounds == 1 #endif #endif ) { if (!e) goto ret; #ifndef ROUND_BIASED_without_Round_Up if (e > 0) { if (e <= Ten_pmax) { #ifdef VAX goto vax_ovfl_check; #else #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { rv.d = -rv.d; sign = 0; } #endif /* rv = */ rounded_product(dval(&rv), tens[e]); goto ret; #endif } i = DBL_DIG - nd; if (e <= Ten_pmax + i) { /* A fancier test would sometimes let us do * this for larger i values. */ #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { rv.d = -rv.d; sign = 0; } #endif e -= i; dval(&rv) *= tens[i]; #ifdef VAX /* VAX exponent range is so narrow we must * worry about overflow here... */ vax_ovfl_check: word0(&rv) -= P*Exp_msk1; /* rv = */ rounded_product(dval(&rv), tens[e]); if ((word0(&rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) goto ovfl; word0(&rv) += P*Exp_msk1; #else /* rv = */ rounded_product(dval(&rv), tens[e]); #endif goto ret; } } #ifndef Inaccurate_Divide else if (e >= -Ten_pmax) { #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { rv.d = -rv.d; sign = 0; } #endif /* rv = */ rounded_quotient(dval(&rv), tens[-e]); goto ret; } #endif #endif /* ROUND_BIASED_without_Round_Up */ } e1 += nd - k; #ifdef IEEE_Arith #ifdef SET_INEXACT bc.inexact = 1; if (k <= DBL_DIG) oldinexact = get_inexact(); #endif #ifdef Avoid_Underflow bc.scale = 0; #endif #ifdef Honor_FLT_ROUNDS if (bc.rounding >= 2) { if (sign) bc.rounding = bc.rounding == 2 ? 0 : 2; else if (bc.rounding != 2) bc.rounding = 0; } #endif #endif /*IEEE_Arith*/ /* Get starting approximation = rv * 10**e1 */ if (e1 > 0) { if ((i = e1 & 15)) dval(&rv) *= tens[i]; if (e1 &= ~15) { if (e1 > DBL_MAX_10_EXP) { ovfl: /* Can't trust HUGE_VAL */ #ifdef IEEE_Arith #ifdef Honor_FLT_ROUNDS switch(bc.rounding) { case 0: /* toward 0 */ case 3: /* toward -infinity */ word0(&rv) = Big0; word1(&rv) = Big1; break; default: word0(&rv) = Exp_mask; word1(&rv) = 0; } #else /*Honor_FLT_ROUNDS*/ word0(&rv) = Exp_mask; word1(&rv) = 0; #endif /*Honor_FLT_ROUNDS*/ #ifdef SET_INEXACT /* set overflow bit */ dval(&rv0) = 1e300; dval(&rv0) *= dval(&rv0); #endif #else /*IEEE_Arith*/ word0(&rv) = Big0; word1(&rv) = Big1; #endif /*IEEE_Arith*/ range_err: if (bd0) { Bfree(bb); Bfree(bd); Bfree(bs); Bfree(bd0); Bfree(delta); } #ifndef NO_ERRNO errno = ERANGE; #endif goto ret; } e1 >>= 4; for(j = 0; e1 > 1; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= bigtens[j]; /* The last multiplication could overflow. */ word0(&rv) -= P*Exp_msk1; dval(&rv) *= bigtens[j]; if ((z = word0(&rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-P)) goto ovfl; if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { /* set to largest number */ /* (Can't trust DBL_MAX) */ word0(&rv) = Big0; word1(&rv) = Big1; } else word0(&rv) += P*Exp_msk1; } } else if (e1 < 0) { e1 = -e1; if ((i = e1 & 15)) dval(&rv) /= tens[i]; if (e1 >>= 4) { if (e1 >= 1 << n_bigtens) goto undfl; #ifdef Avoid_Underflow if (e1 & Scale_Bit) bc.scale = 2*P; for(j = 0; e1 > 0; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= tinytens[j]; if (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask) >> Exp_shift)) > 0) { /* scaled rv is denormal; clear j low bits */ if (j >= 32) { if (j > 54) goto undfl; word1(&rv) = 0; if (j >= 53) word0(&rv) = (P+2)*Exp_msk1; else word0(&rv) &= 0xffffffff << (j-32); } else word1(&rv) &= 0xffffffff << j; } #else for(j = 0; e1 > 1; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= tinytens[j]; /* The last multiplication could underflow. */ dval(&rv0) = dval(&rv); dval(&rv) *= tinytens[j]; if (!dval(&rv)) { dval(&rv) = 2.*dval(&rv0); dval(&rv) *= tinytens[j]; #endif if (!dval(&rv)) { undfl: dval(&rv) = 0.; goto range_err; } #ifndef Avoid_Underflow word0(&rv) = Tiny0; word1(&rv) = Tiny1; /* The refinement below will clean * this approximation up. */ } #endif } } /* Now the hard part -- adjusting rv to the correct value.*/ /* Put digits into bd: true value = bd * 10^e */ bc.nd = nd - nz1; #ifndef NO_STRTOD_BIGCOMP bc.nd0 = nd0; /* Only needed if nd > strtod_diglim, but done here */ /* to silence an erroneous warning about bc.nd0 */ /* possibly not being initialized. */ if (nd > strtod_diglim) { /* ASSERT(strtod_diglim >= 18); 18 == one more than the */ /* minimum number of decimal digits to distinguish double values */ /* in IEEE arithmetic. */ i = j = 18; if (i > nd0) j += bc.dplen; for(;;) { if (--j < bc.dp1 && j >= bc.dp0) j = bc.dp0 - 1; if (s0[j] != '0') break; --i; } e += nd - i; nd = i; if (nd0 > nd) nd0 = nd; if (nd < 9) { /* must recompute y */ y = 0; for(i = 0; i < nd0; ++i) y = 10*y + s0[i] - '0'; for(j = bc.dp1; i < nd; ++i) y = 10*y + s0[j++] - '0'; } } #endif bd0 = s2b(s0, nd0, nd, y, bc.dplen); for(;;) { bd = Balloc(bd0->k); Bcopy(bd, bd0); bb = d2b(&rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ bs = i2b(1); if (e >= 0) { bb2 = bb5 = 0; bd2 = bd5 = e; } else { bb2 = bb5 = -e; bd2 = bd5 = 0; } if (bbe >= 0) bb2 += bbe; else bd2 -= bbe; bs2 = bb2; #ifdef Honor_FLT_ROUNDS if (bc.rounding != 1) bs2++; #endif #ifdef Avoid_Underflow Lsb = LSB; Lsb1 = 0; j = bbe - bc.scale; i = j + bbbits - 1; /* logb(rv) */ j = P + 1 - bbbits; if (i < Emin) { /* denormal */ i = Emin - i; j -= i; if (i < 32) Lsb <<= i; else if (i < 52) Lsb1 = Lsb << (i-32); else Lsb1 = Exp_mask; } #else /*Avoid_Underflow*/ #ifdef Sudden_Underflow #ifdef IBM j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); #else j = P + 1 - bbbits; #endif #else /*Sudden_Underflow*/ j = bbe; i = j + bbbits - 1; /* logb(rv) */ if (i < Emin) /* denormal */ j += P - Emin; else j = P + 1 - bbbits; #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ bb2 += j; bd2 += j; #ifdef Avoid_Underflow bd2 += bc.scale; #endif i = bb2 < bd2 ? bb2 : bd2; if (i > bs2) i = bs2; if (i > 0) { bb2 -= i; bd2 -= i; bs2 -= i; } if (bb5 > 0) { bs = pow5mult(bs, bb5); bb1 = mult(bs, bb); Bfree(bb); bb = bb1; } if (bb2 > 0) bb = lshift(bb, bb2); if (bd5 > 0) bd = pow5mult(bd, bd5); if (bd2 > 0) bd = lshift(bd, bd2); if (bs2 > 0) bs = lshift(bs, bs2); delta = diff(bb, bd); bc.dsign = delta->sign; delta->sign = 0; i = cmp(delta, bs); #ifndef NO_STRTOD_BIGCOMP /*{*/ if (bc.nd > nd && i <= 0) { if (bc.dsign) { /* Must use bigcomp(). */ req_bigcomp = 1; break; } #ifdef Honor_FLT_ROUNDS if (bc.rounding != 1) { if (i < 0) { req_bigcomp = 1; break; } } else #endif i = -1; /* Discarded digits make delta smaller. */ } #endif /*}*/ #ifdef Honor_FLT_ROUNDS /*{*/ if (bc.rounding != 1) { if (i < 0) { /* Error is less than an ulp */ if (!delta->x[0] && delta->wds <= 1) { /* exact */ #ifdef SET_INEXACT bc.inexact = 0; #endif break; } if (bc.rounding) { if (bc.dsign) { adj.d = 1.; goto apply_adj; } } else if (!bc.dsign) { adj.d = -1.; if (!word1(&rv) && !(word0(&rv) & Frac_mask)) { y = word0(&rv) & Exp_mask; #ifdef Avoid_Underflow if (!bc.scale || y > 2*P*Exp_msk1) #else if (y) #endif { delta = lshift(delta,Log2P); if (cmp(delta, bs) <= 0) adj.d = -0.5; } } apply_adj: #ifdef Avoid_Underflow /*{*/ if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) word0(&adj) += (2*P+1)*Exp_msk1 - y; #else #ifdef Sudden_Underflow if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { word0(&rv) += P*Exp_msk1; dval(&rv) += adj.d*ulp(dval(&rv)); word0(&rv) -= P*Exp_msk1; } else #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow}*/ dval(&rv) += adj.d*ulp(&rv); } break; } adj.d = ratio(delta, bs); if (adj.d < 1.) adj.d = 1.; if (adj.d <= 0x7ffffffe) { /* adj = rounding ? ceil(adj) : floor(adj); */ y = adj.d; if (y != adj.d) { if (!((bc.rounding>>1) ^ bc.dsign)) y++; adj.d = y; } } #ifdef Avoid_Underflow /*{*/ if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) word0(&adj) += (2*P+1)*Exp_msk1 - y; #else #ifdef Sudden_Underflow if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { word0(&rv) += P*Exp_msk1; adj.d *= ulp(dval(&rv)); if (bc.dsign) dval(&rv) += adj.d; else dval(&rv) -= adj.d; word0(&rv) -= P*Exp_msk1; goto cont; } #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow}*/ adj.d *= ulp(&rv); if (bc.dsign) { if (word0(&rv) == Big0 && word1(&rv) == Big1) goto ovfl; dval(&rv) += adj.d; } else dval(&rv) -= adj.d; goto cont; } #endif /*}Honor_FLT_ROUNDS*/ if (i < 0) { /* Error is less than half an ulp -- check for * special case of mantissa a power of two. */ if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask #ifdef IEEE_Arith /*{*/ #ifdef Avoid_Underflow || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1 #else || (word0(&rv) & Exp_mask) <= Exp_msk1 #endif #endif /*}*/ ) { #ifdef SET_INEXACT if (!delta->x[0] && delta->wds <= 1) bc.inexact = 0; #endif break; } if (!delta->x[0] && delta->wds <= 1) { /* exact result */ #ifdef SET_INEXACT bc.inexact = 0; #endif break; } delta = lshift(delta,Log2P); if (cmp(delta, bs) > 0) goto drop_down; break; } if (i == 0) { /* exactly half-way between */ if (bc.dsign) { if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 && word1(&rv) == ( #ifdef Avoid_Underflow (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : #endif 0xffffffff)) { /*boundary case -- increment exponent*/ if (word0(&rv) == Big0 && word1(&rv) == Big1) goto ovfl; word0(&rv) = (word0(&rv) & Exp_mask) + Exp_msk1 #ifdef IBM | Exp_msk1 >> 4 #endif ; word1(&rv) = 0; #ifdef Avoid_Underflow bc.dsign = 0; #endif break; } } else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { drop_down: /* boundary case -- decrement exponent */ #ifdef Sudden_Underflow /*{{*/ L = word0(&rv) & Exp_mask; #ifdef IBM if (L < Exp_msk1) #else #ifdef Avoid_Underflow if (L <= (bc.scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) #else if (L <= Exp_msk1) #endif /*Avoid_Underflow*/ #endif /*IBM*/ { if (bc.nd >nd) { bc.uflchk = 1; break; } goto undfl; } L -= Exp_msk1; #else /*Sudden_Underflow}{*/ #ifdef Avoid_Underflow if (bc.scale) { L = word0(&rv) & Exp_mask; if (L <= (2*P+1)*Exp_msk1) { if (L > (P+2)*Exp_msk1) /* round even ==> */ /* accept rv */ break; /* rv = smallest denormal */ if (bc.nd >nd) { bc.uflchk = 1; break; } goto undfl; } } #endif /*Avoid_Underflow*/ L = (word0(&rv) & Exp_mask) - Exp_msk1; #endif /*Sudden_Underflow}}*/ word0(&rv) = L | Bndry_mask1; word1(&rv) = 0xffffffff; #ifdef IBM goto cont; #else #ifndef NO_STRTOD_BIGCOMP if (bc.nd > nd) goto cont; #endif break; #endif } #ifndef ROUND_BIASED #ifdef Avoid_Underflow if (Lsb1) { if (!(word0(&rv) & Lsb1)) break; } else if (!(word1(&rv) & Lsb)) break; #else if (!(word1(&rv) & LSB)) break; #endif #endif if (bc.dsign) #ifdef Avoid_Underflow dval(&rv) += sulp(&rv, &bc); #else dval(&rv) += ulp(&rv); #endif #ifndef ROUND_BIASED else { #ifdef Avoid_Underflow dval(&rv) -= sulp(&rv, &bc); #else dval(&rv) -= ulp(&rv); #endif #ifndef Sudden_Underflow if (!dval(&rv)) { if (bc.nd >nd) { bc.uflchk = 1; break; } goto undfl; } #endif } #ifdef Avoid_Underflow bc.dsign = 1 - bc.dsign; #endif #endif break; } if ((aadj = ratio(delta, bs)) <= 2.) { if (bc.dsign) aadj = aadj1 = 1.; else if (word1(&rv) || word0(&rv) & Bndry_mask) { #ifndef Sudden_Underflow if (word1(&rv) == Tiny1 && !word0(&rv)) { if (bc.nd >nd) { bc.uflchk = 1; break; } goto undfl; } #endif aadj = 1.; aadj1 = -1.; } else { /* special case -- power of FLT_RADIX to be */ /* rounded down... */ if (aadj < 2./FLT_RADIX) aadj = 1./FLT_RADIX; else aadj *= 0.5; aadj1 = -aadj; } } else { aadj *= 0.5; aadj1 = bc.dsign ? aadj : -aadj; #ifdef Check_FLT_ROUNDS switch(bc.rounding) { case 2: /* towards +infinity */ aadj1 -= 0.5; break; case 0: /* towards 0 */ case 3: /* towards -infinity */ aadj1 += 0.5; } #else if (Flt_Rounds == 0) aadj1 += 0.5; #endif /*Check_FLT_ROUNDS*/ } y = word0(&rv) & Exp_mask; /* Check for overflow */ if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { dval(&rv0) = dval(&rv); word0(&rv) -= P*Exp_msk1; adj.d = aadj1 * ulp(&rv); dval(&rv) += adj.d; if ((word0(&rv) & Exp_mask) >= Exp_msk1*(DBL_MAX_EXP+Bias-P)) { if (word0(&rv0) == Big0 && word1(&rv0) == Big1) goto ovfl; word0(&rv) = Big0; word1(&rv) = Big1; goto cont; } else word0(&rv) += P*Exp_msk1; } else { #ifdef Avoid_Underflow if (bc.scale && y <= 2*P*Exp_msk1) { if (aadj <= 0x7fffffff) { if ((z = aadj) <= 0) z = 1; aadj = z; aadj1 = bc.dsign ? aadj : -aadj; } dval(&aadj2) = aadj1; word0(&aadj2) += (2*P+1)*Exp_msk1 - y; aadj1 = dval(&aadj2); adj.d = aadj1 * ulp(&rv); dval(&rv) += adj.d; if (rv.d == 0.) #ifdef NO_STRTOD_BIGCOMP goto undfl; #else { if (bc.nd > nd) bc.dsign = 1; break; } #endif } else { adj.d = aadj1 * ulp(&rv); dval(&rv) += adj.d; } #else #ifdef Sudden_Underflow if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { dval(&rv0) = dval(&rv); word0(&rv) += P*Exp_msk1; adj.d = aadj1 * ulp(&rv); dval(&rv) += adj.d; #ifdef IBM if ((word0(&rv) & Exp_mask) < P*Exp_msk1) #else if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) #endif { if (word0(&rv0) == Tiny0 && word1(&rv0) == Tiny1) { if (bc.nd >nd) { bc.uflchk = 1; break; } goto undfl; } word0(&rv) = Tiny0; word1(&rv) = Tiny1; goto cont; } else word0(&rv) -= P*Exp_msk1; } else { adj.d = aadj1 * ulp(&rv); dval(&rv) += adj.d; } #else /*Sudden_Underflow*/ /* Compute adj so that the IEEE rounding rules will * correctly round rv + adj in some half-way cases. * If rv * ulp(rv) is denormalized (i.e., * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid * trouble from bits lost to denormalization; * example: 1.2e-307 . */ if (y <= (P-1)*Exp_msk1 && aadj > 1.) { aadj1 = (double)(int)(aadj + 0.5); if (!bc.dsign) aadj1 = -aadj1; } adj.d = aadj1 * ulp(&rv); dval(&rv) += adj.d; #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ } z = word0(&rv) & Exp_mask; #ifndef SET_INEXACT if (bc.nd == nd) { #ifdef Avoid_Underflow if (!bc.scale) #endif if (y == z) { /* Can we stop now? */ L = (Long)aadj; aadj -= L; /* The tolerances below are conservative. */ if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask) { if (aadj < .4999999 || aadj > .5000001) break; } else if (aadj < .4999999/FLT_RADIX) break; } } #endif cont: Bfree(bb); Bfree(bd); Bfree(bs); Bfree(delta); } Bfree(bb); Bfree(bd); Bfree(bs); Bfree(bd0); Bfree(delta); #ifndef NO_STRTOD_BIGCOMP if (req_bigcomp) { bd0 = 0; bc.e0 += nz1; bigcomp(&rv, s0, &bc); y = word0(&rv) & Exp_mask; if (y == Exp_mask) goto ovfl; if (y == 0 && rv.d == 0.) goto undfl; } #endif #ifdef SET_INEXACT if (bc.inexact) { if (!oldinexact) { word0(&rv0) = Exp_1 + (70 << Exp_shift); word1(&rv0) = 0; dval(&rv0) += 1.; } } else if (!oldinexact) clear_inexact(); #endif #ifdef Avoid_Underflow if (bc.scale) { word0(&rv0) = Exp_1 - 2*P*Exp_msk1; word1(&rv0) = 0; dval(&rv) *= dval(&rv0); #ifndef NO_ERRNO /* try to avoid the bug of testing an 8087 register value */ #ifdef IEEE_Arith if (!(word0(&rv) & Exp_mask)) #else if (word0(&rv) == 0 && word1(&rv) == 0) #endif errno = ERANGE; #endif } #endif /* Avoid_Underflow */ #ifdef SET_INEXACT if (bc.inexact && !(word0(&rv) & Exp_mask)) { /* set underflow bit */ dval(&rv0) = 1e-300; dval(&rv0) *= dval(&rv0); } #endif ret: if (se) *se = (char *)s; return sign ? -dval(&rv) : dval(&rv); } #ifndef MULTIPLE_THREADS static char *dtoa_result; #endif static char * #ifdef KR_headers rv_alloc(i) int i; #else rv_alloc(int i) #endif { int j, k, *r; j = sizeof(ULong); for(k = 0; sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; j <<= 1) k++; r = (int*)Balloc(k); *r = k; return #ifndef MULTIPLE_THREADS dtoa_result = #endif (char *)(r+1); } static char * #ifdef KR_headers nrv_alloc(s, rve, n) char *s, **rve; int n; #else nrv_alloc(const char *s, char **rve, int n) #endif { char *rv, *t; t = rv = rv_alloc(n); while((*t = *s++)) t++; if (rve) *rve = t; return rv; } /* freedtoa(s) must be used to free values s returned by dtoa * when MULTIPLE_THREADS is #defined. It should be used in all cases, * but for consistency with earlier versions of dtoa, it is optional * when MULTIPLE_THREADS is not defined. */ void #ifdef KR_headers freedtoa(s) char *s; #else freedtoa(char *s) #endif { Bigint *b = (Bigint *)((int *)s - 1); b->maxwds = 1 << (b->k = *(int*)b); Bfree(b); #ifndef MULTIPLE_THREADS if (s == dtoa_result) dtoa_result = 0; #endif } /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. * * Inspired by "How to Print Floating-Point Numbers Accurately" by * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. * * Modifications: * 1. Rather than iterating, we use a simple numeric overestimate * to determine k = floor(log10(d)). We scale relevant * quantities using O(log2(k)) rather than O(k) multiplications. * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't * try to generate digits strictly left to right. Instead, we * compute with fewer bits and propagate the carry if necessary * when rounding the final digit up. This is often faster. * 3. Under the assumption that input will be rounded nearest, * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. * That is, we allow equality in stopping tests when the * round-nearest rule will give the same floating-point value * as would satisfaction of the stopping test with strict * inequality. * 4. We remove common factors of powers of 2 from relevant * quantities. * 5. When converting floating-point integers less than 1e16, * we use floating-point arithmetic rather than resorting * to multiple-precision integers. * 6. When asked to produce fewer than 15 digits, we first try * to get by with floating-point arithmetic; we resort to * multiple-precision integer arithmetic only if we cannot * guarantee that the floating-point calculation has given * the correctly rounded result. For k requested digits and * "uniformly" distributed input, the probability is * something like 10^(k-15) that we must resort to the Long * calculation. */ char * dtoa #ifdef KR_headers (dd, mode, ndigits, decpt, sign, rve) double dd; int mode, ndigits, *decpt, *sign; char **rve; #else (double dd, int mode, int ndigits, int *decpt, int *sign, char **rve) #endif { /* Arguments ndigits, decpt, sign are similar to those of ecvt and fcvt; trailing zeros are suppressed from the returned string. If not null, *rve is set to point to the end of the return value. If d is +-Infinity or NaN, then *decpt is set to 9999. mode: 0 ==> shortest string that yields d when read in and rounded to nearest. 1 ==> like 0, but with Steele & White stopping rule; e.g. with IEEE P754 arithmetic , mode 0 gives 1e23 whereas mode 1 gives 9.999999999999999e22. 2 ==> max(1,ndigits) significant digits. This gives a return value similar to that of ecvt, except that trailing zeros are suppressed. 3 ==> through ndigits past the decimal point. This gives a return value similar to that from fcvt, except that trailing zeros are suppressed, and ndigits can be negative. 4,5 ==> similar to 2 and 3, respectively, but (in round-nearest mode) with the tests of mode 0 to possibly return a shorter string that rounds to d. With IEEE arithmetic and compilation with -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same as modes 2 and 3 when FLT_ROUNDS != 1. 6-9 ==> Debugging modes similar to mode - 4: don't try fast floating-point estimate (if applicable). Values of mode other than 0-9 are treated as mode 0. Sufficient space is allocated to the return value to hold the suppressed trailing zeros. */ int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, spec_case, try_quick; Long L; #ifndef Sudden_Underflow int denorm; ULong x; #endif Bigint *b, *b1, *delta, *mlo, *mhi, *S; U d2, eps, u; double ds; char *s, *s0; #ifndef No_leftright #ifdef IEEE_Arith U eps1; #endif #endif #ifdef SET_INEXACT int inexact, oldinexact; #endif #ifdef Honor_FLT_ROUNDS /*{*/ int Rounding; #ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ Rounding = Flt_Rounds; #else /*}{*/ Rounding = 1; switch(fegetround()) { case FE_TOWARDZERO: Rounding = 0; break; case FE_UPWARD: Rounding = 2; break; case FE_DOWNWARD: Rounding = 3; } #endif /*}}*/ #endif /*}*/ #ifndef MULTIPLE_THREADS if (dtoa_result) { freedtoa(dtoa_result); dtoa_result = 0; } #endif u.d = dd; if (word0(&u) & Sign_bit) { /* set sign for everything, including 0's and NaNs */ *sign = 1; word0(&u) &= ~Sign_bit; /* clear sign bit */ } else *sign = 0; #if defined(IEEE_Arith) + defined(VAX) #ifdef IEEE_Arith if ((word0(&u) & Exp_mask) == Exp_mask) #else if (word0(&u) == 0x8000) #endif { /* Infinity or NaN */ *decpt = 9999; #ifdef IEEE_Arith if (!word1(&u) && !(word0(&u) & 0xfffff)) return nrv_alloc("Infinity", rve, 8); #endif return nrv_alloc("NaN", rve, 3); } #endif #ifdef IBM dval(&u) += 0; /* normalize */ #endif if (!dval(&u)) { *decpt = 1; return nrv_alloc("0", rve, 1); } #ifdef SET_INEXACT try_quick = oldinexact = get_inexact(); inexact = 1; #endif #ifdef Honor_FLT_ROUNDS if (Rounding >= 2) { if (*sign) Rounding = Rounding == 2 ? 0 : 2; else if (Rounding != 2) Rounding = 0; } #endif b = d2b(&u, &be, &bbits); #ifdef Sudden_Underflow i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); #else if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) { #endif dval(&d2) = dval(&u); word0(&d2) &= Frac_mask1; word0(&d2) |= Exp_11; #ifdef IBM if (j = 11 - hi0bits(word0(&d2) & Frac_mask)) dval(&d2) /= 1 << j; #endif /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 * log10(x) = log(x) / log(10) * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) * * This suggests computing an approximation k to log10(d) by * * k = (i - Bias)*0.301029995663981 * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); * * We want k to be too large rather than too small. * The error in the first-order Taylor series approximation * is in our favor, so we just round up the constant enough * to compensate for any error in the multiplication of * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, * adding 1e-13 to the constant term more than suffices. * Hence we adjust the constant term to 0.1760912590558. * (We could get a more accurate k by invoking log10, * but this is probably not worthwhile.) */ i -= Bias; #ifdef IBM i <<= 2; i += j; #endif #ifndef Sudden_Underflow denorm = 0; } else { /* d is denormalized */ i = bbits + be + (Bias + (P-1) - 1); x = i > 32 ? word0(&u) << (64 - i) | word1(&u) >> (i - 32) : word1(&u) << (32 - i); dval(&d2) = x; word0(&d2) -= 31*Exp_msk1; /* adjust exponent */ i -= (Bias + (P-1) - 1) + 1; denorm = 1; } #endif ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; k = (int)ds; if (ds < 0. && ds != k) k--; /* want k = floor(ds) */ k_check = 1; if (k >= 0 && k <= Ten_pmax) { if (dval(&u) < tens[k]) k--; k_check = 0; } j = bbits - i - 1; if (j >= 0) { b2 = 0; s2 = j; } else { b2 = -j; s2 = 0; } if (k >= 0) { b5 = 0; s5 = k; s2 += k; } else { b2 -= k; b5 = -k; s5 = 0; } if (mode < 0 || mode > 9) mode = 0; #ifndef SET_INEXACT #ifdef Check_FLT_ROUNDS try_quick = Rounding == 1; #else try_quick = 1; #endif #endif /*SET_INEXACT*/ if (mode > 5) { mode -= 4; try_quick = 0; } leftright = 1; ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ /* silence erroneous "gcc -Wall" warning. */ switch(mode) { case 0: case 1: i = 18; ndigits = 0; break; case 2: leftright = 0; /* no break */ case 4: if (ndigits <= 0) ndigits = 1; ilim = ilim1 = i = ndigits; break; case 3: leftright = 0; /* no break */ case 5: i = ndigits + k + 1; ilim = i; ilim1 = i - 1; if (i <= 0) i = 1; } s = s0 = rv_alloc(i); #ifdef Honor_FLT_ROUNDS if (mode > 1 && Rounding != 1) leftright = 0; #endif if (ilim >= 0 && ilim <= Quick_max && try_quick) { /* Try to get by with floating-point arithmetic. */ i = 0; dval(&d2) = dval(&u); k0 = k; ilim0 = ilim; ieps = 2; /* conservative */ if (k > 0) { ds = tens[k&0xf]; j = k >> 4; if (j & Bletch) { /* prevent overflows */ j &= Bletch - 1; dval(&u) /= bigtens[n_bigtens-1]; ieps++; } for(; j; j >>= 1, i++) if (j & 1) { ieps++; ds *= bigtens[i]; } dval(&u) /= ds; } else if ((j1 = -k)) { dval(&u) *= tens[j1 & 0xf]; for(j = j1 >> 4; j; j >>= 1, i++) if (j & 1) { ieps++; dval(&u) *= bigtens[i]; } } if (k_check && dval(&u) < 1. && ilim > 0) { if (ilim1 <= 0) goto fast_failed; ilim = ilim1; k--; dval(&u) *= 10.; ieps++; } dval(&eps) = ieps*dval(&u) + 7.; word0(&eps) -= (P-1)*Exp_msk1; if (ilim == 0) { S = mhi = 0; dval(&u) -= 5.; if (dval(&u) > dval(&eps)) goto one_digit; if (dval(&u) < -dval(&eps)) goto no_digits; goto fast_failed; } #ifndef No_leftright if (leftright) { /* Use Steele & White method of only * generating digits needed. */ dval(&eps) = 0.5/tens[ilim-1] - dval(&eps); #ifdef IEEE_Arith if (k0 < 0 && j1 >= 307) { eps1.d = 1.01e256; /* 1.01 allows roundoff in the next few lines */ word0(&eps1) -= Exp_msk1 * (Bias+P-1); dval(&eps1) *= tens[j1 & 0xf]; for(i = 0, j = (j1-256) >> 4; j; j >>= 1, i++) if (j & 1) dval(&eps1) *= bigtens[i]; if (eps.d < eps1.d) eps.d = eps1.d; } #endif for(i = 0;;) { L = dval(&u); dval(&u) -= L; *s++ = '0' + (int)L; if (1. - dval(&u) < dval(&eps)) goto bump_up; if (dval(&u) < dval(&eps)) goto ret1; if (++i >= ilim) break; dval(&eps) *= 10.; dval(&u) *= 10.; } } else { #endif /* Generate ilim digits, then fix them up. */ dval(&eps) *= tens[ilim-1]; for(i = 1;; i++, dval(&u) *= 10.) { L = (Long)(dval(&u)); if (!(dval(&u) -= L)) ilim = i; *s++ = '0' + (int)L; if (i == ilim) { if (dval(&u) > 0.5 + dval(&eps)) goto bump_up; else if (dval(&u) < 0.5 - dval(&eps)) { while(*--s == '0'); s++; goto ret1; } break; } } #ifndef No_leftright } #endif fast_failed: s = s0; dval(&u) = dval(&d2); k = k0; ilim = ilim0; } /* Do we have a "small" integer? */ if (be >= 0 && k <= Int_max) { /* Yes. */ ds = tens[k]; if (ndigits < 0 && ilim <= 0) { S = mhi = 0; if (ilim < 0 || dval(&u) <= 5*ds) goto no_digits; goto one_digit; } for(i = 1;; i++, dval(&u) *= 10.) { L = (Long)(dval(&u) / ds); dval(&u) -= L*ds; #ifdef Check_FLT_ROUNDS /* If FLT_ROUNDS == 2, L will usually be high by 1 */ if (dval(&u) < 0) { L--; dval(&u) += ds; } #endif *s++ = '0' + (int)L; if (!dval(&u)) { #ifdef SET_INEXACT inexact = 0; #endif break; } if (i == ilim) { #ifdef Honor_FLT_ROUNDS if (mode > 1) switch(Rounding) { case 0: goto ret1; case 2: goto bump_up; } #endif dval(&u) += dval(&u); #ifdef ROUND_BIASED if (dval(&u) >= ds) #else if (dval(&u) > ds || (dval(&u) == ds && L & 1)) #endif { bump_up: while(*--s == '9') if (s == s0) { k++; *s = '0'; break; } ++*s++; } break; } } goto ret1; } m2 = b2; m5 = b5; mhi = mlo = 0; if (leftright) { i = #ifndef Sudden_Underflow denorm ? be + (Bias + (P-1) - 1 + 1) : #endif #ifdef IBM 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); #else 1 + P - bbits; #endif b2 += i; s2 += i; mhi = i2b(1); } if (m2 > 0 && s2 > 0) { i = m2 < s2 ? m2 : s2; b2 -= i; m2 -= i; s2 -= i; } if (b5 > 0) { if (leftright) { if (m5 > 0) { mhi = pow5mult(mhi, m5); b1 = mult(mhi, b); Bfree(b); b = b1; } if ((j = b5 - m5)) b = pow5mult(b, j); } else b = pow5mult(b, b5); } S = i2b(1); if (s5 > 0) S = pow5mult(S, s5); /* Check for special case that d is a normalized power of 2. */ spec_case = 0; if ((mode < 2 || leftright) #ifdef Honor_FLT_ROUNDS && Rounding == 1 #endif ) { if (!word1(&u) && !(word0(&u) & Bndry_mask) #ifndef Sudden_Underflow && word0(&u) & (Exp_mask & ~Exp_msk1) #endif ) { /* The special case */ b2 += Log2P; s2 += Log2P; spec_case = 1; } } /* Arrange for convenient computation of quotients: * shift left if necessary so divisor has 4 leading 0 bits. * * Perhaps we should just compute leading 28 bits of S once * and for all and pass them and a shift to quorem, so it * can do shifts and ors to compute the numerator for q. */ i = dshift(S, s2); b2 += i; m2 += i; s2 += i; if (b2 > 0) b = lshift(b, b2); if (s2 > 0) S = lshift(S, s2); if (k_check) { if (cmp(b,S) < 0) { k--; b = multadd(b, 10, 0); /* we botched the k estimate */ if (leftright) mhi = multadd(mhi, 10, 0); ilim = ilim1; } } if (ilim <= 0 && (mode == 3 || mode == 5)) { if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { /* no digits, fcvt style */ no_digits: k = -1 - ndigits; goto ret; } one_digit: *s++ = '1'; k++; goto ret; } if (leftright) { if (m2 > 0) mhi = lshift(mhi, m2); /* Compute mlo -- check for special case * that d is a normalized power of 2. */ mlo = mhi; if (spec_case) { mhi = Balloc(mhi->k); Bcopy(mhi, mlo); mhi = lshift(mhi, Log2P); } for(i = 1;;i++) { dig = quorem(b,S) + '0'; /* Do we yet have the shortest decimal string * that will round to d? */ j = cmp(b, mlo); delta = diff(S, mhi); j1 = delta->sign ? 1 : cmp(b, delta); Bfree(delta); #ifndef ROUND_BIASED if (j1 == 0 && mode != 1 && !(word1(&u) & 1) #ifdef Honor_FLT_ROUNDS && Rounding >= 1 #endif ) { if (dig == '9') goto round_9_up; if (j > 0) dig++; #ifdef SET_INEXACT else if (!b->x[0] && b->wds <= 1) inexact = 0; #endif *s++ = dig; goto ret; } #endif if (j < 0 || (j == 0 && mode != 1 #ifndef ROUND_BIASED && !(word1(&u) & 1) #endif )) { if (!b->x[0] && b->wds <= 1) { #ifdef SET_INEXACT inexact = 0; #endif goto accept_dig; } #ifdef Honor_FLT_ROUNDS if (mode > 1) switch(Rounding) { case 0: goto accept_dig; case 2: goto keep_dig; } #endif /*Honor_FLT_ROUNDS*/ if (j1 > 0) { b = lshift(b, 1); j1 = cmp(b, S); #ifdef ROUND_BIASED if (j1 >= 0 /*)*/ #else if ((j1 > 0 || (j1 == 0 && dig & 1)) #endif && dig++ == '9') goto round_9_up; } accept_dig: *s++ = dig; goto ret; } if (j1 > 0) { #ifdef Honor_FLT_ROUNDS if (!Rounding) goto accept_dig; #endif if (dig == '9') { /* possible if i == 1 */ round_9_up: *s++ = '9'; goto roundoff; } *s++ = dig + 1; goto ret; } #ifdef Honor_FLT_ROUNDS keep_dig: #endif *s++ = dig; if (i == ilim) break; b = multadd(b, 10, 0); if (mlo == mhi) mlo = mhi = multadd(mhi, 10, 0); else { mlo = multadd(mlo, 10, 0); mhi = multadd(mhi, 10, 0); } } } else for(i = 1;; i++) { *s++ = dig = quorem(b,S) + '0'; if (!b->x[0] && b->wds <= 1) { #ifdef SET_INEXACT inexact = 0; #endif goto ret; } if (i >= ilim) break; b = multadd(b, 10, 0); } /* Round off last digit */ #ifdef Honor_FLT_ROUNDS switch(Rounding) { case 0: goto trimzeros; case 2: goto roundoff; } #endif b = lshift(b, 1); j = cmp(b, S); #ifdef ROUND_BIASED if (j >= 0) #else if (j > 0 || (j == 0 && dig & 1)) #endif { roundoff: while(*--s == '9') if (s == s0) { k++; *s++ = '1'; goto ret; } ++*s++; } else { #ifdef Honor_FLT_ROUNDS trimzeros: #endif while(*--s == '0'); s++; } ret: Bfree(S); if (mhi) { if (mlo && mlo != mhi) Bfree(mlo); Bfree(mhi); } ret1: #ifdef SET_INEXACT if (inexact) { if (!oldinexact) { word0(&u) = Exp_1 + (70 << Exp_shift); word1(&u) = 0; dval(&u) += 1.; } } else if (!oldinexact) clear_inexact(); #endif Bfree(b); *s = 0; *decpt = k + 1; if (rve) *rve = s; return s0; } #ifdef __cplusplus } #endif ================================================ FILE: code/EVA/server/server_share/cjson/dtoa_config.h ================================================ #ifndef _DTOA_CONFIG_H #define _DTOA_CONFIG_H #include #include #include /* Ensure dtoa.c does not USE_LOCALE. Lua CJSON must not use locale * aware conversion routines. */ #undef USE_LOCALE /* dtoa.c should not touch errno, Lua CJSON does not use it, and it * may not be threadsafe */ #define NO_ERRNO #define Long int32_t #define ULong uint32_t #define Llong int64_t #define ULLong uint64_t #ifdef IEEE_BIG_ENDIAN #define IEEE_MC68k #else #define IEEE_8087 #endif #define MALLOC(n) xmalloc(n) static void *xmalloc(size_t size) { void *p; p = malloc(size); if (!p) { fprintf(stderr, "Out of memory"); abort(); } return p; } #ifdef MULTIPLE_THREADS /* Enable locking to support multi-threaded applications */ #include static pthread_mutex_t private_dtoa_lock[2] = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }; #define ACQUIRE_DTOA_LOCK(n) do { \ int r = pthread_mutex_lock(&private_dtoa_lock[n]); \ if (r) { \ fprintf(stderr, "pthread_mutex_lock failed with %d\n", r); \ abort(); \ } \ } while (0) #define FREE_DTOA_LOCK(n) do { \ int r = pthread_mutex_unlock(&private_dtoa_lock[n]); \ if (r) { \ fprintf(stderr, "pthread_mutex_unlock failed with %d\n", r);\ abort(); \ } \ } while (0) #endif /* MULTIPLE_THREADS */ #endif /* _DTOA_CONFIG_H */ /* vi:ai et sw=4 ts=4: */ ================================================ FILE: code/EVA/server/server_share/cjson/fpconv.cpp ================================================ /* fpconv - Floating point conversion routines * * Copyright (c) 2011-2012 Mark Pulford * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* JSON uses a '.' decimal separator. strtod() / sprintf() under C libraries * with locale support will break when the decimal separator is a comma. * * fpconv_* will around these issues with a translation buffer if required. */ #include #include #include #include #include "fpconv.h" #include "nel/misc/string_common.h" /* Lua CJSON assumes the locale is the same for all threads within a * process and doesn't change after initialisation. * * This avoids the need for per thread storage or expensive checks * for call. */ static char locale_decimal_point = '.'; /* In theory multibyte decimal_points are possible, but * Lua CJSON only supports UTF-8 and known locales only have * single byte decimal points ([.,]). * * localconv() may not be thread safe (=>crash), and nl_langinfo() is * not supported on some platforms. Use sprintf() instead - if the * locale does change, at least Lua CJSON won't crash. */ static void fpconv_update_locale() { char buf[8]; NLMISC::smprintf(buf, sizeof(buf), "%g", 0.5); /* Failing this test might imply the platform has a buggy dtoa * implementation or wide characters */ if (buf[0] != '0' || buf[2] != '5' || buf[3] != 0) { fprintf(stderr, "Error: wide characters found or printf() bug."); abort(); } locale_decimal_point = buf[1]; } /* Check for a valid number character: [-+0-9a-yA-Y.] * Eg: -0.6e+5, infinity, 0xF0.F0pF0 * * Used to find the probable end of a number. It doesn't matter if * invalid characters are counted - strtod() will find the valid * number if it exists. The risk is that slightly more memory might * be allocated before a parse error occurs. */ static int valid_number_character(char ch) { char lower_ch; if ('0' <= ch && ch <= '9') return 1; if (ch == '-' || ch == '+' || ch == '.') return 1; /* Hex digits, exponent (e), base (p), "infinity",.. */ lower_ch = ch | 0x20; if ('a' <= lower_ch && lower_ch <= 'y') return 1; return 0; } /* Calculate the size of the buffer required for a strtod locale * conversion. */ static int strtod_buffer_size(const char *s) { const char *p = s; while (valid_number_character(*p)) p++; return p - s; } /* Similar to strtod(), but must be passed the current locale's decimal point * character. Guaranteed to be called at the start of any valid number in a string */ double fpconv_strtod(const char *nptr, char **endptr) { char localbuf[FPCONV_G_FMT_BUFSIZE]; char *buf, *endbuf, *dp; int buflen; double value; /* System strtod() is fine when decimal point is '.' */ if (locale_decimal_point == '.') return strtod(nptr, endptr); buflen = strtod_buffer_size(nptr); if (!buflen) { /* No valid characters found, standard strtod() return */ *endptr = (char *)nptr; return 0; } /* Duplicate number into buffer */ if (buflen >= FPCONV_G_FMT_BUFSIZE) { /* Handle unusually large numbers */ buf = (char*)malloc(buflen + 1); if (!buf) { fprintf(stderr, "Out of memory"); abort(); } } else { /* This is the common case.. */ buf = localbuf; } memcpy(buf, nptr, buflen); buf[buflen] = 0; /* Update decimal point character if found */ dp = strchr(buf, '.'); if (dp) *dp = locale_decimal_point; value = strtod(buf, &endbuf); *endptr = (char *)&nptr[endbuf - buf]; if (buflen >= FPCONV_G_FMT_BUFSIZE) free(buf); return value; } /* "fmt" must point to a buffer of at least 6 characters */ static void set_number_format(char *fmt, int precision) { int d1, d2, i; assert(1 <= precision && precision <= 14); /* Create printf format (%.14g) from precision */ d1 = precision / 10; d2 = precision % 10; fmt[0] = '%'; fmt[1] = '.'; i = 2; if (d1) { fmt[i++] = '0' + d1; } fmt[i++] = '0' + d2; fmt[i++] = 'g'; fmt[i] = 0; } /* Assumes there is always at least 32 characters available in the target buffer int fpconv_g_fmt(char *str, double num, int precision) { char buf[FPCONV_G_FMT_BUFSIZE]; char fmt[6]; int len; char *b; set_number_format(fmt, precision); // Pass through when decimal point character is dot. if (locale_decimal_point == '.') return NLMISC::smprintf(str, FPCONV_G_FMT_BUFSIZE, fmt, num); // snprintf() to a buffer then translate for other decimal point characters len = NLMISC::smprintf(buf, FPCONV_G_FMT_BUFSIZE, fmt, num); // Copy into target location. Translate decimal point if required b = buf; do { *str++ = (*b == locale_decimal_point ? '.' : *b); } while(*b++); return len; } */ void fpconv_init() { fpconv_update_locale(); } /* vi:ai et sw=4 ts=4: */ ================================================ FILE: code/EVA/server/server_share/cjson/fpconv.h ================================================ /* Lua CJSON floating point conversion routines */ /* Buffer required to store the largest string representation of a double. * * Longest double printed with %.14g is 21 characters long: * -1.7976931348623e+308 */ # define FPCONV_G_FMT_BUFSIZE 32 //#ifdef USE_INTERNAL_FPCONV //static void fpconv_init() //{ // /* Do nothing - not required */ //} //#else extern void fpconv_init(); //#endif extern int fpconv_g_fmt(char*, double, int); extern double fpconv_strtod(const char*, char**); /* vi:ai et sw=4 ts=4: */ ================================================ FILE: code/EVA/server/server_share/cjson/g_fmt.cpp ================================================ /**************************************************************** * * The author of this software is David M. Gay. * * Copyright (c) 1991, 1996 by Lucent Technologies. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. * ***************************************************************/ /* g_fmt(buf,x) stores the closest decimal approximation to x in buf; * it suffices to declare buf * char buf[32]; */ #ifdef __cplusplus extern "C" { #endif extern char *dtoa(double, int, int, int *, int *, char **); extern int g_fmt(char *, double, int); extern void freedtoa(char*); #ifdef __cplusplus } #endif int fpconv_g_fmt(char *b, double x, int precision) { register int i, k; register char *s; int decpt, j, sign; char *b0, *s0, *se; b0 = b; #ifdef IGNORE_ZERO_SIGN if (!x) { *b++ = '0'; *b = 0; goto done; } #endif s = s0 = dtoa(x, 2, precision, &decpt, &sign, &se); if (sign) *b++ = '-'; if (decpt == 9999) /* Infinity or Nan */ { while((*b++ = *s++)); /* "b" is used to calculate the return length. Decrement to exclude the * Null terminator from the length */ b--; goto done0; } if (decpt <= -4 || decpt > precision) { *b++ = *s++; if (*s) { *b++ = '.'; while((*b = *s++)) b++; } *b++ = 'e'; /* sprintf(b, "%+.2d", decpt - 1); */ if (--decpt < 0) { *b++ = '-'; decpt = -decpt; } else *b++ = '+'; for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10); for(;;) { i = decpt / k; *b++ = i + '0'; if (--j <= 0) break; decpt -= i*k; decpt *= 10; } *b = 0; } else if (decpt <= 0) { *b++ = '0'; *b++ = '.'; for(; decpt < 0; decpt++) *b++ = '0'; while((*b++ = *s++)); b--; } else { while((*b = *s++)) { b++; if (--decpt == 0 && *s) *b++ = '.'; } for(; decpt > 0; decpt--) *b++ = '0'; *b = 0; } done0: freedtoa(s0); #ifdef IGNORE_ZERO_SIGN done: #endif return b - b0; } ================================================ FILE: code/EVA/server/server_share/cjson/lua_cjson.cpp ================================================ /* Lua CJSON - JSON support for Lua * * Copyright (c) 2010-2012 Mark Pulford * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Caveats: * - JSON "null" values are represented as lightuserdata since Lua * tables cannot contain "nil". Compare with cjson.null. * - Invalid UTF-8 characters are not detected and will be passed * untouched. If required, UTF-8 error checking should be done * outside this library. * - Javascript comments are not part of the JSON spec, and are not * currently supported. * * Note: Decoding is slower than encoding. Lua spends significant * time (30%) managing tables when parsing JSON since it is * difficult to know object/array sizes ahead of time. */ #include #include #include #include #include #include "strbuf.h" #include "fpconv.h" #include #ifndef CJSON_MODNAME #define CJSON_MODNAME "cjson" #endif #ifndef CJSON_VERSION #define CJSON_VERSION "2.1devel" #endif #ifdef NL_OS_WINDOWS /* Workaround for Solaris platforms missing isinf() */ #if !defined(isinf) //&& (defined(USE_INTERNAL_ISINF) || defined(MISSING_ISINF)) #define isinf(x) (!isnan(x) && isnan((x) - (x))) #endif #if !defined(isnan) //&& (defined(USE_INTERNAL_ISINF) || defined(MISSING_ISINF)) #define isnan _isnan #endif # define strtoll _strtoi64 #endif // NL_OS_WINDOWS #define DEFAULT_SPARSE_CONVERT 0 #define DEFAULT_SPARSE_RATIO 2 #define DEFAULT_SPARSE_SAFE 10 #define DEFAULT_ENCODE_MAX_DEPTH 1000 #define DEFAULT_DECODE_MAX_DEPTH 1000 #define DEFAULT_ENCODE_INVALID_NUMBERS 0 #define DEFAULT_DECODE_INVALID_NUMBERS 1 #define DEFAULT_ENCODE_KEEP_BUFFER 1 #define DEFAULT_ENCODE_NUMBER_PRECISION 14 #ifdef DISABLE_INVALID_NUMBERS #undef DEFAULT_DECODE_INVALID_NUMBERS #define DEFAULT_DECODE_INVALID_NUMBERS 0 #endif typedef enum { T_OBJ_BEGIN, T_OBJ_END, T_ARR_BEGIN, T_ARR_END, T_STRING, T_NUMBER, T_INTEGER, T_BOOLEAN, T_NULL, T_COLON, T_COMMA, T_END, T_WHITESPACE, T_ERROR, T_UNKNOWN } json_token_type_t; static const char *json_token_type_name[] = { "T_OBJ_BEGIN", "T_OBJ_END", "T_ARR_BEGIN", "T_ARR_END", "T_STRING", "T_NUMBER", "T_INTEGER", "T_BOOLEAN", "T_NULL", "T_COLON", "T_COMMA", "T_END", "T_WHITESPACE", "T_ERROR", "T_UNKNOWN", NULL }; typedef struct { json_token_type_t ch2token[256]; char escape2char[256]; /* Decoding */ /* encode_buf is only allocated and used when * encode_keep_buffer is set */ strbuf_t encode_buf; int encode_sparse_convert; int encode_sparse_ratio; int encode_sparse_safe; int encode_max_depth; int encode_invalid_numbers; /* 2 => Encode as "null" */ int encode_number_precision; int encode_keep_buffer; int decode_invalid_numbers; int decode_max_depth; } json_config_t; typedef struct { const char *data; const char *ptr; strbuf_t *tmp; /* Temporary storage for strings */ json_config_t *cfg; int current_depth; } json_parse_t; typedef struct { json_token_type_t type; int index; union { const char *string; double number; lua_Integer integer; int boolean; } value; int string_len; } json_token_t; static const char *char2escape[256] = { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f", NULL, NULL, "\\\"", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\/", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\\\", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\u007f", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; /* ===== CONFIGURATION ===== */ static json_config_t *json_fetch_config(lua_State *l) { json_config_t *cfg; cfg = (json_config_t *)lua_touserdata(l, lua_upvalueindex(1)); if (!cfg) luaL_error(l, "BUG: Unable to fetch CJSON configuration"); return cfg; } /* Ensure the correct number of arguments have been provided. * Pad with nil to allow other functions to simply check arg[i] * to find whether an argument was provided */ static json_config_t *json_arg_init(lua_State *l, int args) { luaL_argcheck(l, lua_gettop(l) <= args, args + 1, "found too many arguments"); while (lua_gettop(l) < args) lua_pushnil(l); return json_fetch_config(l); } /* Process integer options for configuration functions */ static int json_integer_option(lua_State *l, int optindex, int *setting, int min, int max) { char errmsg[64]; int value; if (!lua_isnil(l, optindex)) { value = luaL_checkinteger(l, optindex); NLMISC::smprintf(errmsg, sizeof(errmsg), "expected integer between %d and %d", min, max); luaL_argcheck(l, min <= value && value <= max, 1, errmsg); *setting = value; } lua_pushinteger(l, *setting); return 1; } /* Process enumerated arguments for a configuration function */ static int json_enum_option(lua_State *l, int optindex, int *setting, const char **options, int bool_true) { static const char *bool_options[] = { "off", "on", NULL }; if (!options) { options = bool_options; bool_true = 1; } if (!lua_isnil(l, optindex)) { if (bool_true && lua_isboolean(l, optindex)) *setting = lua_toboolean(l, optindex) * bool_true; else *setting = luaL_checkoption(l, optindex, NULL, options); } if (bool_true && (*setting == 0 || *setting == bool_true)) lua_pushboolean(l, *setting); else lua_pushstring(l, options[*setting]); return 1; } /* Configures handling of extremely sparse arrays: * convert: Convert extremely sparse arrays into objects? Otherwise error. * ratio: 0: always allow sparse; 1: never allow sparse; >1: use ratio * safe: Always use an array when the max index <= safe */ static int json_cfg_encode_sparse_array(lua_State *l) { json_config_t *cfg = json_arg_init(l, 3); json_enum_option(l, 1, &cfg->encode_sparse_convert, NULL, 1); json_integer_option(l, 2, &cfg->encode_sparse_ratio, 0, INT_MAX); json_integer_option(l, 3, &cfg->encode_sparse_safe, 0, INT_MAX); return 3; } /* Configures the maximum number of nested arrays/objects allowed when * encoding */ static int json_cfg_encode_max_depth(lua_State *l) { json_config_t *cfg = json_arg_init(l, 1); return json_integer_option(l, 1, &cfg->encode_max_depth, 1, INT_MAX); } /* Configures the maximum number of nested arrays/objects allowed when * encoding */ static int json_cfg_decode_max_depth(lua_State *l) { json_config_t *cfg = json_arg_init(l, 1); return json_integer_option(l, 1, &cfg->decode_max_depth, 1, INT_MAX); } /* Configures number precision when converting doubles to text */ static int json_cfg_encode_number_precision(lua_State *l) { json_config_t *cfg = json_arg_init(l, 1); return json_integer_option(l, 1, &cfg->encode_number_precision, 1, 14); } /* Configures JSON encoding buffer persistence */ static int json_cfg_encode_keep_buffer(lua_State *l) { json_config_t *cfg = json_arg_init(l, 1); int old_value; old_value = cfg->encode_keep_buffer; json_enum_option(l, 1, &cfg->encode_keep_buffer, NULL, 1); /* Init / free the buffer if the setting has changed */ if (old_value ^ cfg->encode_keep_buffer) { if (cfg->encode_keep_buffer) strbuf_init(&cfg->encode_buf, 0); else strbuf_free(&cfg->encode_buf); } return 1; } #if defined(DISABLE_INVALID_NUMBERS) && !defined(USE_INTERNAL_FPCONV) void json_verify_invalid_number_setting(lua_State *l, int *setting) { if (*setting == 1) { *setting = 0; luaL_error(l, "Infinity, NaN, and/or hexadecimal numbers are not supported."); } } #else #define json_verify_invalid_number_setting(l, s) do { } while(0) #endif static int json_cfg_encode_invalid_numbers(lua_State *l) { static const char *options[] = { "off", "on", "null", NULL }; json_config_t *cfg = json_arg_init(l, 1); json_enum_option(l, 1, &cfg->encode_invalid_numbers, options, 1); json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers); return 1; } static int json_cfg_decode_invalid_numbers(lua_State *l) { json_config_t *cfg = json_arg_init(l, 1); json_enum_option(l, 1, &cfg->decode_invalid_numbers, NULL, 1); json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers); return 1; } static int json_destroy_config(lua_State *l) { json_config_t *cfg; cfg = (json_config_t *)lua_touserdata(l, 1); if (cfg) strbuf_free(&cfg->encode_buf); cfg = NULL; return 0; } static void json_create_config(lua_State *l) { json_config_t *cfg; int i; cfg = (json_config_t *)lua_newuserdata(l, sizeof(*cfg)); /* Create GC method to clean up strbuf */ lua_newtable(l); lua_pushcfunction(l, json_destroy_config); lua_setfield(l, -2, "__gc"); lua_setmetatable(l, -2); cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT; cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO; cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE; cfg->encode_max_depth = DEFAULT_ENCODE_MAX_DEPTH; cfg->decode_max_depth = DEFAULT_DECODE_MAX_DEPTH; cfg->encode_invalid_numbers = DEFAULT_ENCODE_INVALID_NUMBERS; cfg->decode_invalid_numbers = DEFAULT_DECODE_INVALID_NUMBERS; cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER; cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION; #if DEFAULT_ENCODE_KEEP_BUFFER > 0 strbuf_init(&cfg->encode_buf, 0); #endif /* Decoding init */ /* Tag all characters as an error */ for (i = 0; i < 256; i++) cfg->ch2token[i] = T_ERROR; /* Set tokens that require no further processing */ cfg->ch2token['{'] = T_OBJ_BEGIN; cfg->ch2token['}'] = T_OBJ_END; cfg->ch2token['['] = T_ARR_BEGIN; cfg->ch2token[']'] = T_ARR_END; cfg->ch2token[','] = T_COMMA; cfg->ch2token[':'] = T_COLON; cfg->ch2token['\0'] = T_END; cfg->ch2token[' '] = T_WHITESPACE; cfg->ch2token['\t'] = T_WHITESPACE; cfg->ch2token['\n'] = T_WHITESPACE; cfg->ch2token['\r'] = T_WHITESPACE; /* Update characters that require further processing */ cfg->ch2token['f'] = T_UNKNOWN; /* false? */ cfg->ch2token['i'] = T_UNKNOWN; /* inf, ininity? */ cfg->ch2token['I'] = T_UNKNOWN; cfg->ch2token['n'] = T_UNKNOWN; /* null, nan? */ cfg->ch2token['N'] = T_UNKNOWN; cfg->ch2token['t'] = T_UNKNOWN; /* true? */ cfg->ch2token['"'] = T_UNKNOWN; /* string? */ cfg->ch2token['+'] = T_UNKNOWN; /* number? */ cfg->ch2token['-'] = T_UNKNOWN; for (i = 0; i < 10; i++) cfg->ch2token['0' + i] = T_UNKNOWN; /* Lookup table for parsing escape characters */ for (i = 0; i < 256; i++) cfg->escape2char[i] = 0; /* String error */ cfg->escape2char['"'] = '"'; cfg->escape2char['\\'] = '\\'; cfg->escape2char['/'] = '/'; cfg->escape2char['b'] = '\b'; cfg->escape2char['t'] = '\t'; cfg->escape2char['n'] = '\n'; cfg->escape2char['f'] = '\f'; cfg->escape2char['r'] = '\r'; cfg->escape2char['u'] = 'u'; /* Unicode parsing required */ } /* ===== ENCODING ===== */ static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *json, int lindex, const char *reason) { if (!cfg->encode_keep_buffer) strbuf_free(json); luaL_error(l, "Cannot serialise %s: %s", lua_typename(l, lua_type(l, lindex)), reason); } /* json_append_string args: * - lua_State * - JSON strbuf * - String (Lua stack index) * * Returns nothing. Doesn't remove string from Lua stack */ static void json_append_string(lua_State *l, strbuf_t *json, int lindex) { const char *escstr; int i; const char *str; size_t len; str = lua_tolstring(l, lindex, &len); /* Worst case is len * 6 (all unicode escapes). * This buffer is reused constantly for small strings * If there are any excess pages, they won't be hit anyway. * This gains ~5% speedup. */ strbuf_ensure_empty_length(json, len * 6 + 2); strbuf_append_char_unsafe(json, '\"'); for (i = 0; i < len; i++) { escstr = char2escape[(unsigned char)str[i]]; if (escstr) strbuf_append_string(json, escstr); else strbuf_append_char_unsafe(json, str[i]); } strbuf_append_char_unsafe(json, '\"'); } /* Find the size of the array on the top of the Lua stack * -1 object (not a pure array) * >=0 elements in array */ static int lua_array_length(lua_State *l, json_config_t *cfg, strbuf_t *json) { double k; int max; int items; max = 0; items = 0; lua_pushnil(l); /* table, startkey */ while (lua_next(l, -2) != 0) { /* table, key, value */ if (lua_type(l, -2) == LUA_TNUMBER && (k = lua_tonumber(l, -2))) { /* Integer >= 1 ? */ if (floor(k) == k && k >= 1) { if (k > max) max = k; items++; lua_pop(l, 1); continue; } } /* Must not be an array (non integer key) */ lua_pop(l, 2); return -1; } /* Encode excessively sparse arrays as objects (if enabled) */ if (cfg->encode_sparse_ratio > 0 && max > items * cfg->encode_sparse_ratio && max > cfg->encode_sparse_safe) { if (!cfg->encode_sparse_convert) json_encode_exception(l, cfg, json, -1, "excessively sparse array"); return -1; } return max; } static void json_check_encode_depth(lua_State *l, json_config_t *cfg, int current_depth, strbuf_t *json) { /* Ensure there are enough slots free to traverse a table (key, * value) and push a string for a potential error message. * * Unlike "decode", the key and value are still on the stack when * lua_checkstack() is called. Hence an extra slot for luaL_error() * below is required just in case the next check to lua_checkstack() * fails. * * While this won't cause a crash due to the EXTRA_STACK reserve * slots, it would still be an improper use of the API. */ if (current_depth <= cfg->encode_max_depth && lua_checkstack(l, 3)) return; if (!cfg->encode_keep_buffer) strbuf_free(json); luaL_error(l, "Cannot serialise, excessive nesting (%d)", current_depth); } static void json_append_data(lua_State *l, json_config_t *cfg, int current_depth, strbuf_t *json); /* json_append_array args: * - lua_State * - JSON strbuf * - Size of passwd Lua array (top of stack) */ static void json_append_array(lua_State *l, json_config_t *cfg, int current_depth, strbuf_t *json, int array_length) { int comma, i; strbuf_append_char(json, '['); comma = 0; for (i = 1; i <= array_length; i++) { if (comma) strbuf_append_char(json, ','); else comma = 1; lua_rawgeti(l, -1, i); json_append_data(l, cfg, current_depth, json); lua_pop(l, 1); } strbuf_append_char(json, ']'); } static void json_append_number(lua_State *l, json_config_t *cfg, strbuf_t *json, int lindex) { int len; #if LUA_VERSION_NUM >= 503 if (lua_isinteger(l, lindex)) { lua_Integer num = lua_tointeger(l, lindex); strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE); /* max length of int64 is 19 */ len = sprintf(strbuf_empty_ptr(json), LUA_INTEGER_FMT, num); strbuf_extend_length(json, len); return; } #endif double num = lua_tonumber(l, lindex); if (cfg->encode_invalid_numbers == 0) { /* Prevent encoding invalid numbers */ if (isinf(num) || isnan(num)) json_encode_exception(l, cfg, json, lindex, "must not be NaN or Infinity"); } else if (cfg->encode_invalid_numbers == 1) { /* Encode NaN/Infinity separately to ensure Javascript compatible * values are used. */ if (isnan(num)) { strbuf_append_mem(json, "NaN", 3); return; } if (isinf(num)) { if (num < 0) strbuf_append_mem(json, "-Infinity", 9); else strbuf_append_mem(json, "Infinity", 8); return; } } else { /* Encode invalid numbers as "null" */ if (isinf(num) || isnan(num)) { strbuf_append_mem(json, "null", 4); return; } } strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE); len = fpconv_g_fmt(strbuf_empty_ptr(json), num, cfg->encode_number_precision); strbuf_extend_length(json, len); } static void json_append_object(lua_State *l, json_config_t *cfg, int current_depth, strbuf_t *json) { int comma, keytype; /* Object */ strbuf_append_char(json, '{'); lua_pushnil(l); /* table, startkey */ comma = 0; while (lua_next(l, -2) != 0) { if (comma) strbuf_append_char(json, ','); else comma = 1; /* table, key, value */ keytype = lua_type(l, -2); if (keytype == LUA_TNUMBER) { strbuf_append_char(json, '"'); json_append_number(l, cfg, json, -2); strbuf_append_mem(json, "\":", 2); } else if (keytype == LUA_TSTRING) { json_append_string(l, json, -2); strbuf_append_char(json, ':'); } else { json_encode_exception(l, cfg, json, -2, "table key must be a number or string"); /* never returns */ } /* table, key, value */ json_append_data(l, cfg, current_depth, json); lua_pop(l, 1); /* table, key */ } strbuf_append_char(json, '}'); } /* Serialise Lua data into JSON string. */ static void json_append_data(lua_State *l, json_config_t *cfg, int current_depth, strbuf_t *json) { int len; switch (lua_type(l, -1)) { case LUA_TSTRING: json_append_string(l, json, -1); break; case LUA_TNUMBER: json_append_number(l, cfg, json, -1); break; case LUA_TBOOLEAN: if (lua_toboolean(l, -1)) strbuf_append_mem(json, "true", 4); else strbuf_append_mem(json, "false", 5); break; case LUA_TTABLE: current_depth++; json_check_encode_depth(l, cfg, current_depth, json); len = lua_array_length(l, cfg, json); if (len > 0) json_append_array(l, cfg, current_depth, json, len); else json_append_object(l, cfg, current_depth, json); break; case LUA_TNIL: strbuf_append_mem(json, "null", 4); break; case LUA_TLIGHTUSERDATA: if (lua_touserdata(l, -1) == NULL) { strbuf_append_mem(json, "null", 4); break; } default: /* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, * and LUA_TLIGHTUSERDATA) cannot be serialised */ json_encode_exception(l, cfg, json, -1, "type not supported"); /* never returns */ } } static int json_encode(lua_State *l) { json_config_t *cfg = json_fetch_config(l); strbuf_t local_encode_buf; strbuf_t *encode_buf; char *json; int len; luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); if (!cfg->encode_keep_buffer) { /* Use private buffer */ encode_buf = &local_encode_buf; strbuf_init(encode_buf, 0); } else { /* Reuse existing buffer */ encode_buf = &cfg->encode_buf; strbuf_reset(encode_buf); } json_append_data(l, cfg, 0, encode_buf); json = strbuf_string(encode_buf, &len); lua_pushlstring(l, json, len); if (!cfg->encode_keep_buffer) strbuf_free(encode_buf); return 1; } /* ===== DECODING ===== */ static void json_process_value(lua_State *l, json_parse_t *json, json_token_t *token); static int hexdigit2int(char hex) { if ('0' <= hex && hex <= '9') return hex - '0'; /* Force lowercase */ hex |= 0x20; if ('a' <= hex && hex <= 'f') return 10 + hex - 'a'; return -1; } static int decode_hex4(const char *hex) { int digit[4]; int i; /* Convert ASCII hex digit to numeric digit * Note: this returns an error for invalid hex digits, including * NULL */ for (i = 0; i < 4; i++) { digit[i] = hexdigit2int(hex[i]); if (digit[i] < 0) { return -1; } } return (digit[0] << 12) + (digit[1] << 8) + (digit[2] << 4) + digit[3]; } /* Converts a Unicode codepoint to UTF-8. * Returns UTF-8 string length, and up to 4 bytes in *utf8 */ static int codepoint_to_utf8(char *utf8, int codepoint) { /* 0xxxxxxx */ if (codepoint <= 0x7F) { utf8[0] = codepoint; return 1; } /* 110xxxxx 10xxxxxx */ if (codepoint <= 0x7FF) { utf8[0] = (codepoint >> 6) | 0xC0; utf8[1] = (codepoint & 0x3F) | 0x80; return 2; } /* 1110xxxx 10xxxxxx 10xxxxxx */ if (codepoint <= 0xFFFF) { utf8[0] = (codepoint >> 12) | 0xE0; utf8[1] = ((codepoint >> 6) & 0x3F) | 0x80; utf8[2] = (codepoint & 0x3F) | 0x80; return 3; } /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ if (codepoint <= 0x1FFFFF) { utf8[0] = (codepoint >> 18) | 0xF0; utf8[1] = ((codepoint >> 12) & 0x3F) | 0x80; utf8[2] = ((codepoint >> 6) & 0x3F) | 0x80; utf8[3] = (codepoint & 0x3F) | 0x80; return 4; } return 0; } /* Called when index pointing to beginning of UTF-16 code escape: \uXXXX * \u is guaranteed to exist, but the remaining hex characters may be * missing. * Translate to UTF-8 and append to temporary token string. * Must advance index to the next character to be processed. * Returns: 0 success * -1 error */ static int json_append_unicode_escape(json_parse_t *json) { char utf8[4]; /* Surrogate pairs require 4 UTF-8 bytes */ int codepoint; int surrogate_low; int len; int escape_len = 6; /* Fetch UTF-16 code unit */ codepoint = decode_hex4(json->ptr + 2); if (codepoint < 0) return -1; /* UTF-16 surrogate pairs take the following 2 byte form: * 11011 x yyyyyyyyyy * When x = 0: y is the high 10 bits of the codepoint * x = 1: y is the low 10 bits of the codepoint * * Check for a surrogate pair (high or low) */ if ((codepoint & 0xF800) == 0xD800) { /* Error if the 1st surrogate is not high */ if (codepoint & 0x400) return -1; /* Ensure the next code is a unicode escape */ if (*(json->ptr + escape_len) != '\\' || *(json->ptr + escape_len + 1) != 'u') { return -1; } /* Fetch the next codepoint */ surrogate_low = decode_hex4(json->ptr + 2 + escape_len); if (surrogate_low < 0) return -1; /* Error if the 2nd code is not a low surrogate */ if ((surrogate_low & 0xFC00) != 0xDC00) return -1; /* Calculate Unicode codepoint */ codepoint = (codepoint & 0x3FF) << 10; surrogate_low &= 0x3FF; codepoint = (codepoint | surrogate_low) + 0x10000; escape_len = 12; } /* Convert codepoint to UTF-8 */ len = codepoint_to_utf8(utf8, codepoint); if (!len) return -1; /* Append bytes and advance parse index */ strbuf_append_mem_unsafe(json->tmp, utf8, len); json->ptr += escape_len; return 0; } static void json_set_token_error(json_token_t *token, json_parse_t *json, const char *errtype) { token->type = T_ERROR; token->index = json->ptr - json->data; token->value.string = errtype; } static void json_next_string_token(json_parse_t *json, json_token_t *token) { char *escape2char = json->cfg->escape2char; char ch; /* Caller must ensure a string is next */ assert(*json->ptr == '"'); /* Skip " */ json->ptr++; /* json->tmp is the temporary strbuf used to accumulate the * decoded string value. * json->tmp is sized to handle JSON containing only a string value. */ strbuf_reset(json->tmp); while ((ch = *json->ptr) != '"') { if (!ch) { /* Premature end of the string */ json_set_token_error(token, json, "unexpected end of string"); return; } /* Handle escapes */ if (ch == '\\') { /* Fetch escape character */ ch = *(json->ptr + 1); /* Translate escape code and append to tmp string */ ch = escape2char[(unsigned char)ch]; if (ch == 'u') { if (json_append_unicode_escape(json) == 0) continue; json_set_token_error(token, json, "invalid unicode escape code"); return; } if (!ch) { json_set_token_error(token, json, "invalid escape code"); return; } /* Skip '\' */ json->ptr++; } /* Append normal character or translated single character * Unicode escapes are handled above */ strbuf_append_char_unsafe(json->tmp, ch); json->ptr++; } json->ptr++; /* Eat final quote (") */ strbuf_ensure_null(json->tmp); token->type = T_STRING; token->value.string = strbuf_string(json->tmp, &token->string_len); } /* JSON numbers should take the following form: * -?(0|[1-9]|[1-9][0-9]+)(.[0-9]+)?([eE][-+]?[0-9]+)? * * json_next_number_token() uses strtod() which allows other forms: * - numbers starting with '+' * - NaN, -NaN, infinity, -infinity * - hexadecimal numbers * - numbers with leading zeros * * json_is_invalid_number() detects "numbers" which may pass strtod()'s * error checking, but should not be allowed with strict JSON. * * json_is_invalid_number() may pass numbers which cause strtod() * to generate an error. */ static int json_is_invalid_number(json_parse_t *json) { const char *p = json->ptr; /* Reject numbers starting with + */ if (*p == '+') return 1; /* Skip minus sign if it exists */ if (*p == '-') p++; /* Reject numbers starting with 0x, or leading zeros */ if (*p == '0') { int ch2 = *(p + 1); if ((ch2 | 0x20) == 'x' || /* Hex */ ('0' <= ch2 && ch2 <= '9')) /* Leading zero */ return 1; return 0; } else if (*p <= '9') { return 0; /* Ordinary number */ } /* Reject inf/nan */ if (!NLMISC::nlstricmp(p, "inf")) return 1; if (!NLMISC::nlstricmp(p, "nan")) return 1; /* Pass all other numbers which may still be invalid, but * strtod() will catch them. */ return 0; } static void json_next_number_token(json_parse_t *json, json_token_t *token) { char *endptr; token->value.integer = strtoll(json->ptr, &endptr, 0); if (json->ptr == endptr) { json_set_token_error(token, json, "invalid number"); return; } if (*endptr == '.' || *endptr == 'e' || *endptr == 'E') { token->type = T_NUMBER; token->value.number = fpconv_strtod(json->ptr, &endptr); } else { token->type = T_INTEGER; } json->ptr = endptr; /* Skip the processed number */ return; } /* Fills in the token struct. * T_STRING will return a pointer to the json_parse_t temporary string * T_ERROR will leave the json->ptr pointer at the error. */ static void json_next_token(json_parse_t *json, json_token_t *token) { const json_token_type_t *ch2token = json->cfg->ch2token; int ch; /* Eat whitespace. */ while (1) { ch = (unsigned char)*(json->ptr); token->type = ch2token[ch]; if (token->type != T_WHITESPACE) break; json->ptr++; } /* Store location of new token. Required when throwing errors * for unexpected tokens (syntax errors). */ token->index = json->ptr - json->data; /* Don't advance the pointer for an error or the end */ if (token->type == T_ERROR) { json_set_token_error(token, json, "invalid token"); return; } if (token->type == T_END) { return; } /* Found a known single character token, advance index and return */ if (token->type != T_UNKNOWN) { json->ptr++; return; } /* Process characters which triggered T_UNKNOWN * * Must use strncmp() to match the front of the JSON string. * JSON identifier must be lowercase. * When strict_numbers if disabled, either case is allowed for * Infinity/NaN (since we are no longer following the spec..) */ if (ch == '"') { json_next_string_token(json, token); return; } else if (ch == '-' || ('0' <= ch && ch <= '9')) { if (!json->cfg->decode_invalid_numbers && json_is_invalid_number(json)) { json_set_token_error(token, json, "invalid number"); return; } json_next_number_token(json, token); return; } else if (!strncmp(json->ptr, "true", 4)) { token->type = T_BOOLEAN; token->value.boolean = 1; json->ptr += 4; return; } else if (!strncmp(json->ptr, "false", 5)) { token->type = T_BOOLEAN; token->value.boolean = 0; json->ptr += 5; return; } else if (!strncmp(json->ptr, "null", 4)) { token->type = T_NULL; json->ptr += 4; return; } else if (json->cfg->decode_invalid_numbers && json_is_invalid_number(json)) { /* When decode_invalid_numbers is enabled, only attempt to process * numbers we know are invalid JSON (Inf, NaN, hex) * This is required to generate an appropriate token error, * otherwise all bad tokens will register as "invalid number" */ json_next_number_token(json, token); return; } /* Token starts with t/f/n but isn't recognised above. */ json_set_token_error(token, json, "invalid token"); } /* This function does not return. * DO NOT CALL WITH DYNAMIC MEMORY ALLOCATED. * The only supported exception is the temporary parser string * json->tmp struct. * json and token should exist on the stack somewhere. * luaL_error() will long_jmp and release the stack */ static void json_throw_parse_error(lua_State *l, json_parse_t *json, const char *exp, json_token_t *token) { const char *found; strbuf_free(json->tmp); if (token->type == T_ERROR) found = token->value.string; else found = json_token_type_name[token->type]; /* Note: token->index is 0 based, display starting from 1 */ luaL_error(l, "Expected %s but found %s at character %d", exp, found, token->index + 1); } static inline void json_decode_ascend(json_parse_t *json) { json->current_depth--; } static void json_decode_descend(lua_State *l, json_parse_t *json, int slots) { json->current_depth++; if (json->current_depth <= json->cfg->decode_max_depth && lua_checkstack(l, slots)) { return; } strbuf_free(json->tmp); luaL_error(l, "Found too many nested data structures (%d) at character %d", json->current_depth, json->ptr - json->data); } static void json_parse_object_context(lua_State *l, json_parse_t *json) { json_token_t token; /* 3 slots required: * .., table, key, value */ json_decode_descend(l, json, 3); lua_newtable(l); json_next_token(json, &token); /* Handle empty objects */ if (token.type == T_OBJ_END) { json_decode_ascend(json); return; } while (1) { if (token.type != T_STRING) json_throw_parse_error(l, json, "object key string", &token); /* Push key */ lua_pushlstring(l, token.value.string, token.string_len); json_next_token(json, &token); if (token.type != T_COLON) json_throw_parse_error(l, json, "colon", &token); /* Fetch value */ json_next_token(json, &token); json_process_value(l, json, &token); /* Set key = value */ lua_rawset(l, -3); json_next_token(json, &token); if (token.type == T_OBJ_END) { json_decode_ascend(json); return; } if (token.type != T_COMMA) json_throw_parse_error(l, json, "comma or object end", &token); json_next_token(json, &token); } } /* Handle the array context */ static void json_parse_array_context(lua_State *l, json_parse_t *json) { json_token_t token; int i; /* 2 slots required: * .., table, value */ json_decode_descend(l, json, 2); lua_newtable(l); json_next_token(json, &token); /* Handle empty arrays */ if (token.type == T_ARR_END) { json_decode_ascend(json); return; } for (i = 1; ; i++) { json_process_value(l, json, &token); lua_rawseti(l, -2, i); /* arr[i] = value */ json_next_token(json, &token); if (token.type == T_ARR_END) { json_decode_ascend(json); return; } if (token.type != T_COMMA) json_throw_parse_error(l, json, "comma or array end", &token); json_next_token(json, &token); } } /* Handle the "value" context */ static void json_process_value(lua_State *l, json_parse_t *json, json_token_t *token) { switch (token->type) { case T_STRING: lua_pushlstring(l, token->value.string, token->string_len); break;; case T_NUMBER: lua_pushnumber(l, token->value.number); break;; case T_INTEGER: lua_pushinteger(l, token->value.integer); break;; case T_BOOLEAN: lua_pushboolean(l, token->value.boolean); break;; case T_OBJ_BEGIN: json_parse_object_context(l, json); break;; case T_ARR_BEGIN: json_parse_array_context(l, json); break;; case T_NULL: /* In Lua, setting "t[k] = nil" will delete k from the table. * Hence a NULL pointer lightuserdata object is used instead */ lua_pushlightuserdata(l, NULL); break;; default: json_throw_parse_error(l, json, "value", token); } } static int json_decode(lua_State *l) { json_parse_t json; json_token_t token; size_t json_len; luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); json.cfg = json_fetch_config(l); json.data = luaL_checklstring(l, 1, &json_len); json.current_depth = 0; json.ptr = json.data; /* Detect Unicode other than UTF-8 (see RFC 4627, Sec 3) * * CJSON can support any simple data type, hence only the first * character is guaranteed to be ASCII (at worst: '"'). This is * still enough to detect whether the wrong encoding is in use. */ if (json_len >= 2 && (!json.data[0] || !json.data[1])) luaL_error(l, "JSON parser does not support UTF-16 or UTF-32"); /* Ensure the temporary buffer can hold the entire string. * This means we no longer need to do length checks since the decoded * string must be smaller than the entire json string */ json.tmp = strbuf_new(json_len); json_next_token(&json, &token); json_process_value(l, &json, &token); /* Ensure there is no more input left */ json_next_token(&json, &token); if (token.type != T_END) json_throw_parse_error(l, &json, "the end", &token); strbuf_free(json.tmp); return 1; } /* ===== INITIALISATION ===== */ #if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 /* Compatibility for Lua 5.1. * * luaL_setfuncs() is used to create a module table where the functions have * json_config_t as their first upvalue. Code borrowed from Lua 5.2 source. */ static void luaL_setfuncs (lua_State *l, const luaL_Reg *reg, int nup) { int i; luaL_checkstack(l, nup, "too many upvalues"); for (; reg->name != NULL; reg++) { /* fill the table with given functions */ for (i = 0; i < nup; i++) /* copy upvalues to the top */ lua_pushvalue(l, -nup); lua_pushcclosure(l, reg->func, nup); /* closure with those upvalues */ lua_setfield(l, -(nup + 2), reg->name); } lua_pop(l, nup); /* remove upvalues */ } #endif /* Call target function in protected mode with all supplied args. * Assumes target function only returns a single non-nil value. * Convert and return thrown errors as: nil, "error message" */ static int json_protect_conversion(lua_State *l) { int err; /* Deliberately throw an error for invalid arguments */ luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); /* pcall() the function stored as upvalue(1) */ lua_pushvalue(l, lua_upvalueindex(1)); lua_insert(l, 1); err = lua_pcall(l, 1, 1, 0); if (!err) return 1; if (err == LUA_ERRRUN) { lua_pushnil(l); lua_insert(l, -2); return 2; } /* Since we are not using a custom error handler, the only remaining * errors are memory related */ return luaL_error(l, "Memory allocation error in CJSON protected call"); } /* Return cjson module table */ static int lua_cjson_new(lua_State *l) { luaL_Reg reg[] = { { "encode", json_encode }, { "decode", json_decode }, { "encode_sparse_array", json_cfg_encode_sparse_array }, { "encode_max_depth", json_cfg_encode_max_depth }, { "decode_max_depth", json_cfg_decode_max_depth }, { "encode_number_precision", json_cfg_encode_number_precision }, { "encode_keep_buffer", json_cfg_encode_keep_buffer }, { "encode_invalid_numbers", json_cfg_encode_invalid_numbers }, { "decode_invalid_numbers", json_cfg_decode_invalid_numbers }, { "new", lua_cjson_new }, { NULL, NULL } }; /* Initialise number conversions */ fpconv_init(); /* cjson module table */ lua_newtable(l); /* Register functions with config data as upvalue */ json_create_config(l); luaL_setfuncs(l, reg, 1); /* Set cjson.null */ lua_pushlightuserdata(l, NULL); lua_setfield(l, -2, "null"); /* Set module name / version fields */ lua_pushliteral(l, CJSON_MODNAME); lua_setfield(l, -2, "_NAME"); lua_pushliteral(l, CJSON_VERSION); lua_setfield(l, -2, "_VERSION"); return 1; } /* Return cjson.safe module table */ static int lua_cjson_safe_new(lua_State *l) { const char *func[] = { "decode", "encode", NULL }; int i; lua_cjson_new(l); /* Fix new() method */ lua_pushcfunction(l, lua_cjson_safe_new); lua_setfield(l, -2, "new"); for (i = 0; func[i]; i++) { lua_getfield(l, -1, func[i]); lua_pushcclosure(l, json_protect_conversion, 1); lua_setfield(l, -2, func[i]); } return 1; } int luaopen_cjson(lua_State *l) { lua_cjson_new(l); #ifdef ENABLE_CJSON_GLOBAL /* Register a global "cjson" table. */ lua_pushvalue(l, -1); lua_setglobal(l, CJSON_MODNAME); #endif /* Return cjson table */ return 1; } int luaopen_cjson_safe(lua_State *l) { lua_cjson_safe_new(l); /* Return cjson.safe table */ return 1; } /* vi:ai et sw=4 ts=4: */ ================================================ FILE: code/EVA/server/server_share/cjson/strbuf.cpp ================================================ /* strbuf - String buffer routines * * Copyright (c) 2010-2012 Mark Pulford * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include "strbuf.h" static void die(const char *fmt, ...) { va_list arg; va_start(arg, fmt); vfprintf(stderr, fmt, arg); va_end(arg); fprintf(stderr, "\n"); exit(-1); } void strbuf_init(strbuf_t *s, int len) { int size; if (len <= 0) size = STRBUF_DEFAULT_SIZE; else size = len + 1; /* \0 terminator */ s->buf = NULL; s->size = size; s->length = 0; s->increment = STRBUF_DEFAULT_INCREMENT; s->dynamic = 0; s->reallocs = 0; s->debug = 0; s->buf = (char*)malloc(size); if (!s->buf) die("Out of memory"); strbuf_ensure_null(s); } strbuf_t *strbuf_new(int len) { strbuf_t *s; s = (strbuf_t*)malloc(sizeof(strbuf_t)); if (!s) die("Out of memory"); strbuf_init(s, len); /* Dynamic strbuf allocation / deallocation */ s->dynamic = 1; return s; } void strbuf_set_increment(strbuf_t *s, int increment) { /* Increment > 0: Linear buffer growth rate * Increment < -1: Exponential buffer growth rate */ if (increment == 0 || increment == -1) die("BUG: Invalid string increment"); s->increment = increment; } static inline void debug_stats(strbuf_t *s) { if (s->debug) { fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %d, size: %d\n", (long)s, s->reallocs, s->length, s->size); } } /* If strbuf_t has not been dynamically allocated, strbuf_free() can * be called any number of times strbuf_init() */ void strbuf_free(strbuf_t *s) { debug_stats(s); if (s->buf) { free(s->buf); s->buf = NULL; } if (s->dynamic) free(s); } char *strbuf_free_to_string(strbuf_t *s, int *len) { char *buf; debug_stats(s); strbuf_ensure_null(s); buf = s->buf; if (len) *len = s->length; if (s->dynamic) free(s); return buf; } static int calculate_new_size(strbuf_t *s, int len) { int reqsize, newsize; if (len <= 0) die("BUG: Invalid strbuf length requested"); /* Ensure there is room for optional NULL termination */ reqsize = len + 1; /* If the user has requested to shrink the buffer, do it exactly */ if (s->size > reqsize) return reqsize; newsize = s->size; if (s->increment < 0) { /* Exponential sizing */ while (newsize < reqsize) newsize *= -s->increment; } else { /* Linear sizing */ newsize = ((newsize + s->increment - 1) / s->increment) * s->increment; } return newsize; } /* Ensure strbuf can handle a string length bytes long (ignoring NULL * optional termination). */ void strbuf_resize(strbuf_t *s, int len) { int newsize; newsize = calculate_new_size(s, len); if (s->debug > 1) { fprintf(stderr, "strbuf(%lx) resize: %d => %d\n", (long)s, s->size, newsize); } s->size = newsize; s->buf = (char*)realloc(s->buf, s->size); if (!s->buf) die("Out of memory"); s->reallocs++; } void strbuf_append_string(strbuf_t *s, const char *str) { int space, i; space = strbuf_empty_length(s); for (i = 0; str[i]; i++) { if (space < 1) { strbuf_resize(s, s->length + 1); space = strbuf_empty_length(s); } s->buf[s->length] = str[i]; s->length++; space--; } } /* strbuf_append_fmt() should only be used when an upper bound * is known for the output string. */ void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...) { va_list arg; int fmt_len; strbuf_ensure_empty_length(s, len); va_start(arg, fmt); fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg); va_end(arg); if (fmt_len < 0) die("BUG: Unable to convert number"); /* This should never happen.. */ s->length += fmt_len; } /* strbuf_append_fmt_retry() can be used when the there is no known * upper bound for the output string. */ void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...) { va_list arg; int fmt_len; int test; int empty_len; /* If the first attempt to append fails, resize the buffer appropriately * and try again */ for (test = 0; ; test++) { va_start(arg, fmt); /* Append the new formatted string */ /* fmt_len is the length of the string required, excluding the * trailing NULL */ empty_len = strbuf_empty_length(s); /* Add 1 since there is also space to store the terminating NULL. */ fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg); va_end(arg); if (fmt_len <= empty_len) break; /* SUCCESS */ if (test > 0) die("BUG: length of formatted string changed"); strbuf_resize(s, s->length + fmt_len); } s->length += fmt_len; } /* vi:ai et sw=4 ts=4: */ ================================================ FILE: code/EVA/server/server_share/cjson/strbuf.h ================================================ /* strbuf - String buffer routines * * Copyright (c) 2010-2012 Mark Pulford * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include /* Size: Total bytes allocated to *buf * Length: String length, excluding optional NULL terminator. * Increment: Allocation increments when resizing the string buffer. * Dynamic: True if created via strbuf_new() */ typedef struct { char *buf; int size; int length; int increment; int dynamic; int reallocs; int debug; } strbuf_t; #ifndef STRBUF_DEFAULT_SIZE #define STRBUF_DEFAULT_SIZE 1023 #endif #ifndef STRBUF_DEFAULT_INCREMENT #define STRBUF_DEFAULT_INCREMENT -2 #endif /* Initialise */ extern strbuf_t *strbuf_new(int len); extern void strbuf_init(strbuf_t *s, int len); extern void strbuf_set_increment(strbuf_t *s, int increment); /* Release */ extern void strbuf_free(strbuf_t *s); extern char *strbuf_free_to_string(strbuf_t *s, int *len); /* Management */ extern void strbuf_resize(strbuf_t *s, int len); static int strbuf_empty_length(strbuf_t *s); static int strbuf_length(strbuf_t *s); static char *strbuf_string(strbuf_t *s, int *len); static void strbuf_ensure_empty_length(strbuf_t *s, int len); static char *strbuf_empty_ptr(strbuf_t *s); static void strbuf_extend_length(strbuf_t *s, int len); /* Update */ extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...); extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...); static void strbuf_append_mem(strbuf_t *s, const char *c, int len); extern void strbuf_append_string(strbuf_t *s, const char *str); static void strbuf_append_char(strbuf_t *s, const char c); static void strbuf_ensure_null(strbuf_t *s); /* Reset string for before use */ static inline void strbuf_reset(strbuf_t *s) { s->length = 0; } static inline int strbuf_allocated(strbuf_t *s) { return s->buf != NULL; } /* Return bytes remaining in the string buffer * Ensure there is space for a NULL terminator. */ static inline int strbuf_empty_length(strbuf_t *s) { return s->size - s->length - 1; } static inline void strbuf_ensure_empty_length(strbuf_t *s, int len) { if (len > strbuf_empty_length(s)) strbuf_resize(s, s->length + len); } static inline char *strbuf_empty_ptr(strbuf_t *s) { return s->buf + s->length; } static inline void strbuf_extend_length(strbuf_t *s, int len) { s->length += len; } static inline int strbuf_length(strbuf_t *s) { return s->length; } static inline void strbuf_append_char(strbuf_t *s, const char c) { strbuf_ensure_empty_length(s, 1); s->buf[s->length++] = c; } static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c) { s->buf[s->length++] = c; } static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len) { strbuf_ensure_empty_length(s, len); memcpy(s->buf + s->length, c, len); s->length += len; } static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len) { memcpy(s->buf + s->length, c, len); s->length += len; } static inline void strbuf_ensure_null(strbuf_t *s) { s->buf[s->length] = 0; } static inline char *strbuf_string(strbuf_t *s, int *len) { if (len) *len = s->length; return s->buf; } /* vi:ai et sw=4 ts=4: */ ================================================ FILE: code/EVA/server/server_share/client_msg_desc.cpp ================================================ #include "client_msg_desc.h" #include #include #include #include #include #include #include using namespace std; using namespace NLMISC; void CMsgDesc::LoadMsgXml() { bool res = false; string path = NLMISC::CPath::lookup("msg.xml"); CIFile file; if (file.open (path)) { CIXml xml; if (xml.init (file)) { xmlNodePtr rootPtr = xml.getRootNode(); if ( rootPtr != NULL ) { xmlNodePtr proto_desc = xml.getFirstChildNode (rootPtr, "proto_src"); std::string proto_path = xml.getStringProperty(proto_desc, "path", ""); if ( !proto_path.empty() ) { m_DiskSourceTree->MapPath("",proto_path); } xmlNodePtr proto_file = xml.getFirstChildNode (proto_desc, "file"); for ( ; proto_file; proto_file=xml.getNextChildNode (proto_file, "file") ) { std::string proto_name = xml.getStringProperty(proto_file, "name", ""); m_Importer->Import(proto_name); } } if ( rootPtr != NULL ) { m_MsgDesc.clear(); xmlNodePtr record=xml.getFirstChildNode (rootPtr, "leaf"); for ( ; record; record=xml.getNextChildNode (record, "leaf") ) { MsgLeaf msg_leaf; msg_leaf.msgname = xml.getStringProperty(record, "name", ""); msg_leaf.description = xml.getStringProperty(record, "description", ""); msg_leaf.is_log_event = xml.getIntProperty(record, "log_event", 1) > 0 ? true: false; /// 解析转发到哪个服务器 const CSString sendto = xml.getStringProperty(record, "sendto", ""); CVectorSString vct_str; sendto.splitBySeparator(' ', vct_str); nlassert(vct_str.size()>0); for ( uint i=0; ipool()->FindMessageTypeByName(vct_str[i]); if (descriptor) { msg_leaf.format.push_back(MSG_FORMAT::ProtoMsg); msg_leaf.format_msg.push_back(vct_str[i]); } else { nlwarning("not define %s", vct_str[i].c_str()); } } else { msg_leaf.format.push_back(msg_format); } } /// 保存 std::pair< TMsgDesc::iterator, bool > res; res = m_MsgDesc.insert( make_pair(msg_leaf.msgname, msg_leaf) ); nlassert(res.second); } res = true; } } file.close (); } nlassert(res); } MsgLeaf* CMsgDesc::GetMsgLeaf( std::string msg_name ) { MsgLeaf* pMsgLeaf = NULL; TMsgDesc::iterator iter = m_MsgDesc.find(msg_name); if ( iter != m_MsgDesc.end() ) { pMsgLeaf = &iter->second; } return pMsgLeaf; } CMsgDesc::CMsgDesc() { m_DiskSourceTree = new google::protobuf::compiler::DiskSourceTree(); m_Importer = new google::protobuf::compiler::Importer(m_DiskSourceTree, NULL); m_Factory = new google::protobuf::DynamicMessageFactory(m_Importer->pool()); } CMsgDesc::~CMsgDesc() { SAFE_DELETE(m_Factory); SAFE_DELETE(m_Importer); SAFE_DELETE(m_DiskSourceTree); } google::protobuf::Message* CMsgDesc::CreateMessage( const std::string& typeName ) { google::protobuf::Message* pMsg = NULL; const google::protobuf::Descriptor* pDescriptor = m_Importer->pool()->FindMessageTypeByName(typeName); if (pDescriptor) { const google::protobuf::Message* pPrototype = m_Factory->GetPrototype(pDescriptor); if (pPrototype) { pMsg = pPrototype->New(); } } return pMsg; } //TCallbackItem* CMsgDesc::GetTCPCallbackItem() //{ // return NULL; //} ================================================ FILE: code/EVA/server/server_share/client_msg_desc.h ================================================ #ifndef SERVER_SHARED_CLIENT_MSG_DESC_H #define SERVER_SHARED_CLIENT_MSG_DESC_H #include #include #include #include "game_def.h" #include "msg_leaf.h" namespace google { namespace protobuf { class Message; class DynamicMessageFactory; namespace compiler { class Importer; class DiskSourceTree; } } } class CMsgDesc : public NLMISC::CSingleton { public: CMsgDesc(); ~CMsgDesc(); void LoadMsgXml(); MsgLeaf* GetMsgLeaf( std::string msg_name ); google::protobuf::Message* CreateMessage(const std::string& typeName); // TCallbackItem* GetTCPCallbackItem(); private: typedef std::map TMsgDesc; TMsgDesc m_MsgDesc; google::protobuf::compiler::DiskSourceTree* m_DiskSourceTree; google::protobuf::compiler::Importer* m_Importer; google::protobuf::DynamicMessageFactory* m_Factory; }; #define MsgDesc CMsgDesc::instance() #endif ================================================ FILE: code/EVA/server/server_share/game_def.h ================================================ #ifndef GAME_SHARD_GAME_DEF_H #define GAME_SHARD_GAME_DEF_H #include namespace DEF { #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif typedef uint64 UID; typedef uint32 RPC_SESSION; /// 远程调用session typedef uint64 CLIENT_SESSION; /// 客户端身份 typedef uint32 TEMPLATE_ID; /// 配置表使用的ID typedef uint32 TEMPLATE_TYPE; /// typedef uint32 CHECK_SUM; typedef sint64 MONEY; typedef uint32 EXP; typedef sint64 RMB; typedef uint32 ERROR_TYPE; typedef uint32 SCRIPT_ID; typedef uint32 EVENT_ID; typedef uint32 ACK_IDX; #define RANDOM_SHOP_GRID_NUM 3 #define PLAYERNAME_LENGTH (24) /// 玩家名字最大长度 #define PLAYERNAME_LENGTH_MIN (4) /// 玩家名字最小长度 #define RPC_SESSION_TCP_FLAG 0x80000000 /// rpc_session协议标识,用于区分 tcp 和 udp协议。 #define FLOAT_RATE 10000 /// 万分比 #define FRIEND_FIGHT_NUM 5 #define BAD_CHECK_SUM DEF::CHECK_SUM(-1) #define NEW_PLAYER_FRIEND_LEVEL 5 #define NEW_PLAYER_FIGHT_LEVEL 4 #define ONE_YEAR 60*60*24*365 #define ONE_DAY 60*60*24 /// flag(1) session(24) sid(7) /// flag 是tcp还是udp, 1:TCP 0:UDP inline bool IsTCPSession( RPC_SESSION rpc_session ) { return rpc_session&RPC_SESSION_TCP_FLAG; } #define PROPERTY( type , name )\ private:\ type m_##name;\ public:\ inline void set_##name(type v){ \ m_##name = v;\ }\ inline type get_##name(){\ return m_##name;\ }\ #define SAFE_DELETE( ptr ) do{ if( NULL != ptr ){ delete ptr ; ptr = NULL; } } while(0) #define SAFE_DELETE_ARRAY( ptr ) do{ if( NULL != ptr ){ delete[] ptr; ptr = NULL; } } while(0) #define GET_DBMSG(structname) \ if( !data ) \ return; \ structname* db_msg = (structname*)( data ); \ if( !db_msg ) \ return ; #define GET_WORKER_AND_STMT(__THREAD,__DB,__STMT) \ nl::sql_worker* pWorker = SelectThread(__THREAD).get_worker( __DB );\ if ( NULL == pWorker ){ return ; }\ nl::sql_stmt* pStmt = pWorker->get_stmt( __STMT );\ if( NULL == pStmt ){ return; } #define GET_WORKER_AND_STMT_MAIN(__THREAD,__DB,__STMT) \ nl::sql_worker* pWorker = SelectThread(__THREAD).get_worker( __DB, true );\ if ( NULL == pWorker ){ nlstop; }\ nl::sql_stmt* pStmt = pWorker->get_stmt( __STMT );\ if( NULL == pStmt ){ nlstop; }\ nl::sql_result* pResult = NULL; } #endif // GAME_SHARD_GAME_DEF_H ================================================ FILE: code/EVA/server/server_share/i18n_def.cpp ================================================ #include "i18n_def.h" #include "nel/misc/string_conversion.h" #include using namespace std; using namespace NLMISC; namespace I18N { NL_BEGIN_STRING_CONVERSION_TABLE (TI18N) NL_STRING_CONVERSION_TABLE_ENTRY(LanguageName) // NL_STRING_CONVERSION_TABLE_ENTRY(UID) NL_END_STRING_CONVERSION_TABLE(TI18N, I18nConversion, UNKNOWN) TI18N toEnum(const std::string &str) { return I18nConversion.fromString(str); } const std::string& toString(TI18N i18n_str) { return I18nConversion.toString(i18n_str); } std::string _gstring; const char* GetStr( const char* label ) { _gstring = CI18N::get(label).toUtf8(); return _gstring.c_str(); } #define GET_BUFFER_MAX 512 char _fstring[GET_BUFFER_MAX]={0}; const char* Format( const char* format_ptr, ... ) { va_list _args; va_start (_args, format_ptr); int _res = vsnprintf (_fstring, GET_BUFFER_MAX-1, format_ptr, _args); if (_res == -1 || _res == GET_BUFFER_MAX-1) { _fstring[GET_BUFFER_MAX-1] = '\0'; } va_end (_args); return _fstring; } }; // MSG_FORMAT ================================================ FILE: code/EVA/server/server_share/i18n_def.h ================================================ #ifndef SERVER_SHARED_I18N_DEF_H #define SERVER_SHARED_I18N_DEF_H #include "nel/misc/types_nl.h" #include "nel/misc/i18n.h" namespace I18N { enum TI18N { LanguageName, UNKNOWN }; TI18N toEnum(const std::string &str); const std::string& toString(TI18N i18n_str); const char* GetStr( const char* label ); const char* Format( const char* format_ptr, ... ); }; // I18N #define FORMAT_P0( __format ) I18N::GetStr(__format) #define FORMAT_P1( __format, __param ) I18N::Format( I18N::GetStr(__format) , __param ) #endif // SERVER_SHARED_I18N_DEF_H /* End of i18n_def.h */ ================================================ FILE: code/EVA/server/server_share/id_generate.cpp ================================================ #include "id_generate.h" #include #include CIDGenerate::CIDGenerate():m_CurrentID(0) { } void CIDGenerate::init( uint32 region_id, uint32 service_id, uint64 current_id ) { nlassert(region_id<=0x3ff); nlassert(service_id<=0x3f); if ( m_CurrentID < current_id ) { m_CurrentID = current_id; } else { nlwarning("CIDGenerate::init CurrID>InitID (%lld)>(%lld)", m_CurrentID, current_id); } m_BaseCode = region_id; m_BaseCode = m_BaseCode << PlaceHolderService; m_BaseCode |= service_id; m_BaseCode = m_BaseCode << PlaceHolderIncreaseID; } namespace bin { BEGIN_SCRIPT_CLASS( IDGenerate, CIDGenerate ) DEFINE_CLASS_FUNCTION( Generate, sint64, ()) { r = obj->Generate(); return 1; } DEFINE_STATIC_FUNCTION(NewInstance, CIDGenerate*, (sint64 curr_id)) { r = new CIDGenerate(); uint32 share_id = NLNET::IService::getInstance()->getShardId(); uint32 svr_id = NLNET::IService::getInstance()->getServiceId().get(); r->init(share_id, svr_id, curr_id); r->GetScriptObject().SetDelByScr(true); return 1; } END_SCRIPT_CLASS() } ================================================ FILE: code/EVA/server/server_share/id_generate.h ================================================ #ifndef SERVER_SHARED_ID_GENERATE_H #define SERVER_SHARED_ID_GENERATE_H #include #include /** * ID * ȫGUID * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 * +-----------------------+---------------+---------------------------------------+ * region_id service_id inc_id * len(10) len(6) len(48) * * * \author li9chuan@qq.com * \date 2013 */ class CIDGenerate { DECLARE_SCRIPT_CLASS(); public: CIDGenerate(); /** * IDɳʼ * @param region_id ϷID * @param service_id ID * @param current_id ǰѾﵽID ֻܱm_CurrentID֡ */ ///@{ void init( uint32 region_id, uint32 service_id, uint64 current_id ); ///@} inline uint64 Generate() { ++m_CurrentID; return m_CurrentID | m_BaseCode; } private: uint64 m_BaseCode; uint64 m_CurrentID; /// 10λID 6λID 48λID enum TPlaceHolder { PlaceHolderService = 6, PlaceHolderRegion = 10, PlaceHolderIncreaseID = 48, }; }; #endif ================================================ FILE: code/EVA/server/server_share/lua/lua_base_function.cpp ================================================ #include #include #include #include #include "lua_engine.h" #include "script_mgr.h" #include #include #include using namespace std; using namespace NLMISC; using namespace NLNET; using namespace DEF; void forLuaBaseFunctionForceLink() { ScriptMgr.ExecString( "" ); } namespace bin { BEGIN_SCRIPT_MODULE(Misc) DEFINE_MODULE_FUNCTION(GetBasePath, std::string, (void)) { //nldebug("Calling func5 with (%s, %lld)\n", path.c_str(), a1); r = NLMISC::CPath::getCurrentPath(); return 1; } DEFINE_MODULE_FUNCTION(GetConfigInt, int, (std::string config_field)) { CConfigFile::CVar *pVar = Config.getVarPtr (config_field); if ( pVar!=NULL ) { r = pVar->asInt(); } return 1; } DEFINE_MODULE_FUNCTION(MD5, std::string, (const char* buff, int len)) { CHashKeyMD5 hash_key = getMD5( (const uint8*)buff, len ); r = hash_key.toString(); return 1; } DEFINE_MODULE_FUNCTION(GetLocalTime, sint64, ()) { r = NLMISC::CTime::getLocalTime(); return 1; } DEFINE_MODULE_FUNCTION(PostMain, void, (sint32 threadHandle, CLuaMessage* pMsgIn)) { CMessage* pMsg = new CMessage(); pMsg->swap(pMsgIn->m_Msg); CLuaThread* pThread = LuaThreadMgr.GetLuaThread(threadHandle); if (pThread != NULL) { pThread->PostMain(pMsg); } return 1; } //DEFINE_MODULE_FUNCTION(GetPath, string, (string& moudule_name)) //{ // moudule_name.append(".lua"); // string fullpath = CPath::lookup(moudule_name, false); // if (fullpath.size()>0) // { // r = NLMISC::CPath::getCurrentPath(); // r.append("/"); // r.append(fullpath); // } // return 1; //} DEFINE_MODULE_FUNCTION(GetFileModificationDate, sint64, (string& script_full_path)) { r = CFile::getFileModificationDate(script_full_path); return 1; } DEFINE_MODULE_FUNCTION(ZipCompress, std::string, (const char* buff, int len)) { uLongf dest_len = compressBound(len); r.resize(dest_len); sint32 z_res = compress((Bytef *)&r[0], &dest_len, (Bytef *)buff, len); if (z_res == Z_OK) { r.resize(dest_len); } else { r.resize(0); nlwarning("ZipCompress Error:%d", z_res); } return 1; } END_SCRIPT_MODULE() BEGIN_SCRIPT_MODULE(Debug) DEFINE_MODULE_FUNCTION(Warning, void, (const char* str, int stack_level)) { lua_Debug ar; lua_getstack(lua.GetHandle(),stack_level,&ar); lua_getinfo(lua.GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name ); NLMISC::INelContext::getInstance().getWarningLog()->displayNL(str); return 1; } DEFINE_MODULE_FUNCTION(Info, void, (const char* str, int stack_level)) { lua_Debug ar; lua_getstack(lua.GetHandle(),stack_level,&ar); lua_getinfo(lua.GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getInfoLog()->setPosition( ar.currentline, ar.short_src, ar.name ); NLMISC::INelContext::getInstance().getInfoLog()->displayNL(str); return 1; } DEFINE_MODULE_FUNCTION(Debug, void, (const char* str, int stack_level)) { lua_Debug ar; lua_getstack(lua.GetHandle(),stack_level,&ar); lua_getinfo(lua.GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getDebugLog()->setPosition( ar.currentline, ar.short_src, ar.name ); NLMISC::INelContext::getInstance().getDebugLog()->displayNL(str); return 1; } DEFINE_MODULE_FUNCTION(Stop, void, (const char* str, int stack_level)) { lua_Debug ar; lua_getstack(lua.GetHandle(),stack_level,&ar); lua_getinfo(lua.GetHandle(), "Sln", &ar); static bool ignoreNextTime = false; if (!ignoreNextTime) { if(NLMISC::_assert_stop(ignoreNextTime, ar.currentline, ar.short_src, ar.name, NULL)) NLMISC_BREAKPOINT; } return 1; } END_SCRIPT_MODULE() } ================================================ FILE: code/EVA/server/server_share/lua/lua_engine.cpp ================================================ #include "lua_engine.h" #include "lua_param.h" #include #include #include #include "server_share/bin_luabind/ScriptHandle.h" #include "server_share/bin_luabind/ScriptExporter.h" extern int luaopen_protobuf_c (lua_State* tolua_S); extern int luaopen_cjson(lua_State *l); //void Lua_Trace(lua_State *L, lua_Debug *debug_msg) //{ // char tmp[6]={0}; // char * what = tmp; // strcpy(what,"nl\0\0"); // switch(debug_msg->event) // { // case LUA_HOOKCALL: // what = strcat(what,"uS"); // nlinfo("LUA_HOOKCALL "); // break; // case LUA_HOOKRET: // what = strcat(what,"u"); // nlinfo("LUA_HOOKRETURN "); // break; // case LUA_HOOKTAILRET: // what = strcat(what,"uS"); // nlinfo("LUA_HOOKTAILRETURN "); // break; // case LUA_HOOKLINE: // what = strcat(what,"uS"); // nlinfo("LUA_HOOKLINE "); // break; // case LUA_HOOKCOUNT: // break; // default: // break; // } // //printf("%s",what); // if(debug_msg->currentline >0 ) // nlinfo("curr line = ",debug_msg->currentline); // // if(lua_getinfo(L, what, debug_msg)) // { // //printf("ʼ%dУ%dУʹⲿ%d", debug_msg->linedefined,debug_msg->lastlinedefined,debug_msg->nups); // if(debug_msg->short_src != NULL) printf(debug_msg->short_src); // printf(" "); // if(debug_msg->what != NULL) printf(debug_msg->what); // printf(" "); // if(debug_msg->source != NULL) printf(debug_msg->source); // printf(" "); // if(debug_msg->name != NULL) printf(debug_msg->name); // if(debug_msg->namewhat != NULL)printf(debug_msg->namewhat); // printf("\n"); // } // printf("\n"); //} // //static int Lua_Note(lua_State *L) //{ // // int n = lua_gettop(L); //IJ // int i; // lua_getglobal(L, "tostring"); //űtostringű⺯ѹջ // for (i=1; i<=n; i++) // { // const char *s; // lua_pushvalue(L, -1); //ջıΪtostring ٴѹջ // lua_pushvalue(L, i); //ҪӡֵҲǽűеʱIJѹջ // lua_call(L, 1, 1); //ýűtostring // s = lua_tostring(L, -1); //ֵջж // // if (s == NULL) // { // return luaL_error(L, "`tostring' must return a string to `print'"); // } // // if (i>1) // nldebug("\t"); // // nldebug("%s",s); // lua_pop(L, 1); //ֵ // } // // nldebug("\n"); // return 0; //} void PrintLuaCallstack(lua_State *L, int stack_level = 0) { lua_Debug debug_msg; NLMISC::createDebug(); while (lua_getstack(L, stack_level, &debug_msg) == 1) { if (lua_getinfo(L, "Slnu", &debug_msg)) { NLMISC::INelContext::getInstance().getWarningLog()->setPosition(debug_msg.currentline, debug_msg.short_src, debug_msg.name); NLMISC::INelContext::getInstance().getWarningLog()->displayNL(""); } ++stack_level; } } CLuaEngine::CLuaEngine(void) { m_pLuaState = NULL; m_ScriptHandle = new bin::CScriptHandle(); //CreateLuaState(); } CLuaEngine::~CLuaEngine(void) { } bool CLuaEngine::Init( std::string logpath ) { if(m_pLuaState!=NULL) return true; m_pLuaState = luaL_newstate(); /// һLua״̬ʵ if(m_pLuaState==NULL) { nlerror( "Lua State Create Fail." ); return false; } luaL_openlibs(m_pLuaState); /// LuaĻ //if( !lua_checkstack(m_pLuaState, LUA_MINSTACK) ) /// LuaĶջС //{ // nlerror( "set LuaState size fail(stacksize=1024)." ); // return false; //} //luaopen_protobuf_c(m_pLuaState); luaL_requiref(m_pLuaState, "protobuf.c", luaopen_protobuf_c, 0); luaL_requiref(m_pLuaState, "cjson", luaopen_cjson, 0); m_ScriptHandle->Init(m_pLuaState); //tolua_auto_lua_callback_open(m_pLuaState); //if( !lua_checkstack(m_pLuaState, stacksize) ) //LuaĶջСֹΪջС //{ // nldebug( "set LuaState size fail(stacksize=%d, top=%d, base=%d).", stacksize, m_pLuaState->top, m_pLuaState->base ); // return false; //} //#ifdef _DEBUG // lua_sethook( m_pLuaState, Lua_Trace, LUA_MASKLINE , 0); //#endif //lua_register( m_pLuaState,"note",Lua_Note); return true; } void CLuaEngine::Release() { if(m_pLuaState != NULL) { m_ScriptHandle->Release(); lua_close(m_pLuaState); } } lua_State * CLuaEngine::GetLuaState() { return m_pLuaState; } const char* CLuaEngine::GetLastError() { return lua_tostring(m_pLuaState, -1); } bool CLuaEngine::LoadLuaFile(const char* fileName) { return m_ScriptHandle->Exec(fileName); } bool CLuaEngine::RunMemoryLua(const char* pLuaData, int nDataLen) { if(pLuaData == NULL || nDataLen <= 0) { return false; } int top = lua_gettop(m_pLuaState); if( !luaL_loadbuffer(m_pLuaState, pLuaData, nDataLen, pLuaData) ) { if( !lua_pcall(m_pLuaState, 0, 0, 0) ) { lua_settop(m_pLuaState, top); return true; } } nlwarning("exec memory lua error, cause %s", GetLastError()); PrintLuaCallstack(m_pLuaState, 1); lua_settop(m_pLuaState, top); return false; } bool CLuaEngine::RunLuaFunction(const char* szFunName, const char* szTableName, const char* szSubTableName, LuaParams* pInParams, LuaParam * pOutParam, int nOutNum) { int top = lua_gettop(m_pLuaState); if(szTableName==NULL) { lua_getglobal(m_pLuaState, szFunName); } else if(szSubTableName==NULL) { lua_getglobal(m_pLuaState, szTableName); if(lua_istable(m_pLuaState, -1)) { lua_getfield(m_pLuaState,-1,szFunName); } } else { lua_getglobal(m_pLuaState, szTableName); if(lua_istable(m_pLuaState, -1)) { lua_getfield(m_pLuaState, -1,szSubTableName); if(lua_istable(m_pLuaState, -1)) { lua_getfield(m_pLuaState,-1,szFunName); } } } if(!lua_isfunction(m_pLuaState, -1)) { nlwarning("call function(%s) fail, cause %s", szFunName, GetLastError()); PrintLuaCallstack(m_pLuaState, 1); lua_settop(m_pLuaState, top); return false; } int inParamCnt = pInParams==NULL?0:pInParams->Count(); for(int i = 0; i < inParamCnt; i++) { switch(pInParams->at(i).Type()) { case LUA_TNUMBER: //lua_pushnumber(m_pLuaState, pInParams->at(i).GetInt()); lua_pushinteger(m_pLuaState, pInParams->at(i).GetInt()); break; case LUA_TSTRING: lua_pushlstring(m_pLuaState, (char*)pInParams->at(i).Data(), pInParams->at(i).GetStringLen()); break; case LUA_TLIGHTUSERDATA: lua_pushlightuserdata(m_pLuaState, pInParams->at(i).Data()); break; default: nlwarning("call function(%s) fail, in param type error", szFunName); PrintLuaCallstack(m_pLuaState, 1); lua_settop(m_pLuaState, top); return false; } } if( !lua_pcall(m_pLuaState, inParamCnt, nOutNum, 0) ) { for(int n = 0; n < nOutNum; n++) { int nType = lua_type(m_pLuaState, -1); switch(nType) { case LUA_TNUMBER: pOutParam[n].SetInt( lua_tointeger(m_pLuaState, -1) ); lua_pop(m_pLuaState, 1); break; case LUA_TBOOLEAN: pOutParam[n].SetInt( lua_toboolean(m_pLuaState, -1) ); lua_pop(m_pLuaState, 1); break; case LUA_TSTRING: //pOutParam[n].SetString((char*)lua_tostring(m_pLuaState, -1)); lua_pop(m_pLuaState, 1); break; case LUA_TLIGHTUSERDATA: pOutParam[n].SetDataPointer((void*)lua_topointer(m_pLuaState, -1)); lua_pop(m_pLuaState, 1); break; default: nlwarning("call function(%s) fail, out param type error = %s ", szFunName , lua_typename( m_pLuaState , -1 ) ); PrintLuaCallstack(m_pLuaState, 1); lua_settop(m_pLuaState, top); return false; } } lua_settop(m_pLuaState, top); /// ָջΪδʱ״̬ return true; } nlwarning("call function(%s) fail, cause %s", szFunName, GetLastError()); PrintLuaCallstack(m_pLuaState, 1); lua_settop(m_pLuaState, top); return false; } void CLuaEngine::ExportModule( const char* pszName ) { bin::ScriptExporterManager().ExportModule( pszName, *m_ScriptHandle ); } void CLuaEngine::ExportClass( const char* pszName ) { bin::ScriptExporterManager().ExportClass( pszName, *m_ScriptHandle ); } void CLuaEngine::GcStep() { H_AUTO(CLuaEngineGcStep); lua_gc(m_pLuaState, LUA_GCSTEP, 0); } ================================================ FILE: code/EVA/server/server_share/lua/lua_engine.h ================================================ #ifndef SERVER_SHARD_LUA_ENGINE_H #define SERVER_SHARD_LUA_ENGINE_H #include "lua_param.h" namespace bin{ class CScriptHandle; } class CLuaEngine { public: CLuaEngine(void); virtual ~CLuaEngine(void); public: bool Init(std::string logpath=""); void Release(); lua_State * GetLuaState(); bin::CScriptHandle* GetScriptHandle() { return m_ScriptHandle; } const char* GetLastError(); void GcStep(); bool LoadLuaFile(const char* szName); bool RunMemoryLua(const char* pLuaData, int nDataLen); bool RunLuaFunction(const char* szFunName, const char* szTableName = NULL, const char* szSubTableName = NULL,LuaParams* pInParams=NULL, LuaParam * pOutParam = NULL, int nOutNum = 0); void ExportModule( const char* pszName ); void ExportClass( const char* pszName ); private: lua_State* m_pLuaState; bin::CScriptHandle* m_ScriptHandle; }; #endif ================================================ FILE: code/EVA/server/server_share/lua/lua_param.cpp ================================================ #include "lua_param.h" #include #include static LuaParam err; LuaParam& LuaParams::GetParam( uint index ) { if ( index #include #include #include class LuaParam { public: inline int Type() { return m_Type; } inline void SetInt(lua_Integer num) { m_Int = num; m_Type = LUA_TNUMBER; } inline void SetString(const char* string, uint32 len) { m_DataHandle = (void*)string; m_Type = LUA_TSTRING; m_Int = len; } inline uint32 GetStringLen() { return m_Int; } inline void SetDataPointer(void* pointer) { m_DataHandle = pointer; m_Type = LUA_TLIGHTUSERDATA; } inline void* Data() { if(m_Type == LUA_TNUMBER) return &m_Int; return (void*)m_DataHandle; } inline lua_Integer GetInt() { return m_Int; } LuaParam(void):m_Int(0),m_Type(LUA_TNUMBER),m_DataHandle(NULL) { } LuaParam(void* pointer):m_Int(0),m_DataHandle(pointer),m_Type(LUA_TLIGHTUSERDATA) { } LuaParam(lua_Integer luanumber):m_Int(luanumber),m_Type(LUA_TNUMBER),m_DataHandle(NULL) { } virtual ~LuaParam(void){}; private: sint16 m_Type; void* m_DataHandle; lua_Integer m_Int; }; class LuaParams { public: enum TParamsDefine { MAX_PARAMS = 3, }; LuaParams():m_Count(0){} ~LuaParams(){} LuaParams( const lua_Number param1 ): m_Count(1) { m_Params[0].SetInt(param1); } LuaParams( const lua_Number param1, const lua_Number param2 ): m_Count(2) { m_Params[0].SetInt(param1); m_Params[1].SetInt(param2); } LuaParams( const lua_Number param1, const std::string& param2 ) : m_Count(2) { m_Params[0].SetInt(param1); m_Params[1].SetString(param2.c_str(), param2.size()); } LuaParams( const std::string& param1, const std::string& param2 ): m_Count(2) { m_Params[0].SetString( param1.c_str(), param1.size() ); m_Params[1].SetString( param2.c_str(), param2.size() ); } LuaParams( const lua_Integer param1, const std::string& param2, const std::string& param3 ): m_Count(3) { m_Params[0].SetInt(param1); m_Params[1].SetString( param2.c_str(), param2.size() ); m_Params[2].SetString( param3.c_str(), param3.size() ); } //LuaParams( lua_Number param1, lua_Number param2, lua_Number param3 , lua_Number param4 ): //m_Count(4) //{ // m_Params[0].SetInt(param1); // m_Params[1].SetInt(param2); // m_Params[2].SetInt(param3); // m_Params[3].SetInt(param4); //} //LuaParams( lua_Number param1, lua_Number param2, lua_Number param3 , lua_Number param4 , lua_Number param5 ): //m_Count(5) //{ // m_Params[0].SetInt(param1); // m_Params[1].SetInt(param2); // m_Params[2].SetInt(param3); // m_Params[3].SetInt(param4); // m_Params[4].SetInt(param5); //} //LuaParams( lua_Number param1, lua_Number param2, lua_Number param3 , lua_Number param4 , lua_Number param5 , lua_Number param6 ): //m_Count(6) //{ // m_Params[0].SetInt(param1); // m_Params[1].SetInt(param2); // m_Params[2].SetInt(param3); // m_Params[3].SetInt(param4); // m_Params[4].SetInt(param5); // m_Params[5].SetInt(param6); //} //LuaParams( lua_Number param1, lua_Number param2, lua_Number param3 , lua_Number param4 , lua_Number param5 , lua_Number param6 , lua_Number param7 ): //m_Count(7) //{ // m_Params[0].SetInt(param1); // m_Params[1].SetInt(param2); // m_Params[2].SetInt(param3); // m_Params[3].SetInt(param4); // m_Params[4].SetInt(param5); // m_Params[5].SetInt(param6); // m_Params[6].SetInt(param7); //} //LuaParams( lua_Number param1, lua_Number param2, lua_Number param3 , lua_Number param4 , lua_Number param5 , lua_Number param6 , lua_Number param7 , lua_Number param8 , lua_Number param9 , lua_Number param10 ): //m_Count(10) //{ // m_Params[0].SetInt(param1); // m_Params[1].SetInt(param2); // m_Params[2].SetInt(param3); // m_Params[3].SetInt(param4); // m_Params[4].SetInt(param5); // m_Params[5].SetInt(param6); // m_Params[6].SetInt(param7); // m_Params[7].SetInt(param8); // m_Params[8].SetInt(param9); // m_Params[9].SetInt(param10); //} LuaParam& GetParam( uint index ); //bool AddParam( lua_Number param1 ) //{ // if ( m_Count+1 m_Params; }; #endif ================================================ FILE: code/EVA/server/server_share/lua/lua_thread.cpp ================================================ #include "lua_thread.h" #include #include "script_mgr.h" #include #include using namespace NLMISC; using namespace NLNET; void forLuaThreadForceLink() { nlwarning("forLuaThreadForceLink"); } CLuaThread::CLuaThread( std::string name, sint32 update_tick ) : m_ThreadHandle(NULL), m_ThreadName(name), m_AlreadyStarted(false), m_RequireExit(false), m_LuaThreadHandle(-1), m_UpdateTick(0) { if ( update_tick>0 && update_tick<0x7FFFFFFF ) { m_UpdateTick = update_tick; } } CLuaThread::~CLuaThread( void ) { Close(); LuaThreadMgr.RemoveLuaThread(m_LuaThreadHandle); } sint32 CLuaThread::Start( std::string lua_start, std::string params ) { m_ThreadHandle = NLMISC::IThread::create( this ); if ( m_ThreadHandle != NULL ) { m_SubLuaEngine.Init(); m_SubLuaEngine.ExportModule("Misc"); m_SubLuaEngine.ExportModule("Debug"); m_SubLuaEngine.ExportModule("Net"); m_SubLuaEngine.ExportClass("LuaMessage"); m_SubLuaEngine.ExportClass("LuaThread"); m_SubLuaEngine.ExportClass("LuaCallbackClient"); m_SubLuaEngine.ExportClass("MysqlStmt"); m_SubLuaEngine.ExportClass("MysqlConn"); m_SubLuaEngine.ExportClass("MysqlResult"); m_ToSubEvent.init(1024*1024); m_ToMainEvent.init(1024*1024); //GetScriptObject().SetDelByScr(false); //m_SubLuaEngine.GetScriptHandle()->Set( export_name.c_str(), this ); m_SubLuaEngine.GetScriptHandle()->Exec(lua_start.c_str()); m_LuaThreadHandle = LuaThreadMgr.RegisterLuaThread(this); LuaParams _params(m_LuaThreadHandle, params); m_SubLuaEngine.RunLuaFunction("ThreadInit", NULL, NULL, &_params); m_AlreadyStarted = true; m_ThreadHandle->start(); } return m_LuaThreadHandle; } void CLuaThread::Close( void ) { if ( NULL != m_ThreadHandle ) { m_AlreadyStarted = false; m_RequireExit = true; m_ThreadHandle->wait(); m_ThreadHandle = NULL; } } void CLuaThread::Update( void ) { if (m_AlreadyStarted) { CMessage* pMsg = NULL; bin::CScriptTable functbl; ScriptMgr.GetScriptHandle()->Get("NetWorkHandler", functbl); while ((pMsg = m_ToMainEvent.pop_front()) != NULL) { sint32 nRet = 0; m_LuaMainMsg.m_Msg.swap(*pMsg); m_LuaMainMsg.m_Msg.invert(); functbl.CallFunc("OnMessage", m_LuaThreadHandle, &m_LuaMainMsg, nRet); SAFE_DELETE(pMsg); } } } void CLuaThread::run( void ) { bin::CScriptTable functbl; m_SubLuaEngine.GetScriptHandle()->Get("NetWorkHandler", functbl); NLMISC::TTime last_time = CTime::getLocalTime(); while ( !m_RequireExit ) { CMessage* pMsg = m_ToSubEvent.pop_front(); if ( pMsg != NULL ) { sint32 nRet = 0; m_LuaSubMsg.m_Msg.swap(*pMsg); m_LuaSubMsg.m_Msg.invert(); functbl.CallFunc("OnMessage", m_LuaThreadHandle, &m_LuaSubMsg, nRet); SAFE_DELETE(pMsg); } else { NLMISC::nlSleep( 3 ); } if (m_UpdateTick > 0) { NLMISC::TTime curr_time = CTime::getLocalTime(); if (curr_time - last_time > m_UpdateTick) { m_SubLuaEngine.RunLuaFunction("ThreadUpdate"); last_time = curr_time; } } } } void CLuaThreadMgr::Init() { //CConfigFile::CVar* pVar = Config.getVarPtr("LuaWorkThread"); //if ( pVar != NULL ) //{ // for (uint i = 0; i < pVar->size(); ++i) // { // NLMISC::CSString start_file = pVar->asString(i); // CVectorSString res; // start_file.splitBySeparator( ' ', res ); // if( res.size()!=2 ) { nlwarning( "%s, config format error.", start_file.c_str() ); continue; } // NLMISC::CSString script_full_path = CPath::lookup( res[1] ); // if( !script_full_path.empty() ) // { // CLuaThread* pLuaThread = new CLuaThread( res[0] ); // pLuaThread->Start( script_full_path, res[0] ); // } // else // { // nlwarning( "%s, not found.", script_full_path.c_str() ); // } // } //} } sint32 CLuaThreadMgr::RegisterLuaThread( CLuaThread* pThread ) { sint32 lua_handle = -1; m_LuaThreadMutex.enter(); m_LuaThreadHandles.push_back(pThread); lua_handle = m_LuaThreadHandles.size()-1; m_LuaThreadMutex.leave(); return lua_handle; } void CLuaThreadMgr::Update() { H_AUTO(CLuaThreadMgrUpdate); m_LuaThreadMutex.enter(); for (uint i=0; i< m_LuaThreadHandles.size(); ++i) { m_LuaThreadHandles[i]->Update(); } m_LuaThreadMutex.leave(); } void CLuaThreadMgr::Release() { m_LuaThreadMutex.enter(); for (uint i = 0; i< m_LuaThreadHandles.size(); ++i) { m_LuaThreadHandles[i]->Close(); delete m_LuaThreadHandles[i]; } m_LuaThreadHandles.clear(); m_LuaThreadMutex.leave(); } void CLuaThreadMgr::RemoveLuaThread( sint32 thread_handle ) { m_LuaThreadMutex.enter(); m_LuaThreadHandles[thread_handle] = NULL; m_LuaThreadMutex.leave(); } CLuaThread* CLuaThreadMgr::GetLuaThread( sint32 thread_handle ) { CLuaThread* pLuaThread = NULL; m_LuaThreadMutex.enter(); pLuaThread = m_LuaThreadHandles[thread_handle]; m_LuaThreadMutex.leave(); return pLuaThread; } namespace bin { BEGIN_SCRIPT_CLASS( LuaThread, CLuaThread ) DEFINE_CLASS_FUNCTION( Post, void, (CLuaMessage* pMsgIn)) { CMessage* pMsg = new CMessage(); pMsg->swap(pMsgIn->m_Msg); obj->PostSub(pMsg); return 1; } DEFINE_CLASS_FUNCTION(Start, sint32, (std::string& lua_start, std::string& params)) { r = obj->Start(lua_start, params); return 1; } DEFINE_STATIC_FUNCTION(NewInstance, CLuaThread*, (std::string name, sint32 update_tick)) { r = new CLuaThread(name, update_tick); r->GetScriptObject().SetDelByScr(true); return 1; } END_SCRIPT_CLASS() } ================================================ FILE: code/EVA/server/server_share/lua/lua_thread.h ================================================ #ifndef SERVER_SHARD_LUA_THREAD_H #define SERVER_SHARD_LUA_THREAD_H #include #include #include #include #include #include #include namespace bin{ class CScriptHandle; } class CThreadEvent { public: uint64 m_From; std::string m_Data; std::string m_EventType; }; class CLuaThread : public NLMISC::IRunnable { DECLARE_SCRIPT_CLASS(); public: CLuaThread( std::string name, sint32 update_tick); virtual ~CLuaThread(void); /** * ߳ * @param lua_start ߳luaű· * @param params ݲ * @return lua_thread_handle */ ///@{ sint32 Start(std::string lua_start, std::string params); ///@} // close; void Close( void ); // ̵߳ãȡ m_ToMainEvent void Update( void ); void PostSub(NLNET::CMessage* pMsg) { m_ToSubEvent.push_back(pMsg); } void PostMain(NLNET::CMessage* pMsg ) { m_ToMainEvent.push_back(pMsg); } CLuaEngine& GetLuaEngine() { return m_SubLuaEngine; } protected: // sub threads run; void run( void ); private: NLMISC::IThread* m_ThreadHandle; CLuaEngine m_SubLuaEngine; std::string m_ThreadName; sint32 m_LuaThreadHandle; bool m_AlreadyStarted; sint32 m_UpdateTick; volatile bool m_RequireExit; NLMISC::CBufFIFO2< NLNET::CMessage > m_ToSubEvent; NLMISC::CBufFIFO2< NLNET::CMessage > m_ToMainEvent; CLuaMessage m_LuaMainMsg; CLuaMessage m_LuaSubMsg; }; class CLuaThreadMgr : public NLMISC::CSingleton { public: CLuaThreadMgr() {} sint32 RegisterLuaThread( CLuaThread* pThread ); void RemoveLuaThread( sint32 lua_handle ); CLuaThread* GetLuaThread( sint32 lua_handle); void Init(); void Update(); void Release(); private: typedef std::vector TThreadHandles; TThreadHandles m_LuaThreadHandles; NLMISC::CMutex m_LuaThreadMutex; }; #define LuaThreadMgr CLuaThreadMgr::instance() #endif ================================================ FILE: code/EVA/server/server_share/lua/script_mgr.cpp ================================================ #include "script_mgr.h" #include #include #include #include "lua_engine.h" #include "server_share/bin_luabind/Public.hpp" #include #include #include using namespace std; using namespace DEF; using namespace NLMISC; extern void forLuaMysqlConnForceLink(); extern void forLuaBaseFunctionForceLink(); extern void forLuaMessageForceLink(); extern void forLuaThreadForceLink(); extern void forLuaCallbackClientForceLink(); void luaexportforcelink() { CIDGenerate idgen; forLuaMysqlConnForceLink(); forLuaBaseFunctionForceLink(); forLuaMessageForceLink(); forLuaThreadForceLink(); forLuaCallbackClientForceLink(); } bool CScriptMgr::init( LUA_OPEN pLuaOpen ) { m_IsInit = false; //UpdateServiceBootCount(); //string fn = IService::getInstance()->SaveFilesDirectory.toString(); string log_file = /*fn +*/ Config.getVar("LogDirectory").asString(); string lua_log = log_file + "lua_engine.log"; m_LuaEngine.Release(); nlassert( m_LuaEngine.Init(lua_log) ); if ( pLuaOpen!=NULL ) { pLuaOpen( m_LuaEngine.GetLuaState() ); } /// C++ӿ Export(); CConfigFile::CVar* pVar = NULL; if ((pVar = Config.getVarPtr("StartLuaScript")) != NULL) { string script_full_path = CPath::lookup( pVar->asString() ); nlinfo("Loading %s.", script_full_path.c_str()); m_IsInit = ScriptMgr.LoadScrpit(script_full_path.c_str()); } return m_IsInit; } LuaParams CScriptMgr::run( std::string script_scope, std::string script_name, LuaParams lua_in, uint outnum ) { nlassert(outnum<=LuaParams::MAX_PARAMS); LuaParams lua_out; lua_out.resize(outnum); bool run_ret = m_LuaEngine.RunLuaFunction( script_name.c_str(), script_scope.c_str(), NULL, &lua_in, lua_out.GetParams(), lua_out.Count() ); //nlassert( run_ret ); if ( !run_ret ) { lua_out.resize(0); } return lua_out; } lua_State * CScriptMgr::GetLuaState() { return m_LuaEngine.GetLuaState(); } void CScriptMgr::release() { m_LuaEngine.RunLuaFunction( "ServiceRelease" ); m_LuaEngine.Release(); } bool CScriptMgr::LoadScrpit( const char* szName ) { if( m_LuaEngine.LoadLuaFile(szName) ) { return m_LuaEngine.RunLuaFunction( "ServiceInit" ); } return false; } void CScriptMgr::update() { H_AUTO(CScriptMgrUpdate); if (m_IsInit) { m_LuaEngine.RunLuaFunction("ServiceUpdate"); m_LuaEngine.GcStep(); } } void CScriptMgr::Export() { m_LuaEngine.ExportModule("Misc"); m_LuaEngine.ExportModule("Debug"); m_LuaEngine.ExportModule("Net"); m_LuaEngine.ExportClass("LuaCallbackServer"); m_LuaEngine.ExportClass("LuaMessage"); m_LuaEngine.ExportClass("IDGenerate"); m_LuaEngine.ExportClass("LuaThread"); m_LuaEngine.ExportClass("LuaCallbackClient"); m_LuaEngine.ExportClass("MysqlStmt"); m_LuaEngine.ExportClass("MysqlConn"); m_LuaEngine.ExportClass("MysqlResult"); } void CScriptMgr::ExecString( std::string exec_str ) { m_LuaEngine.GetScriptHandle()->ExecString( exec_str.c_str() ); } void CScriptMgr::UpdateServiceBootCount() { std::string cache_file = "."; cache_file.append( NLNET::IService::getInstance()->getServiceShortName() ); cache_file.append( "-" ); cache_file.append( NLMISC::toString(NLNET::IService::getInstance()->getServiceId().get()) ); cache_file.append( ".che" ); if (!NLMISC::CFile::fileExists(cache_file)) { NLMISC::CFile::createEmptyFile(cache_file); } CConfigFile cf; cf.load(cache_file); if ( !cf.exists("BootCnt") ) { CConfigFile::CVar var; var.forceAsInt(1); cf.insertVar("BootCnt", var); } else { CConfigFile::CVar* pVar = cf.getVarPtr("BootCnt"); uint32 boot_cnt = pVar->asInt(); ++boot_cnt; pVar->setAsInt(boot_cnt); } cf.save(); } NLMISC_COMMAND (lua, "run lua string.", "lua") { if(args.size() != 1) return false; ScriptMgr.ExecString( args[0] ); return true; } NLMISC_COMMAND(hotfix, "lua module hotfix.", "") { if (args.size() != 0) return false; ScriptMgr.ExecString("Hotfix:Update()"); return true; } NLMISC_COMMAND(info, "service information.", "") { if (args.size() != 0) return false; ScriptMgr.ExecString("ServiceInfo()"); return true; } ================================================ FILE: code/EVA/server/server_share/lua/script_mgr.h ================================================ #ifndef SERVER_SHARD_SCRIPT_MGR_H #define SERVER_SHARD_SCRIPT_MGR_H #include #include #include #include "lua_engine.h" typedef int (*LUA_OPEN)(lua_State* tolua_S); namespace bin{ class CScriptHandle; } class CScriptMgr : public NLMISC::CSingleton { public: bool init( LUA_OPEN pToluaOpen=NULL ); void update(); void release(); LuaParams run( std::string script_scope, std::string script_name, LuaParams lua_in, uint outnum=0 ); void ExecString( std::string ); bool LoadScrpit(const char* szName); lua_State* GetLuaState(); CLuaEngine& GetLuaEngine() { return m_LuaEngine; } bin::CScriptHandle* GetScriptHandle() { return m_LuaEngine.GetScriptHandle(); } private: void UpdateServiceBootCount(); void Export(); CLuaEngine m_LuaEngine; bool m_IsInit; }; #define ScriptMgr CScriptMgr::instance() #define ScriptRun ScriptMgr.run #endif ================================================ FILE: code/EVA/server/server_share/lua_mysql/mysql_conn.cpp ================================================ #include #include "mysql_conn.h" #include "mysql_stmt.h" #include "mysql_result.h" #include "string" #include #ifdef NL_OS_WINDOWS static const char* DB_NAMES = "utf8"; #else static const char* DB_NAMES = "utf8mb4"; #endif // NL_OS_WINDOWS CLuaMysqlConn::CLuaMysqlConn( void ) : m_mysql_( NULL ), m_port_( 3306 ), m_errno_( 0 ), m_error_( "" ) { } CLuaMysqlConn::~CLuaMysqlConn( void ) { close(); } // connect. bool CLuaMysqlConn::connect( char const *host_, char const *user_, char const *pwd_, char const *db_, int port_ ) { close(); m_mysql_ = mysql_init( NULL ); if ( NULL != m_mysql_ ) { // set character. mysql_options( m_mysql_, MYSQL_SET_CHARSET_NAME, DB_NAMES ); if ( NULL != mysql_real_connect( m_mysql_, host_, user_, pwd_, db_, port_, NULL, 0 ) ) { m_host_.assign( host_ ); m_user_.assign( user_ ); m_pwd_.assign( pwd_ ); m_db_.assign( db_ ); m_port_ = port_; // set autocommit. mysql_autocommit( m_mysql_, 1 ); // set character set. mysql_set_character_set( m_mysql_, DB_NAMES ); mysql_query(m_mysql_, "SET character_set_client=binary"); nlinfo( "connect mysql server succeed!" ); nlinfo( "mysql client library : %s." , mysql_get_client_info() ); nlinfo( "mysql server version: %s. " , mysql_get_server_info( m_mysql_ ) ); return true; } else { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); nlwarning( "connect mysql server failed, error = %d!" , m_errno_ ); } } else { nlwarning( " connect mysql server failed! " ); } return false; } // close. void CLuaMysqlConn::close( void ) { if ( NULL != m_mysql_ ) { mysql_close( m_mysql_ ); m_mysql_ = NULL; } } //CLuaMysqlStmt* CLuaMysqlConn::create_stmt( char const *sql_, size_t sz_ ) //{ // CLuaMysqlStmt *_ret = NULL; // // if ( NULL != m_mysql_ && NULL != sql_ && sz_ > 0 ) // { // _ret = new (std::nothrow ) CLuaMysqlStmt ; // if ( NULL!=_ret ) // { // _ret->m_sql_.assign( sql_, sz_ ); // } // } // // return _ret; //} // execute. int CLuaMysqlConn::execute( CLuaMysqlStmt *stmt_ ) { int _ret = -1; if ( NULL != m_mysql_ && NULL != stmt_ ) { MYSQL_STMT *_stmt = mysql_stmt_init( m_mysql_ ); if ( NULL != _stmt ) { if ( 0 == mysql_stmt_prepare( _stmt, stmt_->m_sql_.c_str(), stmt_->m_sql_.size() ) ) { my_bool _bl = 1; mysql_stmt_attr_set( _stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &_bl ); stmt_->_bind( mysql_stmt_param_count( _stmt ) ); if ( NULL != stmt_->m_bind_ ) { if ( 0 != mysql_stmt_bind_param( _stmt, stmt_->m_bind_ ) ) { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); mysql_stmt_close( _stmt ); _stmt = NULL; if ( _procerror( stmt_->m_sql_.c_str(), "mysql_stmt_bind_param" ) ) { _ret = execute( stmt_ ); } } } if ( NULL != _stmt ) { if ( 0 == mysql_stmt_execute( _stmt ) ) { _ret = (int)mysql_stmt_affected_rows( _stmt ); /// 检查是否有结果集; MYSQL_RES *_res = mysql_stmt_result_metadata( _stmt ); if ( NULL != _res ) { unsigned int server_status = m_mysql_->server_status; if ( server_status & SERVER_PS_OUT_PARAMS ) { nlwarning( "此调用存储存在返回参数值,请检查sql语句和存储过程实现!" ); mysql_stmt_store_result( _stmt ); mysql_free_result( _res ); mysql_stmt_free_result( _stmt ); } else { nlwarning( "执行查询操作不应该返回任何结果集,请检查sql语句和存储过程实现!" ); mysql_stmt_store_result( _stmt ); mysql_free_result( _res ); mysql_stmt_free_result( _stmt ); while ( 0 == mysql_stmt_next_result( _stmt ) ) { _res = mysql_stmt_result_metadata( _stmt ); if ( NULL != _res ) { server_status = m_mysql_->server_status; mysql_stmt_store_result( _stmt ); mysql_free_result( _res ); mysql_stmt_free_result( _stmt ); if ( server_status & SERVER_PS_OUT_PARAMS ) { nlwarning( " 此调用存储存在返回参数值,请检查sql语句和存储过程实现! " ); break; } else { nlwarning( " 执行查询操作不应该返回任何结果集,请检查sql语句和存储过程实现! " ); } } } } } mysql_stmt_close( _stmt ); _stmt = NULL; _res = NULL; } else { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); mysql_stmt_close( _stmt ); _stmt = NULL; if ( _procerror( stmt_->m_sql_.c_str(), "mysql_stmt_execute" ) ) { _ret = execute( stmt_ ); } } } } else { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); mysql_stmt_close( _stmt ); _stmt = NULL; if ( _procerror( stmt_->m_sql_.c_str(), "mysql_stmt_prepare" ) ) { _ret = execute( stmt_ ); } } } else { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); if ( _procerror( stmt_->m_sql_.c_str(), "mysql_stmt_init" ) ) { _ret = execute( stmt_ ); } } } return _ret; } // query. int CLuaMysqlConn::query( CLuaMysqlStmt *stmt_, CLuaMysqlResult **result_ ) { int _ret = -1; if ( NULL != m_mysql_ && NULL != stmt_ && NULL != result_ ) { MYSQL_STMT *_stmt = mysql_stmt_init( m_mysql_ ); //*result_ = NULL; if ( NULL != _stmt ) { if ( 0 == mysql_stmt_prepare( _stmt, stmt_->m_sql_.c_str(), stmt_->m_sql_.size() ) ) { my_bool _bl = 1; mysql_stmt_attr_set( _stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &_bl ); stmt_->_bind( mysql_stmt_param_count( _stmt ) ); if ( NULL != stmt_->m_bind_ ) { if ( 0 != mysql_stmt_bind_param( _stmt, stmt_->m_bind_ ) ) { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); mysql_stmt_close( _stmt ); _stmt = NULL; if ( _procerror( stmt_->m_sql_.c_str(), "mysql_stmt_bind_param" ) ) { _ret = query( stmt_, result_ ); } } } if ( NULL != _stmt ) { if ( 0 == mysql_stmt_execute( _stmt ) ) { _ret = (int)mysql_stmt_affected_rows( _stmt ); MYSQL_RES *_res = mysql_stmt_result_metadata( _stmt ); if ( NULL != _res ) { unsigned int server_status = m_mysql_->server_status; if ( 0 == mysql_stmt_store_result( _stmt ) ) { CLuaMysqlResult *_result = *result_; if ( *result_ == NULL ) { nlwarning("CLuaMysqlResult == NULL"); _result = new( std::nothrow ) CLuaMysqlResult(); *result_ = _result; } if ( server_status & SERVER_PS_OUT_PARAMS ) { _ret = 0; _result->_retval( _stmt, _res ); mysql_free_result( _res ); mysql_stmt_free_result( _stmt ); } else { _ret = (int)mysql_stmt_num_rows( _stmt ); _result->_init( _stmt, _res ); mysql_free_result( _res ); mysql_stmt_free_result( _stmt ); /// 检查是否还有结果集; while ( 0 == mysql_stmt_next_result( _stmt ) ) { _res = mysql_stmt_result_metadata( _stmt ); if ( NULL != _res ) { server_status = m_mysql_->server_status; if ( 0 == mysql_stmt_store_result( _stmt ) ) { if ( server_status & SERVER_PS_OUT_PARAMS ) { _result->_retval( _stmt, _res ); mysql_free_result( _res ); mysql_stmt_free_result( _stmt ); break; } else { nlwarning( "执行查询操作不应该返回任何结果集,请检查sql语句和存储过程实现!" ); mysql_stmt_store_result( _stmt ); mysql_free_result( _res ); mysql_stmt_free_result( _stmt ); } } } } } mysql_stmt_close( _stmt ); _stmt = NULL; } else { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); mysql_stmt_close( _stmt ); _stmt = NULL; if ( _procerror( stmt_->m_sql_.c_str(), "mysql_stmt_store_result" ) ) { _ret = query( stmt_, result_ ); } else { _ret = -1; } } } else { mysql_stmt_close( _stmt ); _stmt = NULL; } } else { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); mysql_stmt_close( _stmt ); _stmt = NULL; if ( _procerror( stmt_->m_sql_.c_str(), "mysql_stmt_execute" ) ) { _ret = query( stmt_, result_ ); } } } } else { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); mysql_stmt_close( _stmt ); _stmt = NULL; if ( _procerror( stmt_->m_sql_.c_str(), "mysql_stmt_prepare" ) ) { _ret = query( stmt_, result_ ); } } } else { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); if ( _procerror( stmt_->m_sql_.c_str(), "mysql_stmt_init" ) ) { _ret = query( stmt_, result_ ); } } } return _ret; } // reconnect. bool CLuaMysqlConn::_reconnect( void ) { if ( NULL != m_mysql_ && 0 == mysql_ping( m_mysql_ ) ) { return true; } else { nlwarning( "try to reconnect mysql server...\n" ); close(); m_mysql_ = mysql_init( NULL ); if ( NULL != m_mysql_ ) { // set character. mysql_options( m_mysql_, MYSQL_SET_CHARSET_NAME, "utf8" ); if ( NULL != mysql_real_connect( m_mysql_, m_host_.c_str(), m_user_.c_str(), m_pwd_.c_str(), m_db_.c_str(), m_port_, NULL, 0 ) ) { // set autocommit. mysql_autocommit( m_mysql_, 1 ); // set character set. mysql_set_character_set( m_mysql_, "utf8" ); mysql_query(m_mysql_, "SET character_set_client=binary"); nlinfo( "reconnect mysql server succeed!" ); nlinfo( "mysql client library: %s." , mysql_get_client_info() ); nlinfo( "mysql server version: %s. " , mysql_get_server_info( m_mysql_ ) ); return true; } else { nlwarning( "reconnect mysql server failed, error = %d! " , mysql_errno( m_mysql_ ) ); } } else { nlwarning( " reconnect mysql server failed! " ); } } return false; } // process error. bool CLuaMysqlConn::_procerror( char const *op_/* = NULL*/, char const *func_/* = NULL*/ ) { bool _ret = false; if ( NULL != op_ && NULL != func_ ) { nlinfo("op = %s, func = %s.\n" , op_ , func_ ); } else if ( NULL != op_ ) { nlinfo( " op = %s. " , op_ ); } switch ( m_errno_ ) { case CR_SERVER_GONE_ERROR: { nlwarning( "mysql server has gone away, errno = %d!" , m_errno_ ); if ( _reconnect() ) { _ret = true; } else { if ( NULL != m_mysql_ ) { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); //OSSleep( ERROR_SLEEP_TIME ); _ret = _procerror( op_, __FUNCTION__ ); } } } break; case CR_SERVER_LOST: { nlwarning( "lost the connection to mysql server, errno = %d!\n", m_errno_ ); if ( _reconnect() ) { _ret = true; } else { if ( NULL != m_mysql_ ) { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); //OSSleep( ERROR_SLEEP_TIME ); _ret = _procerror( op_, __FUNCTION__ ); } } } break; case CR_INVALID_CONN_HANDLE: { nlwarning( "invalid connection handle, errno = %d!\n", m_errno_ ); if ( _reconnect() ) { _ret = true; } else { if ( NULL != m_mysql_ ) { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); //OSSleep( ERROR_SLEEP_TIME ); _ret = _procerror( op_, __FUNCTION__ ); } } } break; case CR_SERVER_LOST_EXTENDED: { nlwarning( "lost the connection to mysql server error = %d! " , m_errno_ ); if ( _reconnect() ) { _ret = true; } else { if ( NULL != m_mysql_ ) { m_errno_ = mysql_errno( m_mysql_ ); m_error_ = mysql_error( m_mysql_ ); //OSSleep( ERROR_SLEEP_TIME ); _ret = _procerror( op_, __FUNCTION__ ); } } } break; default: { nlwarning( "%s, error = %d! " , m_error_.c_str(), m_errno_ ); } break; } return _ret; } // errno. int CLuaMysqlConn::error( void ) const { return m_errno_; } void forLuaMysqlConnForceLink() { ScriptMgr.ExecString( "" ); } namespace bin { BEGIN_SCRIPT_CLASS( MysqlConn, CLuaMysqlConn ) DEFINE_CLASS_FUNCTION( Connect, bool, (CScriptTable& tb_msg)) { if( tb_msg.IsReferd() ) { std::string myhost; std::string myuser; std::string mypwd; std::string mydb; sint32 myport; tb_msg.Get(1, myhost); tb_msg.Get(2, myuser); tb_msg.Get(3, mypwd); tb_msg.Get(4, mydb); tb_msg.Get(5, myport); r = obj->connect( myhost.c_str(), myuser.c_str(), mypwd.c_str(), mydb.c_str(), myport ); } else { r = false; } return 1; } DEFINE_CLASS_FUNCTION( Close, void, ()) { obj->close(); return 1; } DEFINE_CLASS_FUNCTION( Query, int, (CLuaMysqlStmt* pStmt, CLuaMysqlResult* pResult)) { r = obj->query( pStmt, &pResult ); return 1; } DEFINE_CLASS_FUNCTION( Exec, int, (CLuaMysqlStmt* pStmt)) { r = obj->execute( pStmt ); return 1; } DEFINE_STATIC_FUNCTION(NewInstance, CLuaMysqlConn*, ()) { r = new CLuaMysqlConn(); r->GetScriptObject().SetDelByScr(true); return 1; } END_SCRIPT_CLASS() } ================================================ FILE: code/EVA/server/server_share/lua_mysql/mysql_conn.h ================================================ #ifndef LUA_MYSQL_CONN_H #define LUA_MYSQL_CONN_H # ifdef _MSC_VER # if _MSC_VER < 1700 #include #endif #endif #include #include #include #include #define ERROR_SLEEP_TIME 3000 /// ִSQLʱٴγִмʱ䣨룩 class CLuaMysqlStmt; class CLuaMysqlResult; class CLuaMysqlConn { DECLARE_SCRIPT_CLASS(); public: CLuaMysqlConn( void ); ~CLuaMysqlConn( void ); // connect. bool connect( char const *host_, char const *user_, char const *pwd_, char const *db_, int port_ ); // close. void close( void ); // create statement. //CLuaMysqlStmt* create_stmt( char const *sql_, size_t sz_ ); // execute. int execute( CLuaMysqlStmt *stmt_ ); // query. int query( CLuaMysqlStmt *stmt_, CLuaMysqlResult **result_ ); // errno. int error( void ) const; private: // reconnect. bool _reconnect( void ); // process error. bool _procerror( char const *op_ = NULL, char const *func_ = NULL ); private: MYSQL *m_mysql_; std::string m_host_; std::string m_user_; std::string m_pwd_; std::string m_db_; int m_port_; int m_errno_; std::string m_error_; }; #endif // LUA_MYSQL_CONN_H ================================================ FILE: code/EVA/server/server_share/lua_mysql/mysql_result.cpp ================================================ #include "mysql_result.h" #include "mysql_stmt.h" #include CLuaMysqlResult::CLuaMysqlResult( void ):m_RowCount(0),m_CurrRow(-1),m_FieldCount(0),m_Idx(0) { //m_cur_ = m_res_.end(); } CLuaMysqlResult::~CLuaMysqlResult( void ) { //m_res_.clear(); //m_cur_ = m_res_.end(); //m_row_ = 0; } // close void CLuaMysqlResult::release( void ) { delete this; } void CLuaMysqlResult::clear() { m_Result.clear(); m_RowCount = 0; m_CurrRow = -1; m_FieldCount = 0; m_Idx = 0; } size_t CLuaMysqlResult::count( void ) const { return m_RowCount; } bool CLuaMysqlResult::next( void ) { bool _ret = false; if ( m_CurrRow+1 < m_RowCount ) { m_Idx = 0; ++m_CurrRow; _ret = true; } //if ( 0 == m_row_ && // m_row_ < m_res_.size() && // m_cur_ != m_res_.end() ) //{ // ++ m_row_; // _ret = true; //} //else //{ // if ( m_cur_ != m_res_.end() ) // { // ++ m_cur_; // if ( m_cur_ != m_res_.end() ) // { // ++ m_row_; // _ret = true; // } // } //} return _ret; } my_bool CLuaMysqlResult::get_bool() { bool _ret = false; uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { switch ( _res.type ) { case MYSQL_TYPE_TINY: _ret = ( 0 != ( *(uint8*)_res.buf.c_str() ) ); break; case MYSQL_TYPE_SHORT: _ret = ( 0 != ( *(uint16*)_res.buf.c_str() ) ); break; case MYSQL_TYPE_INT24: _ret = ( 0 != ( *(uint32*)_res.buf.c_str() ) ); break; case MYSQL_TYPE_LONG: _ret = ( 0 != ( *(uint32*)_res.buf.c_str() ) ); break; case MYSQL_TYPE_LONGLONG: _ret = ( 0 != ( *(uint64*)_res.buf.c_str() ) ); break; case MYSQL_TYPE_FLOAT: _ret = ( 0 != ( *(uint32*)_res.buf.c_str() ) ); break; case MYSQL_TYPE_DOUBLE: _ret = ( 0 != ( *(uint64*)_res.buf.c_str() ) ); break; default: break; } ++m_Idx; } } return _ret; } sint8 CLuaMysqlResult::get_int8() { sint8 _ret = 0; uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { switch ( _res.type ) { case MYSQL_TYPE_TINY: _ret = (sint8)( *(uint8*)_res.buf.c_str() ); break; case MYSQL_TYPE_SHORT: _ret = (sint8)( *(uint16*)_res.buf.c_str() ); break; case MYSQL_TYPE_INT24: _ret = (sint8)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONG: _ret = (sint8)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONGLONG: _ret = (sint8)( *(uint64*)_res.buf.c_str() ); break; case MYSQL_TYPE_FLOAT: _ret = (sint8)( *(float*)_res.buf.c_str() ); break; case MYSQL_TYPE_DOUBLE: _ret = (sint8)( *(double*)_res.buf.c_str() ); break; default: break; } ++m_Idx; } } return _ret; } uint8 CLuaMysqlResult::get_uint8() { uint8 _ret = 0; uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { switch ( _res.type ) { case MYSQL_TYPE_TINY: _ret = (uint8)( *(uint8*)_res.buf.c_str() ); break; case MYSQL_TYPE_SHORT: _ret = (uint8)( *(uint16*)_res.buf.c_str() ); break; case MYSQL_TYPE_INT24: _ret = (uint8)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONG: _ret = (uint8)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONGLONG: _ret = (uint8)( *(uint64*)_res.buf.c_str() ); break; case MYSQL_TYPE_FLOAT: _ret = (uint8)( *(float*)_res.buf.c_str() ); break; case MYSQL_TYPE_DOUBLE: _ret = (uint8)( *(double*)_res.buf.c_str() ); break; default: break; } ++m_Idx; } } return _ret; } sint16 CLuaMysqlResult::get_int16() { sint16 _ret = 0; uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { switch ( _res.type ) { case MYSQL_TYPE_TINY: _ret = (sint16)( *(uint8*)_res.buf.c_str() ); break; case MYSQL_TYPE_SHORT: _ret = (sint16)( *(uint16*)_res.buf.c_str() ); break; case MYSQL_TYPE_INT24: _ret = (sint16)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONG: _ret = (sint16)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONGLONG: _ret = (sint16)( *(uint64*)_res.buf.c_str() ); break; case MYSQL_TYPE_FLOAT: _ret = (sint16)( *(float*)_res.buf.c_str() ); break; case MYSQL_TYPE_DOUBLE: _ret = (sint16)( *(double*)_res.buf.c_str() ); break; default: break; } ++m_Idx; } } return _ret; } uint16 CLuaMysqlResult::get_uint16() { uint16 _ret = 0; uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { switch ( _res.type ) { case MYSQL_TYPE_TINY: _ret = (uint16)( *(uint8*)_res.buf.c_str() ); break; case MYSQL_TYPE_SHORT: _ret = (uint16)( *(uint16*)_res.buf.c_str() ); break; case MYSQL_TYPE_INT24: _ret = (uint16)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONG: _ret = (uint16)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONGLONG: _ret = (uint16)( *(uint64*)_res.buf.c_str() ); break; case MYSQL_TYPE_FLOAT: _ret = (uint16)( *(float*)_res.buf.c_str() ); break; case MYSQL_TYPE_DOUBLE: _ret = (uint16)( *(double*)_res.buf.c_str() ); break; default: break; } ++m_Idx; } } return _ret; } sint32 CLuaMysqlResult::get_int32() { sint32 _ret = 0; uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { switch ( _res.type ) { case MYSQL_TYPE_TINY: _ret = (sint32)( *(uint8*)_res.buf.c_str() ); break; case MYSQL_TYPE_SHORT: _ret = (sint32)( *(uint16*)_res.buf.c_str() ); break; case MYSQL_TYPE_INT24: _ret = (sint32)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONG: _ret = (sint32)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONGLONG: _ret = (sint32)( *(uint64*)_res.buf.c_str() ); break; case MYSQL_TYPE_FLOAT: _ret = (sint32)( *(float*)_res.buf.c_str() ); break; case MYSQL_TYPE_DOUBLE: _ret = (sint32)( *(double*)_res.buf.c_str() ); break; default: break; } ++m_Idx; } } return _ret; } uint32 CLuaMysqlResult::get_uint32() { uint32 _ret = 0; uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { switch ( _res.type ) { case MYSQL_TYPE_TINY: _ret = (uint32)( *(uint8*)_res.buf.c_str() ); break; case MYSQL_TYPE_SHORT: _ret = (uint32)( *(uint16*)_res.buf.c_str() ); break; case MYSQL_TYPE_INT24: _ret = (uint32)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONG: _ret = (uint32)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONGLONG: _ret = (uint32)( *(uint64*)_res.buf.c_str() ); break; case MYSQL_TYPE_FLOAT: _ret = (uint32)( *(float*)_res.buf.c_str() ); break; case MYSQL_TYPE_DOUBLE: _ret = (uint32)( *(double*)_res.buf.c_str() ); break; default: break; } ++m_Idx; } } return _ret; } sint64 CLuaMysqlResult::get_int64() { sint64 _ret = 0; uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { switch ( _res.type ) { case MYSQL_TYPE_TINY: _ret = (sint64)( *(uint8*)_res.buf.c_str() ); break; case MYSQL_TYPE_SHORT: _ret = (sint64)( *(uint16*)_res.buf.c_str() ); break; case MYSQL_TYPE_INT24: _ret = (sint64)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONG: _ret = (sint64)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONGLONG: _ret = (sint64)( *(uint64*)_res.buf.c_str() ); break; case MYSQL_TYPE_FLOAT: _ret = (sint64)( *(float*)_res.buf.c_str() ); break; case MYSQL_TYPE_DOUBLE: _ret = (sint64)( *(double*)_res.buf.c_str() ); break; default: break; } ++m_Idx; } } return _ret; } uint64 CLuaMysqlResult::get_uint64() { uint64 _ret = 0; uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { switch ( _res.type ) { case MYSQL_TYPE_TINY: _ret = (uint64)( *(uint8*)_res.buf.c_str() ); break; case MYSQL_TYPE_SHORT: _ret = (uint64)( *(uint16*)_res.buf.c_str() ); break; case MYSQL_TYPE_INT24: _ret = (uint64)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONG: _ret = (uint64)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONGLONG: _ret = (uint64)( *(uint64*)_res.buf.c_str() ); break; case MYSQL_TYPE_FLOAT: _ret = (uint64)( *(float*)_res.buf.c_str() ); break; case MYSQL_TYPE_DOUBLE: _ret = (uint64)( *(double*)_res.buf.c_str() ); break; default: break; } ++m_Idx; } } return _ret; } float CLuaMysqlResult::get_float() { float _ret = 0; uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { switch ( _res.type ) { case MYSQL_TYPE_TINY: _ret = (float)( *(uint8*)_res.buf.c_str() ); break; case MYSQL_TYPE_SHORT: _ret = (float)( *(uint16*)_res.buf.c_str() ); break; case MYSQL_TYPE_INT24: _ret = (float)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONG: _ret = (float)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONGLONG: _ret = (float)( *(uint64*)_res.buf.c_str() ); break; case MYSQL_TYPE_FLOAT: _ret = (float)( *(float*)_res.buf.c_str() ); break; case MYSQL_TYPE_DOUBLE: _ret = (float)( *(double*)_res.buf.c_str() ); break; default: break; } ++m_Idx; } } return _ret; } double CLuaMysqlResult::get_double() { double _ret = 0; uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { switch ( _res.type ) { case MYSQL_TYPE_TINY: _ret = (double)( *(uint8*)_res.buf.c_str() ); break; case MYSQL_TYPE_SHORT: _ret = (double)( *(uint16*)_res.buf.c_str() ); break; case MYSQL_TYPE_INT24: _ret = (double)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONG: _ret = (double)( *(uint32*)_res.buf.c_str() ); break; case MYSQL_TYPE_LONGLONG: _ret = (double)( *(uint64*)_res.buf.c_str() ); break; case MYSQL_TYPE_FLOAT: _ret = (double)( *(float*)_res.buf.c_str() ); break; case MYSQL_TYPE_DOUBLE: _ret = (double)( *(double*)_res.buf.c_str() ); break; default: break; } ++m_Idx; } } return _ret; } std::pair CLuaMysqlResult::get_string() { std::pair _ret( 0, "" ); uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { if ( _res.size > 0 ) { _ret.first = _res.size; _ret.second = _res.buf.c_str(); *(((char*)_ret.second) + _ret.first) = '\0'; } } ++m_Idx; } return _ret; } std::pair CLuaMysqlResult::get_blob() { std::pair _ret( 0, "" ); uint32 curr_idx = row_offset()+m_Idx; //if ( m_cur_ != m_res_.end() && m_Idx < m_cur_->size() ) { result_t& _res = m_Result[curr_idx]; if ( !_res.is_null ) { if ( _res.size > 0 ) { _ret.first = _res.size; _ret.second = _res.buf.c_str(); } } ++m_Idx; } return _ret; } bool CLuaMysqlResult::_init( MYSQL_STMT *stmt_, MYSQL_RES *res_ ) { bool _ret = false; m_RowCount = 0; m_CurrRow = -1; if ( NULL != stmt_ && NULL != res_ ) { size_t _row = mysql_stmt_num_rows( stmt_ ); if ( _row > 0 ) { size_t _count = 0; MYSQL_BIND *_bind = NULL; _count = mysql_stmt_field_count( stmt_ ); if ( _count > 0 ) { m_FieldCount = _count; _bind = (MYSQL_BIND*)malloc( _count * sizeof(MYSQL_BIND) ); memset( _bind, 0, _count * sizeof(MYSQL_BIND) ); } if ( NULL != _bind ) { //std::map _result; std::vector _result; _result.resize(_count); size_t _idx = 0; size_t _buff_max_len = 0; MYSQL_FIELD *pField = mysql_fetch_field( res_ ); while ( NULL != pField ) { size_t _sz = 0; switch ( pField->type ) { case MYSQL_TYPE_TINY: _sz = 1; break; case MYSQL_TYPE_SHORT: _sz = 2; break; case MYSQL_TYPE_INT24: _sz = 4; break; case MYSQL_TYPE_LONG: _sz = 4; break; case MYSQL_TYPE_LONGLONG: _sz = 8; break; case MYSQL_TYPE_FLOAT: _sz = 4; break; case MYSQL_TYPE_DOUBLE: _sz = 8; break; case MYSQL_TYPE_STRING: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_BLOB: case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: _sz = pField->max_length; break; default: nlassert( false ); break; } result_t& _res = _result[_idx]; _res.buf.assign( '\0', _sz ); _res.size = _sz; _res.type = pField->type; _res.is_null = 0; _bind[_idx].buffer_type = pField->type; _bind[_idx].buffer = (void*)_res.buf.c_str(); _bind[_idx].buffer_length = _res.size; _bind[_idx].length = &_res.size; _bind[_idx].is_unsigned = pField->flags & UNSIGNED_FLAG; _bind[_idx].is_null = &_res.is_null; _buff_max_len += _res.size; ++ _idx; pField = mysql_fetch_field( res_ ); } if ( _buff_max_len > 0 && 0 == mysql_stmt_bind_result( stmt_, _bind ) ) { m_Result.resize( _row*_count ); m_RowCount = _row; uint32 ret_idx = 0; //NLMISC::TTime save_time = 0; //uint32 while_count = 0; while ( _row > 0 ) { int _val = mysql_stmt_fetch( stmt_ ); -- _row; if ( 0 == _val || MYSQL_DATA_TRUNCATED == _val ) { uint32 row_offset = ret_idx*_count; for ( size_t _idx = 0; _idx < _count; ++ _idx ) { result_t& src = _result[_idx]; result_t& dest = m_Result[row_offset+_idx]; //NLMISC::TTime sss = NLMISC::CTime::getLocalTime(); dest.buf.assign( src.buf.c_str(), src.size ); //save_time += NLMISC::CTime::getLocalTime() - sss; //++while_count; //dest.buf = src.buf; dest.size = src.size; dest.type = src.type; dest.is_null = src.is_null; } ++ret_idx; } else { m_RowCount = m_RowCount-_row; m_Result.resize( m_RowCount*m_FieldCount ); _row = 0; } } //nlinfo("save itme : %lld while_count:%d",save_time,while_count); _ret = true; } free( _bind ); _result.clear(); } } } return _ret; } bool CLuaMysqlResult::_retval( MYSQL_STMT *stmt_, MYSQL_RES *res_ ) { bool _ret = false; //if ( NULL != stmt_ && NULL != res_ ) //{ // size_t _row = 0; // _row = mysql_stmt_num_rows( stmt_ ); // if ( 1 == _row ) // صĽֻһ // { // size_t _count = 0; // MYSQL_BIND *_bind = NULL; // _count = mysql_stmt_field_count( stmt_ ); // if ( _count > 0 ) // { // _bind = (MYSQL_BIND*)malloc( _count * sizeof(MYSQL_BIND) ); // memset( _bind, 0, _count * sizeof(MYSQL_BIND) ); // } // if ( NULL != _bind ) // { // std::map _result; // size_t _idx = 0; // size_t _buff_max_len = 0; // MYSQL_FIELD *_field = NULL; // _field = mysql_fetch_field( res_ ); // while ( NULL != _field ) // { // size_t _sz = 0; // switch ( _field->type ) // { // case MYSQL_TYPE_TINY: // _sz = 1; // break; // case MYSQL_TYPE_SHORT: // _sz = 2; // break; // case MYSQL_TYPE_INT24: // _sz = 4; // break; // case MYSQL_TYPE_LONG: // _sz = 4; // break; // case MYSQL_TYPE_LONGLONG: // _sz = 8; // break; // case MYSQL_TYPE_FLOAT: // _sz = 4; // break; // case MYSQL_TYPE_DOUBLE: // _sz = 8; // break; // case MYSQL_TYPE_STRING: // case MYSQL_TYPE_VAR_STRING: // case MYSQL_TYPE_BLOB: // case MYSQL_TYPE_TINY_BLOB: // case MYSQL_TYPE_MEDIUM_BLOB: // case MYSQL_TYPE_LONG_BLOB: // _sz = _field->max_length; // break; // default: // break; // } // result_t& _res = _result[_idx]; // _res.buf.assign( '\0', _sz ); // _res.size = _sz; // _res.type = _field->type; // _res.is_null = 0; // _bind[_idx].buffer_type = _field->type; // _bind[_idx].buffer = (void*)_res.buf.c_str(); // _bind[_idx].buffer_length = _res.size; // _bind[_idx].length = &_res.size; // _bind[_idx].is_unsigned = _field->flags & UNSIGNED_FLAG; // _bind[_idx].is_null = &_res.is_null; // _buff_max_len += _res.size; // ++ _idx; // _field = mysql_fetch_field( res_ ); // } // if ( _buff_max_len > 0 && 0 == mysql_stmt_bind_result( stmt_, _bind ) ) // { // int _val = mysql_stmt_fetch( stmt_ ); // if ( 0 == _val || MYSQL_DATA_TRUNCATED == _val ) // { // result_t *_src = NULL; // result_t *_dest = NULL; // for ( size_t _idx = 0; _idx < _count; ++ _idx ) // { // _src = &_result[_idx]; // _dest = &m_ret_[_idx]; // _dest->buf = _src->buf; // _dest->size = _src->size; // _dest->type = _src->type; // _dest->is_null = _src->is_null; // } // } // _ret = true; // } // free( _bind ); // _result.clear(); // } // } //} return _ret; } namespace bin { BEGIN_SCRIPT_CLASS( MysqlResult, CLuaMysqlResult ) DEFINE_CLASS_FUNCTION( Next, bool, ()) { r = obj->next(); return 1; } DEFINE_CLASS_FUNCTION( Count, sint64, () ) { r = obj->count(); return 1; } DEFINE_CLASS_FUNCTION( Clear, void, () ) { obj->clear(); return 1; } DEFINE_CLASS_FUNCTION( GetBool, bool, () ) { r = obj->get_bool(); return 1; } DEFINE_CLASS_FUNCTION( GetInt8, sint64, () ) { r = obj->get_int8(); return 1; } DEFINE_CLASS_FUNCTION( GetUint8, sint64, () ) { r = obj->get_uint8(); return 1; } DEFINE_CLASS_FUNCTION( GetInt32, sint64, () ) { r = obj->get_int32(); return 1; } DEFINE_CLASS_FUNCTION( GetUint32, sint64, () ) { r = obj->get_uint32(); return 1; } DEFINE_CLASS_FUNCTION( GetInt64, sint64, () ) { r = obj->get_int64(); return 1; } DEFINE_CLASS_FUNCTION( GetUint64, sint64, () ) { r = obj->get_uint64(); return 1; } DEFINE_CLASS_FUNCTION( GetFloat, lua_Number, () ) { r = obj->get_float(); return 1; } DEFINE_CLASS_FUNCTION( GetDouble, lua_Number, () ) { r = obj->get_double(); return 1; } DEFINE_CLASS_FUNCTION( GetString, std::string, () ) { std::pair pair = obj->get_string(); r.assign(pair.second, pair.first); return 1; } DEFINE_CLASS_FUNCTION( GetBlob, std::string, () ) { std::pair pair = obj->get_blob(); r.assign((const char*)pair.second, pair.first); //r.Set(1, (const char*)pair.second); //r.Set(2, (int)pair.first); return 1; } DEFINE_STATIC_FUNCTION(NewInstance, CLuaMysqlResult*, ()) { r = new CLuaMysqlResult(); r->GetScriptObject().SetDelByScr(true); return 1; } END_SCRIPT_CLASS() } ================================================ FILE: code/EVA/server/server_share/lua_mysql/mysql_result.h ================================================ #ifndef LUA_MYSQL_RESULT_H #define LUA_MYSQL_RESULT_H #include #include #include #include "mysql_string.h" #include class CLuaMysqlResult { DECLARE_SCRIPT_CLASS(); public: friend class CLuaMysqlConn; // close. void release( void ); void clear(); // next. bool next( void ); // count. size_t count( void ) const; // get bool value. my_bool get_bool(); // get int8 value. sint8 get_int8(); // get uint8 value. uint8 get_uint8(); // get int16 value. sint16 get_int16(); // get uint16 value. uint16 get_uint16(); // get int32 value. sint32 get_int32(); // get uint32 value. uint32 get_uint32(); // get int64 value. sint64 get_int64(); // get uint64 value. uint64 get_uint64(); // get float value. float get_float(); // get double value. double get_double(); // get string. std::pair get_string(); // get blob. std::pair get_blob(); CLuaMysqlResult( void ); ~CLuaMysqlResult( void ); protected: typedef struct _result { CLuaMysqlString buf; unsigned long size; enum_field_types type; my_bool is_null; _result( void ) : size( 0 ), type( MYSQL_TYPE_NULL ), is_null( 0 ) {} } result_t; // initialize. bool _init( MYSQL_STMT *stmt_, MYSQL_RES *res_ ); // returned output parameters. bool _retval( MYSQL_STMT *stmt_, MYSQL_RES *res_ ); uint32 row_offset() { return m_CurrRow<0?0:(m_CurrRow*m_FieldCount); } private: typedef std::vector<_result> TResult; TResult m_Result; uint32 m_RowCount; sint32 m_CurrRow; uint32 m_FieldCount; uint32 m_Idx; //std::map m_ret_; // out parameters. }; #endif // LUA_MYSQL_RESULT_H ================================================ FILE: code/EVA/server/server_share/lua_mysql/mysql_stmt.cpp ================================================ #include "mysql_stmt.h" #include "mysql_conn.h" #include "mysql_result.h" #include #include CLuaMysqlStmt::CLuaMysqlStmt( ) : m_bind_( NULL ), m_count_( 0 ), m_idx(0) { m_Params.resize(64); } CLuaMysqlStmt::~CLuaMysqlStmt( void ) { if ( NULL != m_bind_ ) { free( m_bind_ ); m_bind_ = NULL; m_count_ = 0; m_idx = 0; } } // close. void CLuaMysqlStmt::release( void ) { delete this; } void CLuaMysqlStmt::clear() { m_count_ = 0; m_idx = 0; } // set bool value. void CLuaMysqlStmt::set_bool( my_bool bval_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char)bval_, 1 ); param.type = MYSQL_TYPE_TINY; param.is_unsigned = 0; ++m_idx; } // set int8 value. void CLuaMysqlStmt::set_int8( sint8 i8_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char)i8_, 1 ); param.type = MYSQL_TYPE_TINY; param.is_unsigned = 0; ++m_idx; } // set uint8 value. void CLuaMysqlStmt::set_uint8( uint8 ui8_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char)ui8_, 1 ); param.type = MYSQL_TYPE_TINY; param.is_unsigned = UNSIGNED_FLAG; ++m_idx; } // set int16 value. void CLuaMysqlStmt::set_int16( sint16 i16_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char*)&i16_, 2 ); param.type = MYSQL_TYPE_SHORT; param.is_unsigned = 0; ++m_idx; } // set uint16 value. void CLuaMysqlStmt::set_uint16( uint16 ui16_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char*)&ui16_, 2 ); param.type = MYSQL_TYPE_SHORT; param.is_unsigned = UNSIGNED_FLAG; ++m_idx; } // set int32 value. void CLuaMysqlStmt::set_int32( sint32 i32_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char*)&i32_, 4 ); param.type = MYSQL_TYPE_LONG; param.is_unsigned = 0; ++m_idx; } // set uint32 value. void CLuaMysqlStmt::set_uint32( uint32 ui32_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char*)&ui32_, 4 ); param.type = MYSQL_TYPE_LONG; param.is_unsigned = UNSIGNED_FLAG; ++m_idx; } // set int64 value. void CLuaMysqlStmt::set_int64( sint64 i64_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char*)&i64_, 8 ); param.type = MYSQL_TYPE_LONGLONG; param.is_unsigned = 0; ++m_idx; } // set uint64 value. void CLuaMysqlStmt::set_uint64( uint64 ui64_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char*)&ui64_, 8 ); param.type = MYSQL_TYPE_LONGLONG; param.is_unsigned = UNSIGNED_FLAG; ++m_idx; } // set float value. void CLuaMysqlStmt::set_float( float fval_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char*)&fval_, 4 ); param.type = MYSQL_TYPE_FLOAT; param.is_unsigned = 0; ++m_idx; } // set double value. void CLuaMysqlStmt::set_double( double dval_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char*)&dval_, 8 ); param.type = MYSQL_TYPE_DOUBLE; param.is_unsigned = 0; ++m_idx; } // set string. void CLuaMysqlStmt::set_string( char const *str_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( str_ ); param.type = MYSQL_TYPE_STRING; param.is_unsigned = 0; ++m_idx; } // set string. void CLuaMysqlStmt::set_string( char const *str_, size_t sz_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( str_, sz_ ); param.type = MYSQL_TYPE_STRING; param.is_unsigned = 0; ++m_idx; } // set blob. void CLuaMysqlStmt::set_blob( void const *ptr_, size_t sz_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char*)ptr_, sz_ ); param.type = MYSQL_TYPE_BLOB; param.is_unsigned = 0; ++m_idx; } void CLuaMysqlStmt::set_tinyblob( void const *ptr_, size_t sz_ ) { param_t& param = m_Params[m_idx]; param.buf.assign( (char*)ptr_, sz_ ); param.type = MYSQL_TYPE_TINY_BLOB; param.is_unsigned = 0; ++m_idx; } // bind parameters. void CLuaMysqlStmt::_bind( size_t count_ ) { if ( m_count_ < count_ ) { if ( NULL != m_bind_ ) { free( m_bind_ ); m_bind_ = NULL; } m_bind_ = (MYSQL_BIND*)malloc( count_ * sizeof(MYSQL_BIND) ); m_count_ = count_; } if ( NULL != m_bind_ ) { memset( m_bind_, 0, m_count_ * sizeof( MYSQL_BIND ) ); for ( size_t _idx = 0; _idx < count_; ++ _idx ) { param_t& param = m_Params[_idx]; m_bind_[_idx].buffer = (void*)param.buf.c_str(); m_bind_[_idx].buffer_length = param.buf.size(); m_bind_[_idx].buffer_type = param.type; m_bind_[_idx].is_unsigned = param.is_unsigned; m_bind_[_idx].is_null_value = param.is_null_val; } } } namespace bin { BEGIN_SCRIPT_CLASS( MysqlStmt, CLuaMysqlStmt ) DEFINE_CLASS_FUNCTION( Clear, void, (void)) { obj->clear(); return 1; } DEFINE_CLASS_FUNCTION( SetBool, void, (bool lua_bool)) { obj->set_bool(lua_bool); return 1; } DEFINE_CLASS_FUNCTION( SetInt8, void, (sint32 lua_val)) { obj->set_int8(lua_val); return 1; } DEFINE_CLASS_FUNCTION( SetUint8, void, (sint32 lua_val)) { obj->set_uint8(lua_val); return 1; } DEFINE_CLASS_FUNCTION( SetInt16, void, (sint32 lua_val)) { obj->set_int16(lua_val); return 1; } DEFINE_CLASS_FUNCTION( SetUint16, void, (sint32 lua_val)) { obj->set_uint16(lua_val); return 1; } DEFINE_CLASS_FUNCTION( SetInt32, void, (sint32 lua_val)) { obj->set_int32(lua_val); return 1; } DEFINE_CLASS_FUNCTION( SetUint32, void, (sint32 lua_val)) { obj->set_uint32(lua_val); return 1; } DEFINE_CLASS_FUNCTION( SetInt64, void, (sint64 lua_val)) { obj->set_int64(lua_val); return 1; } DEFINE_CLASS_FUNCTION( SetUint64, void, (sint64 lua_int)) { obj->set_uint64(lua_int); return 1; } DEFINE_CLASS_FUNCTION( SetFloat, void, (lua_Number lua_val)) { obj->set_float(lua_val); return 1; } DEFINE_CLASS_FUNCTION( SetDouble, void, (lua_Number lua_val)) { obj->set_double(lua_val); return 1; } DEFINE_CLASS_FUNCTION( SetString, void, (std::string lua_str)) { obj->set_string(lua_str.c_str(), lua_str.size()); return 1; } DEFINE_CLASS_FUNCTION( SetBlob, void, (const char* _buffer, int _len)) { obj->set_blob(_buffer,_len); return 1; } DEFINE_STATIC_FUNCTION(NewInstance, CLuaMysqlStmt*, (std::string sql)) { CLuaMysqlStmt* pStmt = new (std::nothrow ) CLuaMysqlStmt; if ( NULL!=pStmt ) { pStmt->set_sql( sql ); r = pStmt; r->GetScriptObject().SetDelByScr(true); } return 1; } END_SCRIPT_CLASS() } ================================================ FILE: code/EVA/server/server_share/lua_mysql/mysql_stmt.h ================================================ #ifndef LUA_MSQL_PSTMT_H #define LUA_MSQL_PSTMT_H #include "mysql_result.h" #include class CLuaMysqlStmt { DECLARE_SCRIPT_CLASS(); public: friend class CLuaMysqlConn; // release. void release( void ); void clear(); // set bool value. void set_bool( my_bool bval_ ); // set int8 value. void set_int8( sint8 i8_ ); // set uint8 value. void set_uint8( uint8 ui8_ ); // set int16 value. void set_int16( sint16 i16_ ); // set uint16 value. void set_uint16( uint16 ui16_ ); // set int32 value. void set_int32( sint32 i32_ ); // set uint32 value. void set_uint32( uint32 ui32_ ); // set int64 value. void set_int64( sint64 i64_ ); // set uint64 value. void set_uint64( uint64 ui64_ ); // set float value. void set_float( float fval_ ); // set double value. void set_double( double dval_ ); // set string. void set_string( char const *str_ ); // set string. void set_string( char const *str_, size_t sz_ ); // set blob. void set_blob( void const *ptr_, size_t sz_ ); void set_tinyblob( void const *ptr_, size_t sz_ ); void set_sql( std::string& sql ) { m_sql_.assign(sql.c_str(),sql.size()); } //protected: CLuaMysqlStmt( void ); ~CLuaMysqlStmt( void ); protected: // bind parameters. void _bind( size_t count_ ); private: typedef struct _param { CLuaMysqlString buf; enum_field_types type; my_bool is_unsigned; my_bool is_null_val; _param( void ) : type( MYSQL_TYPE_NULL ), is_unsigned( 0 ), is_null_val( 0 ) {} _param( enum_field_types in_type, my_bool in_unsigned ) : type( in_type ), is_unsigned( in_unsigned ), is_null_val( 0 ) {} } param_t; MYSQL_BIND *m_bind_; size_t m_count_; // count of MYSQL_BIND std::vector m_Params; std::string m_sql_; uint32 m_idx; }; #endif // LUA_MSQL_PSTMT_H ================================================ FILE: code/EVA/server/server_share/lua_mysql/mysql_string.cpp ================================================ #include "mysql_stmt.h" #include CLuaMysqlString::CLuaMysqlString( void ) : m_str_( 0 ), m_off_( 0 ), m_sz_( 0 ) { } CLuaMysqlString::CLuaMysqlString( char const *str_ ) : m_str_( 0 ), m_off_( 0 ), m_sz_( 0 ) { assign( str_ ); } CLuaMysqlString::CLuaMysqlString( char const *str_, size_t sz_ ) : m_str_( 0 ), m_off_( 0 ), m_sz_( 0 ) { assign( str_, sz_ ); } CLuaMysqlString::CLuaMysqlString( CLuaMysqlString const &str_ ) : m_str_( 0 ), m_off_( 0 ), m_sz_( 0 ) { assign( str_ ); } CLuaMysqlString::CLuaMysqlString( char ch_, size_t sz_ ) : m_str_( 0 ), m_off_( 0 ), m_sz_( 0 ) { assign( ch_, sz_ ); } CLuaMysqlString::CLuaMysqlString( size_t sz_ ) : m_str_( 0 ), m_off_( 0 ), m_sz_( 0 ) { assign( '\0', sz_ > 0 ? ( sz_ - 1 ) : sz_ ); } CLuaMysqlString::~CLuaMysqlString( void ) { if ( 0 != m_str_ ) { delete[] m_str_; m_str_ = 0; m_off_ = 0; m_sz_ = 0; } } // to c-string. CLuaMysqlString::operator char const* ( void ) const { return m_str_; } // operator []. char& CLuaMysqlString::operator [] ( int idx ) { return m_str_[idx]; } // operator =. CLuaMysqlString& CLuaMysqlString::operator = ( CLuaMysqlString const &str_ ) { return assign( str_ ); } // operator =. CLuaMysqlString& CLuaMysqlString::operator = ( char const *str_ ) { return assign( str_ ); } // operator =. CLuaMysqlString& CLuaMysqlString::operator = ( char ch_ ) { return assign( ch_, 1 ); } // operator +=. CLuaMysqlString& CLuaMysqlString::operator += ( char ch_ ) { return append( ch_, 1 ); } // operator ==. bool CLuaMysqlString::operator == ( CLuaMysqlString const &str_ ) const { return ( 0 == compare( str_ ) ); } // operator !=. bool CLuaMysqlString::operator == ( char const *str_ ) const { return ( 0 == compare( str_ ) ); } // operator !=. bool CLuaMysqlString::operator != ( CLuaMysqlString const &str_ ) const { return ( 0 != compare( str_ ) ); } // operator !=. bool CLuaMysqlString::operator != ( char const *str_ ) const { return ( 0 != compare( str_ ) ); } // operator <. bool CLuaMysqlString::operator < ( CLuaMysqlString const &str_ ) const { return ( compare( str_ ) < 0 ); } // operator <. bool CLuaMysqlString::operator < ( char const *str_ ) const { return ( compare( str_ ) < 0 ); } // operator <=. bool CLuaMysqlString::operator <= ( CLuaMysqlString const &str_ ) const { return ( compare( str_ ) <= 0 ); } // operator <=. bool CLuaMysqlString::operator <= ( char const *str_ ) const { return ( compare( str_ ) <= 0 ); } // operator >. bool CLuaMysqlString::operator > ( CLuaMysqlString const &str_ ) const { return ( compare( str_ ) > 0 ); } // operator >. bool CLuaMysqlString::operator > ( char const *str_ ) const { return ( compare( str_ ) > 0 ); } // operator >=. bool CLuaMysqlString::operator >= ( CLuaMysqlString const &str_ ) const { return ( compare( str_ ) >= 0 ); } // operator >=. bool CLuaMysqlString::operator >= ( char const *str_ ) const { return ( compare( str_ ) >= 0 ); } CLuaMysqlString& CLuaMysqlString::assign( CLuaMysqlString const &str_ ) { if ( this != &str_ ) { if ( 0 != str_.m_str_ ) { m_off_ = str_.m_off_; if ( m_off_ >= m_sz_ ) { if ( 0 != m_str_ ) { delete[] m_str_; m_str_ = 0; } m_sz_ = m_off_ + 1; m_str_ = new( std::nothrow ) char[ m_sz_ ]; } //memcpy( m_str_, str_.m_str_, m_off_ ); //m_str_[m_off_] = 0; _strncpy( m_str_, str_.m_str_, m_off_ ); } else if ( 0 != m_str_ ) { *m_str_ = '\0'; m_off_ = 0; } } return ( *this ); } CLuaMysqlString& CLuaMysqlString::assign( char const *str_ ) { if ( 0 != str_ ) { m_off_ = ::strlen( str_ ); if ( m_off_ >= m_sz_ ) { if ( 0 != m_str_ ) { delete[] m_str_; m_str_ = 0; } m_sz_ = m_off_ + 1; m_str_ = new( std::nothrow ) char[ m_sz_ ]; } _strncpy( m_str_, str_, m_off_ ); } else if ( 0 != m_str_ ) { *m_str_ = '\0'; m_off_ = 0; } return ( *this ); } CLuaMysqlString& CLuaMysqlString::assign( char const *str_, size_t sz_ ) { if ( 0 != str_ && sz_ > 0 ) { m_off_ = sz_; if ( m_off_ >= m_sz_ ) { if ( 0 != m_str_ ) { delete[] m_str_; m_str_ = 0; } m_sz_ = sz_ + 1; m_str_ = new( std::nothrow ) char[ m_sz_ ]; } memcpy( m_str_, str_, sz_ ); m_str_[sz_] = 0; //_strncpy( m_str_, str_, m_off_ ); } else if ( 0 != m_str_ ) { *m_str_ = '\0'; m_off_ = 0; } return ( *this ); } CLuaMysqlString& CLuaMysqlString::assign( char ch_, size_t sz_ ) { m_off_ = sz_; if ( m_off_ >= m_sz_ ) { if ( 0 != m_str_ ) { delete[] m_str_; m_str_ = 0; } m_sz_ = sz_ + 1; m_str_ = new( std::nothrow ) char[ m_sz_ ]; } char *_str = m_str_; while( sz_-- ) *_str++ = ch_; *_str = '\0'; return ( *this ); } CLuaMysqlString& CLuaMysqlString::append( CLuaMysqlString const &str_ ) { size_t _off, _sz; char *_str; if ( this != &str_ ) { if ( NULL != str_.m_str_ ) { _off = m_off_ + str_.m_off_; if ( _off >= m_sz_ ) { _sz = _off + 1; _str = new( std::nothrow ) char[ _sz ]; // copy if ( NULL != m_str_ ) { _strncpy( _str, m_str_, m_off_ ); delete[] m_str_; } m_str_ = _str; m_sz_ = _sz; } _strncpy( m_str_ + m_off_, str_.m_str_, str_.m_off_ ); m_off_ = _off; } } else if ( NULL != m_str_ ) { _off = m_off_ << 1; if ( _off >= m_sz_ ) { _sz = _off + 1; _str = new( std::nothrow ) char[ _sz ]; // copy _strncpy( _str, m_str_, m_off_ ); _strncpy( _str + m_off_, m_str_, m_off_ ); delete[] m_str_; m_str_ = _str; m_sz_ = _sz; m_off_ = _off; } else { _strncpy( m_str_ + m_off_, m_str_, m_off_ ); m_off_ = _off; } } return ( *this ); } CLuaMysqlString& CLuaMysqlString::append( char const *str_ ) { size_t _off, _sz; char *_str; if ( NULL != str_ ) { _off = m_off_ + ::strlen( str_ ); if ( _off >= m_sz_ ) { _sz = _off + 1; _str = new( std::nothrow ) char[ _sz ]; // copy if ( NULL != m_str_ ) { _strncpy( _str, m_str_, m_off_ ); delete[] m_str_; } m_str_ = _str; m_sz_ = _sz; } _strncpy( m_str_ + m_off_, str_, _off - m_off_ ); m_off_ = _off; } return ( *this ); } CLuaMysqlString& CLuaMysqlString::append( char const *str_, size_t sz_ ) { size_t _off, _sz; char *_str; if ( NULL != str_ && sz_ > 0 ) { _off = m_off_ + sz_; if ( _off >= m_sz_ ) { _sz = _off + 1; _str = new( std::nothrow ) char[ _sz ]; // copy if ( NULL != m_str_ ) { _strncpy( _str, m_str_, m_off_ ); delete[] m_str_; } m_str_ = _str; m_sz_ = _sz; } _strncpy( m_str_ + m_off_, str_, sz_ ); m_off_ = _off; } return ( *this ); } CLuaMysqlString& CLuaMysqlString::append( char ch_, size_t sz_ ) { size_t _off, _sz; char *_str; _off = m_off_ + sz_; if ( _off >= m_sz_ ) { _sz = _off + 1; _str = new( std::nothrow ) char[ _sz ]; // copy if ( NULL != m_str_ ) { _strncpy( _str, m_str_, m_off_ ); delete[] m_str_; m_str_ = 0; } m_str_ = _str; m_sz_ = _sz; } _str = m_str_ + m_off_; while ( sz_-- ) *_str++ = ch_; *_str = '\0'; m_off_ = _off; return ( *this ); } int CLuaMysqlString::compare( CLuaMysqlString const &str_ ) const { if ( this == &str_ ) { return 0; } else if ( 0 != m_str_ && 0 != str_.m_str_ ) { int _ret = 0; size_t _sz0 = m_off_; size_t _sz1 = str_.m_off_; const char *_str0 = m_str_; const char *_str1 = str_.m_str_; while ( !( _ret = (int)( *_str0 - *_str1 ) ) && _sz0 && _sz1 ) { ++ _str0; ++ _str1; -- _sz0; -- _sz1; } if ( _ret < 0 ) _ret = -1; else if ( _ret > 0 ) _ret = 1; else if ( _sz0 ) _ret = 1; else if ( _sz1 ) _ret = -1; return _ret; } else if ( 0 != m_str_ ) { return 1; } else if ( 0 != str_.m_str_ ) { return -1; } else { return 0; } } int CLuaMysqlString::compare( const char *str_ ) const { if ( 0 != m_str_ && 0 != str_ ) { int _ret = 0; size_t _sz0 = m_off_; const char *_str0 = m_str_; const char *_str1 = str_; while ( !( _ret = (int)( *_str0 - *_str1 ) ) && _sz0 && *_str1 ) { ++ _str0; ++ _str1; -- _sz0; } if ( _ret < 0 ) _ret = -1; else if ( _ret > 0 ) _ret = 1; else if ( _sz0 ) _ret = 1; else if ( *_str1 ) _ret = -1; return _ret; } else if ( 0 != m_str_ ) { return 1; } else if ( 0 != str_ ) { return -1; } else { return 0; } } int CLuaMysqlString::compare( const char *str_, size_t sz_ ) const { if ( 0 != m_str_ && 0 != str_ && sz_ > 0 ) { int _ret = 0; size_t _sz0 = m_off_; size_t _sz1 = sz_; const char *_str0 = m_str_; const char *_str1 = str_; while ( !( _ret = (int)( *_str0 - *_str1 ) ) && _sz0 && _sz1 ) { ++ _str0; ++ _str1; -- _sz0; -- _sz1; } if ( _ret < 0 ) _ret = -1; else if ( _ret > 0 ) _ret = 1; else if ( _sz0 ) _ret = 1; else if ( _sz1 ) _ret = -1; return _ret; } else if ( 0 != m_str_ && sz_ > 0 ) { return 1; } else if ( 0 != str_ && sz_ > 0 ) { return -1; } else { return 0; } } const char* CLuaMysqlString::c_str( void ) const { return m_str_; } size_t CLuaMysqlString::size( void ) const { return m_off_; } bool CLuaMysqlString::empty( void ) const { return ( 0 == m_off_ ); } void CLuaMysqlString::clear( void ) { if ( 0 != m_str_ ) { m_str_[0] = '\0'; m_off_ = 0; } } char* CLuaMysqlString::_strncpy( char *dst_, char const *src_, size_t sz_ ) { if ( 0 != dst_ && 0 != src_ ) { char *_str = dst_; while ( sz_-- ) *_str++ = *src_++; *_str = '\0'; return dst_; } return 0; } ================================================ FILE: code/EVA/server/server_share/lua_mysql/mysql_string.h ================================================ #ifndef LUA_MYSQL_STRING_H #define LUA_MYSQL_STRING_H class CLuaMysqlString { public: CLuaMysqlString( void ); CLuaMysqlString( char const *str_ ); CLuaMysqlString( char const *str_, size_t sz_ ); CLuaMysqlString( CLuaMysqlString const &str_ ); CLuaMysqlString( char ch_, size_t sz_ ); CLuaMysqlString( size_t sz_ ); ~CLuaMysqlString( void ); // to c-string. operator char const* ( void ) const; // operator []. char& operator [] ( int idx ); // operator =. CLuaMysqlString& operator = ( CLuaMysqlString const &str_ ); // operator =. CLuaMysqlString& operator = ( char const *str_ ); // operator =. CLuaMysqlString& operator = ( char ch_ ); // operator +=. CLuaMysqlString& operator += ( CLuaMysqlString const &str_ ); // operator +=. CLuaMysqlString& operator += ( char const *str_ ); // operator +=. CLuaMysqlString& operator += ( char ch_ ); // operator ==. bool operator == ( CLuaMysqlString const &str_ ) const; // operator ==. bool operator == ( char const *str_ ) const; // operator !=. bool operator != ( CLuaMysqlString const &str_ ) const; // operator !=. bool operator != ( char const *str_ ) const; // operator <. bool operator < ( CLuaMysqlString const &str_ ) const; // operator <. bool operator < ( char const *str_ ) const; // operator <=. bool operator <= ( CLuaMysqlString const &str_ ) const; // operator <=. bool operator <= ( char const *str_ ) const; // operator >. bool operator > ( CLuaMysqlString const &str_ ) const; // operator >. bool operator > ( char const *str_ ) const; // operator >=. bool operator >= ( CLuaMysqlString const &str_ ) const; // operator >=. bool operator >= ( char const *str_ ) const; // assign. CLuaMysqlString& assign( CLuaMysqlString const &str_ ); // assign. CLuaMysqlString& assign( char const *str_ ); // assign. CLuaMysqlString& assign( char const *str_, size_t sz_ ); // assign. CLuaMysqlString& assign( char ch_, size_t sz_ ); // append. CLuaMysqlString& append( CLuaMysqlString const &str_ ); // append. CLuaMysqlString& append( char const *str_ ); // append. CLuaMysqlString& append( char const *str_, size_t sz_ ); // assign. CLuaMysqlString& append( char ch_, size_t sz_ ); // compare. int compare( CLuaMysqlString const &str_ ) const; // compare. int compare( const char *str_ ) const; // compare. int compare( const char *str_, size_t sz_ ) const; // c-string. const char* c_str( void ) const; // size. size_t size( void ) const; // empty. bool empty( void ) const; // clear. void clear( void ); private: // strncpy. char* _strncpy( char *dst_, char const *src_, size_t sz_ ); private: char *m_str_; size_t m_off_; size_t m_sz_; }; #endif // LUA_MYSQL_STRING_H ================================================ FILE: code/EVA/server/server_share/lua_net/lua_callback_client.cpp ================================================ #include "lua_callback_client.h" #include "lua_message.h" #include #include #include using namespace bin; using namespace NLNET; void forLuaCallbackClientForceLink() { nlwarning("forLuaCallbackClientForceLink"); } void cbLuaClientMsg(CMessage &msgin, TSockId from, CCallbackNetBase &netbase) { CLuaCallbackClient* pClient = (CLuaCallbackClient*)netbase.getUserData(); CScriptTable functbl; pClient->GetScriptHandle().Get("NetWorkHandler", functbl); pClient->m_LuaTmpMsg->m_Msg.swap(msgin); sint32 nRet = 0; sint32 _hdl = pClient->GetHandle(); functbl.CallFunc("OnMessage", _hdl, pClient->m_LuaTmpMsg, nRet); } CLuaCallbackClient::CLuaCallbackClient( std::string& protocal, sint32 thd_handle/*=-1*/) : m_Protocal(protocal), m_MyHandle(0) { if ( protocal=="tcp" ) { CCallbackClient* pClient = new CCallbackClient(); //pClient->setConnectionCallback( cbLuaSvrConnect, this ); //pClient->setDisconnectionCallback( cbLuaSvrDisConnect, this ); pClient->setDefaultCallback(cbLuaClientMsg); m_CallbackClientHandle = pClient; } m_LuaTmpMsg = new CLuaMessage(); m_CallbackClientHandle->setUserData(this); nlassert(m_CallbackClientHandle !=NULL); } CLuaCallbackClient::~CLuaCallbackClient() { delete m_CallbackClientHandle; delete m_LuaTmpMsg; } void CLuaCallbackClient::Connect(std::string & url) { CInetAddress addr(url); CCallbackClient* pClient = (CCallbackClient*)m_CallbackClientHandle; pClient->connect(addr); } /////////////////// namespace bin { BEGIN_SCRIPT_CLASS(LuaCallbackClient, CLuaCallbackClient) DEFINE_CLASS_FUNCTION(Send, void, (CLuaMessage* lua_msg)) { obj->Send(lua_msg->m_Msg); return 1; } DEFINE_CLASS_FUNCTION(DisConnect, void, ()) { return 1; } DEFINE_CLASS_FUNCTION(Connect, void, (std::string& url)) { obj->Connect(url); return 1; } DEFINE_CLASS_FUNCTION(SetHandle, void, (sint32 client_handle)) { obj->SetHandle(client_handle); return 1; } DEFINE_CLASS_FUNCTION(GetHandle, sint32, ()) { r = obj->GetHandle(); return 1; } DEFINE_CLASS_FUNCTION(Connected, bool, ()) { r = obj->Connected(); return 1; } DEFINE_CLASS_FUNCTION(Update, void, ()) { obj->Update(); return 1; } DEFINE_STATIC_FUNCTION(NewInstance, CLuaCallbackClient*, (std::string& protoc)) { r = new CLuaCallbackClient(protoc); r->GetScriptObject().SetDelByScr(true); return 1; } END_SCRIPT_CLASS() } ================================================ FILE: code/EVA/server/server_share/lua_net/lua_callback_client.h ================================================ #ifndef SERVER_SHARD_LUA_CALLBACK_CLIENT_H #define SERVER_SHARD_LUA_CALLBACK_CLIENT_H #include #include "lua_network.h" #include #include #include namespace bin { class CScriptHandle; } class CLuaMessage; class CLuaCallbackClient { DECLARE_SCRIPT_CLASS() public: CLuaCallbackClient( std::string& protocal, sint32 thd_handle=-1 ); ~CLuaCallbackClient(); void Connect( std::string& url ); void Update() { if(m_CallbackClientHandle->connected() ) { m_CallbackClientHandle->update(); } } void Send( const NLNET::CMessage &buffer ) { if (m_CallbackClientHandle->connected()) { m_CallbackClientHandle->send(buffer); } } bool Connected() { return m_CallbackClientHandle->connected(); } uint32 GetHandle() { return m_MyHandle; } void SetHandle(uint32 handle) { m_MyHandle = handle; } uint32 m_MyHandle; CLuaMessage* m_LuaTmpMsg; private: std::string m_Protocal; NLNET::CCallbackNetBase* m_CallbackClientHandle; std::string m_StrBuffer; std::string m_SaveEventStr; }; #endif // SERVER_SHARD_LUA_CALLBACK_CLIENT_H ================================================ FILE: code/EVA/server/server_share/lua_net/lua_callback_server.cpp ================================================ #include "lua_callback_server.h" #include "lua_message.h" #include #include #include #include using namespace bin; using namespace NLNET; NLMISC::CVariable VAR_MSG_COUNT("fes", "MsgCount", "memo", false, 0, true); NLMISC::CVariable VAR_SAVE_EVENT("fes", "SaveEvent", "memo", false, 0, true); void cbLuaServiceMsg ( CMessage &msgin, TSockId from, CCallbackNetBase &netbase ) { CLuaCallbackServer* pServer = (CLuaCallbackServer*)netbase.getUserData(); LuaNetworkMgr.IncReceiveMsgCount(msgin.getName()); MsgLeaf* pMsgLeaf = MsgDesc.GetMsgLeaf( msgin.getName() ); if ( pMsgLeaf!=NULL ) { ClientData* pClient = pServer->GetClientData(from); if ( pClient != NULL ) { pServer->ForwardingMsg( pClient, msgin, pMsgLeaf ); } } else { CScriptTable functbl; ScriptMgr.GetScriptHandle()->Get("NetWorkHandler", functbl); pServer->m_LuaTmpMsg->m_Msg.swap(msgin); sint32 nRet = 0; sint64 _from = (sint64)from; functbl.CallFunc("OnMessage", _from, pServer->m_LuaTmpMsg, nRet); } } CLuaCallbackServer::CLuaCallbackServer( std::string& name, std::string& protocal ) : m_NetName(name), m_Protocal(protocal) { if( protocal=="wss" || protocal=="ws" ) { CCallbackServerWebSocket* pServer = new CCallbackServerWebSocket(); pServer->setConnectionCallback( cbLuaSvrConnect, this ); pServer->setDisconnectionCallback( cbLuaSvrDisConnect, this ); pServer->setDefaultCallback(cbLuaServiceMsg); m_CallbackServerHandle = pServer; } else if ( protocal=="tcp" ) { CCallbackServerTcp* pServer = new CCallbackServerTcp(); pServer->setConnectionCallback( cbLuaSvrConnect, this ); pServer->setDisconnectionCallback( cbLuaSvrDisConnect, this ); pServer->setDefaultCallback(cbLuaServiceMsg); m_CallbackServerHandle = pServer; } m_LuaTmpMsg = new CLuaMessage(); m_CallbackServerHandle->setUserData(this); nlassert(m_CallbackServerHandle!=NULL); LuaNetworkMgr.RegisterNetModule( name, this ); } CLuaCallbackServer::~CLuaCallbackServer() { LuaNetworkMgr.RemoveNetModule(m_NetName); delete m_CallbackServerHandle; delete m_LuaTmpMsg; } void CLuaCallbackServer::Listen( uint16 port ) { if ( m_Protocal=="wss" ) { CCallbackServerWebSocket* pServer = (CCallbackServerWebSocket*)m_CallbackServerHandle; pServer->setupSsl( m_SslCA, m_SslCrt, m_SslPrvKey ); pServer->init(port); } else if ( m_Protocal=="ws" ) { ((CCallbackServerWebSocket*)m_CallbackServerHandle)->init(port); } else if( m_Protocal=="tcp" ) { ((CCallbackServerTcp*)m_CallbackServerHandle)->init(port); } } bool CLuaCallbackServer::ForwardingMsg( ClientData* pClient, NLNET::CMessage& msgin, MsgLeaf* pMsgLeaf ) { google::protobuf::Message* pMessage = NULL; try { NLNET::CMessage msgout( pMsgLeaf->msgname ); std::vector& format = pMsgLeaf->format; std::vector& format_msg = pMsgLeaf->format_msg; m_SaveEventStr.clear(); uint64 id = 0; for ( uint i=0,j=0; iuid); id = pClient->uid; break; } case MSG_FORMAT::PLS: { msgout.serial(pClient->pls_sid); break; } case MSG_FORMAT::JSON: { msgin.serial(m_StrBuffer); // check json msgout.serial(m_StrBuffer); if ( VAR_SAVE_EVENT && pMsgLeaf->is_log_event ) { m_SaveEventStr.append( " " ); m_SaveEventStr.append( m_StrBuffer ); } break; } case MSG_FORMAT::ProtoMsg: { if ( j>=format_msg.size() ) { return false; } pMessage = MsgDesc.CreateMessage(format_msg[j]); if ( pMessage!=NULL ) { msgin.serial(pMessage); msgout.serial(pMessage); if ( VAR_SAVE_EVENT && pMsgLeaf->is_log_event ) { m_SaveEventStr.append( " " ); m_SaveEventStr.append( pMessage->ShortDebugString() ); } SAFE_DELETE(pMessage); } else { nlwarning("msg:% define not found.", format_msg[j].c_str()); return false; } break; } case MSG_FORMAT::d: { double double_val; msgin.serial(double_val); msgout.serial(double_val); break; } case MSG_FORMAT::b: { bool bool_val; msgin.serial(bool_val); msgout.serial(bool_val); break; } case MSG_FORMAT::s: { msgin.serial(m_StrBuffer); msgout.serial(m_StrBuffer); break; } case MSG_FORMAT::s8: { sint8 sint8_val; msgin.serial(sint8_val); msgout.serial(sint8_val); break; } case MSG_FORMAT::s16: { sint16 sint16_val; msgin.serial(sint16_val); msgout.serial(sint16_val); break; } case MSG_FORMAT::s32: { sint32 sint32_val; msgin.serial(sint32_val); msgout.serial(sint32_val); break; } case MSG_FORMAT::s64: { sint64 sint64_val; msgin.serial(sint64_val); msgout.serial(sint64_val); break; } case MSG_FORMAT::u8: { uint8 uint8_val; msgin.serial(uint8_val); msgout.serial(uint8_val); break; } case MSG_FORMAT::u16: { uint16 uint16_val; msgin.serial(uint16_val); msgout.serial(uint16_val); break; } case MSG_FORMAT::u32: { uint32 uint32_val; msgin.serial(uint32_val); msgout.serial(uint32_val); break; } case MSG_FORMAT::u64: { uint64 uint64_val; msgin.serial(uint64_val); msgout.serial(uint64_val); break; } default: return false; } } std::vector& sendto = pMsgLeaf->sendto; for ( uint i=0; ipls_sid != NLNET::TServiceId::InvalidId ) { NLNET::CMessage msgluasvr("_LS"); msgluasvr.serialMessage(msgout); Network->send( pClient->pls_sid, msgluasvr ); } } else { NLNET::CMessage msgluasvr("_LS"); msgluasvr.serialMessage(msgout); Network->send ( sendto[i], msgluasvr ); } } if ( VAR_SAVE_EVENT && pMsgLeaf->is_log_event ) { //LogEvent( id, msgin.getName(), m_SaveEventStr.strip() ); } return true; } catch (NLMISC::Exception &) { SAFE_DELETE(pMessage); return false; } return false; } NLMISC_COMMAND (topmsg, "", "") { if(args.size() != 0) return false; CLuaNetworkMgr::TMsgCount::iterator iter,it_end; iter = LuaNetworkMgr.m_ReceiveMsgCount.begin(); it_end = LuaNetworkMgr.m_ReceiveMsgCount.end(); std::multimap sortmap; while ( iter!=it_end ) { sortmap.insert( make_pair( iter->second, iter->first ) ); ++iter; } std::multimap::reverse_iterator riter,rit_end; riter = sortmap.rbegin(); rit_end = sortmap.rend(); while ( riter!=rit_end ) { log.displayNL("Count: %" NL_I64 "u Msg: %s", riter->first, riter->second.c_str() ); ++riter; } return true; } NLMISC_COMMAND (loadmsg, "", "") { if(args.size() != 0) return false; MsgDesc.LoadMsgXml(); log.displayNL ("ReLoadMsgXml Done."); return true; } ================================================ FILE: code/EVA/server/server_share/lua_net/lua_callback_server.h ================================================ #ifndef SERVER_SHARD_LUA_CALLBACK_SERVER_H #define SERVER_SHARD_LUA_CALLBACK_SERVER_H #include #include "lua_network.h" #include #include #include struct ClientData { DEF::UID uid; NLNET::TSockId sid; NLNET::TServiceId pls_sid; }; struct MsgLeaf; class CLuaMessage; class CLuaCallbackServer { DECLARE_SCRIPT_CLASS() public: CLuaCallbackServer( std::string& name, std::string& protocal ); ~CLuaCallbackServer(); void Listen( uint16 port ); void LoadSslCA( std::string ssl_ca ) { m_SslCA = ssl_ca; } void LoadSslCrt( std::string ssl_crt ) { m_SslCrt = ssl_crt; } void LoadSslPrivateKey( std::string ssl_pk ) { m_SslPrvKey = ssl_pk; } void Update() { if( m_CallbackServerHandle->connected() ) { m_CallbackServerHandle->update(); } } void Send( NLNET::TSockId sock_id, const NLNET::CMessage &buffer ) { m_CallbackServerHandle->send( buffer, sock_id ); } bool ForwardingMsg( ClientData* pClient, NLNET::CMessage& msgin, MsgLeaf* pMsgLeaf ); void DisConnect(NLNET::TSockId sock_id) { m_CallbackServerHandle->disconnect(sock_id); } void SetClientData( ClientData& client_data ) { TClientMap::iterator iter = m_ClientMap.find( client_data.uid ); if ( iter != m_ClientMap.end() ) { m_SockClient.erase(iter->second.sid); m_SockClient[client_data.sid] = client_data; iter->second.sid = client_data.sid; iter->second.pls_sid = client_data.pls_sid; } else { m_ClientMap[client_data.uid] = client_data; m_SockClient[client_data.sid] = client_data; } } void RemoveClientData( DEF::UID uid ) { TClientMap::iterator iter = m_ClientMap.find( uid ); if ( iter != m_ClientMap.end() ) { m_SockClient.erase(iter->second.sid); m_ClientMap.erase(uid); } } void ClearClientData() { m_SockClient.clear(); m_ClientMap.clear(); } NLNET::TSockId GetSockId( DEF::UID uid ) { TClientMap::iterator iter = m_ClientMap.find(uid); if ( iter != m_ClientMap.end() ) { return iter->second.sid; } return NLNET::InvalidSockId; } ClientData* GetClientData( NLNET::TSockId sock_id ) { ClientData* pClient = NULL; TSockClient::iterator iter = m_SockClient.find(sock_id); if ( iter != m_SockClient.end() ) { pClient = &iter->second; } return pClient; } std::string GetName() { return m_NetName; } CLuaMessage* m_LuaTmpMsg; private: std::string m_NetName; std::string m_Protocal; typedef std::map TClientMap; TClientMap m_ClientMap; typedef std::map TSockClient; TSockClient m_SockClient; NLNET::CCallbackNetBase* m_CallbackServerHandle; std::string m_StrBuffer; std::string m_SaveEventStr; std::string m_SslCA; std::string m_SslCrt; std::string m_SslPrvKey; }; #endif // SERVER_SHARD_LUA_CALLBACK_SERVER_H ================================================ FILE: code/EVA/server/server_share/lua_net/lua_message.cpp ================================================ #include "lua_message.h" void forLuaMessageForceLink() { nlwarning("forLuaMessageForceLink"); } namespace bin { BEGIN_SCRIPT_CLASS( LuaMessage, CLuaMessage ) DEFINE_CLASS_FUNCTION( invert, void, ()) { obj->m_Msg.invert(); return 1; } DEFINE_CLASS_FUNCTION( name, std::string, ()) { r = obj->m_Msg.getName(); return 1; } DEFINE_CLASS_FUNCTION( clear, void, (std::string name)) { obj->m_Msg.clear(); return 1; } DEFINE_CLASS_FUNCTION( wbuffer, void, (const char* buff, int len)) { sint32 serial_val=len; obj->m_Msg.serial(serial_val); obj->m_Msg.serialBuffer((uint8*)buff, len); return 1; } DEFINE_CLASS_FUNCTION( wstring, void, (std::string& str)) { obj->m_Msg.serial(str); return 1; } DEFINE_CLASS_FUNCTION(wtable, void, (CScriptTable& tbl)) { try { std::string json_str = ""; obj->GetScriptHandle().CallFunc("Table2Json", tbl, json_str); obj->m_Msg.serial(json_str); } catch (const NLMISC::EStream&) { lua_Debug ar; lua_getstack(obj->GetScriptHandle().GetHandle(), 1, &ar); lua_getinfo(obj->GetScriptHandle().GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition(ar.currentline, ar.short_src, ar.name); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("wtable exception"); } return 1; } DEFINE_CLASS_FUNCTION( wbool, void, (bool in_val)) { obj->m_Msg.serial(in_val); return 1; } DEFINE_CLASS_FUNCTION( wint, void, (sint64 in_val)) { obj->m_Msg.serial(in_val); return 1; } DEFINE_CLASS_FUNCTION( wint32, void, (sint32 in_val)) { obj->m_Msg.serial(in_val); return 1; } DEFINE_CLASS_FUNCTION( wint64, void, (sint64 in_val)) { obj->m_Msg.serial(in_val); return 1; } DEFINE_CLASS_FUNCTION( wuint32, void, (sint64 in_val)) { uint32 serial_val=in_val; obj->m_Msg.serial(serial_val); return 1; } DEFINE_CLASS_FUNCTION( rbool, bool, ()) { nlassert(obj->m_Msg.isReading()); try { obj->m_Msg.serial(r); } catch (const NLMISC::EStream&) { lua_Debug ar; lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar); lua_getinfo(obj->GetScriptHandle().GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name ); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("rbool is nil"); } return 1; } DEFINE_CLASS_FUNCTION( rint32, sint32, ()) { nlassert(obj->m_Msg.isReading()); try { obj->m_Msg.serial(r); } catch (const NLMISC::EStream&) { lua_Debug ar; lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar); lua_getinfo(obj->GetScriptHandle().GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name ); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("rint32 is nil"); } return 1; } DEFINE_CLASS_FUNCTION( ruint32, sint64, ()) { nlassert(obj->m_Msg.isReading()); try { uint32 result=0; obj->m_Msg.serial(result); r = result; } catch (const NLMISC::EStream&) { lua_Debug ar; lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar); lua_getinfo(obj->GetScriptHandle().GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name ); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("ruint32 is nil"); } return 1; } DEFINE_CLASS_FUNCTION( rint64, sint64, ()) { nlassert(obj->m_Msg.isReading()); try { obj->m_Msg.serial(r); } catch (const NLMISC::EStream&) { lua_Debug ar; lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar); lua_getinfo(obj->GetScriptHandle().GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name ); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("rint64 is nil"); } return 1; } DEFINE_CLASS_FUNCTION( rdouble, double, ()) { nlassert(obj->m_Msg.isReading()); try { obj->m_Msg.serial(r); } catch (const NLMISC::EStream&) { lua_Debug ar; lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar); lua_getinfo(obj->GetScriptHandle().GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name ); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("rdouble is nil"); } return 1; } DEFINE_CLASS_FUNCTION( rint, sint64, ()) { nlassert(obj->m_Msg.isReading()); try { obj->m_Msg.serial(r); } catch (const NLMISC::EStream&) { lua_Debug ar; lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar); lua_getinfo(obj->GetScriptHandle().GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name ); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("rint is nil"); } return 1; } DEFINE_CLASS_FUNCTION( rstring, std::string, ()) { nlassert(obj->m_Msg.isReading()); try { obj->m_Msg.serial(r); } catch (const NLMISC::EStream&) { lua_Debug ar; lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar); lua_getinfo(obj->GetScriptHandle().GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name ); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("rstring is nil"); } return 1; } DEFINE_CLASS_FUNCTION(rbuffer, std::string, ()) { nlassert(obj->m_Msg.isReading()); try { obj->m_Msg.serial(r); } catch (const NLMISC::EStream&) { lua_Debug ar; lua_getstack(obj->GetScriptHandle().GetHandle(), 1, &ar); lua_getinfo(obj->GetScriptHandle().GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition(ar.currentline, ar.short_src, ar.name); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("rbuffer is nil"); } return 1; } DEFINE_CLASS_FUNCTION( rtable, CScriptTable, ()) { nlassert(obj->m_Msg.isReading()); try { std::string json_str; obj->m_Msg.serial(json_str); obj->GetScriptHandle().NewTable(r); obj->GetScriptHandle().CallFunc( "Json2Table", json_str, r ); } catch (const NLMISC::EStream&) { lua_Debug ar; lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar); lua_getinfo(obj->GetScriptHandle().GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name ); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("rtable is nil"); } return 1; } DEFINE_CLASS_FUNCTION( rpb, CScriptTable, (std::string& pbstru)) { nlassert(obj->m_Msg.isReading()); try { std::string pb_data; obj->m_Msg.serial(pb_data); obj->GetScriptHandle().NewTable(r); CScriptTable functbl; obj->GetScriptHandle().Get("protobuf", functbl); functbl.CallFunc("decode", pbstru, pb_data, r); } catch (const NLMISC::EStream&) { lua_Debug ar; lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar); lua_getinfo(obj->GetScriptHandle().GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name ); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("rpb is nil"); } return 1; } DEFINE_STATIC_FUNCTION(NewInstance, CLuaMessage*, (std::string name)) { r = new CLuaMessage(name); r->GetScriptObject().SetDelByScr(true); return 1; } END_SCRIPT_CLASS() } ================================================ FILE: code/EVA/server/server_share/lua_net/lua_message.h ================================================ #ifndef SERVER_SHARD_LUA_NETWORK_MESSAGE_H #define SERVER_SHARD_LUA_NETWORK_MESSAGE_H #include #include "server_share/bin_luabind/Public.hpp" class CLuaMessage { DECLARE_SCRIPT_CLASS(); public: CLuaMessage() {} CLuaMessage( std::string& name ) { m_Msg.setType(name); } NLNET::CMessage m_Msg; }; #endif ================================================ FILE: code/EVA/server/server_share/lua_net/lua_network.cpp ================================================ #include "lua_network.h" #include "lua_message.h" #include "lua_callback_server.h" #include #include "server_share/bin_luabind/Public.hpp" #include "curl/curl.h" using namespace NLMISC; using namespace NLNET; static CLuaMessage* pUnifiedServiceMsg = new CLuaMessage(); void cbLuaUnifiedServiceMsg ( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId ) { uint32 subSize; msgin.serial(subSize); msgin.lockSubMessage(subSize); pUnifiedServiceMsg->m_Msg.clear(); pUnifiedServiceMsg->m_Msg.assignFromSubMessage(msgin); msgin.unlockSubMessage(); bin::CScriptTable functbl; ScriptMgr.GetScriptHandle()->Get("NetWorkHandler", functbl); sint32 nRet = 0; sint32 _sid = serviceId.get(); functbl.CallFunc("OnMessage", _sid, pUnifiedServiceMsg, nRet); } /// תͻ void cbLuaSendToClientMsg ( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId ) { DEF::UID client_uid; msgin.serial(client_uid); uint32 subSize; msgin.serial(subSize); msgin.lockSubMessage(subSize); pUnifiedServiceMsg->m_Msg.clear(); pUnifiedServiceMsg->m_Msg.assignFromSubMessage(msgin); msgin.unlockSubMessage(); LuaNetworkMgr.SendToClient( client_uid, pUnifiedServiceMsg->m_Msg ); } NLNET::TUnifiedCallbackItem LuaCallbackArray[] = { { "_LS", cbLuaUnifiedServiceMsg }, { "_LSC", cbLuaSendToClientMsg }, }; void CLuaNetworkMgr::Init() { NLNET::CUnifiedNetwork::getInstance()->addCallbackArray(LuaCallbackArray, sizeof(LuaCallbackArray)/sizeof(LuaCallbackArray[0])); } void CLuaNetworkMgr::RegisterNetModule( std::string name, CLuaCallbackServer* pNet ) { TNetHandle::iterator iter = m_LuaClientNetworkHandle.find(name); if ( iter == m_LuaClientNetworkHandle.end() ) { m_LuaClientNetworkHandle.insert( make_pair(name, pNet) ); } else { nlstop; } } void CLuaNetworkMgr::RemoveNetModule( std::string name ) { m_LuaClientNetworkHandle.erase(name); } void CLuaNetworkMgr::Update() { H_AUTO(CLuaNetworkMgrUpdate); TNetHandle::iterator iter = m_LuaClientNetworkHandle.begin(); while (iter!=m_LuaClientNetworkHandle.end()) { iter->second->Update(); ++iter; } } void CLuaNetworkMgr::Release() { TNetHandle::iterator iter = m_LuaClientNetworkHandle.begin(); while (iter!=m_LuaClientNetworkHandle.end()) { delete iter->second; ++iter; } m_LuaClientNetworkHandle.clear(); } void CLuaNetworkMgr::SendToClient( uint64 uid, NLNET::CMessage& msgin ) { TNetHandle::iterator iter = m_LuaClientNetworkHandle.begin(); while ( iter != m_LuaClientNetworkHandle.end() ) { TSockId sock_id = iter->second->GetSockId(uid); if ( sock_id != InvalidSockId ) { iter->second->Send( sock_id, msgin ); } ++iter; } } void CLuaNetworkMgr::IncReceiveMsgCount(std::string msg_name) { TMsgCount::iterator iter = m_ReceiveMsgCount.find(msg_name); if (iter != m_ReceiveMsgCount.end()) { iter->second += 1; } else { m_ReceiveMsgCount.insert(make_pair(msg_name, 1)); } } void cbLuaSvrConnect( TSockId from, void *arg ) { CLuaCallbackServer* pLuaNetwork = (CLuaCallbackServer*)arg; std::string lua_event = pLuaNetwork->GetName(); lua_event.append("Con"); uint64 msg_from = (uint64)from; std::string msg_buff; LuaParams lua_params( msg_from, lua_event, msg_buff ); ScriptMgr.run( "NetWorkHandler", "OnNetEvent", lua_params ); } void cbLuaSvrDisConnect( TSockId from, void *arg ) { CLuaCallbackServer* pLuaNetwork = (CLuaCallbackServer*)arg; std::string lua_event = pLuaNetwork->GetName(); lua_event.append("Dis"); uint64 msg_from = (uint64)from; std::string msg_buff; LuaParams lua_params( msg_from, lua_event, msg_buff ); ScriptMgr.run( "NetWorkHandler", "OnNetEvent", lua_params ); } void cbConnection( const std::string &serviceName, NLNET::TServiceId sid, void *arg ) { std::string lua_event = serviceName; lua_event.append("Con"); LuaParams lua_params( (uint64)sid.get(), lua_event, serviceName ); ScriptMgr.run( "NetWorkHandler", "OnNetEvent", lua_params ); } void cbDisconnection( const std::string &serviceName, NLNET::TServiceId sid, void *arg ) { std::string lua_event = serviceName; lua_event.append("Dis"); LuaParams lua_params( (uint64)sid.get(), lua_event, serviceName ); ScriptMgr.run( "NetWorkHandler", "OnNetEvent", lua_params ); } static size_t WriteDataFromCurl(char* buffer, size_t size, size_t nmemb, NLMISC::CSString* pWriterData) { if (pWriterData == NULL) return 0; pWriterData->append(buffer, size*nmemb); return size * nmemb; } std::string HttpPost(std::string& url, std::string& params) { std::string m_WriterData; try { CURL* pCurl = curl_easy_init(); if (pCurl != NULL) { curl_easy_setopt(pCurl, CURLOPT_URL, url.c_str()); curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, WriteDataFromCurl); curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &m_WriterData); /* Now specify the POST data */ curl_easy_setopt(pCurl, CURLOPT_POSTFIELDS, params.c_str()); /* Perform the request, res will get the return code */ CURLcode res = curl_easy_perform(pCurl); curl_easy_cleanup(pCurl); /* Check for errors */ if (res != CURLE_OK) { nlwarning("CLuaHttpRequest Post() failed: %s\n", curl_easy_strerror(res)); } } } catch (...) { } return m_WriterData; } std::string HttpGet(std::string& url) { std::string m_WriterData; try { CURL* pCurl = curl_easy_init(); if (pCurl != NULL) { curl_easy_setopt(pCurl, CURLOPT_URL, url.c_str()); curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, WriteDataFromCurl); curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &m_WriterData); /* Perform the request, res will get the return code */ CURLcode res = curl_easy_perform(pCurl); curl_easy_cleanup(pCurl); /* Check for errors */ if (res != CURLE_OK) { nlwarning("CLuaHttpRequest Get() failed: %s\n", curl_easy_strerror(res)); } } } catch (...) { } return m_WriterData; } namespace bin { BEGIN_SCRIPT_CLASS( LuaCallbackServer, CLuaCallbackServer ) DEFINE_CLASS_FUNCTION( Send, void, (sint64 sock_id, CLuaMessage* lua_msg)) { obj->Send( (TSockId)sock_id, lua_msg->m_Msg ); return 1; } DEFINE_CLASS_FUNCTION( SetClientData, void, (CScriptTable& uid_data)) { if( uid_data.IsReferd() ) { ClientData cdata; sint64 int64_val; uid_data.Get(1, int64_val); cdata.uid = int64_val; uid_data.Get(2, int64_val); cdata.sid = (NLNET::TSockId)int64_val; uid_data.Get(3, int64_val); cdata.pls_sid.set(int64_val); obj->SetClientData( cdata ); } return 1; } DEFINE_CLASS_FUNCTION( DisConnect, void, (sint64 sock_id) ) { obj->DisConnect((NLNET::TSockId)sock_id); return 1; } DEFINE_CLASS_FUNCTION( RemoveClientData, void, (sint64 uid)) { obj->RemoveClientData( uid ); return 1; } DEFINE_CLASS_FUNCTION( ClearClientData, void, ()) { obj->ClearClientData(); return 1; } DEFINE_CLASS_FUNCTION( Listen, void, (sint32 port)) { obj->Listen(port); return 1; } DEFINE_CLASS_FUNCTION( LoadSslCA, void, (std::string& ssl_ca)) { obj->LoadSslCA(ssl_ca); return 1; } DEFINE_CLASS_FUNCTION( LoadSslCrt, void, (std::string& ssl_crt)) { obj->LoadSslCrt(ssl_crt); return 1; } DEFINE_CLASS_FUNCTION( LoadSslPrivateKey, void, (std::string& ssl_pk)) { obj->LoadSslPrivateKey(ssl_pk); return 1; } DEFINE_STATIC_FUNCTION(NewInstance, CLuaCallbackServer*, (std::string& svr_name, std::string& svr_protoc)) { r = new CLuaCallbackServer(svr_name, svr_protoc); r->GetScriptObject().SetDelByScr(true); return 1; } END_SCRIPT_CLASS() /// BEGIN_SCRIPT_MODULE(Net) DEFINE_MODULE_FUNCTION(Broadcast, void, (const char* service_name, CLuaMessage* pMsg)) { if( pMsg != NULL ) { NLNET::CMessage msgout("_LS"); msgout.serialMessage(pMsg->m_Msg); Network->send(service_name, msgout, false); } else { lua_Debug ar; lua_getstack(lua.GetHandle(), 2, &ar); lua_getinfo(lua.GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition(ar.currentline, ar.short_src, ar.name); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("Broadcast %s msg is NULL.", service_name); } return 1; } DEFINE_MODULE_FUNCTION(Send, void, (sint32 service_id, CLuaMessage* pMsg)) { if (pMsg != NULL) { NLNET::CMessage msgout("_LS"); msgout.serialMessage(pMsg->m_Msg); Network->send( (NLNET::TServiceId)service_id, msgout ); } else { lua_Debug ar; lua_getstack(lua.GetHandle(), 2, &ar); lua_getinfo(lua.GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition(ar.currentline, ar.short_src, ar.name); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("Send msg is NULL."); } return 1; } DEFINE_MODULE_FUNCTION(SendToClient, void, (CLuaMessage* pMsg, CScriptTable& tb_msg)) { if( tb_msg.IsReferd() ) { if (pMsg != NULL) { int sid; sint64 client_uid; tb_msg.Get(1, sid); tb_msg.Get(2, client_uid); CMessage msg_out("_LSC"); msg_out.serial(client_uid); msg_out.serialMessage(pMsg->m_Msg); Network->send((NLNET::TServiceId)sid, msg_out); } else { lua_Debug ar; lua_getstack(lua.GetHandle(), 2, &ar); lua_getinfo(lua.GetHandle(), "Sln", &ar); NLMISC::createDebug(); NLMISC::INelContext::getInstance().getWarningLog()->setPosition(ar.currentline, ar.short_src, ar.name); NLMISC::INelContext::getInstance().getWarningLog()->displayNL("SendToClient msg is NULL."); } } return 1; } DEFINE_MODULE_FUNCTION(SetConnectionCallback, void, (std::string service_name)) { CUnifiedNetwork::getInstance()->setServiceUpCallback(service_name, cbConnection); return 1; } DEFINE_MODULE_FUNCTION(SetDisConnectionCallback, void, (std::string service_name)) { CUnifiedNetwork::getInstance()->setServiceDownCallback(service_name, cbDisconnection); return 1; } DEFINE_MODULE_FUNCTION(GetServiceID, int, ()) { r = NLNET::IService::getInstance()->getServiceId().get(); return 1; } DEFINE_MODULE_FUNCTION(GetServiceName, std::string, ()) { r = NLNET::IService::getInstance()->getServiceShortName();; return 1; } DEFINE_MODULE_FUNCTION(HttpPost, std::string, (std::string& url, std::string& params)) { r = HttpPost(url, params); return 1; } DEFINE_MODULE_FUNCTION(HttpGet, std::string, (std::string& url)) { r = HttpGet(url); return 1; } END_SCRIPT_MODULE() } ================================================ FILE: code/EVA/server/server_share/lua_net/lua_network.h ================================================ #ifndef SERVER_SHARD_LUA_NETWORK_H #define SERVER_SHARD_LUA_NETWORK_H #include #include #include class CLuaCallbackServer; void cbLuaSvrConnect( NLNET::TSockId from, void *arg ); void cbLuaSvrDisConnect( NLNET::TSockId from, void *arg ); void cbConnection( const std::string &serviceName, NLNET::TServiceId sid, void *arg ); void cbDisconnection( const std::string &serviceName, NLNET::TServiceId sid, void *arg ); class CLuaNetworkMgr : public NLMISC::CSingleton { public: void Init(); void RegisterNetModule( std::string name, CLuaCallbackServer* pNet ); void RemoveNetModule( std::string name ); void SendToClient( uint64 uid, NLNET::CMessage& msgin ); void IncReceiveMsgCount(std::string msg_name); void Update(); void Release(); typedef std::map TMsgCount; TMsgCount m_ReceiveMsgCount; TMsgCount m_SendMsgCount; private: typedef std::map TNetHandle; TNetHandle m_LuaClientNetworkHandle; }; #define LuaNetworkMgr CLuaNetworkMgr::instance() #endif // SERVER_SHARD_LUA_NETWORK_H ================================================ FILE: code/EVA/server/server_share/msg_leaf.cpp ================================================ #include "msg_leaf.h" #include "nel/misc/string_conversion.h" using namespace std; using namespace NLMISC; namespace MSG_FORMAT { NL_BEGIN_STRING_CONVERSION_TABLE (TMsgFormat) NL_STRING_CONVERSION_TABLE_ENTRY(f) NL_STRING_CONVERSION_TABLE_ENTRY(d) NL_STRING_CONVERSION_TABLE_ENTRY(b) NL_STRING_CONVERSION_TABLE_ENTRY(s) NL_STRING_CONVERSION_TABLE_ENTRY(s8) NL_STRING_CONVERSION_TABLE_ENTRY(s16) NL_STRING_CONVERSION_TABLE_ENTRY(s32) NL_STRING_CONVERSION_TABLE_ENTRY(s64) NL_STRING_CONVERSION_TABLE_ENTRY(u8) NL_STRING_CONVERSION_TABLE_ENTRY(u16) NL_STRING_CONVERSION_TABLE_ENTRY(u32) NL_STRING_CONVERSION_TABLE_ENTRY(u64) NL_STRING_CONVERSION_TABLE_ENTRY(UID) NL_STRING_CONVERSION_TABLE_ENTRY(PLS) NL_STRING_CONVERSION_TABLE_ENTRY(JSON) NL_END_STRING_CONVERSION_TABLE(TMsgFormat, MsgFormatConversion, UNKNOWN) TMsgFormat toEnum(const std::string &str) { return MsgFormatConversion.fromString(str); } const std::string& toString(TMsgFormat format) { return MsgFormatConversion.toString(format); } }; // MSG_FORMAT ================================================ FILE: code/EVA/server/server_share/msg_leaf.h ================================================ #ifndef SERVER_SHARED_MSG_LEAF_H #define SERVER_SHARED_MSG_LEAF_H #include "nel/misc/types_nl.h" #include #include namespace MSG_FORMAT { enum TMsgFormat { f, d, b, s, s8, s16, s32, s64, u8, u16, u32, u64, UID, PLS, ProtoMsg, JSON, UNKNOWN }; TMsgFormat toEnum(const std::string &str); const std::string& toString(TMsgFormat format); }; // MSG_FORMAT struct MsgLeaf { std::string msgname; std::vector sendto; std::vector format; std::vector format_msg; std::string description; bool is_log_event; }; #endif // SERVER_SHARED_MSG_LEAF_H /* End of msg_leaf.h */ ================================================ FILE: code/EVA/server/server_share/object_pool.h ================================================ // // CObjectPool: #ifndef OBJECT_POOL_H #define OBJECT_POOL_H #include #include #include #include #include "buf_fifo2.h" namespace NLMISC { template class CObjectPool { public: CObjectPool(); ~CObjectPool(); inline bool init( std::string name, sint32 max ); inline T* alloc(); inline void free( T *pMem ); inline std::string report(); inline uint32 use() { return _fifo2.size(); } private: std::string _name; /// صıʶ uint32 _max; /// صObj std::vector _pool; CBufFIFO2 _fifo2; }; template CObjectPool::CObjectPool(): _name(""),_max(0) {} template CObjectPool::~CObjectPool() {} template inline bool CObjectPool::init(std::string name,sint32 max) { _name = name; _max = max; _pool.resize(_max); _fifo2.init(_max); for( uint32 i=0; i<_max; ++i ) { _fifo2.push_back(&(_pool[i])); } return true; } template inline T* CObjectPool::alloc() { return _fifo2.pop_front(); } template inline void CObjectPool::free(T *pMem) { pMem->reset(); _fifo2.push_back(pMem); } template inline std::string CObjectPool::report() { std::string str_report = ""; // use block : _fifo.size()/_max ; use memory : (_fifo.size()*sizeof(T))/(_max*sizeof(T)) return str_report; } } #endif ================================================ FILE: code/EVA/server/server_share/pbc/alloc.cpp ================================================ #include #include static int _g = 0; void * _pbcM_malloc(size_t sz) { ++ _g; return malloc(sz); } void _pbcM_free(void *p) { if (p) { -- _g; free(p); } } void* _pbcM_realloc(void *p, size_t sz) { return realloc(p,sz); } void _pbcM_memory() { printf("%d\n",_g); } struct heap_page { struct heap_page * next; }; struct heap { struct heap_page *current; int size; int used; }; struct heap * _pbcH_new(int pagesize) { int cap = 1024; while(cap < pagesize) { cap *= 2; } struct heap * h = (struct heap *)_pbcM_malloc(sizeof(struct heap)); h->current = (struct heap_page *)_pbcM_malloc(sizeof(struct heap_page) + cap); h->size = cap; h->used = 0; h->current->next = NULL; return h; } void _pbcH_delete(struct heap *h) { struct heap_page * p = h->current; struct heap_page * next = p->next; for(;;) { _pbcM_free(p); if (next == NULL) break; p = next; next = p->next; } _pbcM_free(h); } void* _pbcH_alloc(struct heap *h, int size) { size = (size + 3) & ~3; if (h->size - h->used < size) { struct heap_page * p; if (size < h->size) { p = (struct heap_page *)_pbcM_malloc(sizeof(struct heap_page) + h->size); } else { p = (struct heap_page *)_pbcM_malloc(sizeof(struct heap_page) + size); } p->next = h->current; h->current = p; h->used = size; return (p+1); } else { char * buffer = (char *)(h->current + 1); buffer += h->used; h->used += size; return buffer; } } ================================================ FILE: code/EVA/server/server_share/pbc/alloc.h ================================================ #ifndef PROTOBUF_C_ALLOC_H #define PROTOBUF_C_ALLOC_H #include #include void * _pbcM_malloc(size_t sz); void _pbcM_free(void *p); void * _pbcM_realloc(void *p, size_t sz); void _pbcM_memory(); struct heap; struct heap * _pbcH_new(int pagesize); void _pbcH_delete(struct heap *); void* _pbcH_alloc(struct heap *, int size); #define HMALLOC(size) ((h) ? _pbcH_alloc(h, size) : _pbcM_malloc(size)) #define pbc_malloc _pbcM_malloc #define pbc_free _pbcM_free #define pbc_realloc _pbcM_realloc #define pbc_memory _pbcM_memory #ifdef _WIN32 #include #endif #ifdef _MSC_VER #define alloca _alloca #endif #endif ================================================ FILE: code/EVA/server/server_share/pbc/array.cpp ================================================ #include "pbc.h" #include "array.h" #include "alloc.h" #include #include struct array { int number; struct heap *heap; union _pbc_var * a; }; #define INNER_FIELD ((PBC_ARRAY_CAP - sizeof(struct array)) / sizeof(pbc_var)) void _pbcA_open(pbc_array _array) { struct array * a = (struct array *)_array; a->number = 0; a->heap = NULL; a->a = (union _pbc_var *)(a+1); } void _pbcA_open_heap(pbc_array _array, struct heap *h) { struct array * a = (struct array *)_array; a->number = 0; a->heap = h; a->a = (union _pbc_var *)(a+1); } void _pbcA_close(pbc_array _array) { struct array * a = (struct array *)_array; if (a->heap == NULL && a->a != NULL && (union _pbc_var *)(a+1) != a->a) { _pbcM_free(a->a); a->a = NULL; } } void _pbcA_push(pbc_array _array, pbc_var var) { struct array * a = (struct array *)_array; if (a->number == 0) { a->a = (union _pbc_var *)(a+1); } else if (a->number >= INNER_FIELD) { if (a->number == INNER_FIELD) { int cap = 1; while (cap <= a->number + 1) cap *= 2; struct heap * h = a->heap; union _pbc_var * outer = (union _pbc_var *)HMALLOC(cap * sizeof(union _pbc_var)); memcpy(outer , a->a , INNER_FIELD * sizeof(pbc_var)); a->a = outer; } else { int size=a->number; if (((size + 1) ^ size) > size) { struct heap * h = a->heap; if (h) { void * old = a->a; a->a = (union _pbc_var *)_pbcH_alloc(h, sizeof(union _pbc_var) * (size+1) * 2); memcpy(a->a, old, sizeof(union _pbc_var) * size); } else { a->a = (union _pbc_var *)_pbcM_realloc(a->a,sizeof(union _pbc_var) * (size+1) * 2); } } } } a->a[a->number] = *var; ++ a->number; } void _pbcA_index(pbc_array _array, int idx, pbc_var var) { struct array * a = (struct array *)_array; var[0] = a->a[idx]; } void * _pbcA_index_p(pbc_array _array, int idx) { struct array * a = (struct array *)_array; return &(a->a[idx]); } int pbc_array_size(pbc_array _array) { struct array * a = (struct array *)_array; return a->number; } uint32_t pbc_array_integer(pbc_array array, int index, uint32_t *hi) { pbc_var var; _pbcA_index(array , index , var); if (hi) { *hi = var->integer.hi; } return var->integer.low; } double pbc_array_real(pbc_array array, int index) { pbc_var var; _pbcA_index(array , index , var); return var->real; } struct pbc_slice * pbc_array_slice(pbc_array _array, int index) { struct array * a = (struct array *)_array; if (index <0 || index > a->number) { return NULL; } return (struct pbc_slice *) &(a->a[index]); } void pbc_array_push_integer(pbc_array array, uint32_t low, uint32_t hi) { pbc_var var; var->integer.low = low; var->integer.hi = hi; _pbcA_push(array,var); } void pbc_array_push_slice(pbc_array array, struct pbc_slice *s) { pbc_var var; var->m = *s; _pbcA_push(array,var); } void pbc_array_push_real(pbc_array array, double v) { pbc_var var; var->real = v; _pbcA_push(array,var); } ================================================ FILE: code/EVA/server/server_share/pbc/array.h ================================================ #ifndef PROTOBUF_C_ARRAY_H #define PROTOBUF_C_ARRAY_H #include "varint.h" #include "pbc.h" #include "alloc.h" typedef union _pbc_var { struct longlong integer; double real; struct { const char * str; int len; } s; struct { int id; const char * name; } e; struct pbc_slice m; void * p[2]; } pbc_var[1]; void _pbcA_open(pbc_array); void _pbcA_open_heap(pbc_array, struct heap *h); void _pbcA_close(pbc_array); void _pbcA_push(pbc_array, pbc_var var); void _pbcA_index(pbc_array , int idx, pbc_var var); void * _pbcA_index_p(pbc_array _array, int idx); #endif ================================================ FILE: code/EVA/server/server_share/pbc/bootstrap.cpp ================================================ #include "pbc.h" #include "map.h" #include "context.h" #include "pattern.h" #include "proto.h" #include "alloc.h" #include "bootstrap.h" #include "stringpool.h" #include "array.h" #include "descriptor.pbc.h" #include #include #include #include /* // Descriptor // google.protobuf.Descriptor.proto encoded in descriptor.pbc.h with proto pbc.file . package pbc; message field { optional string name = 1; optional int32 id = 2; optional int32 label = 3; // 0 optional 1 required 2 repeated optional int32 type = 4; // type_id optional string type_name = 5; optional int32 default_int = 6; optional string default_string = 7; optional double default_real = 8; } message file { optional string name = 1; repeated string dependency = 2; repeated string message_name = 3; repeated int32 message_size = 4; repeated field message_field = 5; repeated string enum_name = 6; repeated int32 enum_size = 7; repeated string enum_string = 8; repeated int32 enum_id = 9; } */ struct field_t { struct pbc_slice name; int32_t id; int32_t label; int32_t type; struct pbc_slice type_name; int32_t default_integer; struct pbc_slice default_string; double default_real; }; struct file_t { struct pbc_slice name; // string pbc_array dependency; // string pbc_array message_name; // string pbc_array message_size; // int32 pbc_array message_field; // field_t pbc_array enum_name; // string pbc_array enum_size; // int32 pbc_array enum_string; // string pbc_array enum_id; // int32 }; static void set_enum_one(struct pbc_env *p, struct file_t *file, const char *name, int start, int sz) { struct map_kv *table = (struct map_kv *)pbc_malloc(sz * sizeof(struct map_kv)); int i; for (i=0;ienum_id, start+i, id); _pbcA_index(file->enum_string, start+i, string); table[i].id = (int)id->integer.low; table[i].pointer = (void *)string->s.str; } _pbcP_push_enum(p,name,table,sz); pbc_free(table); } static void set_enums(struct pbc_env *p, struct file_t *file) { int n = pbc_array_size(file->enum_size); int i; int start = 0; for (i=0;ienum_name,i,name); pbc_var var; _pbcA_index(file->enum_size,i,var); set_enum_one(p, file, name->s.str, start , (int)var->integer.low); start += var->integer.low; } } static void set_default(struct _field *f, struct field_t *input) { switch (f->type) { case PTYPE_DOUBLE: case PTYPE_FLOAT: f->default_v->real = input->default_real; break; case PTYPE_STRING: case PTYPE_ENUM: f->default_v->m = input->default_string; break; default: f->default_v->integer.low = input->default_integer; break; } } static void set_msg_one(struct pbc_pattern * FIELD_T, struct pbc_env *p, struct file_t *file, const char *name, int start, int sz , pbc_array queue) { int i; for (i=0;imessage_field, start+i, _field); struct field_t field; int ret = pbc_pattern_unpack(FIELD_T, &_field->m, &field); if (ret != 0) { continue; } struct _field f; f.id = field.id; f.name = (const char *)field.name.buffer; f.type = field.type; f.label = field.label; f.type_name.n = (const char *)field.type_name.buffer; set_default(&f, &field); _pbcP_push_message(p,name, &f , queue); // don't need to close pattern since no array } _pbcP_init_message(p, name); } static void set_msgs(struct pbc_pattern * FIELD_T, struct pbc_env *p, struct file_t *file , pbc_array queue) { int n = pbc_array_size(file->message_size); int i; int start = 0; for (i=0;imessage_name,i,name); pbc_var sz; _pbcA_index(file->message_size,i,sz); set_msg_one(FIELD_T, p, file, name->s.str, start , (int)sz->integer.low , queue); start += sz->integer.low; } } static void set_field_one(struct pbc_env *p, struct _field *f) { const char * type_name = f->type_name.n; if (f->type == PTYPE_MESSAGE) { f->type_name.m = (struct _message *)_pbcM_sp_query(p->msgs, type_name); // printf("MESSAGE: %s %p\n",type_name, f->type_name.m); } else if (f->type == PTYPE_ENUM) { f->type_name.e = (struct _enum *)_pbcM_sp_query(p->enums, type_name); // printf("ENUM: %s %p ",type_name, f->type_name.e); const char * str = f->default_v->s.str; if (str && str[0]) { int err = _pbcM_si_query(f->type_name.e->name, str , &(f->default_v->e.id)); if (err < 0) goto _default; f->default_v->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id, f->default_v->e.id); // printf("[%s %d]\n",str,f->default_v->e.id); } else { _default: memcpy(f->default_v, f->type_name.e->default_v, sizeof(pbc_var)); // printf("(%s %d)\n",f->default_v->e.name,f->default_v->e.id); } } } void _pbcB_register_fields(struct pbc_env *p, pbc_array queue) { int sz = pbc_array_size(queue); int i; for (i=0;im.buffer; set_field_one(p, f); } } static void _set_string(struct _pattern_field * f) { f->ptype = PTYPE_STRING; f->ctype = CTYPE_VAR; f->defv->s.str = ""; f->defv->s.len = 0; } static void _set_int32(struct _pattern_field * f) { f->ptype = PTYPE_INT32; f->ctype = CTYPE_INT32; } static void _set_double(struct _pattern_field * f) { f->ptype = PTYPE_DOUBLE; f->ctype = CTYPE_DOUBLE; } static void _set_message_array(struct _pattern_field *f) { f->ptype = PTYPE_MESSAGE; f->ctype = CTYPE_ARRAY; } static void _set_string_array(struct _pattern_field * f) { f->ptype = PTYPE_STRING; f->ctype = CTYPE_ARRAY; } static void _set_int32_array(struct _pattern_field * f) { f->ptype = PTYPE_INT32; f->ctype = CTYPE_ARRAY; } #define SET_PATTERN(pat , idx , pat_type, field_name , type) \ pat->f[idx].id = idx+1 ; \ pat->f[idx].offset = offsetof(struct pat_type, field_name); \ _set_##type(&pat->f[idx]); #define F(idx,field_name,type) SET_PATTERN(FIELD_T, idx, field_t ,field_name, type) #define D(idx,field_name,type) SET_PATTERN(FILE_T, idx, file_t ,field_name, type) static int register_internal(struct pbc_env * p, struct pbc_slice *slice) { struct pbc_pattern * FIELD_T = _pbcP_new(p,8); F(0,name,string); F(1,id,int32); F(2,label,int32); F(3,type,int32); F(4,type_name,string); F(5,default_integer,int32); F(6,default_string,string); F(7,default_real,double); struct pbc_pattern * FILE_T = _pbcP_new(p,10); D(0,name,string); D(1,dependency,string_array); D(2,message_name,string_array); D(3,message_size,int32_array); D(4,message_field,message_array); D(5,enum_name,string_array); D(6,enum_size,int32_array); D(7,enum_string,string_array); D(8,enum_id,int32_array); int ret = 0; struct file_t file; int r = pbc_pattern_unpack(FILE_T, slice, &file); if (r != 0) { ret = 1; goto _return; } _pbcM_sp_insert(p->files , (const char *)file.name.buffer, NULL); pbc_array queue; _pbcA_open(queue); set_enums(p, &file); set_msgs(FIELD_T, p, &file, queue); _pbcB_register_fields(p, queue); _pbcA_close(queue); pbc_pattern_close_arrays(FILE_T, &file); _return: pbc_free(FIELD_T); pbc_free(FILE_T); return ret; } void _pbcB_init(struct pbc_env * p) { struct pbc_slice slice = { pbc_descriptor,sizeof(pbc_descriptor) }; register_internal(p,&slice); } ================================================ FILE: code/EVA/server/server_share/pbc/bootstrap.h ================================================ #ifndef PROTOBUF_C_BOOTSTRAP_H #define PROTOBUF_C_BOOTSTRAP_H #include "proto.h" #include "pbc.h" void _pbcB_init(struct pbc_env *); void _pbcB_register_fields(struct pbc_env *, pbc_array queue); #endif ================================================ FILE: code/EVA/server/server_share/pbc/context.cpp ================================================ #include "pbc.h" #include "alloc.h" #include "varint.h" #include "context.h" #include #include #include #ifndef _MSC_VER #include #endif #define INNER_ATOM ((PBC_CONTEXT_CAP - sizeof(struct context)) / sizeof(struct atom)) static char * wiretype_decode(uint8_t *buffer, int cap , struct atom *a , int start) { uint8_t temp[10]; struct longlong r; int len; if (cap >= 10) { len = _pbcV_decode(buffer, &r); if (r.hi !=0) return NULL; } else { memcpy(temp, buffer , cap); len = _pbcV_decode(temp, &r); if (len > cap || r.hi !=0) return NULL; } int wiretype = r.low & 7; a->wire_id = r.low; buffer += len; start += len; cap -=len; switch (wiretype) { case WT_VARINT : if (cap >=10) { len = _pbcV_decode(buffer, &a->v.i); } else { memcpy(temp, buffer , cap); len = _pbcV_decode(temp, &a->v.i); if (cap < len) return NULL; } return (char *)buffer+len; case WT_BIT64 : if (cap < 8) return NULL; a->v.i.low = buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24; a->v.i.hi = buffer[4] | buffer[5] << 8 | buffer[6] << 16 | buffer[7] << 24; return (char *)buffer + 8; case WT_LEND : if (cap >=10) { len = _pbcV_decode(buffer, &r); } else { memcpy(temp, buffer , cap); len = _pbcV_decode(temp, &r); } if (cap < len + r.low || r.hi !=0) return NULL; a->v.s.start = start + len; a->v.s.end = start + len + r.low; return (char *)buffer + len + r.low; case WT_BIT32 : if (cap < 4) return NULL; a->v.i.low = buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24; a->v.i.hi = 0; return (char *)buffer + 4; default: return NULL; } } static inline int _decode_varint(uint8_t * buffer, int size , struct atom * a) { a->wire_id = WT_VARINT; if (size < 10) { uint8_t temp[10]; memcpy(temp,buffer,size); return _pbcV_decode(temp , &(a->v.i)); } else { return _pbcV_decode(buffer , &(a->v.i)); } } static int _open_packed_varint(struct context * ctx , uint8_t * buffer, int size) { struct atom * a = (struct atom *)(ctx + 1); int i; for (i=0;ia = a; } else { int cap = 64; ctx->a = (struct atom *)pbc_malloc(cap * sizeof(struct atom)); while (size > 0) { if (i >= cap) { cap = cap + 64; ctx->a = (struct atom *)pbc_realloc(ctx->a, cap * sizeof(struct atom)); continue; } int len = _decode_varint(buffer, size, &a[i]); buffer += len; size -= len; ++i; } memcpy(ctx->a, a , sizeof(struct atom) * INNER_ATOM); } ctx->number = i; return i; } int _pbcC_open_packed(pbc_ctx _ctx, int ptype, void *buffer, int size) { struct context * ctx = (struct context *)_ctx; ctx->buffer = (char *)buffer; ctx->size = size; ctx->number = 0; ctx->a = NULL; if (buffer == NULL || size == 0) { return 0; } int bits = 0; switch (ptype) { case PTYPE_INT64: case PTYPE_UINT64: case PTYPE_INT32: case PTYPE_BOOL: case PTYPE_UINT32: case PTYPE_ENUM: case PTYPE_SINT32: case PTYPE_SINT64: return _open_packed_varint(ctx , (uint8_t *)buffer, size); case PTYPE_DOUBLE: case PTYPE_FIXED64: case PTYPE_SFIXED64: ctx->number = size / 8; bits = 64; break; case PTYPE_FLOAT: case PTYPE_FIXED32: case PTYPE_SFIXED32: ctx->number = size / 4; bits = 32; break; default: return 0; } struct atom * a = (struct atom *)(ctx + 1); if (ctx->number > INNER_ATOM) { ctx->a = (struct atom *)pbc_malloc(ctx->number * sizeof(struct atom)); a = ctx->a; } else { ctx->a = a; } int i; if (bits == 64) { uint8_t * data = (uint8_t *)buffer; for (i=0;inumber;i++) { a[i].wire_id = WT_BIT64; a[i].v.i.low = data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24; a[i].v.i.hi = data[4] | data[5] << 8 | data[6] << 16 | data[7] << 24; data += 8; } } else { uint8_t * data = (uint8_t *)buffer; for (i=0;inumber;i++) { a[i].wire_id = WT_BIT32; a[i].v.i.low = data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24; a[i].v.i.hi = 0; data += 4; } } return ctx->number; } int _pbcC_open(pbc_ctx _ctx , void *buffer, int size) { struct context * ctx = (struct context *)_ctx; ctx->buffer = (char *)buffer; ctx->size = size; if (buffer == NULL || size == 0) { ctx->number = 0; ctx->a = NULL; return 0; } struct atom * a = (struct atom *)(ctx + 1); int i; int start = 0; ctx->a = a; for (i=0;i 0) { int cap = 64; ctx->a = (struct atom *)pbc_malloc(cap * sizeof(struct atom)); while (size > 0) { if (i >= cap) { cap = cap + 64; ctx->a = (struct atom *)pbc_realloc(ctx->a, cap * sizeof(struct atom)); continue; } char * next = wiretype_decode((uint8_t *)buffer, size , &ctx->a[i] , start); if (next == NULL) { return -i; } start += next - (char *)buffer; size -= next - (char *)buffer; buffer = next; ++i; } memcpy(ctx->a, a , sizeof(struct atom) * INNER_ATOM); } ctx->number = i; return i; } void _pbcC_close(pbc_ctx _ctx) { struct context * ctx = (struct context *)_ctx; if (ctx->a != NULL && (struct atom *)(ctx+1) != ctx->a) { pbc_free(ctx->a); ctx->a = NULL; } } ================================================ FILE: code/EVA/server/server_share/pbc/context.h ================================================ #ifndef PROTOBUF_C_CONTEXT_H #define PROTOBUF_C_CONTEXT_H #include #include "array.h" #define PBC_CONTEXT_CAP 256 // wiretype #define WT_VARINT 0 #define WT_BIT64 1 #define WT_LEND 2 #define WT_BIT32 5 #define CTYPE_INT32 1 #define CTYPE_INT64 2 #define CTYPE_DOUBLE 3 #define CTYPE_FLOAT 4 #define CTYPE_POINTER 5 #define CTYPE_BOOL 6 #define CTYPE_INT8 7 #define CTYPE_INT16 8 #define CTYPE_ARRAY 9 #define CTYPE_VAR 10 #define CTYPE_PACKED 11 #define PTYPE_DOUBLE 1 #define PTYPE_FLOAT 2 #define PTYPE_INT64 3 // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if negative values are likely. #define PTYPE_UINT64 4 #define PTYPE_INT32 5 // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if negative values are likely. #define PTYPE_FIXED64 6 #define PTYPE_FIXED32 7 #define PTYPE_BOOL 8 #define PTYPE_STRING 9 #define PTYPE_GROUP 10 // Tag-delimited aggregate. #define PTYPE_MESSAGE 11 // Length-delimited aggregate. #define PTYPE_BYTES 12 #define PTYPE_UINT32 13 #define PTYPE_ENUM 14 #define PTYPE_SFIXED32 15 #define PTYPE_SFIXED64 16 #define PTYPE_SINT32 17 // Uses ZigZag encoding. #define PTYPE_SINT64 18 // Uses ZigZag encoding. struct slice { int start; int end; }; struct atom { int wire_id; union { struct slice s; struct longlong i; } v; }; struct context { char * buffer; int size; int number; struct atom * a; }; typedef struct _pbc_ctx { char _data[PBC_CONTEXT_CAP]; } pbc_ctx[1]; int _pbcC_open(pbc_ctx , void *buffer, int size); // <=0 failed int _pbcC_open_packed(pbc_ctx _ctx, int ptype, void *buffer, int size); void _pbcC_close(pbc_ctx); static inline double read_double(struct atom * a) { union { uint64_t i; double d; } u; u.i = (uint64_t) a->v.i.low | (uint64_t) a->v.i.hi << 32; return u.d; } static inline float read_float(struct atom * a) { union { uint32_t i; float f; } u; u.i = a->v.i.low; return u.f; } static inline void double_encode(double v , uint8_t * buffer) { union { double v; uint64_t e; } u; u.v = v; buffer[0] = (uint8_t) (u.e & 0xff); buffer[1] = (uint8_t) (u.e >> 8 & 0xff); buffer[2] = (uint8_t) (u.e >> 16 & 0xff); buffer[3] = (uint8_t) (u.e >> 24 & 0xff); buffer[4] = (uint8_t) (u.e >> 32 & 0xff); buffer[5] = (uint8_t) (u.e >> 40 & 0xff); buffer[6] = (uint8_t) (u.e >> 48 & 0xff); buffer[7] = (uint8_t) (u.e >> 56 & 0xff); } static inline void float_encode(float v , uint8_t * buffer) { union { float v; uint32_t e; } u; u.v = v; buffer[0] = (uint8_t) (u.e & 0xff); buffer[1] = (uint8_t) (u.e >> 8 & 0xff); buffer[2] = (uint8_t) (u.e >> 16 & 0xff); buffer[3] = (uint8_t) (u.e >> 24 & 0xff); } #define CHECK_LEND(a,err) if ((a->wire_id & 7) != WT_LEND) return err; #if 0 /* maybe we don't need check these wire type */ #define CHECK_VARINT(a,err) if ((a->wire_id & 7) != WT_VARINT) return err; #define CHECK_BIT32(a,err) if ((a->wire_id & 7) != WT_BIT32) return err; #define CHECK_BIT64(a,err) if ((a->wire_id & 7) != WT_BIT64) return err; #else #define CHECK_VARINT(a,err) #define CHECK_BIT32(a,err) #define CHECK_BIT64(a,err) #endif #endif ================================================ FILE: code/EVA/server/server_share/pbc/decode.cpp ================================================ #include "pbc.h" #include "alloc.h" #include "context.h" #include "proto.h" #include "varint.h" #include static const char * TYPENAME[] = { "invalid", // 0 "integer", // 1 "real", // 2 "boolean", // 3 "enum", // 4 "string", // 5 "message", // 6 "fixed64", // 7 "fixed32", // 8 "bytes", // 9 "int64", // 10 "uint", // 11 }; static int call_unknown(pbc_decoder f, void * ud, int id, struct atom *a, uint8_t * start) { union pbc_value v; switch (a->wire_id & 7) { case WT_VARINT: v.i.low = a->v.i.low; v.i.hi = a->v.i.hi; f(ud, PBC_INT, TYPENAME[PBC_INT], &v, id , NULL); break; case WT_BIT64: v.i.low = a->v.i.low; v.i.hi = a->v.i.hi; f(ud, PBC_FIXED64, TYPENAME[PBC_FIXED64], &v, id , NULL); break; case WT_LEND: v.s.buffer = (char*)start + a->v.s.start; v.s.len = a->v.s.end - a->v.s.start; f(ud, PBC_BYTES, TYPENAME[PBC_BYTES], &v, id , NULL); break; case WT_BIT32: v.i.low = a->v.i.low; v.i.hi = 0; f(ud, PBC_FIXED32, TYPENAME[PBC_FIXED32], &v, id , NULL); break; default: return 1; } return 0; } static int call_type(pbc_decoder pd, void * ud, struct _field *f, struct atom *a, uint8_t * start) { union pbc_value v; const char * type_name = NULL; int type = _pbcP_type(f, &type_name); assert(type != 0); if (type_name == NULL) { type_name = TYPENAME[type & ~PBC_REPEATED]; } switch (f->type) { case PTYPE_DOUBLE: CHECK_BIT64(a, -1); v.f = read_double(a); break; case PTYPE_FLOAT: CHECK_BIT32(a, -1); v.f = (double) read_float(a); break; case PTYPE_ENUM: CHECK_VARINT(a, -1); v.e.id = a->v.i.low; v.e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , v.e.id); break; case PTYPE_INT64: case PTYPE_UINT64: CHECK_VARINT(a, -1); v.i.low = a->v.i.low; v.i.hi = a->v.i.hi; break; case PTYPE_FIXED64: case PTYPE_SFIXED64: CHECK_BIT64(a, -1); v.i.low = a->v.i.low; v.i.hi = a->v.i.hi; break; case PTYPE_INT32: case PTYPE_UINT32: case PTYPE_BOOL: CHECK_VARINT(a, -1); v.i.low = a->v.i.low; v.i.hi = 0; break; case PTYPE_FIXED32: case PTYPE_SFIXED32: CHECK_BIT32(a, -1); v.i.low = a->v.i.low; v.i.hi = 0; break; case PTYPE_SINT32: CHECK_VARINT(a, -1); v.i.low = a->v.i.low; v.i.hi = a->v.i.hi; _pbcV_dezigzag32((struct longlong *)&(v.i)); break; case PTYPE_SINT64: CHECK_VARINT(a, -1); v.i.low = a->v.i.low; v.i.hi = a->v.i.hi; _pbcV_dezigzag64((struct longlong *)&(v.i)); break; case PTYPE_STRING: case PTYPE_BYTES: case PTYPE_MESSAGE: CHECK_LEND(a, -1); v.s.buffer = start + a->v.s.start; v.s.len = a->v.s.end - a->v.s.start; break; default: assert(0); break; } pd(ud, type, type_name, &v, f->id, f->name); return 0; } static int call_array(pbc_decoder pd, void * ud, struct _field *f, uint8_t * buffer , int size) { union pbc_value v; const char * type_name = NULL; int type = _pbcP_type(f, &type_name); assert(type != 0); if (type_name == NULL) { type_name = TYPENAME[type & ~PBC_REPEATED]; } v.i.hi = 0; int i; switch(f->type) { case PTYPE_DOUBLE: if (size % 8 != 0) { return -1; } for (i=0;iid, f->name); } return size/8; case PTYPE_FLOAT: if (size % 4 != 0) return -1; for (i=0;iid, f->name); } return size/4; case PTYPE_FIXED32: case PTYPE_SFIXED32: if (size % 4 != 0) return -1; for (i=0;iid, f->name); } return size/4; case PTYPE_FIXED64: case PTYPE_SFIXED64: if (size % 8 != 0) return -1; for (i=0;iid, f->name); } return size/8; case PTYPE_INT64: case PTYPE_UINT64: case PTYPE_INT32: case PTYPE_UINT32: case PTYPE_BOOL: { int n = 0; while (size > 0) { int len; if (size >= 10) { len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); } else { uint8_t temp[10]; memcpy(temp, buffer, size); len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); if (len > size) return -1; } pd(ud, type , type_name, &v, f->id, f->name); buffer += len; size -= len; ++n; } return n; } case PTYPE_ENUM: { int n = 0; while (size > 0) { int len; if (size >= 10) { len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); } else { uint8_t temp[10]; memcpy(temp, buffer, size); len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); if (len > size) return -1; } v.e.id = v.i.low; v.e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , v.i.low); pd(ud, type , type_name, &v, f->id, f->name); buffer += len; size -= len; ++n; } return n; } case PTYPE_SINT32: { int n = 0; while (size > 0) { int len; if (size >= 10) { len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); _pbcV_dezigzag32((struct longlong *)&(v.i)); } else { uint8_t temp[10]; memcpy(temp, buffer, size); len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); if (len > size) return -1; _pbcV_dezigzag32((struct longlong *)&(v.i)); } pd(ud, type , type_name, &v, f->id, f->name); buffer += len; size -= len; ++n; } return n; } case PTYPE_SINT64: { int n = 0; while (size > 0) { int len; if (size >= 10) { len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); _pbcV_dezigzag64((struct longlong *)&(v.i)); } else { uint8_t temp[10]; memcpy(temp, buffer, size); len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); if (len > size) return -1; _pbcV_dezigzag64((struct longlong *)&(v.i)); } pd(ud, type , type_name, &v, f->id, f->name); buffer += len; size -= len; ++n; } return n; } default: return -1; } } int pbc_decode(struct pbc_env * env, const char * type_name , struct pbc_slice * slice, pbc_decoder pd, void *ud) { struct _message * msg = _pbcP_get_message(env, type_name); if (msg == NULL) { env->lasterror = "Proto not found"; return -1; } if (slice->len == 0) { return 0; } pbc_ctx _ctx; int count = _pbcC_open(_ctx,slice->buffer,slice->len); if (count <= 0) { env->lasterror = "decode context error"; _pbcC_close(_ctx); return count - 1; } struct context * ctx = (struct context *)_ctx; uint8_t * start = (uint8_t *)slice->buffer; int i; for (i=0;inumber;i++) { int id = ctx->a[i].wire_id >> 3; struct _field * f = (struct _field *)_pbcM_ip_query(msg->id , id); if (f==NULL) { int err = call_unknown(pd,ud,id,&ctx->a[i],start); if (err) { _pbcC_close(_ctx); return -i-1; } } else if (f->label == LABEL_PACKED) { struct atom * a = &ctx->a[i]; int n = call_array(pd, ud, f , start + a->v.s.start , a->v.s.end - a->v.s.start); if (n < 0) { _pbcC_close(_ctx); return -i-1; } } else { if (call_type(pd,ud,f,&ctx->a[i],start) != 0) { _pbcC_close(_ctx); return -i-1; } } } _pbcC_close(_ctx); return ctx->number; } ================================================ FILE: code/EVA/server/server_share/pbc/descriptor.pbc.h ================================================ static unsigned char pbc_descriptor[] = { 72,1,72,2,72,3,72,4,72,5,72,6,72,7,72,8, 72,9,72,10,72,11,72,12,72,13,72,14,72,15,72,16, 72,17,72,18,72,1,72,2,72,3,72,1,72,2,72,3, 72,0,72,1,72,2,50,42,103,111,111,103,108,101,46,112, 114,111,116,111,98,117,102,46,70,105,101,108,100,68,101,115, 99,114,105,112,116,111,114,80,114,111,116,111,46,84,121,112, 101,0,50,43,103,111,111,103,108,101,46,112,114,111,116,111, 98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112, 116,111,114,80,114,111,116,111,46,76,97,98,101,108,0,50, 41,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102, 46,70,105,108,101,79,112,116,105,111,110,115,46,79,112,116, 105,109,105,122,101,77,111,100,101,0,50,35,103,111,111,103, 108,101,46,112,114,111,116,111,98,117,102,46,70,105,101,108, 100,79,112,116,105,111,110,115,46,67,84,121,112,101,0,66, 12,84,89,80,69,95,68,79,85,66,76,69,0,66,11,84, 89,80,69,95,70,76,79,65,84,0,66,11,84,89,80,69, 95,73,78,84,54,52,0,66,12,84,89,80,69,95,85,73, 78,84,54,52,0,66,11,84,89,80,69,95,73,78,84,51, 50,0,66,13,84,89,80,69,95,70,73,88,69,68,54,52, 0,66,13,84,89,80,69,95,70,73,88,69,68,51,50,0, 66,10,84,89,80,69,95,66,79,79,76,0,66,12,84,89, 80,69,95,83,84,82,73,78,71,0,66,11,84,89,80,69, 95,71,82,79,85,80,0,66,13,84,89,80,69,95,77,69, 83,83,65,71,69,0,66,11,84,89,80,69,95,66,89,84, 69,83,0,66,12,84,89,80,69,95,85,73,78,84,51,50, 0,66,10,84,89,80,69,95,69,78,85,77,0,66,14,84, 89,80,69,95,83,70,73,88,69,68,51,50,0,66,14,84, 89,80,69,95,83,70,73,88,69,68,54,52,0,66,12,84, 89,80,69,95,83,73,78,84,51,50,0,66,12,84,89,80, 69,95,83,73,78,84,54,52,0,66,15,76,65,66,69,76, 95,79,80,84,73,79,78,65,76,0,66,15,76,65,66,69, 76,95,82,69,81,85,73,82,69,68,0,66,15,76,65,66, 69,76,95,82,69,80,69,65,84,69,68,0,66,6,83,80, 69,69,68,0,66,10,67,79,68,69,95,83,73,90,69,0, 66,13,76,73,84,69,95,82,85,78,84,73,77,69,0,66, 7,83,84,82,73,78,71,0,66,5,67,79,82,68,0,66, 13,83,84,82,73,78,71,95,80,73,69,67,69,0,56,18, 56,3,56,3,56,3,10,11,100,101,115,99,114,105,112,116, 111,114,0,32,1,32,9,32,7,32,2,32,8,32,3,32, 3,32,3,32,4,32,9,32,3,32,5,32,1,32,1,32, 1,32,1,32,7,32,2,32,1,32,2,42,51,24,2,16, 1,32,11,42,36,103,111,111,103,108,101,46,112,114,111,116, 111,98,117,102,46,70,105,108,101,68,101,115,99,114,105,112, 116,111,114,80,114,111,116,111,0,10,5,102,105,108,101,0, 42,13,32,9,24,0,10,5,110,97,109,101,0,16,1,42, 16,32,9,24,0,10,8,112,97,99,107,97,103,101,0,16, 2,42,19,32,9,24,2,10,11,100,101,112,101,110,100,101, 110,99,121,0,16,3,42,55,24,2,16,4,32,11,42,32, 103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, 68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, 10,13,109,101,115,115,97,103,101,95,116,121,112,101,0,42, 56,24,2,16,5,32,11,42,36,103,111,111,103,108,101,46, 112,114,111,116,111,98,117,102,46,69,110,117,109,68,101,115, 99,114,105,112,116,111,114,80,114,111,116,111,0,10,10,101, 110,117,109,95,116,121,112,101,0,42,57,24,2,16,6,32, 11,42,39,103,111,111,103,108,101,46,112,114,111,116,111,98, 117,102,46,83,101,114,118,105,99,101,68,101,115,99,114,105, 112,116,111,114,80,114,111,116,111,0,10,8,115,101,114,118, 105,99,101,0,42,57,24,2,16,7,32,11,42,37,103,111, 111,103,108,101,46,112,114,111,116,111,98,117,102,46,70,105, 101,108,100,68,101,115,99,114,105,112,116,111,114,80,114,111, 116,111,0,10,10,101,120,116,101,110,115,105,111,110,0,42, 46,24,0,16,8,32,11,42,28,103,111,111,103,108,101,46, 112,114,111,116,111,98,117,102,46,70,105,108,101,79,112,116, 105,111,110,115,0,10,8,111,112,116,105,111,110,115,0,42, 58,24,0,16,9,32,11,42,31,103,111,111,103,108,101,46, 112,114,111,116,111,98,117,102,46,83,111,117,114,99,101,67, 111,100,101,73,110,102,111,0,10,17,115,111,117,114,99,101, 95,99,111,100,101,95,105,110,102,111,0,42,13,32,9,24, 0,10,5,110,97,109,101,0,16,1,42,53,24,2,16,2, 32,11,42,37,103,111,111,103,108,101,46,112,114,111,116,111, 98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112, 116,111,114,80,114,111,116,111,0,10,6,102,105,101,108,100, 0,42,57,24,2,16,6,32,11,42,37,103,111,111,103,108, 101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100, 68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, 10,10,101,120,116,101,110,115,105,111,110,0,42,54,24,2, 16,3,32,11,42,32,103,111,111,103,108,101,46,112,114,111, 116,111,98,117,102,46,68,101,115,99,114,105,112,116,111,114, 80,114,111,116,111,0,10,12,110,101,115,116,101,100,95,116, 121,112,101,0,42,56,24,2,16,4,32,11,42,36,103,111, 111,103,108,101,46,112,114,111,116,111,98,117,102,46,69,110, 117,109,68,101,115,99,114,105,112,116,111,114,80,114,111,116, 111,0,10,10,101,110,117,109,95,116,121,112,101,0,42,73, 24,2,16,5,32,11,42,47,103,111,111,103,108,101,46,112, 114,111,116,111,98,117,102,46,68,101,115,99,114,105,112,116, 111,114,80,114,111,116,111,46,69,120,116,101,110,115,105,111, 110,82,97,110,103,101,0,10,16,101,120,116,101,110,115,105, 111,110,95,114,97,110,103,101,0,42,49,24,0,16,7,32, 11,42,31,103,111,111,103,108,101,46,112,114,111,116,111,98, 117,102,46,77,101,115,115,97,103,101,79,112,116,105,111,110, 115,0,10,8,111,112,116,105,111,110,115,0,42,14,32,5, 24,0,10,6,115,116,97,114,116,0,16,1,42,12,32,5, 24,0,10,4,101,110,100,0,16,2,42,13,32,9,24,0, 10,5,110,97,109,101,0,16,1,42,15,32,5,24,0,10, 7,110,117,109,98,101,114,0,16,3,42,59,24,0,16,4, 32,14,42,43,103,111,111,103,108,101,46,112,114,111,116,111, 98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112, 116,111,114,80,114,111,116,111,46,76,97,98,101,108,0,10, 6,108,97,98,101,108,0,42,57,24,0,16,5,32,14,42, 42,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102, 46,70,105,101,108,100,68,101,115,99,114,105,112,116,111,114, 80,114,111,116,111,46,84,121,112,101,0,10,5,116,121,112, 101,0,42,18,32,9,24,0,10,10,116,121,112,101,95,110, 97,109,101,0,16,6,42,17,32,9,24,0,10,9,101,120, 116,101,110,100,101,101,0,16,2,42,22,32,9,24,0,10, 14,100,101,102,97,117,108,116,95,118,97,108,117,101,0,16, 7,42,47,24,0,16,8,32,11,42,29,103,111,111,103,108, 101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100, 79,112,116,105,111,110,115,0,10,8,111,112,116,105,111,110, 115,0,42,13,32,9,24,0,10,5,110,97,109,101,0,16, 1,42,57,24,2,16,2,32,11,42,41,103,111,111,103,108, 101,46,112,114,111,116,111,98,117,102,46,69,110,117,109,86, 97,108,117,101,68,101,115,99,114,105,112,116,111,114,80,114, 111,116,111,0,10,6,118,97,108,117,101,0,42,46,24,0, 16,3,32,11,42,28,103,111,111,103,108,101,46,112,114,111, 116,111,98,117,102,46,69,110,117,109,79,112,116,105,111,110, 115,0,10,8,111,112,116,105,111,110,115,0,42,13,32,9, 24,0,10,5,110,97,109,101,0,16,1,42,15,32,5,24, 0,10,7,110,117,109,98,101,114,0,16,2,42,51,24,0, 16,3,32,11,42,33,103,111,111,103,108,101,46,112,114,111, 116,111,98,117,102,46,69,110,117,109,86,97,108,117,101,79, 112,116,105,111,110,115,0,10,8,111,112,116,105,111,110,115, 0,42,13,32,9,24,0,10,5,110,97,109,101,0,16,1, 42,55,24,2,16,2,32,11,42,38,103,111,111,103,108,101, 46,112,114,111,116,111,98,117,102,46,77,101,116,104,111,100, 68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, 10,7,109,101,116,104,111,100,0,42,49,24,0,16,3,32, 11,42,31,103,111,111,103,108,101,46,112,114,111,116,111,98, 117,102,46,83,101,114,118,105,99,101,79,112,116,105,111,110, 115,0,10,8,111,112,116,105,111,110,115,0,42,13,32,9, 24,0,10,5,110,97,109,101,0,16,1,42,19,32,9,24, 0,10,11,105,110,112,117,116,95,116,121,112,101,0,16,2, 42,20,32,9,24,0,10,12,111,117,116,112,117,116,95,116, 121,112,101,0,16,3,42,48,24,0,16,4,32,11,42,30, 103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, 77,101,116,104,111,100,79,112,116,105,111,110,115,0,10,8, 111,112,116,105,111,110,115,0,42,21,32,9,24,0,10,13, 106,97,118,97,95,112,97,99,107,97,103,101,0,16,1,42, 29,32,9,24,0,10,21,106,97,118,97,95,111,117,116,101, 114,95,99,108,97,115,115,110,97,109,101,0,16,8,42,30, 24,0,16,10,32,8,10,20,106,97,118,97,95,109,117,108, 116,105,112,108,101,95,102,105,108,101,115,0,48,0,42,40, 24,0,16,20,32,8,10,30,106,97,118,97,95,103,101,110, 101,114,97,116,101,95,101,113,117,97,108,115,95,97,110,100, 95,104,97,115,104,0,48,0,42,72,24,0,16,9,32,14, 42,41,103,111,111,103,108,101,46,112,114,111,116,111,98,117, 102,46,70,105,108,101,79,112,116,105,111,110,115,46,79,112, 116,105,109,105,122,101,77,111,100,101,0,10,13,111,112,116, 105,109,105,122,101,95,102,111,114,0,58,6,83,80,69,69, 68,0,42,30,24,0,16,16,32,8,10,20,99,99,95,103, 101,110,101,114,105,99,95,115,101,114,118,105,99,101,115,0, 48,0,42,32,24,0,16,17,32,8,10,22,106,97,118,97, 95,103,101,110,101,114,105,99,95,115,101,114,118,105,99,101, 115,0,48,0,42,30,24,0,16,18,32,8,10,20,112,121, 95,103,101,110,101,114,105,99,95,115,101,114,118,105,99,101, 115,0,48,0,42,68,24,2,16,231,7,32,11,42,36,103, 111,111,103,108,101,46,112,114,111,116,111,98,117,102,46,85, 110,105,110,116,101,114,112,114,101,116,101,100,79,112,116,105, 111,110,0,10,21,117,110,105,110,116,101,114,112,114,101,116, 101,100,95,111,112,116,105,111,110,0,42,34,24,0,16,1, 32,8,10,24,109,101,115,115,97,103,101,95,115,101,116,95, 119,105,114,101,95,102,111,114,109,97,116,0,48,0,42,42, 24,0,16,2,32,8,10,32,110,111,95,115,116,97,110,100, 97,114,100,95,100,101,115,99,114,105,112,116,111,114,95,97, 99,99,101,115,115,111,114,0,48,0,42,68,24,2,16,231, 7,32,11,42,36,103,111,111,103,108,101,46,112,114,111,116, 111,98,117,102,46,85,110,105,110,116,101,114,112,114,101,116, 101,100,79,112,116,105,111,110,0,10,21,117,110,105,110,116, 101,114,112,114,101,116,101,100,95,111,112,116,105,111,110,0, 42,60,24,0,16,1,32,14,42,35,103,111,111,103,108,101, 46,112,114,111,116,111,98,117,102,46,70,105,101,108,100,79, 112,116,105,111,110,115,46,67,84,121,112,101,0,10,6,99, 116,121,112,101,0,58,7,83,84,82,73,78,71,0,42,15, 32,8,24,0,10,7,112,97,99,107,101,100,0,16,2,42, 21,24,0,16,3,32,8,10,11,100,101,112,114,101,99,97, 116,101,100,0,48,0,42,29,32,9,24,0,10,21,101,120, 112,101,114,105,109,101,110,116,97,108,95,109,97,112,95,107, 101,121,0,16,9,42,68,24,2,16,231,7,32,11,42,36, 103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, 85,110,105,110,116,101,114,112,114,101,116,101,100,79,112,116, 105,111,110,0,10,21,117,110,105,110,116,101,114,112,114,101, 116,101,100,95,111,112,116,105,111,110,0,42,68,24,2,16, 231,7,32,11,42,36,103,111,111,103,108,101,46,112,114,111, 116,111,98,117,102,46,85,110,105,110,116,101,114,112,114,101, 116,101,100,79,112,116,105,111,110,0,10,21,117,110,105,110, 116,101,114,112,114,101,116,101,100,95,111,112,116,105,111,110, 0,42,68,24,2,16,231,7,32,11,42,36,103,111,111,103, 108,101,46,112,114,111,116,111,98,117,102,46,85,110,105,110, 116,101,114,112,114,101,116,101,100,79,112,116,105,111,110,0, 10,21,117,110,105,110,116,101,114,112,114,101,116,101,100,95, 111,112,116,105,111,110,0,42,68,24,2,16,231,7,32,11, 42,36,103,111,111,103,108,101,46,112,114,111,116,111,98,117, 102,46,85,110,105,110,116,101,114,112,114,101,116,101,100,79, 112,116,105,111,110,0,10,21,117,110,105,110,116,101,114,112, 114,101,116,101,100,95,111,112,116,105,111,110,0,42,68,24, 2,16,231,7,32,11,42,36,103,111,111,103,108,101,46,112, 114,111,116,111,98,117,102,46,85,110,105,110,116,101,114,112, 114,101,116,101,100,79,112,116,105,111,110,0,10,21,117,110, 105,110,116,101,114,112,114,101,116,101,100,95,111,112,116,105, 111,110,0,42,60,24,2,16,2,32,11,42,45,103,111,111, 103,108,101,46,112,114,111,116,111,98,117,102,46,85,110,105, 110,116,101,114,112,114,101,116,101,100,79,112,116,105,111,110, 46,78,97,109,101,80,97,114,116,0,10,5,110,97,109,101, 0,42,25,32,9,24,0,10,17,105,100,101,110,116,105,102, 105,101,114,95,118,97,108,117,101,0,16,3,42,27,32,4, 24,0,10,19,112,111,115,105,116,105,118,101,95,105,110,116, 95,118,97,108,117,101,0,16,4,42,27,32,3,24,0,10, 19,110,101,103,97,116,105,118,101,95,105,110,116,95,118,97, 108,117,101,0,16,5,42,21,32,1,24,0,10,13,100,111, 117,98,108,101,95,118,97,108,117,101,0,16,6,42,21,32, 12,24,0,10,13,115,116,114,105,110,103,95,118,97,108,117, 101,0,16,7,42,24,32,9,24,0,10,16,97,103,103,114, 101,103,97,116,101,95,118,97,108,117,101,0,16,8,42,18, 32,9,24,1,10,10,110,97,109,101,95,112,97,114,116,0, 16,1,42,21,32,8,24,1,10,13,105,115,95,101,120,116, 101,110,115,105,111,110,0,16,2,42,59,24,2,16,1,32, 11,42,40,103,111,111,103,108,101,46,112,114,111,116,111,98, 117,102,46,83,111,117,114,99,101,67,111,100,101,73,110,102, 111,46,76,111,99,97,116,105,111,110,0,10,9,108,111,99, 97,116,105,111,110,0,42,13,32,5,24,2,10,5,112,97, 116,104,0,16,1,42,13,32,5,24,2,10,5,115,112,97, 110,0,16,2,26,34,103,111,111,103,108,101,46,112,114,111, 116,111,98,117,102,46,70,105,108,101,68,101,115,99,114,105, 112,116,111,114,83,101,116,0,26,36,103,111,111,103,108,101, 46,112,114,111,116,111,98,117,102,46,70,105,108,101,68,101, 115,99,114,105,112,116,111,114,80,114,111,116,111,0,26,32, 103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, 68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, 26,47,103,111,111,103,108,101,46,112,114,111,116,111,98,117, 102,46,68,101,115,99,114,105,112,116,111,114,80,114,111,116, 111,46,69,120,116,101,110,115,105,111,110,82,97,110,103,101, 0,26,37,103,111,111,103,108,101,46,112,114,111,116,111,98, 117,102,46,70,105,101,108,100,68,101,115,99,114,105,112,116, 111,114,80,114,111,116,111,0,26,36,103,111,111,103,108,101, 46,112,114,111,116,111,98,117,102,46,69,110,117,109,68,101, 115,99,114,105,112,116,111,114,80,114,111,116,111,0,26,41, 103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, 69,110,117,109,86,97,108,117,101,68,101,115,99,114,105,112, 116,111,114,80,114,111,116,111,0,26,39,103,111,111,103,108, 101,46,112,114,111,116,111,98,117,102,46,83,101,114,118,105, 99,101,68,101,115,99,114,105,112,116,111,114,80,114,111,116, 111,0,26,38,103,111,111,103,108,101,46,112,114,111,116,111, 98,117,102,46,77,101,116,104,111,100,68,101,115,99,114,105, 112,116,111,114,80,114,111,116,111,0,26,28,103,111,111,103, 108,101,46,112,114,111,116,111,98,117,102,46,70,105,108,101, 79,112,116,105,111,110,115,0,26,31,103,111,111,103,108,101, 46,112,114,111,116,111,98,117,102,46,77,101,115,115,97,103, 101,79,112,116,105,111,110,115,0,26,29,103,111,111,103,108, 101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100, 79,112,116,105,111,110,115,0,26,28,103,111,111,103,108,101, 46,112,114,111,116,111,98,117,102,46,69,110,117,109,79,112, 116,105,111,110,115,0,26,33,103,111,111,103,108,101,46,112, 114,111,116,111,98,117,102,46,69,110,117,109,86,97,108,117, 101,79,112,116,105,111,110,115,0,26,31,103,111,111,103,108, 101,46,112,114,111,116,111,98,117,102,46,83,101,114,118,105, 99,101,79,112,116,105,111,110,115,0,26,30,103,111,111,103, 108,101,46,112,114,111,116,111,98,117,102,46,77,101,116,104, 111,100,79,112,116,105,111,110,115,0,26,36,103,111,111,103, 108,101,46,112,114,111,116,111,98,117,102,46,85,110,105,110, 116,101,114,112,114,101,116,101,100,79,112,116,105,111,110,0, 26,45,103,111,111,103,108,101,46,112,114,111,116,111,98,117, 102,46,85,110,105,110,116,101,114,112,114,101,116,101,100,79, 112,116,105,111,110,46,78,97,109,101,80,97,114,116,0,26, 31,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102, 46,83,111,117,114,99,101,67,111,100,101,73,110,102,111,0, 26,40,103,111,111,103,108,101,46,112,114,111,116,111,98,117, 102,46,83,111,117,114,99,101,67,111,100,101,73,110,102,111, 46,76,111,99,97,116,105,111,110,0, }; ================================================ FILE: code/EVA/server/server_share/pbc/map.cpp ================================================ #include "map.h" #include "alloc.h" #include #include struct _pbcM_ip_slot { int id; void * pointer; int next; }; struct map_ip { size_t array_size; void ** array; size_t hash_size; struct _pbcM_ip_slot * slot; }; struct _pbcM_si_slot { const char *key; size_t hash; int id; int next; }; struct map_si { size_t size; struct _pbcM_si_slot slot[1]; }; static size_t calc_hash(const char *name) { size_t len = strlen(name); size_t h = len; size_t step = (len>>5)+1; size_t i; for (i=len; i>=step; i-=step) h = h ^ ((h<<5)+(h>>2)+(size_t)name[i-1]); return h; } struct map_si * _pbcM_si_new(struct map_kv * table, int size) { size_t sz = sizeof(struct map_si) + (size-1) * sizeof(struct _pbcM_si_slot); struct map_si * ret = (struct map_si *)pbc_malloc(sz); memset(ret,0,sz); ret->size = (size_t)size; int empty = 0; int i; for (i=0;islot[hash]; if (slot->key == NULL) { slot->key = (const char *)table[i].pointer; slot->id = table[i].id; slot->hash = hash_full; } else { while(ret->slot[empty].key != NULL) { ++empty; } struct _pbcM_si_slot * empty_slot = &ret->slot[empty]; empty_slot->next = slot->next; slot->next = empty + 1; empty_slot->id = table[i].id; empty_slot->key = (const char *)table[i].pointer; empty_slot->hash = hash_full; } } return ret; } void _pbcM_si_delete(struct map_si *map) { pbc_free(map); } int _pbcM_si_query(struct map_si *map, const char *key, int *result) { size_t hash_full = calc_hash(key); size_t hash = hash_full % map->size; struct _pbcM_si_slot * slot = &map->slot[hash]; if (slot->key == NULL) { return 1; } for (;;) { if (slot->hash == hash_full && strcmp(slot->key, key) == 0) { *result = slot->id; return 0; } if (slot->next == 0) { return 1; } slot = &map->slot[slot->next-1]; } } static struct map_ip * _pbcM_ip_new_hash(struct map_kv * table, int size) { struct map_ip * ret = (struct map_ip *)pbc_malloc(sizeof(struct map_ip)); ret->array = NULL; ret->array_size = 0; ret->hash_size = (size_t)size; ret->slot = (struct _pbcM_ip_slot *)pbc_malloc(sizeof(struct _pbcM_ip_slot) * size); memset(ret->slot,0,sizeof(struct _pbcM_ip_slot) * size); int empty = 0; int i; for (i=0;islot[hash]; if (slot->pointer == NULL) { slot->pointer = table[i].pointer; slot->id = table[i].id; } else { while(ret->slot[empty].pointer != NULL) { ++empty; } struct _pbcM_ip_slot * empty_slot = &ret->slot[empty]; empty_slot->next = slot->next; slot->next = empty + 1; empty_slot->id = table[i].id; empty_slot->pointer = table[i].pointer; } } return ret; } struct map_ip * _pbcM_ip_new(struct map_kv * table, int size) { int i; int max = table[0].id; if (max > size * 2 || max < 0) return _pbcM_ip_new_hash(table,size); for (i=1;i max) { max = table[i].id; if (max > size * 2) return _pbcM_ip_new_hash(table,size); } } struct map_ip * ret = (struct map_ip *)pbc_malloc(sizeof(struct map_ip)); ret->hash_size = size; ret->slot = NULL; ret->array_size = max + 1; ret->array = (void **)pbc_malloc((max+1) * sizeof(void *)); memset(ret->array,0,(max+1) * sizeof(void *)); for (i=0;iarray[table[i].id] = table[i].pointer; } return ret; } void _pbcM_ip_delete(struct map_ip * map) { if (map) { pbc_free(map->array); pbc_free(map->slot); pbc_free(map); } } static void _inject(struct map_kv * table, struct map_ip *map) { if (map->array) { int n = 0; int i; for (i=0;i<(int)map->array_size;i++) { if (map->array[i]) { table[n].id = i; table[n].pointer = map->array[i]; ++ n; } } } else { int i; for (i=0;i<(int)map->hash_size;i++) { table[i].id = map->slot[i].id; table[i].pointer = map->slot[i].pointer; } } } struct map_ip * _pbcM_ip_combine(struct map_ip *a, struct map_ip *b) { int sz = (int)(a->hash_size + b->hash_size); struct map_kv * table = (struct map_kv *)pbc_malloc(sz * sizeof(struct map_kv)); memset(table , 0 , sz * sizeof(struct map_kv)); _inject(table, a); _inject(table + a->hash_size, b); struct map_ip * r = _pbcM_ip_new(table, sz); pbc_free(table); return r; } void * _pbcM_ip_query(struct map_ip * map, int id) { if (map == NULL) return NULL; if (map->array) { if (id>=0 && id<(int)map->array_size) return map->array[id]; return NULL; } int hash = (unsigned)id % map->hash_size; struct _pbcM_ip_slot * slot = &map->slot[hash]; for (;;) { if (slot->id == id) { return slot->pointer; } if (slot->next == 0) { return NULL; } slot = &map->slot[slot->next-1]; } } struct _pbcM_sp_slot { const char *key; size_t hash; void *pointer; int next; }; struct map_sp { size_t cap; size_t size; struct heap *heap; struct _pbcM_sp_slot * slot; }; struct map_sp * _pbcM_sp_new(int max , struct heap *h) { struct map_sp * ret = (struct map_sp *)HMALLOC(sizeof(struct map_sp)); int cap = 1; while (cap < max) { cap *=2; } ret->cap = cap; ret->size = 0; ret->slot = (struct _pbcM_sp_slot *)HMALLOC(ret->cap * sizeof(struct _pbcM_sp_slot)); memset(ret->slot,0,sizeof(struct _pbcM_sp_slot) * ret->cap); ret->heap = h; return ret; } void _pbcM_sp_delete(struct map_sp *map) { if (map && map->heap == NULL) { _pbcM_free(map->slot); _pbcM_free(map); } } static void _pbcM_sp_rehash(struct map_sp *map); static void _pbcM_sp_insert_hash(struct map_sp *map, const char *key, size_t hash_full, void * value) { if (map->cap > map->size) { size_t hash = hash_full & (map->cap-1); struct _pbcM_sp_slot * slot = &map->slot[hash]; if (slot->key == NULL) { slot->key = key; slot->pointer = value; slot->hash = hash_full; } else { int empty = (hash + 1) & (map->cap-1); while(map->slot[empty].key != NULL) { empty = (empty + 1) & (map->cap-1); } struct _pbcM_sp_slot * empty_slot = &map->slot[empty]; empty_slot->next = slot->next; slot->next = empty + 1; empty_slot->pointer = value; empty_slot->key = key; empty_slot->hash = hash_full; } map->size++; return; } _pbcM_sp_rehash(map); _pbcM_sp_insert_hash(map, key, hash_full, value); } static void _pbcM_sp_rehash(struct map_sp *map) { struct heap * h = map->heap; struct _pbcM_sp_slot * old_slot = map->slot; size_t size = map->size; map->size = 0; map->cap *= 2; map->slot = (struct _pbcM_sp_slot *)HMALLOC(sizeof(struct _pbcM_sp_slot)*map->cap); memset(map->slot,0,sizeof(struct _pbcM_sp_slot)*map->cap); size_t i; for (i=0;icap-1); struct _pbcM_sp_slot * slot = &map->slot[hash]; if (slot->key == NULL) { if (map->cap <= map->size) goto _rehash; slot->key = key; slot->hash = hash_full; map->size++; return &(slot->pointer); } else { for (;;) { if (slot->hash == hash_full && strcmp(slot->key, key) == 0) return &(slot->pointer); if (slot->next == 0) { break; } slot = &map->slot[slot->next-1]; } if (map->cap <= map->size) goto _rehash; int empty = (hash + 1) & (map->cap-1); while(map->slot[empty].key != NULL) { empty = (empty + 1) & (map->cap-1); } struct _pbcM_sp_slot * empty_slot = &map->slot[empty]; empty_slot->next = slot->next; slot->next = empty + 1; empty_slot->key = key; empty_slot->hash = hash_full; map->size++; return &(empty_slot->pointer); } _rehash: _pbcM_sp_rehash(map); return _pbcM_sp_query_insert_hash(map, key, hash_full); } void _pbcM_sp_insert(struct map_sp *map, const char *key, void * value) { _pbcM_sp_insert_hash(map,key,calc_hash(key),value); } void ** _pbcM_sp_query_insert(struct map_sp *map, const char *key) { return _pbcM_sp_query_insert_hash(map,key,calc_hash(key)); } void * _pbcM_sp_query(struct map_sp *map, const char *key) { if (map == NULL) return NULL; size_t hash_full = calc_hash(key); size_t hash = hash_full & (map->cap -1); struct _pbcM_sp_slot * slot = &map->slot[hash]; if (slot->key == NULL) return NULL; for (;;) { if (slot->hash == hash_full && strcmp(slot->key, key) == 0) { return slot->pointer; } if (slot->next == 0) { return NULL; } slot = &map->slot[slot->next-1]; } } void _pbcM_sp_foreach(struct map_sp *map, void (*func)(void *p)) { size_t i; for (i=0;icap;i++) { if (map->slot[i].pointer) { func(map->slot[i].pointer); } } } void _pbcM_sp_foreach_ud(struct map_sp *map, void (*func)(void *p, void *ud), void *ud) { size_t i; for (i=0;icap;i++) { if (map->slot[i].pointer) { func(map->slot[i].pointer,ud); } } } static int _find_first(struct map_sp *map) { size_t i; for (i=0;icap;i++) { if (map->slot[i].pointer) { return i; } } return -1; } static int _find_next(struct map_sp *map, const char *key) { size_t hash_full = calc_hash(key); size_t hash = hash_full & (map->cap -1); struct _pbcM_sp_slot * slot = &map->slot[hash]; if (slot->key == NULL) return -1; for (;;) { if (slot->hash == hash_full && strcmp(slot->key, key) == 0) { int i = slot - map->slot + 1; while(icap) { if (map->slot[i].pointer) { return i; } ++i; } return -1; } if (slot->next == 0) { return -1; } slot = &map->slot[slot->next-1]; } } void * _pbcM_sp_next(struct map_sp *map, const char ** key) { if (map == NULL) { *key = NULL; return NULL; } int idx; if (*key == NULL) { idx = _find_first(map); } else { idx = _find_next(map, *key); } if (idx < 0) { *key = NULL; return NULL; } *key = map->slot[idx].key; return map->slot[idx].pointer; } ================================================ FILE: code/EVA/server/server_share/pbc/map.h ================================================ #ifndef PROTOBUF_C_MAP_H #define PROTOBUF_C_MAP_H #include "alloc.h" struct map_ip; struct map_si; struct map_sp; struct map_kv { int id; void *pointer; }; struct map_si * _pbcM_si_new(struct map_kv * table, int size); int _pbcM_si_query(struct map_si *map, const char *key, int *result); void _pbcM_si_delete(struct map_si *map); struct map_ip * _pbcM_ip_new(struct map_kv * table, int size); struct map_ip * _pbcM_ip_combine(struct map_ip * a, struct map_ip * b); void * _pbcM_ip_query(struct map_ip * map, int id); void _pbcM_ip_delete(struct map_ip *map); struct map_sp * _pbcM_sp_new(int max, struct heap *h); void _pbcM_sp_insert(struct map_sp *map, const char *key, void * value); void * _pbcM_sp_query(struct map_sp *map, const char *key); void ** _pbcM_sp_query_insert(struct map_sp *map, const char *key); void _pbcM_sp_delete(struct map_sp *map); void _pbcM_sp_foreach(struct map_sp *map, void (*func)(void *p)); void _pbcM_sp_foreach_ud(struct map_sp *map, void (*func)(void *p, void *ud), void *ud); void * _pbcM_sp_next(struct map_sp *map, const char ** key); #endif ================================================ FILE: code/EVA/server/server_share/pbc/pattern.cpp ================================================ #include "alloc.h" #include "context.h" #include "varint.h" #include "pattern.h" #include "array.h" #include "proto.h" #include "map.h" #include #ifndef _MSC_VER #include #endif #include #include #include #include static void set_default_v(void * output, int ctype, pbc_var defv) { switch (ctype) { case CTYPE_INT32: *(uint32_t *)output = defv->integer.low; break; case CTYPE_INT64: *(uint64_t *)output = (uint64_t)defv->integer.low | (uint64_t)defv->integer.hi << 32; break; case CTYPE_DOUBLE: *(double *)output = defv->real; break; case CTYPE_FLOAT: *(float *)output = (float)defv->real; break; case CTYPE_BOOL: *(bool *)output = (defv->integer.low != 0); break; case CTYPE_INT8: *(uint8_t *)output = (uint8_t)defv->integer.low; break; case CTYPE_INT16: *(uint16_t *)output = (uint16_t)defv->integer.low; break; case CTYPE_VAR: *(union _pbc_var *)output = *defv; break; } } static void _pattern_set_default(struct _pattern_field *field, char *output) { if (field->ctype == CTYPE_ARRAY || field->ctype == CTYPE_PACKED) { struct _pbc_array *array = (struct _pbc_array *)(output + field->offset); _pbcA_open(array); } else if (field->ptype == PTYPE_ENUM) { pbc_var defv; defv->integer.low = field->defv->e.id; defv->integer.hi = 0; set_default_v(output + field->offset, field->ctype, defv); } set_default_v(output + field->offset, field->ctype, field->defv); } void pbc_pattern_set_default(struct pbc_pattern *pat, void *output) { int i; for (i=0;icount;i++) { _pattern_set_default(&pat->f[i], (char *)output); } } // pattern unpack static struct _pattern_field * bsearch_pattern(struct pbc_pattern *pat, int id) { int begin = 0; int end = pat->count; while (begin < end) { int mid = (begin + end)/2; struct _pattern_field * f = &pat->f[mid]; if (id == f->id) { return f; } if (id < f->id) { end = mid; } else { begin = mid + 1; } } return NULL; } static inline int write_real(int ctype, double v, void *out) { switch(ctype) { case CTYPE_DOUBLE: *(double *)out = v; return 0; case CTYPE_FLOAT: *(float *)out = (float)v; return 0; case CTYPE_VAR: ((union _pbc_var *)out)->real = v; return 0; } return -1; } static inline int write_longlong(int ctype, struct longlong *i, void *out) { switch(ctype) { case CTYPE_INT32: *(uint32_t *)out = i->low; return 0; case CTYPE_INT64: *(uint64_t *)out = (uint64_t)i->low | (uint64_t)i->hi << 32; return 0; case CTYPE_BOOL: *(bool *)out = (i->low !=0) ; return 0; case CTYPE_INT8: *(uint8_t *)out = (uint8_t)i->low; return 0; case CTYPE_INT16: *(uint8_t *)out = (uint16_t)i->low; return 0; case CTYPE_VAR: ((union _pbc_var *)out)->integer = *i; return 0; } return -1; } static inline int write_integer(int ctype, struct atom *a, void *out) { return write_longlong(ctype, &(a->v.i), out); } static int unpack_array(int ptype, char *buffer, struct atom *, pbc_array _array); int _pbcP_unpack_packed(uint8_t *buffer, int size, int ptype, pbc_array array) { pbc_var var; var->integer.hi = 0; int i; switch(ptype) { case PTYPE_DOUBLE: if (size % 8 != 0) return -1; for (i=0;ireal = u.d; _pbcA_push(array, var); } return size/8; case PTYPE_FLOAT: if (size % 4 != 0) return -1; for (i=0;ireal = (double)u.f; _pbcA_push(array, var); } return size/4; case PTYPE_FIXED32: case PTYPE_SFIXED32: if (size % 4 != 0) return -1; for (i=0;iinteger.low = (uint32_t)buffer[i] | (uint32_t)buffer[i+1] << 8 | (uint32_t)buffer[i+2] << 16 | (uint32_t)buffer[i+3] << 24; _pbcA_push(array, var); } return size/4; case PTYPE_FIXED64: case PTYPE_SFIXED64: if (size % 8 != 0) return -1; for (i=0;iinteger.low = (uint32_t)buffer[i] | (uint32_t)buffer[i+1] << 8 | (uint32_t)buffer[i+2] << 16 | (uint32_t)buffer[i+3] << 24; var->integer.hi = (uint32_t)buffer[i+4] | (uint32_t)buffer[i+5] << 8 | (uint32_t)buffer[i+6] << 16 | (uint32_t)buffer[i+7] << 24; _pbcA_push(array, var); } return size/8; case PTYPE_INT64: case PTYPE_UINT64: case PTYPE_INT32: case PTYPE_UINT32: case PTYPE_ENUM: // enum must be integer type in pattern mode case PTYPE_BOOL: { int n = 0; while (size > 0) { int len; if (size >= 10) { len = _pbcV_decode(buffer, &(var->integer)); } else { uint8_t temp[10]; memcpy(temp, buffer, size); len = _pbcV_decode(buffer, &(var->integer)); if (len > size) return -1; } _pbcA_push(array, var); buffer += len; size -= len; ++n; } return n; } case PTYPE_SINT32: { int n = 0; while (size > 0) { int len; if (size >= 10) { len = _pbcV_decode(buffer, &(var->integer)); _pbcV_dezigzag32(&(var->integer)); } else { uint8_t temp[10]; memcpy(temp, buffer, size); len = _pbcV_decode(buffer, &(var->integer)); if (len > size) return -1; _pbcV_dezigzag32(&(var->integer)); } _pbcA_push(array, var); buffer += len; size -= len; ++n; } return n; } case PTYPE_SINT64: { int n = 0; while (size > 0) { int len; if (size >= 10) { len = _pbcV_decode(buffer, &(var->integer)); _pbcV_dezigzag64(&(var->integer)); } else { uint8_t temp[10]; memcpy(temp, buffer, size); len = _pbcV_decode(buffer, &(var->integer)); if (len > size) return -1; _pbcV_dezigzag64(&(var->integer)); } _pbcA_push(array, var); buffer += len; size -= len; ++n; } return n; } } return -1; } static int unpack_field(int ctype, int ptype, char * buffer, struct atom * a, void *out) { if (ctype == CTYPE_ARRAY) { return unpack_array(ptype, buffer, a , (struct _pbc_array *)out); } if (ctype == CTYPE_PACKED) { return _pbcP_unpack_packed((uint8_t *)buffer + a->v.s.start, a->v.s.end - a->v.s.start, ptype, (struct _pbc_array *)out); } switch(ptype) { case PTYPE_DOUBLE: CHECK_BIT64(a, -1); return write_real(ctype, read_double(a), out); case PTYPE_FLOAT: CHECK_BIT32(a, -1); return write_real(ctype, read_float(a), out); case PTYPE_INT64: case PTYPE_UINT64: case PTYPE_INT32: case PTYPE_UINT32: case PTYPE_ENUM: // enum must be integer type in pattern mode case PTYPE_BOOL: CHECK_VARINT(a, -1); return write_integer(ctype, a , out); case PTYPE_FIXED32: case PTYPE_SFIXED32: CHECK_BIT32(a, -1); return write_integer(ctype, a , out); case PTYPE_FIXED64: case PTYPE_SFIXED64: CHECK_BIT64(a, -1); return write_integer(ctype, a , out); case PTYPE_SINT32: { CHECK_VARINT(a, -1); struct longlong temp = a->v.i; _pbcV_dezigzag32(&temp); return write_longlong(ctype, &temp , out); } case PTYPE_SINT64: { CHECK_LEND(a, -1); struct longlong temp = a->v.i; _pbcV_dezigzag64(&temp); return write_longlong(ctype, &temp , out); } case PTYPE_MESSAGE: CHECK_LEND(a, -1); ((union _pbc_var *)out)->m.buffer = buffer + a->v.s.start; ((union _pbc_var *)out)->m.len = a->v.s.end - a->v.s.start; return 0; case PTYPE_STRING: case PTYPE_BYTES: CHECK_LEND(a, -1); ((struct pbc_slice *)out)->buffer = buffer + a->v.s.start; ((struct pbc_slice *)out)->len = a->v.s.end - a->v.s.start; return 0; } return -1; } static int unpack_array(int ptype, char *buffer, struct atom * a, pbc_array _array) { pbc_var var; int r = unpack_field(CTYPE_VAR, ptype, buffer, a , var); if (r !=0 ) return r; _pbcA_push(_array , var); return 0; } void pbc_pattern_close_arrays(struct pbc_pattern *pat, void * data) { int i; for (i=0;icount;i++) { if (pat->f[i].ctype == CTYPE_ARRAY || pat->f[i].ctype == CTYPE_PACKED) { void *array = (char *)data + pat->f[i].offset; _pbcA_close((struct _pbc_array *)array); } } } static inline int _pack_wiretype(uint32_t wt, struct pbc_slice *s) { int len; if (s->len < 10) { uint8_t temp[10]; len = _pbcV_encode32(wt, temp); if (len > s->len) return -1; memcpy(s->buffer, temp, len); } else { len = _pbcV_encode32(wt, (uint8_t *)s->buffer); } s->buffer = (char *)s->buffer + len; s->len -= len; return len; } static inline int _pack_varint64(uint64_t i64, struct pbc_slice *s) { int len; if (s->len < 10) { uint8_t temp[10]; len = _pbcV_encode(i64, temp); if (len > s->len) return -1; memcpy(s->buffer, temp, len); } else { len = _pbcV_encode(i64, (uint8_t *)s->buffer); } s->buffer = (char *)s->buffer + len; s->len -= len; return len; } static inline int _pack_sint32(uint32_t v, struct pbc_slice *s) { int len; if (s->len < 10) { uint8_t temp[10]; len = _pbcV_zigzag32(v, temp); if (len > s->len) return -1; memcpy(s->buffer, temp, len); } else { len = _pbcV_zigzag32(v, (uint8_t *)s->buffer); } s->buffer = (char *)s->buffer + len; s->len -= len; return len; } static inline int _pack_sint64(uint64_t v, struct pbc_slice *s) { int len; if (s->len < 10) { uint8_t temp[10]; len = _pbcV_zigzag(v, temp); if (len > s->len) return -1; memcpy(s->buffer, temp, len); } else { len = _pbcV_zigzag(v, (uint8_t *)s->buffer); } s->buffer = (char *)s->buffer + len; s->len -= len; return len; } static inline void _fix32_encode(uint32_t v , uint8_t *buffer) { buffer[0] = (uint8_t) v; buffer[1] = (uint8_t) (v >> 8); buffer[2] = (uint8_t) (v >> 16); buffer[3] = (uint8_t) (v >> 24); } static inline void _fix64_encode(struct longlong *v , uint8_t *buffer) { _fix32_encode(v->low , buffer); _fix32_encode(v->hi, buffer + 4); } static int _pack_number(int ptype , int ctype , struct pbc_slice *s, void *input) { pbc_var var; if (ctype == CTYPE_VAR) { memcpy(var, input, sizeof(var)); } else { switch (ctype) { case CTYPE_INT32: var->integer.low = *(uint32_t *)input; var->integer.hi = 0; break; case CTYPE_INT64: { uint64_t v = *(uint64_t *)input; var->integer.low = (uint32_t) (v & 0xffffffff); var->integer.hi = (uint32_t) (v >> 32); break; } case CTYPE_INT16: var->integer.low = *(uint16_t *)input; var->integer.hi = 0; break; case CTYPE_INT8: var->integer.low = *(uint8_t *)input; var->integer.hi = 0; break; case CTYPE_BOOL: var->integer.low = *(bool *)input; var->integer.hi = 0; break; case CTYPE_DOUBLE: var->real = *(double *)input; break; case CTYPE_FLOAT: var->real = *(float *)input; break; } } switch(ptype) { case PTYPE_FIXED64: case PTYPE_SFIXED64: if (s->len < 8) return -1; _fix64_encode(&(var->integer), (uint8_t *)s->buffer); s->buffer = (char *)s->buffer + 8; s->len -= 8; return 8; case PTYPE_DOUBLE: if (s->len < 8) return -1; double_encode(var->real , (uint8_t *)s->buffer); s->buffer = (char *)s->buffer + 8; s->len -= 8; return 8; case PTYPE_FLOAT: if (s->len < 4) return -1; float_encode((float)var->real , (uint8_t *)s->buffer); s->buffer = (char *)s->buffer + 4; s->len -= 4; return 4; case PTYPE_FIXED32: case PTYPE_SFIXED32: if (s->len < 4) return -1; _fix32_encode(var->integer.low, (uint8_t *)s->buffer); s->buffer = (char *)s->buffer + 4; s->len -= 4; return 4; case PTYPE_UINT64: case PTYPE_INT64: case PTYPE_INT32: return _pack_varint64((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32, s); case PTYPE_UINT32: case PTYPE_BOOL: case PTYPE_ENUM: return _pack_wiretype(var->integer.low , s); case PTYPE_SINT32: return _pack_sint32(var->integer.low , s); case PTYPE_SINT64: return _pack_sint64((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , s); default: return -1; } } static int _pack_field(struct _pattern_field *pf , int ctype, struct pbc_slice *s, void *input) { int wiretype; int ret = 0; int len; struct pbc_slice * input_slice; struct pbc_slice string_slice; switch(pf->ptype) { case PTYPE_FIXED64: case PTYPE_SFIXED64: case PTYPE_DOUBLE: wiretype = WT_BIT64; goto _number; case PTYPE_FIXED32: case PTYPE_SFIXED32: case PTYPE_FLOAT: wiretype = WT_BIT32; goto _number; case PTYPE_UINT64: case PTYPE_INT64: case PTYPE_INT32: case PTYPE_BOOL: case PTYPE_UINT32: case PTYPE_ENUM: case PTYPE_SINT32: case PTYPE_SINT64: wiretype = WT_VARINT; goto _number; case PTYPE_STRING: wiretype = WT_LEND; input_slice = (struct pbc_slice *)input; if (input_slice->len >= 0) goto _string; string_slice.buffer = input_slice->buffer; string_slice.len = strlen((const char *)string_slice.buffer) - input_slice->len; input_slice = &string_slice; goto _string; case PTYPE_MESSAGE: case PTYPE_BYTES: wiretype = WT_LEND; goto _bytes; default: break; } return 0; _bytes: input_slice = (struct pbc_slice *)input; _string: len = _pack_wiretype(pf->id << 3 | WT_LEND , s); if (len < 0) { return len; } ret += len; len = _pack_wiretype(input_slice->len , s); if (len < 0) { return len; } ret += len; if (input_slice->len > s->len) return -1; memcpy(s->buffer , input_slice->buffer, input_slice->len); ret += input_slice->len; s->buffer = (char *)s->buffer + input_slice->len; s->len -= input_slice->len; return ret; _number: len = _pack_wiretype(pf->id << 3 | wiretype , s); if (len < 0) { return len; } ret += len; len = _pack_number(pf->ptype, ctype , s, input); if (len < 0) { return len; } ret += len; return ret; } static int _pack_repeated(struct _pattern_field *pf , struct pbc_slice *s, pbc_array array) { int n = pbc_array_size(array); int ret = 0; if (n>0) { int i; for (i=0;ilen - len < n * width) return -1; int i; for (i=0;iptype, CTYPE_VAR , s, _pbcA_index_p(array, i)); } return len + n * width; } static int _pack_packed_varint(struct _pattern_field *pf , struct pbc_slice *slice, pbc_array array) { struct pbc_slice s = * slice; int n = pbc_array_size(array); int estimate = n; int estimate_len = _pack_wiretype(estimate , &s); if (estimate_len < 0) { return -1; } int i; int packed_len = 0; for (i=0;iptype, CTYPE_VAR , &s, _pbcA_index_p(array, i)); if (len < 0) return -1; packed_len += len; } if (packed_len == estimate) { *slice = s; return packed_len + estimate_len; } uint8_t temp[10]; struct pbc_slice header_slice = { temp , 10 }; int header_len = _pack_wiretype(packed_len , &header_slice); if (header_len == estimate_len) { memcpy(slice->buffer , temp , header_len); *slice = s; return packed_len + estimate_len; } if (header_len + packed_len > slice->len) return -1; memmove((char *)slice->buffer + header_len , (char *)slice->buffer + estimate_len, packed_len); memcpy(slice->buffer , temp , header_len); slice->buffer = (char *)slice->buffer + packed_len + header_len; slice->len -= packed_len + header_len; return packed_len + header_len; } static int _pack_packed(struct _pattern_field *pf , struct pbc_slice *s, pbc_array array) { int n = pbc_array_size(array); if (n == 0) return 0; int ret = 0; int len; len = _pack_wiretype(pf->id << 3 | WT_LEND , s); if (len < 0) { return len; } ret += len; switch (pf->ptype) { case PTYPE_FIXED64: case PTYPE_SFIXED64: case PTYPE_DOUBLE: len = _pack_packed_fixed(pf, 8, s , array); if (len < 0) return len; break; case PTYPE_FIXED32: case PTYPE_SFIXED32: case PTYPE_FLOAT: len = _pack_packed_fixed(pf, 4, s , array); if (len < 0) return len; break; case PTYPE_UINT64: case PTYPE_INT64: case PTYPE_INT32: case PTYPE_BOOL: case PTYPE_UINT32: case PTYPE_ENUM: case PTYPE_SINT32: case PTYPE_SINT64: len = _pack_packed_varint(pf, s, array); if (len < 0) return len; break; } ret += len; return ret; } static bool _is_default(struct _pattern_field * pf, void * in) { switch (pf->ctype) { case CTYPE_INT64: { struct longlong * d64 = &pf->defv->integer; return ((uint64_t)d64->low | (uint64_t)d64->hi << 32) == *(uint64_t *)in; } case CTYPE_DOUBLE: return pf->defv->real == *(double *)in; case CTYPE_FLOAT: return (float)(pf->defv->real) == *(float *)in; case CTYPE_INT32: return pf->defv->integer.low == *(uint32_t *)in; case CTYPE_INT16: return (uint16_t)(pf->defv->integer.low) == *(uint16_t *)in; case CTYPE_INT8: return (uint8_t)(pf->defv->integer.low) == *(uint8_t *)in; case CTYPE_BOOL: if (pf->defv->integer.low) return *(bool *)in == true; else return *(bool *)in == false; } if (pf->ptype == PTYPE_STRING) { struct pbc_slice *slice = (struct pbc_slice *)in; if (slice->buffer == NULL) { return pf->defv->s.str[0] == '\0'; } int len = slice->len; if (len <= 0) { return strcmp(pf->defv->s.str, (const char *)slice->buffer) == 0; } return len == pf->defv->s.len && memcmp(pf->defv->s.str, slice->buffer, len)==0; } else if (pf->ptype == PTYPE_BYTES) { struct pbc_slice *slice = (struct pbc_slice *)in; if (slice->buffer == NULL) return true; } return false; } int pbc_pattern_pack(struct pbc_pattern *pat, void *input, struct pbc_slice * s) { struct pbc_slice slice = *s; int i; for (i=0;icount;i++) { struct _pattern_field * pf = &pat->f[i]; void * in = (char *)input + pf->offset; int len = 0; switch(pf->label) { case LABEL_OPTIONAL: if (_is_default(pf , in)) { break; } case LABEL_REQUIRED: len = _pack_field(pf, pf->ctype, &slice, in); break; case LABEL_REPEATED: len = _pack_repeated(pf, &slice , (struct _pbc_array *)in); break; case LABEL_PACKED: len = _pack_packed(pf, &slice , (struct _pbc_array *)in); break; } if (len < 0) { return len; } } int len = (char *)slice.buffer - (char *)s->buffer; int ret = s->len - len; s->len = len; return ret; } int pbc_pattern_unpack(struct pbc_pattern *pat, struct pbc_slice *s, void * output) { if (s->len == 0) { pbc_pattern_set_default(pat, output); return 0; } pbc_ctx _ctx; int r = _pbcC_open(_ctx, s->buffer, s->len); if (r <= 0) { pat->env->lasterror = "Pattern unpack open context error"; _pbcC_close(_ctx); return r-1; } struct context * ctx = (struct context *)_ctx; bool * field = (bool *)alloca(pat->count * sizeof(bool)); memset(field, 0, pat->count * sizeof(bool)); int i; int fc = 0; for (i=0;inumber;i++) { struct _pattern_field * f = bsearch_pattern(pat, ctx->a[i].wire_id >> 3); if (f) { int index = f - pat->f; if (field[index] == false) { field[index] = true; ++fc; if ((f->ctype == CTYPE_ARRAY || f->ctype == CTYPE_PACKED)) { struct _pbc_array *array = (struct _pbc_array *)((char *)output + f->offset); _pbcA_open(array); } } char * out = (char *)output + f->offset; if (unpack_field(f->ctype , f->ptype , ctx->buffer , &ctx->a[i], out) < 0) { int j; for (j=0;jcount;j++) { if (field[j] == true && (pat->f[j].ctype == CTYPE_ARRAY || pat->f[j].ctype == CTYPE_PACKED)) { void *array = (char *)output + pat->f[j].offset; _pbcA_close((struct _pbc_array *)array); } } _pbcC_close(_ctx); pat->env->lasterror = "Pattern unpack field error"; return -i-1; } } } _pbcC_close(_ctx); if (fc != pat->count) { for (i=0;icount;i++) { if (field[i] == false) { _pattern_set_default(&pat->f[i], (char *)output); } } } return 0; } /* format : key %type %f float %F double %d int32 %D int64 %b bool %h int16 %c int8 %s slice %a array */ static int _ctype(const char * ctype) { if (ctype[0]!='%') return -1; switch (ctype[1]) { case 'f': return CTYPE_FLOAT; case 'F': return CTYPE_DOUBLE; case 'd': return CTYPE_INT32; case 'D': return CTYPE_INT64; case 'b': return CTYPE_BOOL; case 'h': return CTYPE_INT16; case 'c': return CTYPE_INT8; case 's': return CTYPE_VAR; case 'a': return CTYPE_ARRAY; default: return -1; } } static int _ctype_size(const char *ctype) { switch (ctype[1]) { case 'f': return sizeof(float); case 'F': return sizeof(double); case 'd': return sizeof(int32_t); case 'D': return sizeof(int64_t); case 'b': return sizeof(bool); case 'h': return sizeof(int16_t); case 'c': return sizeof(int8_t); case 's': return sizeof(struct pbc_slice); case 'a': return sizeof(pbc_array); default: return 0; } } static const char * _copy_string(const char *format , char ** temp) { char * output = *temp; while (*format == ' ' || *format == '\t' || *format == '\n' || *format == '\r') { ++format; } while (*format != '\0' && *format != ' ' && *format != '\t' && *format != '\n' && *format != '\r') { *output = *format; ++output; ++format; } *output = '\0'; ++output; *temp = output; return format; } static int _scan_pattern(const char * format , char * temp) { int n = 0; for(;;) { format = _copy_string(format , &temp); if (format[0] == '\0') return 0; ++n; format = _copy_string(format , &temp); if (format[0] == '\0') return n; } } static int _comp_field(const void * a, const void * b) { const struct _pattern_field * fa = (const struct _pattern_field *)a; const struct _pattern_field * fb = (const struct _pattern_field *)b; return fa->id - fb->id; } struct pbc_pattern * _pbcP_new(struct pbc_env * env, int n) { size_t sz = sizeof(struct pbc_pattern) + (sizeof(struct _pattern_field)) * (n-1); struct pbc_pattern * ret = (struct pbc_pattern *)pbc_malloc(sz); memset(ret, 0 , sz); ret->count = n; ret->env = env; return ret; } static int _check_ctype(struct _field * field, struct _pattern_field *f) { if (field->label == LABEL_REPEATED) { return f->ctype != CTYPE_ARRAY; } if (field->label == LABEL_PACKED) { return f->ctype != CTYPE_PACKED; } if (field->type == PTYPE_STRING || field->type == PTYPE_MESSAGE || field->type == PTYPE_BYTES) { return f->ctype != CTYPE_VAR; } if (field->type == PTYPE_FLOAT || field->type == PTYPE_DOUBLE) { return !(f->ctype == CTYPE_DOUBLE || f->ctype == CTYPE_FLOAT); } if (field->type == PTYPE_ENUM) { return !(f->ctype == CTYPE_INT8 || f->ctype == CTYPE_INT8 || f->ctype == CTYPE_INT16 || f->ctype == CTYPE_INT32 || f->ctype == CTYPE_INT64); } return f->ctype == CTYPE_VAR || f->ctype == CTYPE_ARRAY || f->ctype == CTYPE_PACKED || f->ctype == CTYPE_DOUBLE || f->ctype == CTYPE_FLOAT; } struct pbc_pattern * _pattern_new(struct _message *m, const char *format) { int len = strlen(format); char * temp = (char *)alloca(len+1); int n = _scan_pattern(format, temp); struct pbc_pattern * pat = _pbcP_new(m->env, n); int i; const char *ptr = temp; int offset = 0; for (i=0;if[i]); struct _field * field = (struct _field *)_pbcM_sp_query(m->name, ptr); if (field == NULL) { m->env->lasterror = "Pattern @new query none exist field"; goto _error; } f->id = field->id; f->ptype = field->type; *f->defv = *field->default_v; f->offset = offset; f->label = field->label; ptr += strlen(ptr) + 1; f->ctype = _ctype(ptr); if (f->ctype < 0) { m->env->lasterror = "Pattern @new use an invalid ctype"; goto _error; } if (f->ctype == CTYPE_ARRAY && field->label == LABEL_PACKED) { f->ctype = CTYPE_PACKED; } if (_check_ctype(field, f)) { m->env->lasterror = "Pattern @new ctype check error"; goto _error; } offset += _ctype_size(ptr); ptr += strlen(ptr) + 1; } pat->count = n; qsort(pat->f , n , sizeof(struct _pattern_field), _comp_field); return pat; _error: pbc_free(pat); return NULL; } struct pbc_pattern * pbc_pattern_new(struct pbc_env * env , const char * message, const char * format, ... ) { struct _message *m = _pbcP_get_message(env, message); if (m==NULL) { env->lasterror = "Pattern new can't find proto"; return NULL; } if (format[0]=='@') { return _pattern_new(m , format+1); } int len = strlen(format); char * temp = (char *)alloca(len+1); int n = _scan_pattern(format, temp); struct pbc_pattern * pat = _pbcP_new(env, n); int i; va_list ap; va_start(ap , format); const char *ptr = temp; for (i=0;if[i]); struct _field * field = (struct _field *)_pbcM_sp_query(m->name, ptr); if (field == NULL) { env->lasterror = "Pattern new query none exist field"; goto _error; } f->id = field->id; f->ptype = field->type; *f->defv = *field->default_v; f->offset = va_arg(ap, int); f->label = field->label; ptr += strlen(ptr) + 1; f->ctype = _ctype(ptr); if (f->ctype < 0) { env->lasterror = "Pattern new use an invalid ctype"; goto _error; } if (f->ctype == CTYPE_ARRAY && field->label == LABEL_PACKED) { f->ctype = CTYPE_PACKED; } if (_check_ctype(field, f)) { env->lasterror = "Pattern new ctype check error"; goto _error; } ptr += strlen(ptr) + 1; } va_end(ap); pat->count = n; qsort(pat->f , n , sizeof(struct _pattern_field), _comp_field); return pat; _error: pbc_free(pat); return NULL; } void pbc_pattern_delete(struct pbc_pattern * pat) { pbc_free(pat); } ================================================ FILE: code/EVA/server/server_share/pbc/pattern.h ================================================ #ifndef PROTOBUF_C_PATTERN_H #define PROTOBUF_C_PATTERN_H #include "pbc.h" #include "context.h" #include "array.h" struct _pattern_field { int id; int offset; int ptype; int ctype; int label; pbc_var defv; }; struct pbc_pattern { struct pbc_env * env; int count; struct _pattern_field f[1]; }; struct pbc_pattern * _pbcP_new(struct pbc_env * env, int n); int _pbcP_unpack_packed(uint8_t *buffer, int size, int ptype, pbc_array array); #endif ================================================ FILE: code/EVA/server/server_share/pbc/pbc-lua53.cpp ================================================ #ifdef __cplusplus extern "C" { #endif #include "lua.h" #include "lualib.h" #include "lauxlib.h" #ifdef __cplusplus } #endif #if defined(__APPLE__) #include #else #include #endif #ifndef _MSC_VER #include #else #define alloca _alloca #endif #include #include #include #include "pbc.h" static inline void * checkuserdata(lua_State *L, int index) { void * ud = lua_touserdata(L,index); if (ud == NULL) { luaL_error(L, "userdata %d is nil",index); } return ud; } static int _env_new(lua_State *L) { struct pbc_env * env = pbc_new(); lua_pushlightuserdata(L, env); return 1; } static int _env_register(lua_State *L) { struct pbc_env * env = (struct pbc_env *)checkuserdata(L,1); size_t sz = 0; const char * buffer = luaL_checklstring(L, 2 , &sz); struct pbc_slice slice; slice.buffer = (void *)buffer; slice.len = (int)sz; int ret = pbc_register(env, &slice); if (ret) { return luaL_error(L, "register fail"); } return 0; } static int _env_enum_id(lua_State *L) { struct pbc_env * env = (struct pbc_env *)checkuserdata(L,1); size_t sz = 0; const char* enum_type = luaL_checklstring(L, 2, &sz); const char* enum_name = luaL_checklstring(L, 3, &sz); int32_t enum_id = pbc_enum_id(env, enum_type, enum_name); if (enum_id < 0) return 0; lua_pushinteger(L, enum_id); return 1; } static int _rmessage_new(lua_State *L) { struct pbc_env * env = (struct pbc_env *)checkuserdata(L,1); const char * type_name = luaL_checkstring(L,2); struct pbc_slice slice; if (lua_isstring(L,3)) { size_t sz = 0; slice.buffer = (void *)lua_tolstring(L,3,&sz); slice.len = (int)sz; } else { slice.buffer = lua_touserdata(L,3); slice.len = luaL_checkinteger(L,4); } struct pbc_rmessage * m = pbc_rmessage_new(env, type_name, &slice); if (m==NULL) return 0; lua_pushlightuserdata(L,m); return 1; } static int _rmessage_delete(lua_State *L) { struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); pbc_rmessage_delete(m); return 0; } static int _rmessage_int(lua_State *L) { struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); const char * key = luaL_checkstring(L,2); int index = luaL_checkinteger(L,3); uint32_t hi,low; low = pbc_rmessage_integer(m, key, index, &hi); int64_t v = (int64_t)((uint64_t)hi << 32 | (uint64_t)low); lua_pushinteger(L,v); return 1; } static int _rmessage_real(lua_State *L) { struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); const char * key = luaL_checkstring(L,2); int index = luaL_checkinteger(L,3); double v = pbc_rmessage_real(m, key, index); lua_pushnumber(L,v); return 1; } static int _rmessage_string(lua_State *L) { struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); const char * key = luaL_checkstring(L,2); int index = lua_tointeger(L,3); int sz = 0; const char * v = pbc_rmessage_string(m,key,index,&sz); lua_pushlstring(L,v,sz); return 1; } static int _rmessage_message(lua_State *L) { struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); const char * key = luaL_checkstring(L,2); int index = lua_tointeger(L,3); struct pbc_rmessage * v = pbc_rmessage_message(m,key,index); lua_pushlightuserdata(L,v); return 1; } static int _rmessage_size(lua_State *L) { struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); const char * key = luaL_checkstring(L,2); int sz = pbc_rmessage_size(m, key); lua_pushinteger(L, sz); return 1; } static int _env_type(lua_State *L) { lua_settop(L,3); struct pbc_env * env = (struct pbc_env *)checkuserdata(L,1); const char * type_name = luaL_checkstring(L,2); if (lua_isnil(L,3)) { int ret = pbc_type(env, type_name, NULL, NULL); lua_pushboolean(L,ret); return 1; } const char * key = luaL_checkstring(L,3); const char * type = NULL; int ret = pbc_type(env, type_name, key, &type); lua_pushinteger(L,ret); if (type == NULL) { return 1; } { lua_pushstring(L, type); return 2; } } static int _wmessage_new(lua_State *L) { struct pbc_env * env = (struct pbc_env *)checkuserdata(L,1); const char * type_name = luaL_checkstring(L,2); struct pbc_wmessage * ret = pbc_wmessage_new(env, type_name); lua_pushlightuserdata(L,ret); return 1; } static int _wmessage_delete(lua_State *L) { struct pbc_wmessage * m = (struct pbc_wmessage *)lua_touserdata(L,1); pbc_wmessage_delete(m); return 0; } static int _wmessage_real(lua_State *L) { struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); const char * key = luaL_checkstring(L,2); double number = luaL_checknumber(L,3); pbc_wmessage_real(m, key, number); return 0; } static int _wmessage_string(lua_State *L) { struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); const char * key = luaL_checkstring(L,2); size_t len = 0; const char * v = luaL_checklstring(L,3,&len); int err = pbc_wmessage_string(m, key, v, (int)len); if (err) { return luaL_error(L, "Write string error : %s", v); } return 0; } static int _wmessage_message(lua_State *L) { struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); const char * key = luaL_checkstring(L,2); struct pbc_wmessage * ret = pbc_wmessage_message(m, key); lua_pushlightuserdata(L, ret); return 1; } static int _wmessage_int(lua_State *L) { struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); const char * key = luaL_checkstring(L,2); int64_t number; // compat float for some historical reasons. if (lua_isinteger(L, 3)) { number = lua_tointeger(L,3); } else { number = (int64_t)lua_tonumber(L,3); } uint32_t hi = (uint32_t)(number >> 32); pbc_wmessage_integer(m, key, (uint32_t)number, hi); return 0; } static int _wmessage_buffer(lua_State *L) { struct pbc_slice slice; struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); pbc_wmessage_buffer(m , &slice); lua_pushlightuserdata(L, slice.buffer); lua_pushinteger(L, slice.len); return 2; } static int _wmessage_buffer_string(lua_State *L) { struct pbc_slice slice; struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); pbc_wmessage_buffer(m , &slice); lua_pushlstring(L, (const char *)slice.buffer, slice.len); return 1; } /* lightuserdata env */ static int _last_error(lua_State *L) { struct pbc_env * env = (struct pbc_env *)checkuserdata(L, 1); const char * err = pbc_error(env); lua_pushstring(L,err); return 1; } /* lightuserdata env string message string format */ static int _pattern_new(lua_State *L) { struct pbc_env * env = (struct pbc_env *)checkuserdata(L, 1); const char * message = luaL_checkstring(L,2); const char * format = luaL_checkstring(L,3); struct pbc_pattern * pat = pbc_pattern_new(env, message, format); if (pat == NULL) { return luaL_error(L, "create patten %s (%s) failed", message , format); } lua_pushlightuserdata(L,pat); return 1; } static int _pattern_delete(lua_State *L) { struct pbc_pattern * pat = (struct pbc_pattern *)lua_touserdata(L,1); pbc_pattern_delete(pat); return 0; } static void * _push_value(lua_State *L, char * ptr, char type) { switch(type) { case 'd': { uint64_t v = *(uint64_t*)ptr; ptr += 8; lua_pushinteger(L, v); break; } case 'i': { int32_t v = *(int32_t*)ptr; ptr += 4; lua_pushinteger(L,v); break; } case 'b': { int32_t v = *(int32_t*)ptr; ptr += 4; lua_pushboolean(L,v); break; } case 'r': { double v = *(double *)ptr; ptr += 8; lua_pushnumber(L,v); break; } case 's': { struct pbc_slice * slice = (struct pbc_slice *)ptr; lua_pushlstring(L,(const char *)slice->buffer, slice->len); ptr += sizeof(struct pbc_slice); break; } case 'm': { struct pbc_slice * slice = (struct pbc_slice *)ptr; lua_createtable(L,2,0); lua_pushlightuserdata(L, slice->buffer); lua_rawseti(L,-2,1); lua_pushinteger(L,slice->len); lua_rawseti(L,-2,2); ptr += sizeof(struct pbc_slice); break; } } return ptr; } static void _push_array(lua_State *L, pbc_array array, char type, int index) { switch (type) { case 'I': { int v = pbc_array_integer(array, index, NULL); lua_pushinteger(L, v); break; } case 'D': { uint32_t hi = 0; uint32_t low = pbc_array_integer(array, index, &hi); uint64_t v = (uint64_t)hi << 32 | (uint64_t)low; lua_pushinteger(L, v); break; } case 'B': { int v = pbc_array_integer(array, index, NULL); lua_pushboolean(L, v); break; } case 'X': { uint32_t hi = 0; uint32_t low = pbc_array_integer(array, index, &hi); uint64_t v = (uint64_t)low | (uint64_t)hi << 32; lua_pushlstring(L, (char *)&v, 8); break; } case 'R': { double v = pbc_array_real(array, index); lua_pushnumber(L, v); break; } case 'S': { struct pbc_slice * slice = pbc_array_slice(array, index); lua_pushlstring(L, (const char *)slice->buffer,slice->len); break; } case 'M': { struct pbc_slice * slice = pbc_array_slice(array, index); lua_createtable(L,2,0); lua_pushlightuserdata(L,slice->buffer); lua_rawseti(L,-2,1); lua_pushinteger(L,slice->len); lua_rawseti(L,-2,2); break; } } lua_rawseti(L,-2,index+1); } /* lightuserdata pattern string format "ixrsmb" integer size lightuserdata buffer integer buffer_len */ static int _pattern_unpack(lua_State *L) { struct pbc_pattern * pat = (struct pbc_pattern *)checkuserdata(L, 1); if (pat == NULL) { return luaL_error(L, "unpack pattern is NULL"); } size_t format_sz = 0; const char * format = lua_tolstring(L,2,&format_sz); int size = lua_tointeger(L,3); struct pbc_slice slice; if (lua_isstring(L,4)) { size_t buffer_len = 0; const char *buffer = luaL_checklstring(L,4,&buffer_len); slice.buffer = (void *)buffer; slice.len = buffer_len; } else { if (!lua_isuserdata(L,4)) { return luaL_error(L, "Need a userdata"); } slice.buffer = lua_touserdata(L,4); slice.len = luaL_checkinteger(L,5); } char * temp = (char *)alloca(size); int ret = pbc_pattern_unpack(pat, &slice, temp); if (ret < 0) { return 0; } lua_checkstack(L, format_sz + 3); int i; char * ptr = temp; bool array = false; for (i=0;i= 'a' && type <='z') { ptr = (char *)_push_value(L,ptr,type); } else { array = true; int n = pbc_array_size((struct _pbc_array *)ptr); lua_createtable(L,n,0); int j; for (j=0;jbuffer = (void*)str; slice->len = sz; return ptr + sizeof(struct pbc_slice); } case 'm': { struct pbc_slice * slice = (struct pbc_slice *)ptr; if (lua_istable(L,index)) { lua_rawgeti(L,index,1); slice->buffer = lua_touserdata(L,-1); lua_rawgeti(L,index,2); slice->len = lua_tointeger(L,-1); lua_pop(L,2); } else { size_t sz = 0; const char * buffer = luaL_checklstring(L, index, &sz); slice->buffer = (void *)buffer; slice->len = sz; } return ptr + sizeof(struct pbc_slice); } default: luaL_error(L,"unknown format %c", type); return ptr; } } static void _get_array_value(lua_State *L, pbc_array array, char type) { switch(type) { case 'I': { int32_t v = luaL_checkinteger(L, -1); uint32_t hi = 0; if (v<0) { hi = ~0; } pbc_array_push_integer(array, v, hi); break; } case 'D' : { uint64_t v = (uint64_t)luaL_checknumber(L, -1); pbc_array_push_integer(array, (uint32_t)v, (uint32_t)(v >> 32)); break; } case 'B': { int32_t v = lua_toboolean(L, -1); pbc_array_push_integer(array, v ? 1: 0, 0); break; } case 'R': { double v = luaL_checknumber(L, -1); pbc_array_push_real(array, v); break; } case 'S': { size_t sz = 0; const char * str = luaL_checklstring(L, -1, &sz); struct pbc_slice slice; slice.buffer = (void*)str; slice.len = sz; pbc_array_push_slice(array, &slice); break; } case 'M': { struct pbc_slice slice; if (lua_istable(L,-1)) { lua_rawgeti(L,-1,1); slice.buffer = lua_touserdata(L,-1); lua_rawgeti(L,-2,2); slice.len = lua_tointeger(L,-1); lua_pop(L,2); } else { size_t sz = 0; const char * buffer = luaL_checklstring(L, -1, &sz); slice.buffer = (void *)buffer; slice.len = sz; } pbc_array_push_slice(array, &slice); break; } } } /* lightuserdata pattern string format "ixrsmbp" integer size */ static int _pattern_pack(lua_State *L) { struct pbc_pattern * pat = (struct pbc_pattern *)checkuserdata(L,1); if (pat == NULL) { return luaL_error(L, "pack pattern is NULL"); } size_t format_sz = 0; const char * format = lua_tolstring(L,2,&format_sz); int size = lua_tointeger(L,3); char * data = (char *)alloca(size); // A trick , we don't need default value. zero buffer for array and message field. // pbc_pattern_set_default(pat, data); memset(data, 0 , size); char * ptr = data; int i; for (i=0;i= 'a' && format[i] <='z') { ptr = _get_value(L, 4+i, ptr, format[i]); } else { if (!lua_istable(L,4+i)) { luaL_error(L,"need table for array type"); } int j; int n = lua_rawlen(L,4+i); for (j=0;ji.low); break; case PBC_REAL: lua_pushnumber(L, v->f); break; case PBC_BOOL: lua_pushboolean(L, v->i.low); break; case PBC_ENUM: lua_pushstring(L, v->e.name); break; case PBC_BYTES: case PBC_STRING: lua_pushlstring(L, (const char *)v->s.buffer , v->s.len); break; case PBC_MESSAGE: lua_pushvalue(L, -3); lua_pushstring(L, type_name); lua_pushlstring(L, (const char *)v->s.buffer , v->s.len); lua_call(L, 2 , 1); break; case PBC_FIXED64: case PBC_UINT: case PBC_INT64: { uint64_t v64 = (uint64_t)(v->i.hi) << 32 | (uint64_t)(v->i.low); lua_pushinteger(L,v64); break; } default: luaL_error(L, "Unknown type %s", type_name); break; } } /* -3: function decode -2: table key -1: table id */ static void decode_cb(void *ud, int type, const char * type_name, union pbc_value *v, int id, const char *key) { lua_State *L = (lua_State *)ud; if (key == NULL) { // undefined field return; } if (type & PBC_REPEATED) { push_value(L, type & ~PBC_REPEATED, type_name, v); new_array(L, id , key); // func.decode table.key table.id value array int n = lua_rawlen(L,-1); lua_insert(L, -2); // func.decode table.key table.id array value lua_rawseti(L, -2 , n+1); // func.decode table.key table.id array lua_pop(L,1); } else { push_value(L, type, type_name, v); lua_setfield(L, -3 , key); } } /* :1 lightuserdata env :2 function decode_message :3 table target :4 string type :5 string data :5 lightuserdata pointer :6 integer len table */ static int _decode(lua_State *L) { struct pbc_env * env = (struct pbc_env *)checkuserdata(L,1); luaL_checktype(L, 2 , LUA_TFUNCTION); luaL_checktype(L, 3 , LUA_TTABLE); const char * type = luaL_checkstring(L,4); struct pbc_slice slice; if (lua_type(L,5) == LUA_TSTRING) { size_t len; slice.buffer = (void *)luaL_checklstring(L,5,&len); slice.len = (int)len; } else { slice.buffer = checkuserdata(L,5); slice.len = luaL_checkinteger(L,6); } lua_pushvalue(L, 2); lua_pushvalue(L, 3); lua_newtable(L); int n = pbc_decode(env, type, &slice, decode_cb, L); if (n<0) { lua_pushboolean(L,0); } else { lua_pushboolean(L,1); } return 1; } struct gcobj { struct pbc_env * env; int size_pat; int cap_pat; struct pbc_pattern ** pat; int size_msg; int cap_msg; struct pbc_rmessage ** msg; }; static int _clear_gcobj(lua_State *L) { struct gcobj * obj = (struct gcobj *)lua_touserdata(L,1); int i; for (i=0;isize_pat;i++) { pbc_pattern_delete(obj->pat[i]); } for (i=0;isize_msg;i++) { pbc_rmessage_delete(obj->msg[i]); } free(obj->pat); free(obj->msg); obj->pat = NULL; obj->msg = NULL; if (obj->env) { pbc_delete(obj->env); obj->env = NULL; } return 0; } static int _gc(lua_State *L) { struct gcobj * obj; lua_settop(L,1); obj = (struct gcobj *)lua_newuserdata(L,sizeof(*obj)); obj->env = (struct pbc_env *)lua_touserdata(L,1); obj->size_pat = 0; obj->cap_pat = 4; obj->size_msg = 0; obj->cap_msg = 4; obj->pat = (struct pbc_pattern **)malloc(obj->cap_pat * sizeof(struct pbc_pattern *)); obj->msg = (struct pbc_rmessage **)malloc(obj->cap_msg * sizeof(struct pbc_rmessage *)); lua_createtable(L,0,1); lua_pushcfunction(L, _clear_gcobj); lua_setfield(L,-2,"__gc"); lua_setmetatable(L,-2); return 1; } static int _add_pattern(lua_State *L) { struct gcobj * obj = (struct gcobj *)lua_touserdata(L,1); if (obj->size_pat >= obj->cap_pat) { obj->cap_pat *= 2; obj->pat = (struct pbc_pattern **)realloc(obj->pat, obj->cap_pat * sizeof(struct pbc_pattern *)); } struct pbc_pattern * pat = (struct pbc_pattern *)lua_touserdata(L,2); obj->pat[obj->size_pat++] = pat; return 0; } static int _add_rmessage(lua_State *L) { struct gcobj * obj = (struct gcobj *)lua_touserdata(L,1); if (obj->size_msg >= obj->cap_msg) { obj->cap_msg *= 2; obj->msg = (struct pbc_rmessage **)realloc(obj->msg, obj->cap_msg * sizeof(struct pbc_rmessage *)); } struct pbc_rmessage * msg = (struct pbc_rmessage *)lua_touserdata(L,2); obj->msg[obj->size_msg++] = msg; return 0; } int luaopen_protobuf_c(lua_State *L) { luaL_Reg reg[] = { {"_env_new" , _env_new }, {"_env_register" , _env_register }, {"_env_type", _env_type }, {"_rmessage_new" , _rmessage_new }, {"_rmessage_delete" , _rmessage_delete }, {"_rmessage_int", _rmessage_int }, {"_rmessage_real" , _rmessage_real }, {"_rmessage_string" , _rmessage_string }, {"_rmessage_message" , _rmessage_message }, {"_rmessage_size" , _rmessage_size }, {"_wmessage_new", _wmessage_new }, {"_wmessage_delete", _wmessage_delete }, {"_wmessage_real", _wmessage_real }, {"_wmessage_string", _wmessage_string }, {"_wmessage_message", _wmessage_message }, {"_wmessage_int", _wmessage_int }, {"_wmessage_buffer", _wmessage_buffer }, {"_wmessage_buffer_string", _wmessage_buffer_string }, {"_pattern_new", _pattern_new }, {"_pattern_delete", _pattern_delete }, {"_pattern_size", _pattern_size }, {"_pattern_unpack", _pattern_unpack }, {"_pattern_pack", _pattern_pack }, {"_last_error", _last_error }, {"_decode", _decode }, {"_gc", _gc }, {"_add_pattern", _add_pattern }, {"_add_rmessage", _add_rmessage }, {"_env_enum_id", _env_enum_id}, {NULL,NULL}, }; luaL_checkversion(L); luaL_newlib(L, reg); return 1; } ================================================ FILE: code/EVA/server/server_share/pbc/pbc.h ================================================ #ifndef PROTOBUF_C_H #define PROTOBUF_C_H #include #include #define PBC_ARRAY_CAP 64 #define PBC_NOEXIST -1 #define PBC_INT 1 #define PBC_REAL 2 #define PBC_BOOL 3 #define PBC_ENUM 4 #define PBC_STRING 5 #define PBC_MESSAGE 6 #define PBC_FIXED64 7 #define PBC_FIXED32 8 #define PBC_BYTES 9 #define PBC_INT64 10 #define PBC_UINT 11 #define PBC_UNKNOWN 12 #define PBC_REPEATED 128 #ifdef __cplusplus extern "C" { #endif typedef struct _pbc_array { char _data[PBC_ARRAY_CAP]; } pbc_array[1]; struct pbc_slice { void *buffer; int len; }; struct pbc_pattern; struct pbc_env; struct pbc_rmessage; struct pbc_wmessage; struct pbc_env * pbc_new(void); void pbc_delete(struct pbc_env *); int pbc_register(struct pbc_env *, struct pbc_slice * slice); int pbc_type(struct pbc_env *, const char * type_name , const char * key , const char ** type); const char * pbc_error(struct pbc_env *); // callback api union pbc_value { struct { uint32_t low; uint32_t hi; } i; double f; struct pbc_slice s; struct { int id; const char * name; } e; }; typedef void (*pbc_decoder)(void *ud, int type, const char * type_name, union pbc_value *v, int id, const char *key); int pbc_decode(struct pbc_env * env, const char * type_name , struct pbc_slice * slice, pbc_decoder f, void *ud); // message api struct pbc_rmessage * pbc_rmessage_new(struct pbc_env * env, const char * type_name , struct pbc_slice * slice); void pbc_rmessage_delete(struct pbc_rmessage *); uint32_t pbc_rmessage_integer(struct pbc_rmessage * , const char *key , int index, uint32_t *hi); double pbc_rmessage_real(struct pbc_rmessage * , const char *key , int index); const char * pbc_rmessage_string(struct pbc_rmessage * , const char *key , int index, int *sz); struct pbc_rmessage * pbc_rmessage_message(struct pbc_rmessage *, const char *key, int index); int pbc_rmessage_size(struct pbc_rmessage *, const char *key); int pbc_rmessage_next(struct pbc_rmessage *, const char **key); struct pbc_wmessage * pbc_wmessage_new(struct pbc_env * env, const char *type_name); void pbc_wmessage_delete(struct pbc_wmessage *); // for negative integer, pass -1 to hi int pbc_wmessage_integer(struct pbc_wmessage *, const char *key, uint32_t low, uint32_t hi); int pbc_wmessage_real(struct pbc_wmessage *, const char *key, double v); int pbc_wmessage_string(struct pbc_wmessage *, const char *key, const char * v, int len); struct pbc_wmessage * pbc_wmessage_message(struct pbc_wmessage *, const char *key); void * pbc_wmessage_buffer(struct pbc_wmessage *, struct pbc_slice * slice); // array api int pbc_array_size(pbc_array); uint32_t pbc_array_integer(pbc_array array, int index, uint32_t *hi); double pbc_array_real(pbc_array array, int index); struct pbc_slice * pbc_array_slice(pbc_array array, int index); void pbc_array_push_integer(pbc_array array, uint32_t low, uint32_t hi); void pbc_array_push_slice(pbc_array array, struct pbc_slice *); void pbc_array_push_real(pbc_array array, double v); struct pbc_pattern * pbc_pattern_new(struct pbc_env * , const char * message, const char *format, ...); void pbc_pattern_delete(struct pbc_pattern *); // return unused bytes , -1 for error int pbc_pattern_pack(struct pbc_pattern *, void *input, struct pbc_slice * s); // <0 for error int pbc_pattern_unpack(struct pbc_pattern *, struct pbc_slice * s , void * output); void pbc_pattern_set_default(struct pbc_pattern * , void *data); void pbc_pattern_close_arrays(struct pbc_pattern *, void *data); int pbc_enum_id(struct pbc_env *env, const char *enum_type, const char *enum_name); #ifdef __cplusplus } #endif #endif ================================================ FILE: code/EVA/server/server_share/pbc/proto.cpp ================================================ #include "pbc.h" #include "proto.h" #include "pattern.h" #include "map.h" #include "alloc.h" #include "stringpool.h" #include "bootstrap.h" #include #include const char * pbc_error(struct pbc_env * p) { const char *err = p->lasterror; p->lasterror = ""; return err; } struct _message * _pbcP_get_message(struct pbc_env * p , const char *name) { return (struct _message *)_pbcM_sp_query(p->msgs, name); } struct pbc_env * pbc_new(void) { struct pbc_env * p = (struct pbc_env *)pbc_malloc(sizeof(*p)); p->files = _pbcM_sp_new(0 , NULL); p->enums = _pbcM_sp_new(0 , NULL); p->msgs = _pbcM_sp_new(0 , NULL); p->lasterror = ""; _pbcB_init(p); return p; } static void free_enum(void *p) { struct _enum * e = (struct _enum *)p; _pbcM_ip_delete(e->id); _pbcM_si_delete(e->name); pbc_free(p); } static void free_stringpool(void *p) { _pbcS_delete((struct _stringpool *)p); } static void free_msg(void *p) { struct _message * m = (struct _message *)p; if (m->id) _pbcM_ip_delete(m->id); pbc_free(m->def); _pbcM_sp_foreach(m->name, pbc_free); _pbcM_sp_delete(m->name); pbc_free(p); } void pbc_delete(struct pbc_env *p) { _pbcM_sp_foreach(p->enums, free_enum); _pbcM_sp_delete(p->enums); _pbcM_sp_foreach(p->msgs, free_msg); _pbcM_sp_delete(p->msgs); _pbcM_sp_foreach(p->files, free_stringpool); _pbcM_sp_delete(p->files); pbc_free(p); } struct _enum * _pbcP_push_enum(struct pbc_env * p, const char *name, struct map_kv *table, int sz) { void * check = _pbcM_sp_query(p->enums, name); if (check) return NULL; struct _enum * v = (struct _enum *)pbc_malloc(sizeof(*v)); v->key = name; v->id = _pbcM_ip_new(table,sz); v->name = _pbcM_si_new(table,sz); v->default_v->e.id = table[0].id; v->default_v->e.name = (const char *)table[0].pointer; _pbcM_sp_insert(p->enums, name , v); return v; } void _pbcP_push_message(struct pbc_env * p, const char *name, struct _field *f , pbc_array queue) { struct _message * m = (struct _message *)_pbcM_sp_query(p->msgs, name); if (m==NULL) { m = (struct _message *)pbc_malloc(sizeof(*m)); m->def = NULL; m->key = name; m->id = NULL; m->name = _pbcM_sp_new(0 , NULL); m->env = p; _pbcM_sp_insert(p->msgs, name, m); } struct _field * field = (struct _field *)pbc_malloc(sizeof(*field)); memcpy(field,f,sizeof(*f)); _pbcM_sp_insert(m->name, field->name, field); pbc_var atom; atom->m.buffer = field; if (f->type == PTYPE_MESSAGE || f->type == PTYPE_ENUM) { _pbcA_push(queue, atom); } } struct _iter { int count; struct map_kv * table; }; static void _count(void *p, void *ud) { struct _iter *iter = (struct _iter *)ud; iter->count ++; } static void _set_table(void *p, void *ud) { struct _field * field = (struct _field *)p; struct _iter *iter = (struct _iter *)ud; iter->table[iter->count].id = field->id; iter->table[iter->count].pointer = field; ++iter->count; } struct _message * _pbcP_init_message(struct pbc_env * p, const char *name) { struct _message * m = (struct _message *)_pbcM_sp_query(p->msgs, name); if (m == NULL) { m = (struct _message *)pbc_malloc(sizeof(*m)); m->def = NULL; m->key = name; m->id = NULL; m->name = _pbcM_sp_new(0 , NULL); m->env = p; _pbcM_sp_insert(p->msgs, name, m); return m; } if (m->id) { // extend message, delete old id map. _pbcM_ip_delete(m->id); } struct _iter iter = { 0, NULL }; _pbcM_sp_foreach_ud(m->name, _count, &iter); iter.table = (struct map_kv *)pbc_malloc(iter.count * sizeof(struct map_kv)); iter.count = 0; _pbcM_sp_foreach_ud(m->name, _set_table, &iter); m->id = _pbcM_ip_new(iter.table , iter.count); pbc_free(iter.table); return m; } int _pbcP_message_default(struct _message * m, const char * name, pbc_var defv) { struct _field * f= (struct _field *)_pbcM_sp_query(m->name, name); if (f==NULL) { // invalid key defv->p[0] = NULL; defv->p[1] = NULL; return -1; } *defv = *(f->default_v); return f->type; } int _pbcP_type(struct _field * field, const char ** type) { if (field == NULL) { return 0; } int ret = 0; switch (field->type) { case PTYPE_DOUBLE: case PTYPE_FLOAT: ret = PBC_REAL; break; case PTYPE_INT64: case PTYPE_SINT64: ret = PBC_INT64; break; case PTYPE_INT32: case PTYPE_SINT32: ret = PBC_INT; break; case PTYPE_UINT32: case PTYPE_UINT64: ret = PBC_UINT; break; case PTYPE_FIXED32: case PTYPE_SFIXED32: ret = PBC_FIXED32; break; case PTYPE_SFIXED64: case PTYPE_FIXED64: ret = PBC_FIXED64; break; case PTYPE_BOOL: ret = PBC_BOOL; break; case PTYPE_STRING: ret = PBC_STRING; break; case PTYPE_BYTES: ret = PBC_BYTES; break; case PTYPE_ENUM: ret = PBC_ENUM; if (type) { *type = field->type_name.e->key; } break; case PTYPE_MESSAGE: ret = PBC_MESSAGE; if (type) { *type = field->type_name.m->key; } break; default: return 0; } if (field->label == LABEL_REPEATED || field->label == LABEL_PACKED) { ret |= PBC_REPEATED; } return ret; } int pbc_type(struct pbc_env * p, const char * type_name , const char * key , const char ** type) { struct _message *m = _pbcP_get_message(p, type_name); if (m==NULL) { return 0; } if (key == NULL) { return PBC_NOEXIST; } struct _field * field = (struct _field *)_pbcM_sp_query(m->name, key); return _pbcP_type(field, type); } int pbc_enum_id(struct pbc_env *env, const char *enum_type, const char *enum_name) { struct _enum *enum_map = (struct _enum *)_pbcM_sp_query(env->enums, enum_type); if(!enum_map) { return -1; } int32_t enum_id = 0; int err = _pbcM_si_query(enum_map->name, enum_name, &enum_id); if(err) { return -1; } return enum_id; } ================================================ FILE: code/EVA/server/server_share/pbc/proto.h ================================================ #ifndef PROTOBUFC_PROTO_H #define PROTOBUFC_PROTO_H #include "pbc.h" #include "map.h" #include "array.h" #ifndef _MSC_VER #include #endif #include struct map_ip; struct map_si; struct map_sp; struct _message; struct _enum; #define LABEL_OPTIONAL 0 #define LABEL_REQUIRED 1 #define LABEL_REPEATED 2 #define LABEL_PACKED 3 struct _field { int id; const char *name; int type; int label; pbc_var default_v; union { const char * n; struct _message * m; struct _enum * e; } type_name; }; struct _message { const char * key; struct map_ip * id; // id -> _field struct map_sp * name; // string -> _field struct pbc_rmessage * def; // default message struct pbc_env * env; }; struct _enum { const char * key; struct map_ip * id; struct map_si * name; pbc_var default_v; }; struct pbc_env { struct map_sp * files; // string -> void * struct map_sp * enums; // string -> _enum struct map_sp * msgs; // string -> _message const char * lasterror; }; struct _message * _pbcP_init_message(struct pbc_env * p, const char *name); void _pbcP_push_message(struct pbc_env * p, const char *name, struct _field *f , pbc_array queue); struct _enum * _pbcP_push_enum(struct pbc_env * p, const char *name, struct map_kv *table, int sz ); int _pbcP_message_default(struct _message * m, const char * name, pbc_var defv); struct _message * _pbcP_get_message(struct pbc_env * p, const char *name); int _pbcP_type(struct _field * field, const char **type); #endif ================================================ FILE: code/EVA/server/server_share/pbc/register.cpp ================================================ #include "pbc.h" #include "proto.h" #include "alloc.h" #include "map.h" #include "bootstrap.h" #include "context.h" #include "stringpool.h" #include #include #ifdef _MSC_VER #define strtoll _strtoi64 #endif static const char * _concat_name(struct _stringpool *p , const char *prefix , int prefix_sz , const char *name , int name_sz, int *sz) { if (prefix_sz == 0) { if (sz) { *sz = name_sz; } return _pbcS_build(p , name, name_sz); } char * temp = (char *)alloca(name_sz + prefix_sz + 2); memcpy(temp,prefix,prefix_sz); temp[prefix_sz] = '.'; memcpy(temp+prefix_sz+1,name,name_sz); temp[name_sz + prefix_sz + 1] = '\0'; if (sz) { *sz = name_sz + prefix_sz + 1; } const char * ret = _pbcS_build(p , temp, name_sz + prefix_sz + 1); return ret; } static void _register_enum(struct pbc_env *p, struct _stringpool *pool, struct pbc_rmessage * enum_type, const char *prefix, int prefix_sz) { int field_count = pbc_rmessage_size(enum_type, "value"); struct map_kv *table = (struct map_kv *)pbc_malloc(field_count * sizeof(struct map_kv)); int i; for (i=0;itype == PTYPE_STRING || f->type == PTYPE_BYTES) { f->default_v->s.str = ""; f->default_v->s.len = 0; } else { f->default_v->integer.low = 0; f->default_v->integer.hi = 0; } return; } switch (f->type) { case PTYPE_DOUBLE: case PTYPE_FLOAT: f->default_v->real = strtod(value,NULL); break; case PTYPE_STRING: f->default_v->s.str = _pbcS_build(pool, value , sz); f->default_v->s.len = sz; break; case PTYPE_ENUM: // enum default value will be converted to f->default_v->e in bootstrap.c : set_field_one() f->default_v->s.str = value; f->default_v->s.len = sz; break; case PTYPE_BOOL: if (strcmp(value,"true") == 0) { f->default_v->integer.low = 1; } else { f->default_v->integer.low = 0; } f->default_v->integer.hi = 0; break; case PTYPE_UINT64: case PTYPE_INT64: case PTYPE_SFIXED64: case PTYPE_SINT64: { long long v = strtoll(value, NULL, 10); f->default_v->integer.low = (long) v; f->default_v->integer.hi = (long)(v >> 32); break; } case PTYPE_INT32: case PTYPE_FIXED32: case PTYPE_SFIXED32: case PTYPE_SINT32: { int low = strtol(value, NULL, 10); f->default_v->integer.low = low; if (low < 0) { f->default_v->integer.hi = -1; } else { f->default_v->integer.hi = 0; } break; } case PTYPE_UINT32: f->default_v->integer.low = strtoul(value, NULL, 10); f->default_v->integer.hi = 0; break; case PTYPE_BYTES: case PTYPE_MESSAGE: // bytes and message types have no default value f->default_v->m.buffer = 0; f->default_v->m.len = 0; break; default: f->default_v->integer.low = 0; f->default_v->integer.hi = 0; break; } } static void _register_field(struct pbc_rmessage * field, struct _field * f, struct _stringpool *pool) { f->id = pbc_rmessage_integer(field, "number", 0 , 0); f->type = pbc_rmessage_integer(field, "type", 0 , 0); // enum f->label = pbc_rmessage_integer(field, "label", 0, 0) - 1; // LABEL_OPTIONAL = 0 if (pbc_rmessage_size(field , "options") > 0) { struct pbc_rmessage * options = pbc_rmessage_message(field, "options" , 0); int packed = pbc_rmessage_integer(options , "packed" , 0 , NULL); if (packed) { f->label = LABEL_PACKED; } } f->type_name.n = pbc_rmessage_string(field, "type_name", 0 , NULL) +1; // abandon prefix '.' int vsz; const char * default_value = pbc_rmessage_string(field, "default_value", 0 , &vsz); _set_default(pool , f , f->type, default_value , vsz); } static void _register_extension(struct pbc_env *p, struct _stringpool *pool , const char * prefix, int prefix_sz, struct pbc_rmessage * msg, pbc_array queue) { int extension_count = pbc_rmessage_size(msg , "extension"); if (extension_count <= 0) return; int i; const char * last = NULL; for (i=0;ifiles, filename)) { return CHECK_FILE_EXIST; } int sz = pbc_rmessage_size(file, "dependency"); int i; for (i=0;ifiles, dname) == NULL) { return CHECK_FILE_DEPENDENCY; } } *fname = filename; return CHECK_FILE_OK; } static int _register_no_dependency(struct pbc_env * p,struct pbc_rmessage ** files , int n ) { int r = 0; int i; for (i=0;ifiles , filename, pool); _register(p,files[i],pool); files[i] = NULL; } break; } } return r; } int pbc_register(struct pbc_env * p, struct pbc_slice *slice) { struct pbc_rmessage * message = pbc_rmessage_new(p, "google.protobuf.FileDescriptorSet", slice); if (message == NULL) { p->lasterror = "register open google.protobuf.FileDescriptorSet fail"; return 1; } int n = pbc_rmessage_size(message, "file"); struct pbc_rmessage ** files = (struct pbc_rmessage **)alloca(n * sizeof(struct pbc_rmessage *)); int i; if (n == 0) { p->lasterror = "register empty"; pbc_rmessage_delete(message); return 1; } for (i=0;ilasterror = "register open fail"; pbc_rmessage_delete(message); return 1; } } int r = n; do { int rr = _register_no_dependency(p,files , n); if (rr == r) { p->lasterror = "register dependency error"; pbc_rmessage_delete(message); return 1; } r = rr; } while (r>0); pbc_rmessage_delete(message); return 0; } ================================================ FILE: code/EVA/server/server_share/pbc/rmessage.cpp ================================================ #include "pbc.h" #include "alloc.h" #include "map.h" #include "context.h" #include "proto.h" #include "pattern.h" #include "varint.h" #include #include struct pbc_rmessage { struct _message * msg; struct map_sp * index; // key -> struct value * struct heap * heap; }; union _var { pbc_var var; pbc_array array; struct pbc_rmessage message; } ; struct value { struct _field * type; union _var v; }; int pbc_rmessage_next(struct pbc_rmessage *m, const char **key) { struct value * v = (struct value *)_pbcM_sp_next(m->index, key); if (*key == NULL) { return 0; } return _pbcP_type(v->type, NULL); } #define SIZE_VAR (offsetof(struct value, v) + sizeof(pbc_var)) #define SIZE_ARRAY (offsetof(struct value, v) + sizeof(pbc_array)) #define SIZE_MESSAGE (offsetof(struct value, v) + sizeof(struct pbc_rmessage)) static struct value * read_string(struct heap *h, struct atom *a,struct _field *f, uint8_t *buffer) { const char * temp = (const char *) (buffer + a->v.s.start); int len = a->v.s.end - a->v.s.start; if (len > 0 && temp[len-1] == '\0') { struct value * v = (struct value *)_pbcH_alloc(h, SIZE_VAR); v->v.var->s.str = temp; v->v.var->s.len = len; return v; } else { struct value * v = (struct value *)_pbcH_alloc(h, SIZE_VAR + len + 1); memcpy(((char *)v) + SIZE_VAR , temp, len); *(((char *)v) + SIZE_VAR + len) = '\0'; v->v.var->s.str = ((char *)v) + SIZE_VAR; v->v.var->s.len = len; return v; } } static void read_string_var(struct heap *h, pbc_var var,struct atom *a,struct _field *f,uint8_t *buffer) { const char * temp = (const char *) (buffer + a->v.s.start); int len = a->v.s.end - a->v.s.start; if (len == 0) { var->s.str = ""; var->s.len = 0; } else if (temp[len-1] == '\0') { var->s.str = temp; var->s.len = len; } else { char * temp2 = (char *)_pbcH_alloc(h, len + 1); memcpy(temp2, temp, len); temp2[len]='\0'; var->s.str = temp2; var->s.len = -len; } } static void _pbc_rmessage_new(struct pbc_rmessage * ret , struct _message * type , void *buffer, int size, struct heap *h); static struct value * read_value(struct heap *h, struct _field *f, struct atom * a, uint8_t *buffer) { struct value * v; switch (f->type) { case PTYPE_DOUBLE: CHECK_BIT64(a,NULL); v = (struct value *)_pbcH_alloc(h, SIZE_VAR); v->v.var->real = read_double(a); break; case PTYPE_FLOAT: CHECK_BIT32(a,NULL); v = (struct value *)_pbcH_alloc(h, SIZE_VAR); v->v.var->real = (double) read_float(a); break; case PTYPE_ENUM: CHECK_VARINT(a,NULL); v = (struct value *)_pbcH_alloc(h, SIZE_VAR); v->v.var->e.id = a->v.i.low; v->v.var->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , a->v.i.low); break; case PTYPE_INT64: case PTYPE_UINT64: case PTYPE_INT32: case PTYPE_UINT32: case PTYPE_BOOL: CHECK_VARINT(a,NULL); v = (struct value *)_pbcH_alloc(h, SIZE_VAR); v->v.var->integer = a->v.i; break; case PTYPE_FIXED32: case PTYPE_SFIXED32: CHECK_BIT32(a,NULL); v = (struct value *)_pbcH_alloc(h, SIZE_VAR); v->v.var->integer = a->v.i; break; case PTYPE_FIXED64: case PTYPE_SFIXED64: CHECK_BIT64(a,NULL); v = (struct value *)_pbcH_alloc(h, SIZE_VAR); v->v.var->integer = a->v.i; break; case PTYPE_SINT32: CHECK_VARINT(a,NULL); v = (struct value *)_pbcH_alloc(h, SIZE_VAR); v->v.var->integer = a->v.i; _pbcV_dezigzag32(&(v->v.var->integer)); break; case PTYPE_SINT64: CHECK_VARINT(a,NULL); v = (struct value *)_pbcH_alloc(h, SIZE_VAR); v->v.var->integer = a->v.i; _pbcV_dezigzag64(&(v->v.var->integer)); break; case PTYPE_STRING: CHECK_LEND(a,NULL); v = read_string(h,a,f,buffer); break; case PTYPE_BYTES: CHECK_LEND(a,NULL); v = (struct value *)_pbcH_alloc(h, SIZE_VAR); v->v.var->s.str = (const char *)(buffer + a->v.s.start); v->v.var->s.len = a->v.s.end - a->v.s.start; break; case PTYPE_MESSAGE: CHECK_LEND(a,NULL); v = (struct value *)_pbcH_alloc(h, SIZE_MESSAGE); _pbc_rmessage_new(&(v->v.message), f->type_name.m , buffer + a->v.s.start , a->v.s.end - a->v.s.start,h); break; default: return NULL; } v->type = f; return v; } static void push_value_packed(struct _message * type, pbc_array array, struct _field *f, struct atom * aa, uint8_t *buffer) { int n = _pbcP_unpack_packed((uint8_t *)buffer + aa->v.s.start, aa->v.s.end - aa->v.s.start, f->type , array); if (n<=0) { // todo : error type->env->lasterror = "Unpack packed field error"; return; } if (f->type == PTYPE_ENUM) { int i; for (i=0;iinteger.low; v->e.id = id; v->e.name = (const char*)_pbcM_ip_query(f->type_name.e->id , id); } } } static void push_value_array(struct heap *h, pbc_array array, struct _field *f, struct atom * a, uint8_t *buffer) { pbc_var v; switch (f->type) { case PTYPE_DOUBLE: v->real = read_double(a); break; case PTYPE_FLOAT: v->real = (double) read_float(a); break; case PTYPE_ENUM: v->e.id = a->v.i.low; v->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , a->v.i.low); break; case PTYPE_INT64: case PTYPE_UINT64: case PTYPE_INT32: case PTYPE_UINT32: case PTYPE_FIXED32: case PTYPE_FIXED64: case PTYPE_SFIXED32: case PTYPE_SFIXED64: case PTYPE_BOOL: v->integer = a->v.i; break; case PTYPE_SINT32: v->integer = a->v.i; _pbcV_dezigzag32(&(v->integer)); break; case PTYPE_SINT64: v->integer = a->v.i; _pbcV_dezigzag64(&(v->integer)); break; case PTYPE_STRING: CHECK_LEND(a, ); read_string_var(h,v,a,f,buffer); break; case PTYPE_BYTES: CHECK_LEND(a, ); v->s.str = (const char *)(buffer + a->v.s.start); v->s.len = a->v.s.end - a->v.s.start; break; case PTYPE_MESSAGE: { CHECK_LEND(a, ); struct pbc_rmessage message; _pbc_rmessage_new(&message, f->type_name.m , buffer + a->v.s.start , a->v.s.end - a->v.s.start,h); if (message.msg == NULL) { return; } v->p[0] = message.msg; v->p[1] = message.index; break; } default: return; } _pbcA_push(array,v); } static void _pbc_rmessage_new(struct pbc_rmessage * ret , struct _message * type , void *buffer, int size , struct heap *h) { if (size == 0) { ret->msg = type; ret->index = _pbcM_sp_new(0 , h); ret->heap = h; return; } pbc_ctx _ctx; int count = _pbcC_open(_ctx,buffer,size); if (count <= 0) { type->env->lasterror = "rmessage decode context error"; memset(ret , 0, sizeof(*ret)); return; } struct context * ctx = (struct context *)_ctx; ret->msg = type; ret->index = _pbcM_sp_new(count, h); ret->heap = h; int i; for (i=0;inumber;i++) { int id = ctx->a[i].wire_id >> 3; struct _field * f = (struct _field *)_pbcM_ip_query(type->id , id); if (f) { if (f->label == LABEL_REPEATED || f->label == LABEL_PACKED) { struct value * v; void ** vv = _pbcM_sp_query_insert(ret->index, f->name); if (*vv == NULL) { v = (struct value *)_pbcH_alloc(h, SIZE_ARRAY); v->type = f; _pbcA_open_heap(v->v.array,ret->heap); *vv = v; } else { v= (struct value *)*vv; } if (f->label == LABEL_PACKED) { push_value_packed(type, v->v.array , f , &(ctx->a[i]), (uint8_t *)buffer); if (pbc_array_size(v->v.array) == 0) { type->env->lasterror = "rmessage decode packed data error"; *vv = NULL; } } else { push_value_array(h,v->v.array , f, &(ctx->a[i]), (uint8_t *)buffer); if (pbc_array_size(v->v.array) == 0) { type->env->lasterror = "rmessage decode repeated data error"; *vv = NULL; } } } else { struct value * v = read_value(h, f, &(ctx->a[i]), (uint8_t *)buffer); if (v) { _pbcM_sp_insert(ret->index, f->name, v); } else { type->env->lasterror = "rmessage decode data error"; } } } } _pbcC_close(_ctx); } struct pbc_rmessage * pbc_rmessage_new(struct pbc_env * env, const char * type_name , struct pbc_slice * slice) { struct _message * msg = _pbcP_get_message(env, type_name); if (msg == NULL) { env->lasterror = "Proto not found"; return NULL; } struct pbc_rmessage temp; struct heap * h = _pbcH_new(slice->len); _pbc_rmessage_new(&temp, msg , slice->buffer, slice->len , h); if (temp.msg == NULL) { _pbcH_delete(h); return NULL; } struct pbc_rmessage *m = (struct pbc_rmessage *)_pbcH_alloc(temp.heap, sizeof(*m)); *m = temp; return m; } void pbc_rmessage_delete(struct pbc_rmessage * m) { if (m) { _pbcH_delete(m->heap); } } const char * pbc_rmessage_string(struct pbc_rmessage * m , const char *key , int index, int *sz) { struct value * v = (struct value *)_pbcM_sp_query(m->index,key); int type = 0; pbc_var var; if (v == NULL) { type = _pbcP_message_default(m->msg, key, var); } else { if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { _pbcA_index(v->v.array, index, var); } else { var[0] = v->v.var[0]; } type = v->type->type; } if (type == PTYPE_ENUM) { if (sz) { *sz = strlen(var->e.name); } return var->e.name; } if (sz) { int len = var->s.len; if (len<0) { len = - len; } *sz = len; } return var->s.str; } uint32_t pbc_rmessage_integer(struct pbc_rmessage *m , const char *key , int index, uint32_t *hi) { struct value * v = (struct value *)_pbcM_sp_query(m->index,key); pbc_var var; int type = 0; if (v == NULL) { type = _pbcP_message_default(m->msg, key, var); } else { if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { _pbcA_index(v->v.array, index, var); } else { var[0] = v->v.var[0]; } type = v->type->type; } if (type == PTYPE_ENUM) { if (hi) { *hi = 0; } return var->e.id; } if (hi) { *hi = var->integer.hi; } return var->integer.low; } double pbc_rmessage_real(struct pbc_rmessage * m, const char *key , int index) { struct value * v = (struct value *)_pbcM_sp_query(m->index,key); pbc_var var; if (v == NULL) { _pbcP_message_default(m->msg, key, var); } else { if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { _pbcA_index(v->v.array, index, var); } else { return v->v.var->real; } } return var->real; } struct pbc_rmessage * pbc_rmessage_message(struct pbc_rmessage * rm, const char *key, int index) { struct value * v = (struct value *)_pbcM_sp_query(rm->index,key); if (v == NULL) { struct _field * f = (struct _field *)_pbcM_sp_query(rm->msg->name, key); if (f == NULL) { rm->msg->env->lasterror = "Invalid key for sub-message"; // invalid key return NULL; } struct _message * m = f->type_name.m; if (m->def == NULL) { // m->def will be free at the end (pbc_delete). m->def = (struct pbc_rmessage *)pbc_malloc(sizeof(struct pbc_rmessage)); m->def->msg = m; m->def->index = NULL; } return m->def; } else { if (v->type->label == LABEL_REPEATED) { return (struct pbc_rmessage *)_pbcA_index_p(v->v.array,index); } else { return &(v->v.message); } } } int pbc_rmessage_size(struct pbc_rmessage *m, const char *key) { struct value * v = (struct value *)_pbcM_sp_query(m->index,key); if (v == NULL) { return 0; } if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { return pbc_array_size(v->v.array); } else { return 1; } } ================================================ FILE: code/EVA/server/server_share/pbc/stringpool.cpp ================================================ #include "alloc.h" #include #include #define PAGE_SIZE 256 struct _stringpool { char * buffer; size_t len; struct _stringpool *next; }; struct _stringpool * _pbcS_new(void) { struct _stringpool * ret = (struct _stringpool *)pbc_malloc(sizeof(struct _stringpool) + PAGE_SIZE); ret->buffer = (char *)(ret + 1); ret->len = 0; ret->next = NULL; return ret; } void _pbcS_delete(struct _stringpool *pool) { while(pool) { struct _stringpool *next = pool->next; pbc_free(pool); pool = next; } } const char * _pbcS_build(struct _stringpool *pool, const char * str , int sz) { size_t s = sz + 1; if (s < PAGE_SIZE - pool->len) { char * ret = pool->buffer + pool->len; memcpy(pool->buffer + pool->len, str, s); pool->len += s; return ret; } if (s > PAGE_SIZE) { struct _stringpool * next = (struct _stringpool *)pbc_malloc(sizeof(struct _stringpool) + s); next->buffer = (char *)(next + 1); memcpy(next->buffer, str, s); next->len = s; next->next = pool->next; pool->next = next; return next->buffer; } struct _stringpool *next = (struct _stringpool *)pbc_malloc(sizeof(struct _stringpool) + PAGE_SIZE); next->buffer = pool->buffer; next->next = pool->next; next->len = pool->len; pool->next = next; pool->buffer = (char *)(next + 1); memcpy(pool->buffer, str, s); pool->len = s; return pool->buffer; } ================================================ FILE: code/EVA/server/server_share/pbc/stringpool.h ================================================ #ifndef PROTOBUF_C_STRINGPOOL_H #define PROTOBUF_C_STRINGPOOL_H struct _stringpool; struct _stringpool * _pbcS_new(void); void _pbcS_delete(struct _stringpool *pool); const char * _pbcS_build(struct _stringpool *pool, const char * str , int sz); #endif ================================================ FILE: code/EVA/server/server_share/pbc/varint.cpp ================================================ #include "varint.h" #include "pbc.h" #include //inline int int _pbcV_encode32(uint32_t number, uint8_t buffer[10]) { if (number < 0x80) { buffer[0] = (uint8_t) number ; return 1; } buffer[0] = (uint8_t) (number | 0x80 ); if (number < 0x4000) { buffer[1] = (uint8_t) (number >> 7 ); return 2; } buffer[1] = (uint8_t) ((number >> 7) | 0x80 ); if (number < 0x200000) { buffer[2] = (uint8_t) (number >> 14); return 3; } buffer[2] = (uint8_t) ((number >> 14) | 0x80 ); if (number < 0x10000000) { buffer[3] = (uint8_t) (number >> 21); return 4; } buffer[3] = (uint8_t) ((number >> 21) | 0x80 ); buffer[4] = (uint8_t) (number >> 28); return 5; } int _pbcV_encode(uint64_t number, uint8_t buffer[10]) { if ((number & 0xffffffff) == number) { return _pbcV_encode32((uint32_t)number , buffer); } int i = 0; do { buffer[i] = (uint8_t)(number | 0x80); number >>= 7; ++i; } while (number >= 0x80); buffer[i] = (uint8_t)number; return i+1; } int _pbcV_decode(uint8_t buffer[10], struct longlong *result) { if (!(buffer[0] & 0x80)) { result->low = buffer[0]; result->hi = 0; return 1; } uint32_t r = buffer[0] & 0x7f; int i; for (i=1;i<4;i++) { r |= ((buffer[i]&0x7f) << (7*i)); if (!(buffer[i] & 0x80)) { result->low = r; result->hi = 0; return i+1; } } uint64_t lr = 0; for (i=4;i<10;i++) { lr |= ((uint64_t)(buffer[i] & 0x7f) << (7*(i-4))); if (!(buffer[i] & 0x80)) { result->hi = (uint32_t)(lr >> 4); result->low = r | (((uint32_t)lr & 0xf) << 28); return i+1; } } result->low = 0; result->hi = 0; return 10; } int _pbcV_zigzag32(int32_t n, uint8_t buffer[10]) { n = (n << 1) ^ (n >> 31); return _pbcV_encode32(n,buffer); } int _pbcV_zigzag(int64_t n, uint8_t buffer[10]) { n = (n << 1) ^ (n >> 63); return _pbcV_encode(n,buffer); } void _pbcV_dezigzag64(struct longlong *r) { uint32_t low = r->low; r->low = ((low >> 1) | ((r->hi & 1) << 31)) ^ - (low & 1); r->hi = (r->hi >> 1) ^ - (low & 1); } void _pbcV_dezigzag32(struct longlong *r) { uint32_t low = r->low; r->low = (low >> 1) ^ - (low & 1); r->hi = -(low >> 31); } ================================================ FILE: code/EVA/server/server_share/pbc/varint.h ================================================ #ifndef PROTOBUF_C_VARINT_H #define PROTOBUF_C_VARINT_H #include struct longlong { uint32_t low; uint32_t hi; }; int _pbcV_encode32(uint32_t number, uint8_t buffer[10]); int _pbcV_encode(uint64_t number, uint8_t buffer[10]); int _pbcV_zigzag32(int32_t number, uint8_t buffer[10]); int _pbcV_zigzag(int64_t number, uint8_t buffer[10]); int _pbcV_decode(uint8_t buffer[10], struct longlong *result); void _pbcV_dezigzag64(struct longlong *r); void _pbcV_dezigzag32(struct longlong *r); #endif ================================================ FILE: code/EVA/server/server_share/pbc/wmessage.cpp ================================================ #include "pbc.h" #include "context.h" #include "alloc.h" #include "varint.h" #include "map.h" #include "proto.h" #include #include #include #ifndef _MSC_VER #include #endif #define WMESSAGE_SIZE 64 struct pbc_wmessage { struct _message *type; uint8_t * buffer; uint8_t * ptr; uint8_t * endptr; pbc_array sub; struct map_sp *packed; struct heap * heap; }; struct _packed { int id; int ptype; pbc_array data; }; static struct pbc_wmessage * _wmessage_new(struct heap *h, struct _message *msg) { struct pbc_wmessage * m = (struct pbc_wmessage *)_pbcH_alloc(h, sizeof(*m)); m->type = msg; m->buffer = (uint8_t *)_pbcH_alloc(h, WMESSAGE_SIZE); m->ptr = m->buffer; m->endptr = m->buffer + WMESSAGE_SIZE; _pbcA_open_heap(m->sub, h); m->packed = NULL; m->heap = h; return m; } struct pbc_wmessage * pbc_wmessage_new(struct pbc_env * env, const char *type_name) { struct _message * msg = _pbcP_get_message(env, type_name); if (msg == NULL) return NULL; struct heap *h = _pbcH_new(0); return _wmessage_new(h, msg); } void pbc_wmessage_delete(struct pbc_wmessage *m) { if (m) { _pbcH_delete(m->heap); } } static void _expand_message(struct pbc_wmessage *m, int sz) { if (m->ptr + sz > m->endptr) { int cap = m->endptr - m->buffer; sz = m->ptr + sz - m->buffer; do { cap = cap * 2; } while ( sz > cap ) ; int old_size = m->ptr - m->buffer; uint8_t * buffer = (uint8_t *)_pbcH_alloc(m->heap, cap); memcpy(buffer, m->buffer, old_size); m->ptr = buffer + (m->ptr - m->buffer); m->endptr = buffer + cap; m->buffer = buffer; } } static struct _packed * _get_packed(struct pbc_wmessage *m , struct _field *f , const char *key) { if (m->packed == NULL) { m->packed = _pbcM_sp_new(4, m->heap); } void ** v = _pbcM_sp_query_insert(m->packed , key); if (*v == NULL) { *v = _pbcH_alloc(m->heap, sizeof(struct _packed)); struct _packed *p = (struct _packed *)*v; p->id = f->id; p->ptype = f->type; _pbcA_open_heap(p->data, m->heap); return p; } return (struct _packed *)*v; } static void _packed_integer(struct pbc_wmessage *m, struct _field *f, const char *key , uint32_t low, uint32_t hi) { struct _packed * packed = _get_packed(m,f,key); pbc_var var; var->integer.low = low; var->integer.hi = hi; _pbcA_push(packed->data , var); } static void _packed_real(struct pbc_wmessage *m, struct _field *f, const char *key , double v) { struct _packed * packed = _get_packed(m,f,key); pbc_var var; var->real = v; _pbcA_push(packed->data , var); } static inline void int64_encode(uint32_t low, uint32_t hi , uint8_t * buffer) { buffer[0] = (uint8_t)(low & 0xff); buffer[1] = (uint8_t)(low >> 8 & 0xff); buffer[2] = (uint8_t)(low >> 16 & 0xff); buffer[3] = (uint8_t)(low >> 24 & 0xff); buffer[4] = (uint8_t)(hi & 0xff); buffer[5] = (uint8_t)(hi >> 8 & 0xff); buffer[6] = (uint8_t)(hi >> 16 & 0xff); buffer[7] = (uint8_t)(hi >> 24 & 0xff); } static inline void int32_encode(uint32_t low, uint8_t * buffer) { buffer[0] = (uint8_t)(low & 0xff); buffer[1] = (uint8_t)(low >> 8 & 0xff); buffer[2] = (uint8_t)(low >> 16 & 0xff); buffer[3] = (uint8_t)(low >> 24 & 0xff); } int pbc_wmessage_integer(struct pbc_wmessage *m, const char *key, uint32_t low, uint32_t hi) { struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); if (f==NULL) { // todo : error m->type->env->lasterror = "wmessage_interger query key error"; return -1; } if (f->label == LABEL_PACKED) { _packed_integer(m , f, key , low, hi); return 0; } if (f->label == LABEL_OPTIONAL) { if (f->type == PTYPE_ENUM) { if (low == f->default_v->e.id) return 0; } else { if (low == f->default_v->integer.low && hi == f->default_v->integer.hi) { return 0; } } } int id = f->id << 3; _expand_message(m,20); switch (f->type) { case PTYPE_INT64: case PTYPE_UINT64: case PTYPE_INT32: id |= WT_VARINT; m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_encode((uint64_t)low | (uint64_t)hi << 32 , m->ptr); break; case PTYPE_UINT32: case PTYPE_ENUM: case PTYPE_BOOL: id |= WT_VARINT; m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_encode32(low, m->ptr); break; case PTYPE_FIXED64: case PTYPE_SFIXED64: id |= WT_BIT64; m->ptr += _pbcV_encode32(id, m->ptr); int64_encode(low,hi,m->ptr); m->ptr += 8; break; case PTYPE_FIXED32: case PTYPE_SFIXED32: id |= WT_BIT32; m->ptr += _pbcV_encode32(id, m->ptr); int32_encode(low,m->ptr); m->ptr += 4; break; case PTYPE_SINT32: id |= WT_VARINT; m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_zigzag32(low, m->ptr); break; case PTYPE_SINT64: id |= WT_VARINT; m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_zigzag((uint64_t)low | (uint64_t)hi << 32 , m->ptr); break; } return 0; } int pbc_wmessage_real(struct pbc_wmessage *m, const char *key, double v) { struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); if (f == NULL) { // todo : error m->type->env->lasterror = "wmessage_real query key error"; return -1; } if (f->label == LABEL_PACKED) { _packed_real(m , f, key , v); return 0; } if (f->label == LABEL_OPTIONAL) { if (v == f->default_v->real) return 0; } int id = f->id << 3; _expand_message(m,18); switch (f->type) { case PTYPE_FLOAT: { id |= WT_BIT32; m->ptr += _pbcV_encode32(id, m->ptr); float_encode(v , m->ptr); m->ptr += 4; break; } case PTYPE_DOUBLE: id |= WT_BIT64; m->ptr += _pbcV_encode32(id, m->ptr); double_encode(v , m->ptr); m->ptr += 8; break; } return 0; } int pbc_wmessage_string(struct pbc_wmessage *m, const char *key, const char * v, int len) { struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); if (f == NULL) { // todo : error m->type->env->lasterror = "wmessage_string query key error"; return -1; } bool varlen = false; if (len <=0) { varlen = true; // -1 for add '\0' len = strlen(v) - len; } if (f->label == LABEL_PACKED) { if (f->type == PTYPE_ENUM) { char * temp = (char *)alloca(len + 1); if (!varlen || v[len] != '\0') { memcpy(temp,v,len); temp[len]='\0'; v = temp; } int enum_id = 0; int err = _pbcM_si_query(f->type_name.e->name, v , &enum_id); if (err) { // todo : error , invalid enum m->type->env->lasterror = "wmessage_string packed invalid enum"; return -1; } _packed_integer(m , f, key , enum_id , 0); } return 0; } if (f->label == LABEL_OPTIONAL) { if (f->type == PTYPE_ENUM) { if (strncmp(v , f->default_v->e.name, len) == 0 && f->default_v->e.name[len] =='\0') { return 0; } } else if (f->type == PTYPE_STRING) { if (len == f->default_v->s.len && strcmp(v, f->default_v->s.str) == 0) { return 0; } } else if (f->type == PTYPE_BYTES) { if (len == 0) { return 0; } } } int id = f->id << 3; _expand_message(m,20); switch (f->type) { case PTYPE_ENUM : { char * temp = (char *)alloca(len+1); if (!varlen || v[len] != '\0') { memcpy(temp,v,len); temp[len]='\0'; v = temp; } int enum_id = 0; int err = _pbcM_si_query(f->type_name.e->name, v, &enum_id); if (err) { // todo : error , enum invalid m->type->env->lasterror = "wmessage_string invalid enum"; return -1; } id |= WT_VARINT; m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_encode32(enum_id, m->ptr); break; } case PTYPE_STRING: case PTYPE_BYTES: id |= WT_LEND; m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_encode32(len, m->ptr); _expand_message(m,len); memcpy(m->ptr , v , len); m->ptr += len; break; } return 0; } struct pbc_wmessage * pbc_wmessage_message(struct pbc_wmessage *m, const char *key) { struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); if (f == NULL) { // todo : error m->type->env->lasterror = "wmessage_message query key error"; return NULL; } pbc_var var; var->p[0] = _wmessage_new(m->heap, f->type_name.m); var->p[1] = f; _pbcA_push(m->sub , var); return (struct pbc_wmessage *)var->p[0]; } static void _pack_packed_64(struct _packed *p,struct pbc_wmessage *m) { int n = pbc_array_size(p->data); int len = n * 8; int i; pbc_var var; _expand_message(m,10 + len); m->ptr += _pbcV_encode32(len, m->ptr); switch (p->ptype) { case PTYPE_DOUBLE: for (i=0;idata, i, var); double_encode(var->real , m->ptr + i * 8); } break; default: for (i=0;idata, i, var); int64_encode(var->integer.low , var->integer.hi, m->ptr + i * 8); } break; } m->ptr += len; } static void _pack_packed_32(struct _packed *p,struct pbc_wmessage *m) { int n = pbc_array_size(p->data); int len = n * 4; int i; pbc_var var; _expand_message(m,10 + len); m->ptr += _pbcV_encode32(len, m->ptr); switch (p->ptype) { case PTYPE_FLOAT: for (i=0;idata, i, var); float_encode(var->real , m->ptr + i * 8); } break; default: for (i=0;idata, i, var); int32_encode(var->integer.low , m->ptr + i * 8); } break; } m->ptr += len; } static void _pack_packed_varint(struct _packed *p,struct pbc_wmessage *m) { int n = pbc_array_size(p->data); int offset = m->ptr - m->buffer; int len = n * 2; if (p->ptype == PTYPE_BOOL) { len = n; } int i; pbc_var var; _expand_message(m,10 + len); int len_len = _pbcV_encode32(len, m->ptr); m->ptr += len_len; switch (p->ptype) { case PTYPE_INT64: case PTYPE_UINT64: for (i=0;idata, i, var); _expand_message(m,10); m->ptr += _pbcV_encode((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , m->ptr); } break; case PTYPE_INT32: case PTYPE_BOOL: case PTYPE_UINT32: case PTYPE_ENUM: for (i=0;idata, i, var); _expand_message(m,10); m->ptr += _pbcV_encode32(var->integer.low , m->ptr); } break; case PTYPE_SINT32: for (i=0;idata, i, var); _expand_message(m,10); m->ptr += _pbcV_zigzag32(var->integer.low, m->ptr); } break; case PTYPE_SINT64: for (i=0;idata, i, var); _expand_message(m,10); m->ptr += _pbcV_zigzag((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , m->ptr); } break; default: // error memset(m->ptr , 0 , n); m->ptr += n; m->type->env->lasterror = "wmessage type error when pack packed"; break; } int end_offset = m->ptr - m->buffer; int end_len = end_offset - (offset + len_len); if (end_len != len) { uint8_t temp[10]; int end_len_len = _pbcV_encode32(end_len, temp); if (end_len_len != len_len) { _expand_message(m, end_len_len); memmove(m->buffer + offset + end_len_len , m->buffer + offset + len_len , end_len); m->ptr += end_len_len - len_len; } memcpy(m->buffer + offset , temp, end_len_len); } } static void _pack_packed(void *p, void *ud) { struct _packed *packed = (struct _packed *)p; struct pbc_wmessage * m = (struct pbc_wmessage *)ud; int id = packed->id << 3 | WT_LEND; _expand_message(m,10); m->ptr += _pbcV_encode32(id, m->ptr); switch(packed->ptype) { case PTYPE_DOUBLE: case PTYPE_FIXED64: case PTYPE_SFIXED64: _pack_packed_64(packed,m); break; case PTYPE_FLOAT: case PTYPE_FIXED32: case PTYPE_SFIXED32: _pack_packed_32(packed,m); break; default: _pack_packed_varint(packed,m); break; } } void * pbc_wmessage_buffer(struct pbc_wmessage *m, struct pbc_slice *slice) { if (m->packed) { _pbcM_sp_foreach_ud(m->packed , _pack_packed, m); } int i; int n = pbc_array_size(m->sub); for (i=0;isub, i , var); struct pbc_slice s; pbc_wmessage_buffer((struct pbc_wmessage *)var->p[0] , &s); if (s.buffer) { struct _field * f = (struct _field *)var->p[1]; int id = f->id << 3 | WT_LEND; _expand_message(m,20+s.len); m->ptr += _pbcV_encode32(id, m->ptr); m->ptr += _pbcV_encode32(s.len, m->ptr); memcpy(m->ptr, s.buffer, s.len); m->ptr += s.len; } } slice->buffer = m->buffer; slice->len = m->ptr - m->buffer; return m->buffer; } ================================================ FILE: code/EVA/server/server_share/ranking_change_near.h ================================================ #ifndef GAME_SHARE_RANKING_CHANGE_NEAR_H #define GAME_SHARE_RANKING_CHANGE_NEAR_H #include #include #include "game_def.h" /** 排名管理器 * 使用PID作为索引,SCORE作为排名依据,获取排名。 * 每次SetScore() 分数或排名变动跨越的人数小于100时适用。 * * \author li9chuan * \date 2013-1-14 */ class CRankingChangeNear { public: CRankingChangeNear () { _vctScore.reserve(1024*128); _vctScore.resize(1); // 占用第0位,排名从1开始 } ~CRankingChangeNear (){} /** * 设置玩家积分 * * \param nID * \param nScore * \return 排名从1开始,0表示异常 */ DEF::RANKING SetScore( const DEF::PID nID, const DEF::SCORE nScore ) { DEF::RANKING nRankingNew = GetIDRanking(nID); if ( nRankingNew == 0 ) { DEF::RANKING nRanking = _addRankingBack( nID, nScore ); nRankingNew = _upRanking( nRanking, nScore ); } else { nRankingNew = _adjustRanking( nRankingNew, nScore ); } return nRankingNew; } /** * 获取排名 * * \param nID * \return 排名从1开始,0表示没有找到此ID */ DEF::RANKING GetRanking( const DEF::PID nID ) { return GetIDRanking(nID); } unsigned int GetMaxRow() { return _vctScore.size(); } uint32 GetPage( const DEF::PID nID, const uint32 nPageRow ) { uint32 page = 0; DEF::RANKING ranking = GetRanking( nID ); if ( ranking != 0 && nPageRow != 0 ) { page = ranking / nPageRow; if ( ranking % nPageRow != 0 ) { ++page; } } return page; } /// 获得分页 bool GetPage( const uint32 nPage, const uint32 nPageRow, std::vector& vct ) { vct.clear(); if ( nPage == 0 ) { return false; } uint32 pageStartIdx = (nPage-1)*nPageRow+1; uint32 pageEndIdx = pageStartIdx + nPageRow; if ( pageEndIdx > _vctScore.size() ) { pageEndIdx = (uint32)_vctScore.size(); } if ( pageEndIdx >= pageStartIdx ) { uint32 count = pageEndIdx-pageStartIdx; if ( count > 100 ) { return false; } for ( pageStartIdx; pageStartIdx& GetRankingInfo() { return _vctScore; } private: /** * 调整排名 * 中间会改变多个玩家的名次。 * * \param nRanking 调整前,玩家的排名 * \param nScore 玩家的分数 * \return 调整后,玩家的排名 */ DEF::RANKING _adjustRanking( const DEF::RANKING nRanking, const DEF::SCORE nScore ) { DEF::RANKING nNewRanking = nRanking; if ( nScore > _vctScore[nRanking].nScore ) // 如果积分增加了 { nNewRanking = _upRanking( nRanking, nScore ); } else if( nScore < _vctScore[nRanking].nScore ) // 如果积分降低了 { nNewRanking = _downRanking( nRanking, nScore ); } return nNewRanking; } /** * 增加一条新的排名积分记录 * 直接增加到尾部,最后一名。 * * \param nScore 玩家的分数 * \return 加入后,玩家的排名 */ DEF::RANKING _addRankingBack( const DEF::PID nID, const DEF::SCORE nScore ) { SPlayerInfo PlayerInfo; PlayerInfo.nScore = nScore; PlayerInfo.nID = nID; _vctScore.push_back(PlayerInfo); return SetIDRanking( nID, _vctScore.size()-1 ); } void _updateMapRanking( const DEF::RANKING nRanking ) { SetIDRanking( _vctScore[nRanking].nID, nRanking ); } DEF::RANKING _upRanking( const DEF::RANKING nOldRanking, const DEF::SCORE nScore ) { DEF::RANKING nNewRanking = nOldRanking; /// 缓存 SPlayerInfo PlayerInfo; PlayerInfo.nID = _vctScore[nOldRanking].nID; PlayerInfo.nScore = nScore; /// 排名上移 for ( nNewRanking; nNewRanking>1; --nNewRanking ) { if (_vctScore[nNewRanking-1].nScorenScore ) { _vctScore[nNewRanking] = _vctScore[nNewRanking+1]; _updateMapRanking(nNewRanking); } else { _vctScore[nNewRanking] = PlayerInfo; _updateMapRanking(nNewRanking); break; } } if ( nNewRanking == _vctScore.size()-1 ) { _vctScore[nNewRanking] = PlayerInfo; _updateMapRanking(nNewRanking); } return nNewRanking; } private: struct HashPIDRnk { DEF::PID pid; DEF::RANKING ranking; HashPIDRnk():pid(0) { } }; std::vector _vctScore; enum _THashEnum { HashDepthMask = 0x1, HashDepth = HashDepthMask+1, HashSpaceMask = 0xFFFFF, // 100W HashSpaceMax = HashSpaceMask+1, }; HashPIDRnk _HashIDRanking[HashSpaceMax]; /// 一级哈希空间 typedef std::map TIDRanking; TIDRanking _HashRankingSecond; /// 二级哈希空间 /// return hash idx inline uint HashFunctionPID( DEF::PID pid ) { //return (pid>>10) & HashSpaceMask; return (pid) & HashSpaceMask; } DEF::RANKING SetIDRanking( DEF::PID pid, DEF::RANKING ranking ) { uint idx = HashFunctionPID(pid); if ( _HashIDRanking[idx].pid==pid ) { _HashIDRanking[idx].ranking = ranking; } else if ( _HashIDRanking[idx].pid==0 ) { _HashIDRanking[idx].pid = pid; _HashIDRanking[idx].ranking = ranking; } else { TIDRanking::iterator iter = _HashRankingSecond.find(pid); if ( iter!=_HashRankingSecond.end() ) { iter->second = ranking; } else { _HashRankingSecond.insert( std::make_pair(pid, ranking) ); } } return ranking; } DEF::RANKING GetIDRanking( DEF::PID pid ) { DEF::RANKING ranking = 0; uint idx = HashFunctionPID(pid); if ( _HashIDRanking[idx].pid==pid ) { ranking = _HashIDRanking[idx].ranking; } else if ( _HashIDRanking[idx].pid==0 ) { } else { TIDRanking::iterator iter = _HashRankingSecond.find(pid); if ( iter!=_HashRankingSecond.end() ) { ranking = iter->second; } } return ranking; } }; #endif // GAME_SHARE_RANKING_CHANGE_NEAR_H /* End of ranking_change_near.h */ ================================================ FILE: code/EVA/server/server_share/ranking_slot.h ================================================ #ifndef GAME_SHARD_RANKING_SLOT_H #define GAME_SHARD_RANKING_SLOT_H #include #include #include #include #include "game_def.h" /** 排名槽管理器 * 使用PID作为索引,SCORE作为排名依据,获取排名。 * 按积分槽排名。 * 分数槽小于1W时效率较高: UpdateRanking<2ms 。 * 分数槽小于10W时(Release): UpdateRanking<10ms 。 * * \author li9chuan * \date 2015-1 */ class CRankingSlot { public: typedef std::set _TPIDs; typedef std::vector _TVctPIDs; struct _Ranking { DEF::RANKING Ranking; _TPIDs PIDs; _Ranking():Ranking(0){} }; typedef std::map TMapScore; typedef std::map TMapRanking; CRankingSlot():_UpdateSeconds(0),_PreUpdateSecond1970(0),_FastSortMax(0){} /** * 初始化排行处理逻辑 * * \param update_seconds 调用 UpdateRanking() 的最小间隔时间。 * \param fast_sort_num SetScore时,在fast_sort_num前的排名会即时更新。 */ void InitRanking( uint32 update_seconds, uint32 fast_sort_num ) { _UpdateSeconds = update_seconds; _FastSortMax = fast_sort_num; } /** * 设置玩家积分 * * \param nID * \param nScore */ void SetScore( const DEF::PID pid, const DEF::SCORE score ) { DEF::RANKING nRankingNew = 0; /// 移除玩家旧排名 TMapScore::iterator itscr = _MapScore.find( pid ); if ( itscr!=_MapScore.end() ) { DEF::SCORE old_score = itscr->second; if ( old_score==score ) { return; } TMapRanking::iterator itrnk = _MapRanking.find( old_score ); if ( itrnk!=_MapRanking.end() ) { itrnk->second.PIDs.erase(pid); if ( itrnk->second.PIDs.empty() ) { _MapRanking.erase(itrnk); } } itscr->second = score; } else { _MapScore.insert( std::make_pair(pid,score) ); } /// 插入玩家新排名 TMapRanking::iterator itrnk = _MapRanking.find( score ); if ( itrnk!=_MapRanking.end() ) { /// 如果已存在积分排名,插入对应积分槽内。 itrnk->second.PIDs.insert( pid ); nRankingNew = itrnk->second.Ranking; } else { /// 如果没有输入的积分,新插入一条 _Ranking Rnk; Rnk.PIDs.insert(pid); std::pair ret = _MapRanking.insert( std::make_pair( score, Rnk ) ); if ( ret.first != _MapRanking.begin() ) { TMapRanking::iterator it_cur = ret.first; TMapRanking::iterator it_pre = --ret.first; nRankingNew = it_pre->second.Ranking + it_pre->second.PIDs.size(); it_cur->second.Ranking = nRankingNew; } else { nRankingNew = 1; ret.first->second.Ranking = nRankingNew; } } /// 如果是前几名,那么即时排,不等update if ( nRankingNew <= _FastSortMax ) { _TopRnkPIDs.clear(); uint rnk_idx = 0; TMapRanking::reverse_iterator itrnk = _MapRanking.rbegin(); TMapRanking::reverse_iterator itrnk_end = _MapRanking.rend(); if ( itrnk!=itrnk_end ) { itrnk->second.Ranking = 1; _TPIDs::iterator itpids = itrnk->second.PIDs.begin(); _TPIDs::iterator itpids_end = itrnk->second.PIDs.end(); while ( itpids!=itpids_end ) { _TopRnkPIDs.push_back( *itpids ); ++rnk_idx; ++itpids; if ( rnk_idx>_FastSortMax ) { return; } } ++itrnk; } while ( itrnk!=itrnk_end ) { TMapRanking::reverse_iterator it_pre = itrnk; --it_pre; itrnk->second.Ranking = it_pre->second.Ranking + it_pre->second.PIDs.size(); _TPIDs::iterator itpids = itrnk->second.PIDs.begin(); _TPIDs::iterator itpids_end = itrnk->second.PIDs.end(); while ( itpids!=itpids_end ) { _TopRnkPIDs.push_back( *itpids ); ++rnk_idx; ++itpids; if ( rnk_idx>_FastSortMax ) { return; } } ++itrnk; } } } /** * 获取排名 * * \param nID * \return 排名从1开始,0表示没有找到此ID */ DEF::RANKING GetRanking( const DEF::SCORE score ) { DEF::RANKING rnk = 0; TMapRanking::iterator iter = _MapRanking.find(score); if ( iter!=_MapRanking.end() ) { rnk = iter->second.Ranking; } return rnk; } void UpdateRanking( ) { uint32 curr_seconds = NLMISC::CTime::getSecondsSince1970(); if ( curr_seconds - _PreUpdateSecond1970 < _UpdateSeconds ) { return; } _PreUpdateSecond1970 = curr_seconds; _ResortRanking(); } DEF::SCORE GetScore( DEF::PID unRoleID ) { std::map ::iterator it = _MapScore.find( unRoleID ); if ( it == _MapScore.end() ) { return 0; } return it->second; } std::vector& GetTopRanking() { return _TopRnkPIDs; } private: void _ResortRanking() { TMapRanking::reverse_iterator itrnk = _MapRanking.rbegin(); TMapRanking::reverse_iterator itrnk_end = _MapRanking.rend(); if ( itrnk!=itrnk_end ) { itrnk->second.Ranking = 1; ++itrnk; } while ( itrnk!=itrnk_end ) { TMapRanking::reverse_iterator it_pre = itrnk; --it_pre; itrnk->second.Ranking = it_pre->second.Ranking + it_pre->second.PIDs.size(); ++itrnk; } } _TVctPIDs _TopRnkPIDs; TMapRanking _MapRanking; TMapScore _MapScore; uint32 _UpdateSeconds; uint32 _PreUpdateSecond1970; uint32 _FastSortMax; }; #endif // GAME_SHARD_RANKING_SLOT_H /* End of ranking_solt.h */ ================================================ FILE: code/EVA/server/server_share/server_def.cpp ================================================ #include "server_def.h" ================================================ FILE: code/EVA/server/server_share/server_def.h ================================================ #ifndef SERVICE_SHARED_SERVER_DEF_H #define SERVICE_SHARED_SERVER_DEF_H #include #include #include //#include #include #include #include #include "game_def.h" #include "tools.h" //NLMISC::CLog& Loger(); #define MaxUDPPacketSize 512 //#ifdef NL_RELEASE //# if defined(NL_COMP_VC) && NL_COMP_VC_VERSION >= 71 //# define DebugLoger __noop //# else //# define DebugLoger 0&& //# endif //#else // NL_RELEASE //# define DebugLoger Loger().displayNL //#endif // NL_RELEASE #define Network NLNET::CUnifiedNetwork::getInstance() #define Config NLNET::IService::getInstance()->ConfigFile const std::string LogicService = "PLS"; const std::string EntitiesServer = "EGS"; const std::string Persistent = "PDS"; /// msg name const std::string T2C = "T2C"; const std::string U2C = "U2C"; const std::string ERR = "ERR"; const std::string DB_PUT = "DB_PUT"; const std::string DB_GET = "DB_GET"; const std::string PLS2DB = "PLS2DB"; const std::string DB2PLS = "DB2PLS"; inline void SendToClient( DEF::RPC_SESSION session, NLNET::CMessage& msgout, bool disconnect=true ) { NLNET::CMessage _msgout(T2C); _msgout.serial(session); _msgout.serial(disconnect); _msgout.serialMessage(msgout); Network->send( NLNET::TServiceId(GetSID(session)), _msgout ); } inline void SendToClient( DEF::RPC_SESSION session, std::string name, google::protobuf::Message* message, bool disconnect=true ) { NLNET::CMessage msgout(name); msgout.serial(message); SendToClient(session,msgout,disconnect); } /** * @brief ͻ˼ʱ͵ϢͻUDP˿ڿʱЧ * @param conFES ǰTServiceId * @param uid ˺ID * @param name Ϣ * @param auto_resend ʧʱǷҪ㳢Զط */ inline void SendUDP( NLNET::TServiceId conFES, DEF::UID uid, std::string name, google::protobuf::Message* message, bool auto_resend ) { NLNET::CMessage msgsub(name); msgsub.serial(message); NLNET::CMessage msgout(U2C); msgout.serial(uid); msgout.serial(auto_resend); msgout.serialMessage(msgsub); if ( NLNET::TServiceId::InvalidId == conFES || conFES.get()==0 ) { nlwarning("------ %s %d",name.c_str(), conFES.get()); return; } Network->send( conFES, msgout ); } inline void SendUDP( NLNET::TServiceId conFES, DEF::UID uid, NLNET::CMessage& msgout, bool auto_resend ) { NLNET::CMessage _msgout(U2C); _msgout.serial(uid); _msgout.serial(auto_resend); _msgout.serialMessage(msgout); if ( NLNET::TServiceId::InvalidId == conFES || conFES.get()==0 ) { nlwarning("------ %s %d", msgout.getName().c_str(), conFES.get()); return; } Network->send( conFES, _msgout ); } inline void AddToClientBuffer( NLNET::TServiceId conFES, DEF::UID uid, NLNET::CMessage& msgout ) { NLNET::CMessage _msgout("ADD_MSG_BUF"); _msgout.serial(uid); _msgout.serialMessage(msgout); Network->send( conFES, _msgout ); } inline void AddToClientBuffer( NLNET::TServiceId conFES, DEF::UID uid, std::string name, google::protobuf::Message* message ) { NLNET::CMessage msgout(name); msgout.serial(message); AddToClientBuffer(conFES,uid,msgout); } //inline google::protobuf::Message* CreateMessage(const std::string& typeName) //{ // google::protobuf::Message* message = NULL; // const google::protobuf::Descriptor* descriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(typeName); // if (descriptor) // { // const google::protobuf::Message* prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor); // if (prototype) // { // message = prototype->New(); // } // } // return message; //} #define SaveToDB( opt, id, stru ) do {\ DB_OPT _opt = opt;\ DEF::PID _pid = id;\ NLNET::CMessage msg_pds( DB_PUT );\ msg_pds.serial(_opt);\ msg_pds.serial(_pid);\ msg_pds.serial(stru);\ Network->send( Persistent, msg_pds ); \ } while(0) #define GetFromDB( opt , id , stru ) do{\ DB_OPT _opt = opt;\ DEF::PID _pid = id;\ NLNET::CMessage msg_pds( DB_GET );\ msg_pds.serial(_opt);\ msg_pds.serial( _pid );\ msg_pds.serial( stru );\ Network->send( Persistent , msg_pds );\ }while( 0 ) inline void SendErrorToClient( DEF::ERROR_TYPE errNO, DEF::RPC_SESSION session ) { NLNET::CMessage msgsub(ERR); msgsub.serial(errNO); SendToClient( session, msgsub ); } inline void SendErrorToClient( DEF::ERROR_TYPE errNO, DEF::RPC_SESSION session, sint64 param ) { NLNET::CMessage msgsub(ERR); msgsub.serial(errNO); msgsub.serial(param); SendToClient( session, msgsub ); } inline void SendErrorToClient( NLNET::TServiceId conFES, DEF::UID uid, DEF::ERROR_TYPE errNO ) { NLNET::CMessage msgsub(ERR); msgsub.serial(errNO); SendUDP( conFES, uid, msgsub, true); } inline void SendErrorToClient( NLNET::TServiceId conFES, DEF::UID uid, DEF::ERROR_TYPE errNO, sint64 param ) { NLNET::CMessage msgsub(ERR); msgsub.serial(errNO); msgsub.serial(param); SendUDP( conFES, uid, msgsub, true); } inline void SendErrorToClient( NLNET::TServiceId conFES, DEF::UID uid, DEF::ERROR_TYPE errNO, sint64 param1 , sint64 param2) { NLNET::CMessage msgsub(ERR); msgsub.serial(errNO); msgsub.serial(param1); msgsub.serial(param2); SendUDP( conFES, uid, msgsub, true); } #endif ================================================ FILE: code/EVA/server/server_share/sigslot.h ================================================ // sigslot.h: Signal/Slot classes // // Written by Sarah Thompson (sarah@telergy.com) 2002. // // License: Public domain. You are free to use this code however you like, with the proviso that // the author takes on no responsibility or liability for any use. // // QUICK DOCUMENTATION // // (see also the full documentation at http://sigslot.sourceforge.net/) // // #define switches // SIGSLOT_PURE_ISO - Define this to force ISO C++ compliance. This also disables // all of the thread safety support on platforms where it is // available. // // SIGSLOT_USE_POSIX_THREADS - Force use of Posix threads when using a C++ compiler other than // gcc on a platform that supports Posix threads. (When using gcc, // this is the default - use SIGSLOT_PURE_ISO to disable this if // necessary) // // SIGSLOT_DEFAULT_MT_POLICY - Where thread support is enabled, this defaults to multi_threaded_global. // Otherwise, the default is single_threaded. #define this yourself to // override the default. In pure ISO mode, anything other than // single_threaded will cause a compiler error. // // PLATFORM NOTES // // Win32 - On Win32, the WIN32 symbol must be #defined. Most mainstream // compilers do this by default, but you may need to define it // yourself if your build environment is less standard. This causes // the Win32 thread support to be compiled in and used automatically. // // Unix/Linux/BSD, etc. - If you're using gcc, it is assumed that you have Posix threads // available, so they are used automatically. You can override this // (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using // something other than gcc but still want to use Posix threads, you // need to #define SIGSLOT_USE_POSIX_THREADS. // // ISO C++ - If none of the supported platforms are detected, or if // SIGSLOT_PURE_ISO is defined, all multithreading support is turned off, // along with any code that might cause a pure ISO C++ environment to // complain. Before you ask, gcc -ansi -pedantic won't compile this // library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of // errors that aren't really there. If you feel like investigating this, // please contact the author. // // // THREADING MODES // // single_threaded - Your program is assumed to be single threaded from the point of view // of signal/slot usage (i.e. all objects using signals and slots are // created and destroyed from a single thread). Behaviour if objects are // destroyed concurrently is undefined (i.e. you'll get the occasional // segmentation fault/memory exception). // // multi_threaded_global - Your program is assumed to be multi threaded. Objects using signals and // slots can be safely created and destroyed from any thread, even when // connections exist. In multi_threaded_global mode, this is achieved by a // single global mutex (actually a critical section on Windows because they // are faster). This option uses less OS resources, but results in more // opportunities for contention, possibly resulting in more context switches // than are strictly necessary. // // multi_threaded_local - Behaviour in this mode is essentially the same as multi_threaded_global, // except that each signal, and each object that inherits has_slots, all // have their own mutex/critical section. In practice, this means that // mutex collisions (and hence context switches) only happen if they are // absolutely essential. However, on some platforms, creating a lot of // mutexes can slow down the whole OS, so use this option with care. // // USING THE LIBRARY // // See the full documentation at http://sigslot.sourceforge.net/ // // // Libjingle specific: // This file has been modified such that has_slots and signalx do not have to be // using the same threading requirements. E.g. it is possible to connect a // has_slots and signal0 or // has_slots and signal0. // If has_slots is single threaded the user must ensure that it is not trying // to connect or disconnect to signalx concurrently or data race may occur. // If signalx is single threaded the user must ensure that disconnect, connect // or signal is not happening concurrently or data race may occur. #ifndef WEBRTC_BASE_SIGSLOT_H__ #define WEBRTC_BASE_SIGSLOT_H__ #include #include #include // On our copy of sigslot.h, we set single threading as default. #define SIGSLOT_DEFAULT_MT_POLICY single_threaded #if defined(SIGSLOT_PURE_ISO) || (!defined(WIN32) && !defined(__GNUG__) && !defined(SIGSLOT_USE_POSIX_THREADS)) # define _SIGSLOT_SINGLE_THREADED #elif defined(WIN32) # define _SIGSLOT_HAS_WIN32_THREADS # if !defined(WIN32_LEAN_AND_MEAN) # define WIN32_LEAN_AND_MEAN # endif # include #elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS) # define _SIGSLOT_HAS_POSIX_THREADS # include #else # define _SIGSLOT_SINGLE_THREADED #endif #ifndef SIGSLOT_DEFAULT_MT_POLICY # ifdef _SIGSLOT_SINGLE_THREADED # define SIGSLOT_DEFAULT_MT_POLICY single_threaded # else # define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local # endif #endif // TODO: change this namespace to rtc? namespace sigslot { class single_threaded { public: single_threaded() { ; } virtual ~single_threaded() { ; } virtual void lock() { ; } virtual void unlock() { ; } }; #ifdef _SIGSLOT_HAS_WIN32_THREADS // The multi threading policies only get compiled in if they are enabled. class multi_threaded_global { public: multi_threaded_global() { static bool isinitialised = false; if(!isinitialised) { InitializeCriticalSection(get_critsec()); isinitialised = true; } } multi_threaded_global(const multi_threaded_global&) { ; } virtual ~multi_threaded_global() { ; } virtual void lock() { EnterCriticalSection(get_critsec()); } virtual void unlock() { LeaveCriticalSection(get_critsec()); } private: CRITICAL_SECTION* get_critsec() { static CRITICAL_SECTION g_critsec; return &g_critsec; } }; class multi_threaded_local { public: multi_threaded_local() { InitializeCriticalSection(&m_critsec); } multi_threaded_local(const multi_threaded_local&) { InitializeCriticalSection(&m_critsec); } virtual ~multi_threaded_local() { DeleteCriticalSection(&m_critsec); } virtual void lock() { EnterCriticalSection(&m_critsec); } virtual void unlock() { LeaveCriticalSection(&m_critsec); } private: CRITICAL_SECTION m_critsec; }; #endif // _SIGSLOT_HAS_WIN32_THREADS #ifdef _SIGSLOT_HAS_POSIX_THREADS // The multi threading policies only get compiled in if they are enabled. class multi_threaded_global { public: multi_threaded_global() { pthread_mutex_init(get_mutex(), NULL); } multi_threaded_global(const multi_threaded_global&) { ; } virtual ~multi_threaded_global() { ; } virtual void lock() { pthread_mutex_lock(get_mutex()); } virtual void unlock() { pthread_mutex_unlock(get_mutex()); } private: pthread_mutex_t* get_mutex() { static pthread_mutex_t g_mutex; return &g_mutex; } }; class multi_threaded_local { public: multi_threaded_local() { pthread_mutex_init(&m_mutex, NULL); } multi_threaded_local(const multi_threaded_local&) { pthread_mutex_init(&m_mutex, NULL); } virtual ~multi_threaded_local() { pthread_mutex_destroy(&m_mutex); } virtual void lock() { pthread_mutex_lock(&m_mutex); } virtual void unlock() { pthread_mutex_unlock(&m_mutex); } private: pthread_mutex_t m_mutex; }; #endif // _SIGSLOT_HAS_POSIX_THREADS template class lock_block { public: mt_policy *m_mutex; lock_block(mt_policy *mtx) : m_mutex(mtx) { m_mutex->lock(); } ~lock_block() { m_mutex->unlock(); } }; class has_slots_interface; template class _connection_base0 { public: virtual ~_connection_base0() {} virtual has_slots_interface* getdest() const = 0; virtual void emit() = 0; virtual _connection_base0* clone() = 0; virtual _connection_base0* duplicate(has_slots_interface* pnewdest) = 0; }; template class _connection_base1 { public: virtual ~_connection_base1() {} virtual has_slots_interface* getdest() const = 0; virtual void emit(arg1_type) = 0; virtual _connection_base1* clone() = 0; virtual _connection_base1* duplicate(has_slots_interface* pnewdest) = 0; }; template class _connection_base2 { public: virtual ~_connection_base2() {} virtual has_slots_interface* getdest() const = 0; virtual void emit(arg1_type, arg2_type) = 0; virtual _connection_base2* clone() = 0; virtual _connection_base2* duplicate(has_slots_interface* pnewdest) = 0; }; template class _connection_base3 { public: virtual ~_connection_base3() {} virtual has_slots_interface* getdest() const = 0; virtual void emit(arg1_type, arg2_type, arg3_type) = 0; virtual _connection_base3* clone() = 0; virtual _connection_base3* duplicate(has_slots_interface* pnewdest) = 0; }; template class _connection_base4 { public: virtual ~_connection_base4() {} virtual has_slots_interface* getdest() const = 0; virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type) = 0; virtual _connection_base4* clone() = 0; virtual _connection_base4* duplicate(has_slots_interface* pnewdest) = 0; }; template class _connection_base5 { public: virtual ~_connection_base5() {} virtual has_slots_interface* getdest() const = 0; virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type) = 0; virtual _connection_base5* clone() = 0; virtual _connection_base5* duplicate(has_slots_interface* pnewdest) = 0; }; template class _connection_base6 { public: virtual ~_connection_base6() {} virtual has_slots_interface* getdest() const = 0; virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type) = 0; virtual _connection_base6* clone() = 0; virtual _connection_base6* duplicate(has_slots_interface* pnewdest) = 0; }; template class _connection_base7 { public: virtual ~_connection_base7() {} virtual has_slots_interface* getdest() const = 0; virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type) = 0; virtual _connection_base7* clone() = 0; virtual _connection_base7* duplicate(has_slots_interface* pnewdest) = 0; }; template class _connection_base8 { public: virtual ~_connection_base8() {} virtual has_slots_interface* getdest() const = 0; virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, arg8_type) = 0; virtual _connection_base8* clone() = 0; virtual _connection_base8* duplicate(has_slots_interface* pnewdest) = 0; }; class _signal_base_interface { public: virtual void slot_disconnect(has_slots_interface* pslot) = 0; virtual void slot_duplicate(const has_slots_interface* poldslot, has_slots_interface* pnewslot) = 0; }; template class _signal_base : public _signal_base_interface, public mt_policy { }; class has_slots_interface { public: has_slots_interface() { ; } virtual void signal_connect(_signal_base_interface* sender) = 0; virtual void signal_disconnect(_signal_base_interface* sender) = 0; virtual ~has_slots_interface() { } virtual void disconnect_all() = 0; }; template class has_slots : public has_slots_interface, public mt_policy { private: typedef std::set<_signal_base_interface*> sender_set; typedef sender_set::const_iterator const_iterator; public: has_slots() { ; } has_slots(const has_slots& hs) { lock_block lock(this); const_iterator it = hs.m_senders.begin(); const_iterator itEnd = hs.m_senders.end(); while(it != itEnd) { (*it)->slot_duplicate(&hs, this); m_senders.insert(*it); ++it; } } void signal_connect(_signal_base_interface* sender) { lock_block lock(this); m_senders.insert(sender); } void signal_disconnect(_signal_base_interface* sender) { lock_block lock(this); m_senders.erase(sender); } virtual ~has_slots() { disconnect_all(); } void disconnect_all() { lock_block lock(this); const_iterator it = m_senders.begin(); const_iterator itEnd = m_senders.end(); while(it != itEnd) { (*it)->slot_disconnect(this); ++it; } m_senders.erase(m_senders.begin(), m_senders.end()); } private: sender_set m_senders; }; template class _signal_base0 : public _signal_base { public: typedef std::list<_connection_base0 *> connections_list; _signal_base0() { ; } _signal_base0(const _signal_base0& s) : _signal_base(s) { lock_block lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } ~_signal_base0() { disconnect_all(); } bool is_empty() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); return it == itEnd; } void disconnect_all() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } #ifdef _DEBUG bool connected(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; if ((*it)->getdest() == pclass) return true; it = itNext; } return false; } #endif void disconnect(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots_interface* pslot) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if((*it)->getdest() == pslot) { delete *it; m_connected_slots.erase(it); } it = itNext; } } void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } protected: connections_list m_connected_slots; }; template class _signal_base1 : public _signal_base { public: typedef std::list<_connection_base1 *> connections_list; _signal_base1() { ; } _signal_base1(const _signal_base1& s) : _signal_base(s) { lock_block lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base1() { disconnect_all(); } bool is_empty() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); return it == itEnd; } void disconnect_all() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } #ifdef _DEBUG bool connected(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; if ((*it)->getdest() == pclass) return true; it = itNext; } return false; } #endif void disconnect(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots_interface* pslot) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if((*it)->getdest() == pslot) { delete *it; m_connected_slots.erase(it); } it = itNext; } } protected: connections_list m_connected_slots; }; template class _signal_base2 : public _signal_base { public: typedef std::list<_connection_base2 *> connections_list; _signal_base2() { ; } _signal_base2(const _signal_base2& s) : _signal_base(s) { lock_block lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base2() { disconnect_all(); } bool is_empty() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); return it == itEnd; } void disconnect_all() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } #ifdef _DEBUG bool connected(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; if ((*it)->getdest() == pclass) return true; it = itNext; } return false; } #endif void disconnect(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots_interface* pslot) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if((*it)->getdest() == pslot) { delete *it; m_connected_slots.erase(it); } it = itNext; } } protected: connections_list m_connected_slots; }; template class _signal_base3 : public _signal_base { public: typedef std::list<_connection_base3 *> connections_list; _signal_base3() { ; } _signal_base3(const _signal_base3& s) : _signal_base(s) { lock_block lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base3() { disconnect_all(); } bool is_empty() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); return it == itEnd; } void disconnect_all() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } #ifdef _DEBUG bool connected(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; if ((*it)->getdest() == pclass) return true; it = itNext; } return false; } #endif void disconnect(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots_interface* pslot) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if((*it)->getdest() == pslot) { delete *it; m_connected_slots.erase(it); } it = itNext; } } protected: connections_list m_connected_slots; }; template class _signal_base4 : public _signal_base { public: typedef std::list<_connection_base4 *> connections_list; _signal_base4() { ; } _signal_base4(const _signal_base4& s) : _signal_base(s) { lock_block lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base4() { disconnect_all(); } bool is_empty() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); return it == itEnd; } void disconnect_all() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } #ifdef _DEBUG bool connected(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; if ((*it)->getdest() == pclass) return true; it = itNext; } return false; } #endif void disconnect(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots_interface* pslot) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if((*it)->getdest() == pslot) { delete *it; m_connected_slots.erase(it); } it = itNext; } } protected: connections_list m_connected_slots; }; template class _signal_base5 : public _signal_base { public: typedef std::list<_connection_base5 *> connections_list; _signal_base5() { ; } _signal_base5(const _signal_base5& s) : _signal_base(s) { lock_block lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base5() { disconnect_all(); } bool is_empty() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); return it == itEnd; } void disconnect_all() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } #ifdef _DEBUG bool connected(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; if ((*it)->getdest() == pclass) return true; it = itNext; } return false; } #endif void disconnect(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots_interface* pslot) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if((*it)->getdest() == pslot) { delete *it; m_connected_slots.erase(it); } it = itNext; } } protected: connections_list m_connected_slots; }; template class _signal_base6 : public _signal_base { public: typedef std::list<_connection_base6 *> connections_list; _signal_base6() { ; } _signal_base6(const _signal_base6& s) : _signal_base(s) { lock_block lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base6() { disconnect_all(); } bool is_empty() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); return it == itEnd; } void disconnect_all() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } #ifdef _DEBUG bool connected(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; if ((*it)->getdest() == pclass) return true; it = itNext; } return false; } #endif void disconnect(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots_interface* pslot) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if((*it)->getdest() == pslot) { delete *it; m_connected_slots.erase(it); } it = itNext; } } protected: connections_list m_connected_slots; }; template class _signal_base7 : public _signal_base { public: typedef std::list<_connection_base7 *> connections_list; _signal_base7() { ; } _signal_base7(const _signal_base7& s) : _signal_base(s) { lock_block lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base7() { disconnect_all(); } bool is_empty() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); return it == itEnd; } void disconnect_all() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } #ifdef _DEBUG bool connected(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; if ((*it)->getdest() == pclass) return true; it = itNext; } return false; } #endif void disconnect(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots_interface* pslot) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if((*it)->getdest() == pslot) { delete *it; m_connected_slots.erase(it); } it = itNext; } } protected: connections_list m_connected_slots; }; template class _signal_base8 : public _signal_base { public: typedef std::list<_connection_base8 *> connections_list; _signal_base8() { ; } _signal_base8(const _signal_base8& s) : _signal_base(s) { lock_block lock(this); typename connections_list::const_iterator it = s.m_connected_slots.begin(); typename connections_list::const_iterator itEnd = s.m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_connect(this); m_connected_slots.push_back((*it)->clone()); ++it; } } void slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == oldtarget) { m_connected_slots.push_back((*it)->duplicate(newtarget)); } ++it; } } ~_signal_base8() { disconnect_all(); } bool is_empty() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); return it == itEnd; } void disconnect_all() { lock_block lock(this); typename connections_list::const_iterator it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { (*it)->getdest()->signal_disconnect(this); delete *it; ++it; } m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); } #ifdef _DEBUG bool connected(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; if ((*it)->getdest() == pclass) return true; it = itNext; } return false; } #endif void disconnect(has_slots_interface* pclass) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { if((*it)->getdest() == pclass) { delete *it; m_connected_slots.erase(it); pclass->signal_disconnect(this); return; } ++it; } } void slot_disconnect(has_slots_interface* pslot) { lock_block lock(this); typename connections_list::iterator it = m_connected_slots.begin(); typename connections_list::iterator itEnd = m_connected_slots.end(); while(it != itEnd) { typename connections_list::iterator itNext = it; ++itNext; if((*it)->getdest() == pslot) { delete *it; m_connected_slots.erase(it); } it = itNext; } } protected: connections_list m_connected_slots; }; template class _connection0 : public _connection_base0 { public: _connection0() { m_pobject = NULL; m_pmemfun = NULL; } _connection0(dest_type* pobject, void (dest_type::*pmemfun)()) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual ~_connection0() { } virtual _connection_base0* clone() { return new _connection0(*this); } virtual _connection_base0* duplicate(has_slots_interface* pnewdest) { return new _connection0((dest_type *)pnewdest, m_pmemfun); } virtual void emit() { (m_pobject->*m_pmemfun)(); } virtual has_slots_interface* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(); }; template class _connection1 : public _connection_base1 { public: _connection1() { m_pobject = NULL; m_pmemfun = NULL; } _connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual ~_connection1() { } virtual _connection_base1* clone() { return new _connection1(*this); } virtual _connection_base1* duplicate(has_slots_interface* pnewdest) { return new _connection1((dest_type *)pnewdest, m_pmemfun); } virtual void emit(arg1_type a1) { (m_pobject->*m_pmemfun)(a1); } virtual has_slots_interface* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type); }; template class _connection2 : public _connection_base2 { public: _connection2() { m_pobject = NULL; m_pmemfun = NULL; } _connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, arg2_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual ~_connection2() { } virtual _connection_base2* clone() { return new _connection2(*this); } virtual _connection_base2* duplicate(has_slots_interface* pnewdest) { return new _connection2((dest_type *)pnewdest, m_pmemfun); } virtual void emit(arg1_type a1, arg2_type a2) { (m_pobject->*m_pmemfun)(a1, a2); } virtual has_slots_interface* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type, arg2_type); }; template class _connection3 : public _connection_base3 { public: _connection3() { m_pobject = NULL; m_pmemfun = NULL; } _connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, arg2_type, arg3_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual ~_connection3() { } virtual _connection_base3* clone() { return new _connection3(*this); } virtual _connection_base3* duplicate(has_slots_interface* pnewdest) { return new _connection3((dest_type *)pnewdest, m_pmemfun); } virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3) { (m_pobject->*m_pmemfun)(a1, a2, a3); } virtual has_slots_interface* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type); }; template class _connection4 : public _connection_base4 { public: _connection4() { m_pobject = NULL; m_pmemfun = NULL; } _connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual ~_connection4() { } virtual _connection_base4* clone() { return new _connection4(*this); } virtual _connection_base4* duplicate(has_slots_interface* pnewdest) { return new _connection4((dest_type *)pnewdest, m_pmemfun); } virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) { (m_pobject->*m_pmemfun)(a1, a2, a3, a4); } virtual has_slots_interface* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type); }; template class _connection5 : public _connection_base5 { public: _connection5() { m_pobject = NULL; m_pmemfun = NULL; } _connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual ~_connection5() { } virtual _connection_base5* clone() { return new _connection5(*this); } virtual _connection_base5* duplicate(has_slots_interface* pnewdest) { return new _connection5((dest_type *)pnewdest, m_pmemfun); } virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5) { (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5); } virtual has_slots_interface* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type); }; template class _connection6 : public _connection_base6 { public: _connection6() { m_pobject = NULL; m_pmemfun = NULL; } _connection6(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual ~_connection6() { } virtual _connection_base6* clone() { return new _connection6(*this); } virtual _connection_base6* duplicate(has_slots_interface* pnewdest) { return new _connection6((dest_type *)pnewdest, m_pmemfun); } virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6) { (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6); } virtual has_slots_interface* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type); }; template class _connection7 : public _connection_base7 { public: _connection7() { m_pobject = NULL; m_pmemfun = NULL; } _connection7(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual ~_connection7() { } virtual _connection_base7* clone() { return new _connection7(*this); } virtual _connection_base7* duplicate(has_slots_interface* pnewdest) { return new _connection7((dest_type *)pnewdest, m_pmemfun); } virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6, arg7_type a7) { (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7); } virtual has_slots_interface* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type); }; template class _connection8 : public _connection_base8 { public: _connection8() { m_pobject = NULL; m_pmemfun = NULL; } _connection8(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, arg8_type)) { m_pobject = pobject; m_pmemfun = pmemfun; } virtual ~_connection8() { } virtual _connection_base8* clone() { return new _connection8(*this); } virtual _connection_base8* duplicate(has_slots_interface* pnewdest) { return new _connection8((dest_type *)pnewdest, m_pmemfun); } virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) { (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7, a8); } virtual has_slots_interface* getdest() const { return m_pobject; } private: dest_type* m_pobject; void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, arg8_type); }; template class signal0 : public _signal_base0 { public: typedef _signal_base0 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; signal0() { ; } signal0(const signal0& s) : _signal_base0(s) { ; } template void connect(desttype* pclass, void (desttype::*pmemfun)()) { lock_block lock(this); _connection0* conn = new _connection0(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emit() { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(); it = itNext; } } void operator()() { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(); it = itNext; } } }; template class signal1 : public _signal_base1 { public: typedef _signal_base1 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; signal1() { ; } signal1(const signal1& s) : _signal_base1(s) { ; } template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type)) { lock_block lock(this); _connection1* conn = new _connection1(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emit(arg1_type a1) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1); it = itNext; } } void operator()(arg1_type a1) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1); it = itNext; } } }; template class signal2 : public _signal_base2 { public: typedef _signal_base2 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; signal2() { ; } signal2(const signal2& s) : _signal_base2(s) { ; } template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, arg2_type)) { lock_block lock(this); _connection2* conn = new _connection2(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emit(arg1_type a1, arg2_type a2) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2); it = itNext; } } void operator()(arg1_type a1, arg2_type a2) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2); it = itNext; } } }; template class signal3 : public _signal_base3 { public: typedef _signal_base3 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; signal3() { ; } signal3(const signal3& s) : _signal_base3(s) { ; } template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, arg2_type, arg3_type)) { lock_block lock(this); _connection3* conn = new _connection3(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emit(arg1_type a1, arg2_type a2, arg3_type a3) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2, a3); it = itNext; } } void operator()(arg1_type a1, arg2_type a2, arg3_type a3) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2, a3); it = itNext; } } }; template class signal4 : public _signal_base4 { public: typedef _signal_base4 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; signal4() { ; } signal4(const signal4& s) : _signal_base4(s) { ; } template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type)) { lock_block lock(this); _connection4* conn = new _connection4(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2, a3, a4); it = itNext; } } void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2, a3, a4); it = itNext; } } }; template class signal5 : public _signal_base5 { public: typedef _signal_base5 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; signal5() { ; } signal5(const signal5& s) : _signal_base5(s) { ; } template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type)) { lock_block lock(this); _connection5* conn = new _connection5(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2, a3, a4, a5); it = itNext; } } void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2, a3, a4, a5); it = itNext; } } }; template class signal6 : public _signal_base6 { public: typedef _signal_base6 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; signal6() { ; } signal6(const signal6& s) : _signal_base6(s) { ; } template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type)) { lock_block lock(this); _connection6* conn = new _connection6(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2, a3, a4, a5, a6); it = itNext; } } void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2, a3, a4, a5, a6); it = itNext; } } }; template class signal7 : public _signal_base7 { public: typedef _signal_base7 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; signal7() { ; } signal7(const signal7& s) : _signal_base7(s) { ; } template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type)) { lock_block lock(this); _connection7* conn = new _connection7(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6, arg7_type a7) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2, a3, a4, a5, a6, a7); it = itNext; } } void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6, arg7_type a7) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2, a3, a4, a5, a6, a7); it = itNext; } } }; template class signal8 : public _signal_base8 { public: typedef _signal_base8 base; typedef typename base::connections_list connections_list; using base::m_connected_slots; signal8() { ; } signal8(const signal8& s) : _signal_base8(s) { ; } template void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, arg8_type)) { lock_block lock(this); _connection8* conn = new _connection8(pclass, pmemfun); m_connected_slots.push_back(conn); pclass->signal_connect(this); } void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8); it = itNext; } } void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) { lock_block lock(this); typename connections_list::const_iterator itNext, it = m_connected_slots.begin(); typename connections_list::const_iterator itEnd = m_connected_slots.end(); while(it != itEnd) { itNext = it; ++itNext; (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8); it = itNext; } } }; }; // namespace sigslot #endif // WEBRTC_BASE_SIGSLOT_H__ ================================================ FILE: code/EVA/server/server_share/singleton_registry.h ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* NOTE: The following extension would be intelligent: --------------------------------------------------- - add 'preInit', 'preServiceUpdate', 'preTickUpdate' and 'preRelease' methods - add 'postInit', 'postServiceUpdate', 'postTickUpdate' and 'postRelease' methods - call all 'preXXX' methods followed by all XXX methods followed by all postXXX methods => This allows one to open log files etc in pre-init, start counters in pre-update, stop counters in post-update, etc... */ #ifndef SINGLETON_REGISTRY_H #define SINGLETON_REGISTRY_H //------------------------------------------------------------------------------------------------- // includes //------------------------------------------------------------------------------------------------- #include //------------------------------------------------------------------------------------------------- // class IServiceSingleton //------------------------------------------------------------------------------------------------- class IServiceSingleton { public: // overloadable method called at service initialisation virtual void init() {} // overloadable method called in the service update virtual void serviceUpdate() {} // overloadable method called in the tick update virtual void tickUpdate() {} // overloadable method called at service release virtual void release() {} protected: // protect from untrolled instantiation // this method registers the singleton with the singleton registry IServiceSingleton(); virtual ~IServiceSingleton() {} private: // prohibit copy IServiceSingleton(const IServiceSingleton&); }; //------------------------------------------------------------------------------------------------- // class CSingletonRegistry //------------------------------------------------------------------------------------------------- class CSingletonRegistry { public: // public interface for getting hold of the singleton instance static CSingletonRegistry* getInstance(); // registration of an IServiceSingleton object with the singleton void registerSingleton(IServiceSingleton*); // methods called from the service loop void init(); void serviceUpdate(); void tickUpdate(); void release(); private: // prohibit uncontrolled instantiation CSingletonRegistry() {} CSingletonRegistry(const CSingletonRegistry&); typedef std::set TSingletons; TSingletons _Singletons; }; #define SingletonRegistry CSingletonRegistry::getInstance() //------------------------------------------------------------------------------------------------- // inlines IServiceSingleton //------------------------------------------------------------------------------------------------- inline IServiceSingleton::IServiceSingleton() { CSingletonRegistry::getInstance()->registerSingleton(this); } //------------------------------------------------------------------------------------------------- // inlines CSingletonRegistry //------------------------------------------------------------------------------------------------- inline CSingletonRegistry* CSingletonRegistry::getInstance() { static CSingletonRegistry* instance= NULL; if (instance==NULL) { instance=new CSingletonRegistry; } return instance; } inline void CSingletonRegistry::registerSingleton(IServiceSingleton* singleton) { _Singletons.insert(singleton); } inline void CSingletonRegistry::init() { for (TSingletons::iterator it=_Singletons.begin(); it!=_Singletons.end();++it) (*it)->init(); } inline void CSingletonRegistry::tickUpdate() { for (TSingletons::iterator it=_Singletons.begin(); it!=_Singletons.end();++it) (*it)->tickUpdate(); } inline void CSingletonRegistry::serviceUpdate() { for (TSingletons::iterator it=_Singletons.begin(); it!=_Singletons.end();++it) (*it)->serviceUpdate(); } inline void CSingletonRegistry::release() { for (TSingletons::iterator it=_Singletons.begin(); it!=_Singletons.end();++it) (*it)->release(); } //------------------------------------------------------------------------------------------------- #endif ================================================ FILE: code/EVA/server/server_share/stdpch.cpp ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" ================================================ FILE: code/EVA/server/server_share/stdpch.h ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "nel/misc/types_nl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include #ifndef _CLIENT_ //#include #endif #include ================================================ FILE: code/EVA/server/server_share/timer.cpp ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . //------------------------------------------------------------------------------------------------- // includes //------------------------------------------------------------------------------------------------- #include "stdpch.h" #include "nel/misc/hierarchical_timer.h" #include "nel/misc/variable.h" #include "nel/misc/config_file.h" #include // for config #include "timer.h" using namespace NLMISC; NLMISC::CVariable NbProcessedEventsInTimerManagerUpdate("timer", "NbProcessedEventInTimerManagerUpdate", "", 0); NLMISC::CVariable NbEventsToProcessInTimerManagerUpdate("timer", "NbEventsToProcessInTimerManagerUpdate", "", 0); NL_INSTANCE_COUNTER_IMPL(CTimerEvent); ////------------------------------------------------------------------------------------------------- //// syncTick() ////------------------------------------------------------------------------------------------------- //void CTimerManager::syncTick() //{ // uint32 delta= CTickEventHandler::getGameCycle()-_LastTick; // // // update the time values // for (NLMISC::TGameCycle i=0;i<256;++i) // { // TEventVector& vect= getEventVector(i); // for (uint32 j=0;j_Time+= delta; // } // // // re-locate the event vectors to line them back up with the time values that they represent // for (NLMISC::TGameCycle i=0;i<256;++i) // { // TEventVector& vect= _EventVectors[i]; // while (!vect.empty() && ((uint8)vect[0]->_Time)!=i) // { // uint8 swapPos= (uint8)_EventVectors[i][0]->_Time; // std::swap(_EventVectors[i],_EventVectors[swapPos]); // } // } // // _LastTick= CTickEventHandler::getGameCycle(); //} void CTimerManager::init() { CConfigFile::CVar *var; if ((var = NLNET::IService::getInstance()->ConfigFile.getVarPtr("UpdateTimeout")) != NULL) { _UpdateTimeout = var->asInt(); } _BaseTime = CTime::getLocalTime(); _LocalTime = _BaseTime; } //------------------------------------------------------------------------------------------------- // tickUpdate() //------------------------------------------------------------------------------------------------- void CTimerManager::tickUpdate() { H_AUTO(CTimerManagerUpdate); NLMISC::TTime NextTime = 0; do { // update time ++_CurrentTick; _LocalTime = CTime::getLocalTime(); // select this game cycle's phrase event vector TEventVector &vect= getInstance()->getEventVector(_CurrentTick); // iterate through the vector processing its events uint32 nextFreeSlot=0; uint32 size=(uint32)vect.size(); for (uint32 i=0;i eventPtr=vect[i]; // if the event is no longer valid then just skip it if (eventPtr->getOwner()==NULL) continue; // if the event isn't valid yet then keep it for later // BUG when event time is too high, like 0xffffffff which is used in special cases, so change the test //if ((sint32)(eventPtr->getTime()-time)>0) if (eventPtr->getTime() > _CurrentTick) { vect[nextFreeSlot]=eventPtr; ++nextFreeSlot; continue; } // process the event eventPtr->processEvent(); } if (!vect.empty()) { //nlinfo("TimerManagerUpdate: Processed %d of %d events",vect.size()-nextFreeSlot, vect.size()); NbEventsToProcessInTimerManagerUpdate = (uint32)vect.size(); NbProcessedEventsInTimerManagerUpdate = NbEventsToProcessInTimerManagerUpdate.get() - nextFreeSlot; } // resize the vector back down to keep only the events that we haven't dealt with yet vect.resize(nextFreeSlot); /// check time NextTime = _BaseTime + (_CurrentTick+1)*_UpdateTimeout; } while (NextTime < _LocalTime); } ================================================ FILE: code/EVA/server/server_share/timer.h ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* Intro: ------ This file contains a complete timer system. It is robust and can be used widely. The user creates classes derived from CTimerEvent to represent their event handlers. When the classes' set() or setRemaining() methods are called an entry is added to the event system provoking a callback of the user's timerCallback() method at the given time. If a CTimer object is destroyed its callback is automatically canceled. A single timer may only have a single time set for it. Setting the time more than once will cancel the previous time. NOTE: The only requirement for the system is that the CTimerManager::tickUpdate() method is called every tick Example 1: - a class containing a timer ---------- class CMyClass { public: void startTimer() { // set the timer to trigger in 50 ticks _Timer.setRemaining(50); } void update() { if (_Timer.isActive()) { nlinfo("time remaining: ",_Timer.getTimeRemaining()); } else { // set the timer to trigger in 20 ticks _Timer.setRemaining(20); } } private: CTimer _Timer; }; Example 2: - a class using a timer and a custom event handler to trigger regular actions ---------- class CMyClass; class CMyTimerEvent; class CMyTimerEvent: public CTimerEvent { public: CMyTimerEvent(CMyClass* parent); void timerCallback(CTimer* owner); private: CMyClass* _Parent; } class CMyClass { public: void startTimer() { // set the timer to trigger in 50 ticks _Timer.setRemaining(50,new CMyTimerEvent(this)); } void doSomething(CTimerEvent* event) { nlinfo("hello world"); // set the timer to trigger in 20 ticks with the same event handler _Timer.setRemaining(20,event); } private: CMyTimer _Timer; }; void CMyTimerEvent::CMyTimerEvent(CMyClass* parent) { _Parent=parent; } void CMyTimerEvent::timerCallback(CTimer* owner) { _Parent->doSomething(this); } */ #ifndef TIMER_H #define TIMER_H //------------------------------------------------------------------------------------------------- // includes //------------------------------------------------------------------------------------------------- // stl #include // misc #include "nel/misc/types_nl.h" #include "nel/misc/time_nl.h" #include "nel/misc/common.h" #include "nel/misc/smart_ptr.h" // game share #include "utils.h" #include "singleton_registry.h" #include "tools.h" //------------------------------------------------------------------------------------------------- // forward class declarations //------------------------------------------------------------------------------------------------- class CTimer; class CTimerEvent; class CTimerManager; //------------------------------------------------------------------------------------------------- // class CTimer //------------------------------------------------------------------------------------------------- // generic timer class class CTimer { public: // ctor and dtor CTimer(); virtual ~CTimer(); // set the timer for a given target time & clear the custom event object void set(NLMISC::TTicks tick); // set the timer for somewhere between (time) and (time + variation) // also clear the custom event object void set(NLMISC::TTicks tick,uint32 variation); // set the timer for a given target time with given custom event handler object void set(NLMISC::TTicks tick,CTimerEvent* eventObject); // set the timer for somewhere between (time) and (time + variation) // also set given custom event handler object void set(NLMISC::TTicks tick,CTimerEvent* eventObject,uint32 variation); // set the timer for (current time + time) & clear the custom event object void setRemaining(NLMISC::TTicks tick); // set the timer for somewhere between (current time + time) and (current time + time + variation) // also clear the custom event object void setRemaining(NLMISC::TTicks tick,uint32 variation); // set the timer for (current time + time) with given custom event handler object void setRemaining(NLMISC::TTicks tick,CTimerEvent* eventObject); // set the timer for somewhere between (current time + time) and (current time + time + variation) // also set given custom event handler object void setRemaining(NLMISC::TTicks tick,CTimerEvent* eventObject,uint32 variation); /** * @brief 在未来某一时刻触发。 * @param SecondSince1970 触发的具体时间。 * @param eventObject 定时器事件。 * @param millisecond 可以散布在SecondSince1970之后的多少毫秒内触发(避免某一帧内的事件过多)。 */ bool setTime(NLMISC::TTime SecondSince1970,CTimerEvent* eventObject,uint32 millisecond=0); // test whether timer is running bool isActive() const; // reset the timer and clear the custom timer event void reset(); // get the target time for the timer - return 0 if the event is not active NLMISC::TGameCycle getTime() const; // get the time remaining before the target time for the timer - return 0 if the event is not active NLMISC::TGameCycle getTimeRemaining() const; // get a pointer to the current custom event object CTimerEvent* getEvent(); private: // prohibit copy CTimer(const CTimer&); CTimer& operator=(const CTimer&); // a smart pointer to the timer event - the event is reffed by a second smart ptr from the event system NLMISC::CSmartPtr _Event; }; //------------------------------------------------------------------------------------------------- // class CTimerEvent //------------------------------------------------------------------------------------------------- // specialisable timer event class class CTimerEvent: public NLMISC::CRefCount { NL_INSTANCE_COUNTER_DECL(CTimerEvent); public: // callback to be specialised virtual void timerCallback(CTimer* owner) {} public: // ctor CTimerEvent(); // dtor virtual ~CTimerEvent(); // read accessors NLMISC::TGameCycle getTime() const; // get hold of the object that created the event (or NULL if the object has been deleted) CTimer* getOwner() const; // return true if the event is active otherwise false bool isActive() const; private: // the following interface is reserved for use by the CTimer class friend class CTimer; // setup the event void set(CTimer* owner,NLMISC::TGameCycle time); // setup the event, selecting a time between 'time' and 'time'+'variation' void set(CTimer* owner,NLMISC::TGameCycle time,uint32 variation); // clear the event - mark it for deletion void clear(); private: // the following interface is reserved for use by the CTimerManager class friend class CTimerManager; // method used by the event system to call the timer callback and kill off the event void processEvent(); private: // the correct time for executing the event NLMISC::TTime _Time; // a pointer to the owner object - is NULL if owner object has been deleted or this event has been invalidated CTimer* _Owner; }; //------------------------------------------------------------------------------------------------- // class CTimerManager //------------------------------------------------------------------------------------------------- // singleton timer manager class CTimerManager: public IServiceSingleton { public: virtual void init(); // update called each tick in service update // updates events and cleans out event vectors virtual void tickUpdate(); //serviceUpdate // get the singleton instance... static CTimerManager* getInstance(); // callback called when the tick service connects - used to ajust time values of event objects //void syncTick(); NLMISC::TGameCycle getTick() { return _CurrentTick; } //NLMISC::TTime getTime() { return _LocalTime; } NLMISC::TTime getUpdateTimeout() { return _UpdateTimeout; } enum { TIMER_VECTOR_MASK = 0xffff, TIMER_VECTOR_SIZE, }; private: // this is a singleton so prohibit construction CTimerManager(); // the type of the event vector for a given time hash typedef std::vector > TEventVector; // the event vector is filled directly by CTimerEvent objects friend class CTimerEvent; // singleton encapsulation of event vector set TEventVector& getEventVector(NLMISC::TGameCycle time); // data /// Select timeout value in milliseconds between to call of user update() NLMISC::TTime _UpdateTimeout; NLMISC::TGameCycle _CurrentTick; NLMISC::TGameCycle _LastTick; NLMISC::TTime _LocalTime; NLMISC::TTime _BaseTime; TEventVector _EventVectors[TIMER_VECTOR_SIZE]; }; #define TimerManager CTimerManager::getInstance() //------------------------------------------------------------------------------------------------- // class CTimer //------------------------------------------------------------------------------------------------- inline CTimer::CTimer() { } inline CTimer::~CTimer() { reset(); } inline void CTimer::set(NLMISC::TTime time) { nlassertd(time>0); set(time,new CTimerEvent); } inline void CTimer::set(NLMISC::TTime time,uint32 variation) { nlassertd(time>0); set(time,new CTimerEvent,variation); } inline void CTimer::set(NLMISC::TTime time,CTimerEvent* eventObject) { nlassertd(time>0); if (_Event!=NULL) _Event->clear(); _Event= eventObject; NLMISC::TGameCycle add_cycle = (time /*- TimerManager->getTime()*/)/TimerManager->getUpdateTimeout(); if ( add_cycle == 0 ) { ++add_cycle; } NLMISC::TGameCycle game_cycle = TimerManager->getTick() + add_cycle; eventObject->set(this,game_cycle); } inline void CTimer::set(NLMISC::TTime time,CTimerEvent* eventObject,uint32 variation) { nlassertd(time>0); if (_Event!=NULL) _Event->clear(); _Event= eventObject; NLMISC::TGameCycle add_cycle = (time/* - TimerManager->getTime()*/)/TimerManager->getUpdateTimeout(); if ( add_cycle == 0 ) { ++add_cycle; } NLMISC::TGameCycle game_cycle = TimerManager->getTick() + add_cycle; eventObject->set(this,game_cycle,variation); } inline void CTimer::setRemaining(NLMISC::TTime time) { set(/*TimerManager->getTime()+*/time); } inline void CTimer::setRemaining(NLMISC::TTime time,uint32 variation) { set(/*TimerManager->getTime()+*/time,variation); } inline void CTimer::setRemaining(NLMISC::TTime time,CTimerEvent* eventObject) { set(/*TimerManager->getTime()+*/time,eventObject); } inline void CTimer::setRemaining(NLMISC::TTime time,CTimerEvent* eventObject,uint32 variation) { set(/*TimerManager->getTime()+*/time,eventObject,variation); } inline bool CTimer::setTime( NLMISC::TTime SecondSince1970,CTimerEvent* eventObject,uint32 millisecond ) { NLMISC::TTicks ticks = SecondSince1970 - NLMISC::CTime::getSecondsSince1970(); if ( ticks <= 0 ) { nlwarning("Set Timer Fail . %s", LocalTime.printtime( SecondSince1970 )); //delete eventObject; if (_Event!=NULL) _Event->clear(); //_Event= eventObject; return false; } ticks *= 1000; if ( millisecond!=0 ) { uint32 variation = millisecond/TimerManager->getUpdateTimeout(); if (variation==0) { variation = 1; } setRemaining( ticks, eventObject, variation ); } else { setRemaining( ticks, eventObject ); } return true; } inline void CTimer::reset() { if (_Event==NULL) return; _Event->clear(); _Event=NULL; } inline bool CTimer::isActive() const { return (_Event!=NULL) && _Event->isActive(); } inline NLMISC::TGameCycle CTimer::getTime() const { if (!isActive()) return 0; return _Event->getTime(); } inline NLMISC::TGameCycle CTimer::getTimeRemaining() const { if (!isActive()) return 0; return getTime()/*-(TimerManager->getTime())*/; } inline CTimerEvent* CTimer::getEvent() { return _Event; } //------------------------------------------------------------------------------------------------- // inlines CTimerEvent //------------------------------------------------------------------------------------------------- inline CTimerEvent::CTimerEvent() { _Owner = NULL; _Time = 0; } inline CTimerEvent::~CTimerEvent() { } inline void CTimerEvent::set(CTimer* owner,NLMISC::TGameCycle time) { BOMB_IF(owner==NULL,"Impossible to set a timer with a NULL owner",return); BOMB_IF(_Owner!=NULL && _Owner!=owner,"Attempt to change owner of an active event",return); _Owner = owner; _Time = time; CTimerManager::getInstance()->getEventVector(time).push_back(this); } inline void CTimerEvent::set(CTimer* owner,NLMISC::TGameCycle time,uint32 variation) { BOMB_IF(variation==0,"shouldn't call this method with variation value of 0", set(owner,time)); BOMB_IF(variation>256,"shouldn't call this method with variation value of >256", variation=256); BOMB_IF(owner==NULL,"Impossible to set a timer with a NULL owner", return); BOMB_IF(_Owner!=NULL && _Owner!=owner,"Attempt to change owner of an active event", return); _Owner = owner; CTimerManager* mgr=CTimerManager::getInstance(); CTimerManager::TEventVector *best=NULL; uint32 bestLength=~0u; for (uint32 i=0;igetEventVector(time+i); uint32 length=(uint32)vect.size(); if (length<=bestLength) { bestLength= length; best=&vect; _Time = time + i; } } BOMB_IF(best==NULL,"BUG: This can never happen!",return) best->push_back(this); } inline NLMISC::TGameCycle CTimerEvent::getTime() const { return _Time; } inline CTimer* CTimerEvent::getOwner() const { return _Owner; } inline bool CTimerEvent::isActive() const { return _Owner!=NULL; } inline void CTimerEvent::clear() { _Owner=NULL; } inline void CTimerEvent::processEvent() { CTimer* owner=_Owner; BOMB_IF(owner==NULL,"Attempt to process an event that no longer has a valid owner",return) // mark the event as expired - the state may be chnaged during the timer callback... // NOTE: This operation results in '_Owner' being set to NULL _Owner->reset(); // call the virtual callback timerCallback(owner); } //------------------------------------------------------------------------------------------------- // inlines CTimerManager //------------------------------------------------------------------------------------------------- inline CTimerManager::CTimerManager() : _CurrentTick(0), _LastTick(0), _LocalTime(0), _UpdateTimeout(100) {} inline CTimerManager* CTimerManager::getInstance() { static CTimerManager* instance= NULL; if (instance==NULL) { instance=new CTimerManager; } return instance; } inline CTimerManager::TEventVector& CTimerManager::getEventVector(NLMISC::TGameCycle time) { return _EventVectors[uint32(time&TIMER_VECTOR_MASK)]; } //------------------------------------------------------------------------------------------------- #endif ================================================ FILE: code/EVA/server/server_share/tools.cpp ================================================ #include "tools.h" #include using namespace std; using namespace NLMISC; //NLMISC::CMutex LocalTime.m_mutex("LocalTime.m_mutex"); //char LocalTime.m_cstime[LocalTime.TIME_STR_MAX]; //NLMISC::TTime LocalTime.m_CurrTime; CLocalTime::CLocalTime():m_mutex("LocalTime.m_mutex"),m_TimeZone(0) { m_CurrTime = CTime::getLocalTime(); CalcTimeZone(); } tm CLocalTime::gettime( const time_t time ) { struct tm timeinfo; #ifdef NL_OS_UNIX localtime_r(&time, &timeinfo); #else localtime_s(&timeinfo, &time); #endif // NL_OS_UNIX //m_mutex.enter(); //tm *tms = std::localtime(&time); //timeinfo = *tms; //m_mutex.leave(); return timeinfo; } tm CLocalTime::gettime() { //time_t t; //time(&t); return gettime(std::time(NULL)); } uint32 CLocalTime::str2time(std::string strTime) { tm CurTime = LocalTime.gettime(CTime::getSecondsSince1970()); // ; std::string::size_type unOffsetA = strTime.find_first_of( '-' ); // ; if ( unOffsetA != std::string::npos ) { std::string year = strTime.substr( 0 , unOffsetA ); if ( year.empty() ) return 0; CurTime.tm_year = atoi( year.c_str() )-1900; strTime = strTime.substr( unOffsetA + 1 ); // ; unOffsetA = strTime.find_first_of( '-' ); if ( unOffsetA != std::string::npos ) { std::string mon = strTime.substr( 0 , unOffsetA ); if ( mon.empty() ) return -1; CurTime.tm_mon = atoi( mon.c_str() )-1; strTime = strTime.substr( unOffsetA + 1 ); // ; unOffsetA = strTime.find_first_of(' '); if ( unOffsetA != std::string::npos ) { std::string day = strTime.substr( 0 , unOffsetA ); if ( day.empty() ) return -1; CurTime.tm_mday = atoi( day.c_str() ); strTime = strTime.substr( unOffsetA + 1 ); } } } // ʱ; unOffsetA = strTime.find_first_of( ':' ); if ( unOffsetA != std::string::npos ) { std::string hour = strTime.substr( 0 , unOffsetA ); if ( hour.empty() ) return -1; CurTime.tm_hour = atoi( hour.c_str() ); strTime = strTime.substr( unOffsetA + 1 ); // ; unOffsetA = strTime.find_first_of( ':' ); if ( unOffsetA != std::string::npos ) { std::string min = strTime.substr( 0 , unOffsetA ); if ( min.empty() ) return -1; CurTime.tm_min = atoi( min.c_str() ); strTime = strTime.substr( unOffsetA + 1 ); // ; if ( !strTime.empty() ) { CurTime.tm_sec = atoi( strTime.c_str() ); } } } return (uint32)std::mktime(&CurTime); } uint32 CLocalTime::mktime( const uint year, const uint month, const uint day, const uint hour, const uint minute, const uint second ) { tm tms; tms.tm_year = year; tms.tm_mon = month; tms.tm_mday = day; tms.tm_hour = hour; tms.tm_min = minute; tms.tm_sec = second; tms.tm_isdst= 0; return (uint32)std::mktime(&tms); //nl_mktime } uint32 CLocalTime::gettime( TTimeOperaion time_opt, sint32 time_val, uint32 base_time ) { uint32 change_second = ( base_time > 0 ) ? base_time : CTime::getSecondsSince1970(); tm t = gettime( change_second ); switch (time_opt) { case NEXT_DAY: { // tm_mday [1-31] if ( t.tm_mday > time_val ) { // ǰڴҪڣ Ϊ¸µ ++t.tm_mon; t.tm_mday = time_val; } else { t.tm_mday = time_val; } change_second = std::mktime(&t); break; } case NEXT_WEEK: { // tm_mday [0-6] if ( t.tm_wday > time_val ) { // ǰڴҪڣ Ϊڵ sint day = t.tm_wday - time_val; change_second -= DAY_SECONDS * day; change_second += WEEK_SECONDS; } else { sint day = time_val - t.tm_wday; change_second += DAY_SECONDS * day; } break; } case NEXT_HOUR: { // tm_hour [0,23] if ( t.tm_hour > time_val ) { // ǰʱҪʱ䣬 Ϊڶʱ sint hour = t.tm_hour - time_val; change_second -= HOUR_SECONDS * hour; change_second += DAY_SECONDS; } else { sint hour = time_val - t.tm_hour; change_second += HOUR_SECONDS * hour; } break; } case ADD_HOUR: { sint32 day = time_val / DAY_HOURS; if (day>0) { //ҪNext_Hourһ tm_mdayϴڵ t.tm_mday += day; } else { t.tm_hour += time_val; } change_second = std::mktime(&t); break; } default: nlassertd(0); break; } return change_second; } uint32 CLocalTime::gettime( vector vct_opt ) { uint32 change_second = CTime::getSecondsSince1970(); //for ( uint i=0; itm_hour; } ================================================ FILE: code/EVA/server/server_share/tools.h ================================================ #ifndef SWG_TOOLS_H #define SWG_TOOLS_H #include #include #include #include #include "game_def.h" #include "utils.h" /// 基础小工具命名空间 //namespace SWG inline uint64 get_id64( uint64 regionid, uint64 idx ) { regionid = regionid << 48; uint64 id64 = regionid | idx; return id64; } //inline NLNET::TServiceId GetSID( DEF::RPC_SESSION session ) //{ // uint16 sid = session & 0x7f; // return NLNET::TServiceId(sid); //} inline uint16 GetSID( DEF::RPC_SESSION session ) { return session & 0x7f; } struct BaseTime { uint32 start_time; uint32 base_year; uint32 base_mon; uint32 base_mday; uint32 base_hour; uint32 base_min; uint32 base_sec; BaseTime(uint32 _time, uint32 _year, uint32 _mon, uint32 _mday, uint32 _hour, uint32 _min, uint32 _sec) : start_time( _time ), base_year( _year ), base_mon( _mon ), base_mday( _mday ), base_hour( _hour ), base_min( _min ), base_sec( _sec ) {} }; enum TTimeOperaion { NEXT_YEAR, NEXT_MON, NEXT_DAY, NEXT_WEEK, NEXT_HOUR, ADD_HOUR, }; struct TimeOPT { TTimeOperaion opt_type; sint32 value; TimeOPT( TTimeOperaion _opt, sint _value ) :opt_type(_opt),value(_value) {} }; const sint32 DAY_HOURS = 24; const sint32 MINUTE_SECONDS = 60; const sint32 HOUR_SECONDS = MINUTE_SECONDS * 60; const sint32 DAY_SECONDS = HOUR_SECONDS * 24; const sint32 WEEK_SECONDS = DAY_SECONDS * 7; //struct ADD_DAY : public TimeOPT //{ // ADD_DAY( sint day ) // :TimeOPT(TimeOPT::ADD_DAY,day){} //}; // //TimeOPT TimeOPTArray[] = //{ // TimeOPT(TimeOPT::ADD_DAY, 1), //}; class CLocalTime : public NLMISC::CSingleton { public: CLocalTime(); tm gettime(); tm gettime( const time_t time ); /// 根据字符串获取时间 接受格式:2014-12-26 3:0:0 uint32 str2time(std::string strTime); uint32 gettime( TTimeOperaion time_opt, sint32 time_val, uint32 _time=0/*, BaseTime base_time*/ ); uint32 gettime( std::vector vct_opt ); uint32 mktime( const uint year, const uint month, const uint day, const uint hour, const uint minute, const uint second ); const char* printtime(tm& tms); const char* printtime(const uint32 time); const NLMISC::TTime GetCurrTime() { return m_CurrTime; } void SetCurrTime( NLMISC::TTime curr_time ) { m_CurrTime = curr_time; } inline uint32 GetDay( uint32 time_seconds ) { return (time_seconds+(HOUR_SECONDS*m_TimeZone))/DAY_SECONDS; } inline bool SameDay( uint32 time_seconds1, uint32 time_seconds2 ) { return GetDay(time_seconds1)==GetDay(time_seconds2); } private: void CalcTimeZone(); private: enum { TIME_STR_MAX = 25, }; NLMISC::CMutex m_mutex; char m_cstime[TIME_STR_MAX]; NLMISC::TTime m_CurrTime; uint32 m_TimeZone; }; #define LocalTime CLocalTime::instance() const uint32 Crc32Table[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; inline uint32 crc32(uint32 crc, const uint8* buffer, uint length) { crc = crc ^ 0xffffffffL; for (uint i = 0; i < length; ++i) { crc = Crc32Table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8); } return (crc ^ 0xffffffffL); } #endif ================================================ FILE: code/EVA/server/server_share/utils.cpp ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . //------------------------------------------------------------------------------------------------- // includes //------------------------------------------------------------------------------------------------- #include "stdpch.h" #include "nel/misc/sstring.h" //------------------------------------------------------------------------------------------------- // namespaces //------------------------------------------------------------------------------------------------- using namespace NLMISC; //----------------------------------------------------------------------------- // cleanPath - convert a path to standardised format //----------------------------------------------------------------------------- CSString cleanPath(const CSString& path,bool addTrailingSlash) { CSString result; // split the path up into its component elements CVectorSString pathComponents; path.unquoteIfQuoted().splitByOneOfSeparators("/\\",pathComponents,false,false,true,false,true); // iterate over path components collapsing '.' and '..' entries for (uint32 i=0;i::max()) { pathComponents[j].clear(); pathComponents[i].clear(); } continue; } } // treat the special case where original path started with a '/' or '//' if (path.left(1)=="/" || path.left(1)=="\\") { result= (path.left(2).right(1)=="/" || path.left(2).right(1)=="\\")? "//": "/"; } // concatenate the path bits for (uint32 i=0;i // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UTILS_H #define UTILS_H //------------------------------------------------------------------------------------------------- // includes //------------------------------------------------------------------------------------------------- #include "nel/misc/types_nl.h" #include "nel/misc/common.h" #include "nel/misc/debug.h" #include "nel/misc/sstring.h" #include //------------------------------------------------------------------------------------------------- // UTILITY FUNCTIONS //------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------- inline std::string capitalize(const std::string & s) { if ( s.empty() ) return s; return NLMISC::toUpper( s.substr(0,1) ) + NLMISC::toLower( s.substr(1,std::string::npos) ); } inline ucstring capitalize(const ucstring & s) { if ( s.empty() ) return s; return NLMISC::toUpper( s.substr(0,1) ) + NLMISC::toLower( s.substr(1,std::string::npos) ); } //------------------------------------------------------------------------------------------------- // HANDY MACROS - For forcing the pre-preprocessor to evaluate concatenation operations nicely //------------------------------------------------------------------------------------------------- // a Few examples: // --------------- // // #define TOTO TATA // MACRO_CONCAT(a,TOTO) => aTOTO // MACRO_CONCAT2(a,TOTO) => aTATA // MACRO_TOTXT(TOTO) => "TOTO" // MACRO_TOTXT2(TOTO) => "TATA" // /// MACRO_CONCAT(a,__LINE__) => a__LINE__ // MACRO_CONCAT2(a,__LINE__) => a123 // MACRO_TOTXT(__LINE__) => "__LINE__" // MACRO_TOTXT2(__LINE__) => "123" // // __FILE_LINE__ => "utils.h:123:" #define MACRO_CONCAT(a,b) a##b #define MACRO_CONCAT2(a,b) CONCAT(a,b) #define MACRO_TOTXT(a) #a #define MACRO_TOTXT2(a) TOTXT(a) #define __FILE_LINE__ __FILE__ ":" TOTXT2(__LINE__)":" //------------------------------------------------------------------------------------------------- // LOGGING / DEBUGGING MACROS //------------------------------------------------------------------------------------------------- #ifdef NL_DEBUG #define DEBUG_STOP nlstop; #define nlassertd(a) nlassert(a) #else #define DEBUG_STOP \ std::string stack; \ NLMISC::getCallStack(stack); \ std::vector contexts;\ NLMISC::explode(stack, std::string("\n"), contexts);\ nldebug("Dumping callstack :"); \ for (uint i=0; i>test.cpp:21: Call Stack: // INF 3980: >>test.cpp:17 // INF 3980: >>test.cpp:17 // INF 3980: >>test.cpp:17 // INF 3980: >>test.cpp:26: foo // INF 3980: // INF 3980: >>test.cpp:33: Call Stack: // INF 3980: >>test.cpp:31: i=[0] // INF 3980: >>test.cpp:30: i=>[1] // INF 3980: >>test.cpp:26: foo // INF 3980: // WRN 3980: >>test.cpp:35: Call Stack: // WRN 3980: >>test.cpp:26: foo // WRN 3980: //------------------------------------------------------------------------------------------------- // A Little CallStack system - MACROS //------------------------------------------------------------------------------------------------- // CSTRACE - displays source file and line number // CSTRACE_MSG(msg) - as with trace but with additional simple text message eg TRACE_MSG("hello world") // CSTRACE_VAL(type,name) - displays a value (calculated at the moment that the trace is created) // CSTRACE_VAR(type,name) - displays the value of the given variable at the moment that callstack is displayed // SHOW_CALLSTACK - displays the callstack using NLMISC::InfoLog // WARN_CALLSTACK - displays the callstack using NLMISC::WarningLog #define CSTRACE\ class __CCallStackEntry##__LINE__: public ICallStackEntry\ {\ public:\ virtual void displayEntry(NLMISC::CLog& log) const\ {\ log.displayNL(">>"__FILE__":%d",__LINE__);\ }\ }\ __callStackEntry##__LINE__; #define CSTRACE_MSG(msg)\ class __CCallStackEntry##__LINE__: public ICallStackEntry\ {\ public:\ virtual void displayEntry(NLMISC::CLog& log) const\ {\ log.displayNL(">>"__FILE__":%d: %s",__LINE__,msg);\ }\ }\ __callStackEntry##__LINE__; #define CSTRACE_VAL(type,var)\ class __TraceVal_##var: public ICallStackEntry\ {\ public:\ __TraceVal_##var(const type& var): _Val(var) \ {\ }\ virtual void displayEntry(NLMISC::CLog& log) const\ {\ log.displayNL(">>"__FILE__":%d: %s=[%s]",__LINE__,#var,NLMISC::toString(_Val).c_str());\ }\ const type _Val;\ }\ __traceVal_##var(var); #define CSTRACE_VAR(type,var)\ class __TraceVar_##var: public ICallStackEntry\ {\ public:\ __TraceVar_##var(const type& var): _Var(var) \ {\ }\ virtual void displayEntry(NLMISC::CLog& log) const\ {\ log.displayNL(">>"__FILE__":%d: %s=>[%s]",__LINE__,#var,NLMISC::toString(_Var).c_str());\ }\ const type& _Var;\ }\ __traceVar_##var(var); #define SHOW_CALLSTACK { CSTRACE_MSG("Call Stack:"); CCallStackSingleton::display(NLMISC::InfoLog); } #define WARN_CALLSTACK { CSTRACE_MSG("Call Stack:"); CCallStackSingleton::display(NLMISC::WarningLog); } //------------------------------------------------------------------------------------------------- // A Little CallStack system - Private stack entry base class //------------------------------------------------------------------------------------------------- class ICallStackEntry { public: ICallStackEntry(); virtual ~ICallStackEntry(); void displayStack(NLMISC::CLog& log) const; virtual void displayEntry(NLMISC::CLog& log) const=0; private: ICallStackEntry* _Next; }; //------------------------------------------------------------------------------------------------- // A Little CallStack system - Public Singleton Class //------------------------------------------------------------------------------------------------- class CCallStackSingleton { public: static ICallStackEntry* getTopStackEntry(); static void setTopStackEntry(ICallStackEntry* newEntry); static void display(NLMISC::CLog *log=NLMISC::InfoLog); private: // this is a singleton so prohibit public construction CCallStackSingleton() {} // encapsulation of a variable to make it a singleton static ICallStackEntry*& topStackEntry(); }; //------------------------------------------------------------------------------------------------- // A Little CallStack system - Public Singleton inlines //------------------------------------------------------------------------------------------------- inline ICallStackEntry* CCallStackSingleton::getTopStackEntry() { return topStackEntry(); } inline void CCallStackSingleton::setTopStackEntry(ICallStackEntry* newEntry) { topStackEntry()= newEntry; } inline void CCallStackSingleton::display(NLMISC::CLog *log) { nlassert(log!=NULL); getTopStackEntry()->displayStack(*log); log->displayNL(""); } inline ICallStackEntry*& CCallStackSingleton::topStackEntry() { static ICallStackEntry* stackEntry=NULL; return stackEntry; } //------------------------------------------------------------------------------------------------- // A Little CallStack system - Private stack entry base inlines //------------------------------------------------------------------------------------------------- inline ICallStackEntry::ICallStackEntry() { // add self to the call stack _Next=CCallStackSingleton::getTopStackEntry(); CCallStackSingleton::setTopStackEntry(this); } inline ICallStackEntry::~ICallStackEntry() { // if this object is in the call stack then pop items off the top of the stack // until this object is no longer in the stack while (_Next!=this) { // get a pointer to the top object on the call stack ICallStackEntry* entry= CCallStackSingleton::getTopStackEntry(); nlassertd(entry!=NULL); // pop the object off the callstack CCallStackSingleton::setTopStackEntry(entry->_Next); // mark object as no longer in callstack entry->_Next=entry; } } inline void ICallStackEntry::displayStack(NLMISC::CLog& log) const { // stop recursing when we reach a NULL object // (this is implemented in this way in order to ximplify call code) if (this==NULL) return; // display this entry displayEntry(log); // recurse through call stack _Next->displayStack(log); } //------------------------------------------------------------------------------------------------- // HANDY Utility methods... //------------------------------------------------------------------------------------------------- inline NLMISC::CVectorSString& operator<<(NLMISC::CVectorSString& vect,const NLMISC::CSString s) { vect.push_back(s); return vect; } template inline T& vectAppend(std::vector& vect) { vect.resize(vect.size()+1); return vect.back(); } template inline void vectInsert(std::vector& vect,const T1& value) { for (uint32 i=0;i inline T& listAppend(std::list& list) { list.resize(list.size()+1); return list.back(); } inline NLMISC::CSString popString(NLMISC::IStream& stream) { std::string s; stream.serial(s); return s; } inline sint32 popSint(NLMISC::IStream& stream) { sint32 val; stream.serial(val); return val; } inline uint32 popUint(NLMISC::IStream& stream) { uint32 val; stream.serial(val); return val; } inline bool popBool(NLMISC::IStream& stream) { bool val; stream.serial(val); return val; } template inline void pushToStream(NLMISC::IStream& stream,const T& value) { stream.serial(const_cast(value)); } inline void pushToStream(NLMISC::IStream& stream,const char* txt) { std::string s(txt); stream.serial(s); } //------------------------------------------------------------------------------------------------- // HANDY IPtr and IConstPtr CLASSES //------------------------------------------------------------------------------------------------- // This class gives a base that can be specialised in order to make pointer encapsulation classes // it offers the basic standard methods that you have to define every time in the normal way... template class IPtr { public: IPtr() { _Ptr= NULL; } IPtr(C* p) { operator=(p); } IPtr& operator=(C* p) { _Ptr=p; return *this; } IPtr& operator=(IPtr& other) { _Ptr=other._Ptr; return *this; } IPtr& operator++() { ++_Ptr; return *this; } IPtr& operator--() { --_Ptr; return *this; } const C* operator->() const { return _Ptr; } const C& operator*() const { return *_Ptr; } operator C const *() const { return _Ptr; } C* operator->() { return _Ptr; } C& operator*() { return *_Ptr; } operator C*() { return _Ptr; } bool operator==(const IPtr& other) const { return _Ptr==other._Ptr; } bool operator!=(const IPtr& other) const { return _Ptr!=other._Ptr; } bool operator==(const C* p) const { return _Ptr==p; } bool operator!=(const C* p) const { return _Ptr!=p; } private: C * _Ptr; }; template class IConstPtr { public: IConstPtr() { _Ptr= NULL; } IConstPtr(const C* p) { operator=(p); } IConstPtr& operator=(const C* p) { _Ptr=p; return *this; } IConstPtr& operator=(const IConstPtr& other) { _Ptr=other._Ptr; return *this; } IConstPtr& operator++() { ++_Ptr; return *this; } IConstPtr& operator--() { --_Ptr; return *this; } const C* operator->() const { return _Ptr; } const C& operator*() const { return *_Ptr; } operator C const *() const { return _Ptr; } bool operator==(const IConstPtr& other) const { return _Ptr==other._Ptr; } bool operator!=(const IConstPtr& other) const { return _Ptr!=other._Ptr; } bool operator==(const C* p) const { return _Ptr==p; } bool operator!=(const C* p) const { return _Ptr!=p; } private: C const * _Ptr; }; //------------------------------------------------------------------------------------------------- // HANDY cleanPath() method for cleaning file system paths //------------------------------------------------------------------------------------------------- // Clean a path performing the following operations: // - convert '\\' characters to '/' // - replace '//' strings in the middle of the path with '/' // - remove '.' directory entries // - colapse '..' directory entries (removing parent entries) // - append a final '/' (optionally) // // examples: // - a:/bcd/efg/ => a:/bcd/efg/ (no change) // - a:\bcd\efg => a:/bcd/efg/ // - \bcd\\efg => /bcd/efg/ // - \\bcd\efg => //bcd/efg/ // - \bcd\.\efg => /bcd/efg/ // - \bcd\..\efg => /efg/ // - bcd\..\efg => efg/ // - bcd\..\..\efg => ../efg/ // - \bcd\..\..\efg => /efg/ (NOTE: the redundant '..' entry is lost due to leading '\') // NLMISC::CSString cleanPath(const NLMISC::CSString& path,bool addTrailingSlash); // //template //struct TTypeLimits //{ // static T max(); // static T min(); // static T floor(T value); //}; // //template <> //struct TTypeLimits //{ // static uint8 max() { return (uint8)0xff; } // static uint8 min() { return 0; } // enum // { // IsSigned = 0, // IsInteger = 1, // }; // static uint8 floor(uint8 value) { return value; } //}; //template <> //struct TTypeLimits //{ // static uint16 max() { return (uint16)0xffff; } // static uint16 min() { return 0; } // enum // { // IsSigned = 0, // IsInteger = 1, // }; // static uint16 floor(uint16 value) { return value; } //}; //template <> //struct TTypeLimits //{ // static uint32 max() { return 0xffffffffu; } // static uint32 min() { return 0; } // enum // { // IsSigned = 0, // IsInteger = 1, // }; // static uint32 floor(uint32 value) { return value; } //}; ///* //#ifdef NL_OS_WINDOWS //template <> //struct TTypeLimits : public TTypeLimits //{ //}; //#endif //*/ //template <> //struct TTypeLimits //{ // static uint64 max() { return UINT64_CONSTANT(0xffffffffffffffff); } // static uint64 min() { return 0; } // enum // { // IsSigned = 0, // IsInteger = 1, // }; // static uint64 floor(uint64 value) { return value; } //}; // //template <> //struct TTypeLimits //{ // static sint8 max() { return (sint8)0x7f; } // static sint8 min() { return (sint8)0x80; } // enum // { // IsSigned = 1, // IsInteger = 1, // }; // static sint8 floor(sint8 value) { return value; } //}; //template <> //struct TTypeLimits //{ // static sint16 max() { return (sint16)0x7fff; } // static sint16 min() { return (sint16)0x8000; } // enum // { // IsSigned = 1, // IsInteger = 1, // }; // static sint16 floor(sint16 value) { return value; } //}; //template <> //struct TTypeLimits //{ // static sint32 max() { return (sint32)0x7fffffff; } // static sint32 min() { return (sint32)0x80000000; } // enum // { // IsSigned = 1, // IsInteger = 1, // }; // static sint32 floor(sint32 value) { return value; } //}; ///*#ifdef NL_OS_WINDOWS //template <> //struct TTypeLimits : public TTypeLimits //{ //}; //#endif*/ //template <> //struct TTypeLimits //{ // static sint64 max() { return SINT64_CONSTANT(0x7fffffffffffffff); } // static sint64 min() { return SINT64_CONSTANT(0x8000000000000000); } // enum // { // IsSigned = 1, // IsInteger = 1, // }; // static sint64 floor(sint64 value) { return value; } //}; // //template <> //struct TTypeLimits //{ // static float max() { return FLT_MAX; } // static float min() { return FLT_MIN; } // enum // { // IsSigned = 1, // IsInteger = 0, // }; // static float floor(float f) { return f < 0 ? (float)::ceil(f) : (float)::floor(f); } //}; //template <> //struct TTypeLimits //{ // static double max() { return DBL_MAX; } // static double min() { return DBL_MIN; } // enum // { // IsSigned = 1, // IsInteger = 0, // }; // static double floor(double d) { return d < 0 ? ::ceil(d) : ::floor(d); } //}; // // // //template //inline T checkedCast(U val) //{ // typedef TTypeLimits TLimitIn; // typedef TTypeLimits TLimitOut; // // // Only allow checked cast to integer type ! // nlctassert(TLimitOut::IsInteger); // // T dest = (T) val; // U check = (U) dest; // // if (val < 0) // { // BOMB_IF(check != TLimitIn::floor(val), "checkedCast : Value "< ./aes_alias_name.cfg if [ $(grep "AESPort[ \t]*=" */*cfg | grep -v debug | sed "s/.*=[ \t]*//" | sort -u | wc -l) -gt 1 ] ; then echo - FIXME: services don\'t agree on AESPort ; read fi if [ $(grep "AESPort[ \t]*=" */*cfg | grep -v debug | sed "s/.*=[ \t]*//" | sort -u | wc -l) -eq 1 ] ; then echo AESPort=$(grep "AESPort[ \t]*=" */*cfg| grep -v debug | sed "s/.*=[ \t]*//" | sort -u) >> ./aes_alias_name.cfg fi if [ $(grep "ASPort[ \t]*=" */*cfg | grep -v debug | sed "s/.*=[ \t]*//" | sort -u | wc -l) -gt 1 ] ; then echo - FIXME: services don\'t agree on ASPort ; read fi if [ $(grep "ASPort[ \t]*=" */*cfg | grep -v debug | sed "s/.*=[ \t]*//" | sort -u | wc -l) -eq 1 ] ; then echo ASPort=$(grep "ASPort[ \t]*=" */*cfg| grep -v debug | sed "s/.*=[ \t]*//" | sort -u) >> ./aes_alias_name.cfg fi ./live/service_ryzom_admin_service/ryzom_admin_service -A. -C. -L. --nobreak --fulladminname=admin_executor_service --shortadminname=AES sleep 2 done ================================================ FILE: code/EVA/tools/scripts/linux/mt_domain_screen_wrapper.sh ================================================ #!/bin/sh CMD=$1 #DOMAIN=$(pwd|sed s%/home/nevrax/%%) DOMAIN=shard if [ "$CMD" = "" ] then echo echo Screen sessions currently running: screen -list echo echo "Commands:" echo " 'start' to start the shard" echo " 'stop' to stop the ${DOMAIN}" echo " 'join' to join the ${DOMAIN}'s screen session" echo " 'share' to join the screen session in shared mode" echo " 'state' to view state information for the ${DOMAIN}" echo printf "Enter a command: " read CMD fi if [ "$CMD" = "stop" ] then if [ $(screen -list | grep \\\.${DOMAIN} | wc -l) != 1 ] then echo Cannot stop domain \'${DOMAIN}\' because no screen by that name appears to be running screen -list else screen -d -r $(screen -list | grep \\\.${DOMAIN}| sed 's/(.*)//') -X quit> /dev/null rm -v */*.state rm -v */*launch_ctrl ./global.launch_ctrl fi fi STARTARGS= if [ "$CMD" = "batchstart" ] then STARTARGS='-d -m' CMD='start' fi if [ "$CMD" = "start" ] then ulimit -c unlimited screen -wipe > /dev/null if [ $( screen -list | grep \\\.${DOMAIN} | wc -w ) != 0 ] then echo Cannot start domain \'${DOMAIN}\' because this domain is already started screen -list | grep $DOMAIN else screen $STARTARGS -S ${DOMAIN} -c ${DOMAIN}.screen.rc fi if [ "$STARTARGS" != "" ] then # on "batchstart", AES needs to be launched and AES will then launch other services printf LAUNCH > aes/aes.launch_ctrl fi fi if [ "$CMD" = "join" ] then if [ $(screen -list | grep \\\.${DOMAIN} | wc -l) != 1 ] then echo Cannot join domain \'${DOMAIN}\' because no screen by that name appears to be running screen -list else screen -r $(screen -list | grep \\\.${DOMAIN}| sed 's/(.*)//') fi fi if [ "$CMD" = "share" ] then if [ $(screen -list | grep \\\.${DOMAIN} | wc -l) != 1 ] then echo Cannot join domain \'${DOMAIN}\' because no screen by that name appears to be running screen -list else screen -r -x $(screen -list | grep \\\.${DOMAIN}| sed 's/(.*)//') fi fi if [ "$CMD" = "state" ] then echo State of domain ${DOMAIN}: if [ "$(echo */*.state)" = "*/*.state" ] then echo - No state files found else grep RUNNING */*state fi fi ================================================ FILE: code/EVA/tools/scripts/linux/service_launcher.sh ================================================ #!/bin/sh # the object is to make a launcher script that works with a command file to determine when to launch the application that it is responsible for #DOMAIN=$(pwd |sed "s%/home/nevrax/%%" | sed "s%/.*%%") DOMAIN=shard #NAME_BASE=$(pwd | sed 's/\/home\/nevrax\///' | sed 's/^.*\///') NAME_BASE="$1/$1" mkdir $1 shift #if [ _$DOMAIN == _pre_live ] # then CTRL_FILE=${NAME_BASE}.launch_ctrl NEXT_CTRL_FILE=${NAME_BASE}.deferred_launch_ctrl #elif [ _$DOMAIN == _pre_pre_live ] # then # CTRL_FILE=${NAME_BASE}.launch_ctrl # NEXT_CTRL_FILE=${NAME_BASE}.deferred_launch_ctrl #else # CTRL_FILE=${NAME_BASE}_immediate.launch_ctrl # NEXT_CTRL_FILE=${NAME_BASE}_waiting.launch_ctrl #fi STATE_FILE=${NAME_BASE}.state START_COUNTER_FILE=${NAME_BASE}.start_count CTRL_CMDLINE=$* echo echo --------------------------------------------------------------------------------- echo Starting service launcher echo --------------------------------------------------------------------------------- printf "%-16s = " CMDLINE ; echo $CTRL_CMDLINE printf "%-16s = " CTRL_FILE ; echo $CTRL_FILE printf "%-16s = " NEXT_CTRL_FILE ; echo $NEXT_CTRL_FILE printf "%-16s = " STATE_FILE ; echo $STATE_FILE echo --------------------------------------------------------------------------------- echo # reinit the start counter echo 0 > $START_COUNTER_FILE START_COUNTER=0 echo Press ENTER to launch program while true do # see if the conditions are right to launch the app if [ -e $CTRL_FILE ] then # a control file exists so read it's contents CTRL_COMMAND=_$(cat $CTRL_FILE)_ # do we have a 'launch' command? if [ $CTRL_COMMAND = _LAUNCH_ ] then # update the start counter START_COUNTER=$(( $START_COUNTER + 1 )) echo $START_COUNTER > $START_COUNTER_FILE # big nasty hack to deal with the special cases of ryzom_naming_service and ryzom_admin_service who have badly names cfg files #for f in ryzom_*cfg # do # cp $f $(echo $f | sed "s/ryzom_//") #done # we have a launch command so prepare, launch, wait for exit and do the housekeeping echo ----------------------------------------------------------------------- echo Launching ... echo printf RUNNING > $STATE_FILE $CTRL_CMDLINE echo ----------------------------------------------------------------------- printf STOPPED > $STATE_FILE # consume (remove) the control file to allow start once rm -f $CTRL_FILE echo Press ENTER to relaunch fi fi # either we haven't launched the app yet or we have launched and it has exitted if [ -e $NEXT_CTRL_FILE ] then # we have some kind of relaunch directive lined up so deal with it mv $NEXT_CTRL_FILE $CTRL_FILE else # give the terminal user a chance to press enter to provoke a re-launch when auto-relaunch in AES is disabled HOLD=`sh -ic '{ read a; echo "ENTER" 1>&3; kill 0; } | { sleep 2; kill 0; }' 3>&1 2>/dev/null` if [ "${HOLD}" = "ENTER" ] then printf LAUNCH > $CTRL_FILE fi fi done ================================================ FILE: code/EVA/tools/scripts/linux/shard ================================================ #!/bin/sh if [ -z "${MT_PATH+xxx}" ]; then echo "ERROR: The variable MT_PATH must be set! (e.g. /home/username/mt/code/mt)"; exit 1; fi cd $MT_PATH/server /bin/sh $MT_PATH/tools/scripts/linux/mt_domain_screen_wrapper.sh $* ================================================ FILE: code/EVA/tools/scripts/linux/utilities ================================================ #!/bin/sh - SSH_AGENT_FILE="$HOME/ssh_agent_file" BASENAME=`basename $0` LOG_INFO="$MT_PATH/log/${BASENAME}_info.log" LOG_ERROR="$MT_PATH/log/${BASENAME}_error.log" # first param is the subject line # others params are email send_mail() { SUBJECT=$1 shift echo Send mail to $* with log $LOG_ERROR in body and subject $SUBJECT cat $LOG_ERROR | mail -s "$SUBJECT on `hostname`" $* } print_success() { echo "*********************** $* SUCCESS !" echo } print_failure() { echo "***************************************************" echo "***************************************************" echo "*********************** $* FAILED" echo "***************************************************" echo "***************************************************" } # failed fill the log and send email if necessary # argument are the error message failed() { print_failure $* if [ "X$LOG_INFO" != "X" ] then print_failure $* >> $LOG_INFO fi if [ "X$LOG_ERROR" != "X" ] then print_failure $* >> $LOG_ERROR fi if [ "X$MAIL_ERROR" != "X" ] then send_mail "$* FAILED" $MAIL_ERROR else echo "No email to send the error mail" >> $LOG_ERROR fi echo "exiting..." exit } # useful function to avoid continuing if something goes wrong # first param is $? and second is the string that will display verify() { if [ $1 -eq 0 ] then shift print_success $* if [ "X$LOG_INFO" != "X" ] then print_success $* >> $LOG_INFO fi if [ "X$LOG_ERROR" != "X" ] then print_success $* >> $LOG_ERROR fi else shift failed $* fi } # step_failed() fills the log and increments $STEPS_FAILURES step_failed() { print_failure $* if [ "X$LOG_INFO" != "X" ] then print_failure $* >> $LOG_INFO fi if [ "X$LOG_ERROR" != "X" ] then print_failure $* >> $LOG_ERROR fi if [ "X$STEPS_FAILURES" = "X" ] then STEPS_FAILURES=0 else STEPS_FAILURES=`expr $STEPS_FAILURES + 1` fi } # call init_steps() before you use step() # it takes a label for following steps as parameter init_steps() { STEPS_LABEL="$*" STEPS_FAILURES=0 } # like verify() but will continue even if step failed until verify_steps() is called # first param is $? and second is the string that will display step() { if [ $1 -eq 0 ] then shift print_success $* if [ "X$LOG_INFO" != "X" ] then print_success $* >> $LOG_INFO fi if [ "X$LOG_ERROR" != "X" ] then print_success $* >> $LOG_ERROR fi else shift step_failed $* fi } # call verify_steps() when you want to stop if error(s) occured in previous steps verify_steps() { if [ $STEPS_FAILURES -eq 0 ] then print_success $STEPS_LABEL if [ "X$LOG_INFO" != "X" ] then print_success $STEPS_LABEL >> $LOG_INFO fi if [ "X$LOG_ERROR" != "X" ] then print_success $STEPS_LABEL >> $LOG_ERROR fi else if [ $STEPS_FAILURES -eq 1 ] then failed "1 step failed: $STEPS_LABEL" else failed "$STEPS_FAILURES steps failed: $STEPS_LABEL" fi fi } ask_confirmation() { echo "Using this script will destroy the current version, type 'yes' if you really want to do that" read CONF if [ "X$CONF" != "Xyes" ]; then failed "You didn't answer 'yes', I stop the script!" fi } check_host() { HOST=`hostname -s` if [ "X$HOST" != "X$1" ]; then failed "You can execute this script only on '$1' and not on '$HOST'" fi } # useful function to initialize the default log for all scripts init() { if [ "X$LOG_INFO" != "X" ] then test -d `dirname $LOG_INFO` || mkdir -p `dirname $LOG_INFO` test ! -f $LOG_INFO || rm $LOG_INFO touch $LOG_INFO # display all ulimit in the log ulimit -a >>$LOG_INFO fi if [ "X$LOG_ERROR" != "X" ] then test -d `dirname $LOG_ERROR` || mkdir -p `dirname $LOG_ERROR` test ! -f $LOG_ERROR || rm $LOG_ERROR touch $LOG_ERROR fi } init_ssh() { if [ ! -f $SSH_AGENT_FILE ] then failed "the file $SSH_AGENT_FILE not exist, you must call create_ssh_agent_file first" fi eval `cat $SSH_AGENT_FILE` } ================================================ FILE: code/README ================================================ ================================================ FILE: code/changelog.template ================================================ # To generate ChangeLog files use these commands : # hg log -M --style ./changelog.template nel > nel/ChangeLog # hg log -M --style ./changelog.template ryzom > ryzom/ChangeLog header = '\n{date|shortdate} {author}\n\n' changeset = '\t* {desc|fill68|tabindent|strip} [r{rev}]\n' ================================================ FILE: code/config.h.cmake ================================================ #ifndef CONFIG_H #define CONFIG_H #cmakedefine HAVE_DL_H 1 #cmakedefine HAVE_EXECINFO_H 1 #cmakedefine HAVE_ICONV 1 #cmakedefine HAVE_INTTYPES_H 1 #cmakedefine HAVE_LANGINFO_CODESET 1 #cmakedefine HAVE_LIMITS_H 1 #cmakedefine HAVE_MALLOC_H 1 #cmakedefine HAVE_PAM_MISC_H 1 #cmakedefine HAVE_PAM_PAM_APPL_H 1 #cmakedefine HAVE_PTHREAD 1 #cmakedefine HAVE_SECURITY_PAM_APPL_H 1 #cmakedefine HAVE_SECURITY_PAM_MISC_H 1 #cmakedefine HAVE_STDINT_H 1 #cmakedefine HAVE_SYS_MOUNT_H 1 #cmakedefine HAVE_SYS_PARAM_H 1 #cmakedefine HAVE_SYS_STATVFS_H 1 #cmakedefine HAVE_SYS_TYPES_H 1 #cmakedefine HAVE_UNISTD_H 1 #cmakedefine HAVE_UTIME_H 1 #cmakedefine HAVE_WCHAR_H 1 #cmakedefine HAVE_BACKTRACE 1 #cmakedefine HAVE_INET_NTOA 1 #cmakedefine HAVE_INET_NTOP 1 #cmakedefine HAVE_INET_PTON 1 #cmakedefine HAVE_STRERROR 1 #cmakedefine HAVE_STRLCAT 1 #cmakedefine HAVE_STRPTIME 1 #cmakedefine HAVE_STRTOK_R 1 #cmakedefine HAVE_STRTOULL 1 #cmakedefine HAVE_STATVFS 1 #cmakedefine HAVE_STAT64 1 #cmakedefine NL_OPENGL_AVAILABLE ${NL_OPENGL_AVAILABLE} #cmakedefine NL_OPENGLES_AVAILABLE ${NL_OPENGLES_AVAILABLE} #cmakedefine NL_DIRECT3D_AVAILABLE ${NL_DIRECT3D_AVAILABLE} #cmakedefine NL_FMOD_AVAILABLE ${NL_FMOD_AVAILABLE} #cmakedefine NL_OPENAL_AVAILABLE ${NL_OPENAL_AVAILABLE} #cmakedefine NL_DSOUND_AVAILABLE ${NL_DSOUND_AVAILABLE} #cmakedefine NL_XAUDIO2_AVAILABLE ${NL_XAUDIO2_AVAILABLE} #cmakedefine NL_BIN_PREFIX "${NL_BIN_ABSOLUTE_PREFIX}" #cmakedefine NL_ETC_PREFIX "${NL_ETC_ABSOLUTE_PREFIX}" #cmakedefine NL_SHARE_PREFIX "${NL_SHARE_ABSOLUTE_PREFIX}" #cmakedefine NL_LIB_PREFIX "${NL_LIB_ABSOLUTE_PREFIX}" #cmakedefine NL_DRIVER_PREFIX "${NL_DRIVER_ABSOLUTE_PREFIX}" #cmakedefine RYZOM_BIN_PREFIX "${RYZOM_BIN_ABSOLUTE_PREFIX}" #cmakedefine RYZOM_ETC_PREFIX "${RYZOM_ETC_ABSOLUTE_PREFIX}" #cmakedefine RYZOM_SHARE_PREFIX "${RYZOM_SHARE_ABSOLUTE_PREFIX}" #endif // CONFIG_H ================================================ FILE: code/nel/AUTHORS ================================================ Please check www.nevrax.org for more information ================================================ FILE: code/nel/CMakeLists.txt ================================================ PROJECT(NeL CXX C) IF(WITH_STATIC_DRIVERS) ADD_DEFINITIONS(-DNL_STATIC) ENDIF(WITH_STATIC_DRIVERS) # On Windows we need to find DirectInput for NLMISC. # This is how we get events. IF(WIN32) # FIND_PACKAGE(DirectXSDK REQUIRED) # On Win32 we can also build the MAX plugins. IF(WITH_NEL_MAXPLUGIN) FIND_PACKAGE(3dsMaxSDK) ENDIF(WITH_NEL_MAXPLUGIN) ENDIF(WIN32) IF(WITH_3D) FIND_PACKAGE(FreeType) IF(WITH_NEL_CEGUI) FIND_PACKAGE(CEGUI) ENDIF(WITH_NEL_CEGUI) ENDIF(WITH_3D) IF(WITH_SOUND) FIND_PACKAGE(Ogg) FIND_PACKAGE(Vorbis) IF(WITH_DRIVER_OPENAL) FIND_PACKAGE(OpenAL) ENDIF(WITH_DRIVER_OPENAL) IF(WITH_DRIVER_FMOD) FIND_PACKAGE(FMOD) ENDIF(WITH_DRIVER_FMOD) ENDIF(WITH_SOUND) IF(WITH_GTK) FIND_PACKAGE(GTK2) ENDIF(WITH_GTK) IF(WITH_INSTALL_LIBRARIES) IF(UNIX) SET(prefix ${CMAKE_INSTALL_PREFIX}) SET(exec_prefix ${NL_BIN_ABSOLUTE_PREFIX}) SET(libdir ${NL_LIB_ABSOLUTE_PREFIX}) SET(includedir ${CMAKE_INSTALL_PREFIX}/include) SET(enable_ligo ${WITH_LIGO}) SET(enable_logic ${WITH_LOGIC}) SET(enable_georges ${WITH_GEORGES}) SET(enable_net ${WITH_NET}) SET(enable_3d ${WITH_3D}) SET(enable_pacs ${WITH_PACS}) SET(enable_sound ${WITH_SOUND}) CONFIGURE_FILE(nel-config.in ${CMAKE_CURRENT_BINARY_DIR}/nel-config) INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/nel-config DESTINATION ${NL_BIN_PREFIX}) ENDIF(UNIX) ADD_SUBDIRECTORY(include) ENDIF(WITH_INSTALL_LIBRARIES) ADD_SUBDIRECTORY(src) IF(WITH_NEL_SAMPLES) ADD_SUBDIRECTORY(samples) ENDIF(WITH_NEL_SAMPLES) # Allow to compile only max plugins without other tools. IF(WITH_NEL_TOOLS OR WITH_NEL_MAXPLUGIN) IF(WITH_NEL_TOOLS) FIND_PACKAGE(Squish) ENDIF(WITH_NEL_TOOLS) ADD_SUBDIRECTORY(tools) ENDIF(WITH_NEL_TOOLS OR WITH_NEL_MAXPLUGIN) ================================================ FILE: code/nel/COPYING ================================================ GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . ================================================ FILE: code/nel/ChangeLog ================================================ Please check http://dev.ryzom.com/projects/nel/roadmap for more information. ================================================ FILE: code/nel/INSTALL ================================================ Please check www.nevrax.org for more information ================================================ FILE: code/nel/NEWS ================================================ Please check www.nevrax.org for more information ================================================ FILE: code/nel/README ================================================ Introduction ------------ NeL is a software platform for creating and running massively multi-user entertainment in a 3D environment over the Internet. The NeL library is further divided into specific modules: network, ai, 3d and misc. If you want to use any of these, you also need to use the misc part of the library, but ai, 3d and network are totally independant from each other so you can use only the parts you really need in your project. If you want know more about the library content and functionalities, you should take a look on the documents present in the doc directory. NeL is currently developped and tested under GNU/Linux and Windows environments. License ------- NeL is a Free Software project under the GNU Affero General Public License, which means all its code is available for everyone to download, examine, use, modify, and distribute, subject to the usual restrictions attached to any GPL software. If you are not familiar with the AGPL, see the COPYING file for for more details on license terms and other legal issues. Installation ------------ Please check the dev.ryzom.com for more information ================================================ FILE: code/nel/include/CMakeLists.txt ================================================ SUBDIRS(nel) ================================================ FILE: code/nel/include/nel/CMakeLists.txt ================================================ SUBDIRS(misc) IF(WITH_3D) SUBDIRS(3d) ENDIF(WITH_3D) IF(WITH_GUI) ADD_SUBDIRECTORY(gui) ENDIF(WITH_GUI) IF(WITH_GEORGES) SUBDIRS(georges) ENDIF(WITH_GEORGES) IF(WITH_LIGO) SUBDIRS(ligo) ENDIF(WITH_LIGO) IF(WITH_LOGIC) SUBDIRS(logic) ENDIF(WITH_LOGIC) IF(WITH_NET) SUBDIRS(net) ENDIF(WITH_NET) IF(WITH_SOUND) SUBDIRS(sound) ENDIF(WITH_SOUND) IF(WITH_PACS) SUBDIRS(pacs) ENDIF(WITH_PACS) IF(WITH_NEL_CEGUI) SUBDIRS(cegui) ENDIF(WITH_NEL_CEGUI) ================================================ FILE: code/nel/include/nel/georges/CMakeLists.txt ================================================ FILE(GLOB HEADERS *.h) INSTALL(FILES ${HEADERS} DESTINATION include/nel/georges COMPONENT headers) ================================================ FILE: code/nel/include/nel/georges/form.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_FORM_H #define NL_FORM_H #include "nel/misc/types_nl.h" #include "nel/georges/u_form.h" #include "form_elm.h" #include "header.h" extern bool convertFormFile (const char *oldFileName, const char *newFileName); namespace NLGEORGES { class UFormElm; /** * This class implement a georges form. */ class CForm : public UForm { friend class CFormLoader; friend bool convertFormFile (const char *oldFileName, const char *newFileName); public: enum { HeldElementCount = 4 }; // From UForm UFormElm& getRootNode (); const UFormElm& getRootNode () const; const std::string &getComment () const; void write (class NLMISC::IStream &stream); void getDependencies (std::set &dependencies) const; uint getNumParent () const; UForm *getParentForm (uint parent) const; #ifdef NL_OS_WINDOWS # pragma warning (disable : 4355) #endif CForm (); ~CForm (); // Clean the form. Erase parents. void clean (); // ** Types // ** Header CFileHeader Header; // ** Body /// Vector of CFormElm* CFormElmStruct Elements; /// Backup slots CFormElmStruct *HeldElements[HeldElementCount]; // ** IO functions // Set the filename before saving the form void write (xmlDocPtr doc, const char *filename); // ** Parent access // Insert parent before parent indexed "before". bool insertParent (uint before, const char *filename, CForm *parent); // Remove a parent from parent list void removeParent (uint parent); // Get a parent CForm * getParent (uint parent) const; const std::string &getParentFilename (uint parent) const; // Get parent count uint getParentCount () const; // Clear parents void clearParents (); // Get the form filename with extension const std::string &getFilename () const; // Error handling void warning (bool exception, const char *function, const char *format, ... ) const; private: // A parent structure class CParent { public: std::string ParentFilename; NLMISC::CSmartPtr Parent; }; /// Pointer on the parent std::vector ParentList; // CFormLoader call it // Set the filename before reading the form void read (xmlNodePtr node, CFormLoader &loader, CFormDfn *dfn, const char *filename); // Called by read void readParent (const char *parent, CFormLoader &loader); // The form filename std::string _Filename; }; } // NLGEORGES #endif // NL_FORM_H ================================================ FILE: code/nel/include/nel/georges/form_dfn.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_FORM_DFN_H #define NL_FORM_DFN_H #include "nel/misc/types_nl.h" #include "nel/misc/smart_ptr.h" #include "nel/georges/u_form_dfn.h" #include "nel/georges/u_form_elm.h" #include "header.h" #include "type.h" bool convertDfnFile (const char *oldFileName, const char *newFileName); namespace NLGEORGES { class CFormLoader; /** * This class is the defnition for a family of forms. */ class CFormDfn : public UFormDfn { friend class CForm; friend class CType; friend class CFormElm; friend class CFormLoader; friend class CFormElmStruct; friend bool convertDfnFile (const char *oldFileName, const char *newFileName); public: // Default cstr CFormDfn () { Round = 0xffffffff; } virtual ~CFormDfn () { } // A form definition entry class CEntry { friend class CType; friend class CForm; friend class CFormElm; friend class CFormDfn; friend class CFormElmStruct; friend bool convertDfnFile (const char *oldFileName, const char *newFileName); public: CEntry () { TypeElement = EntryType; FilenameExt = "*.*"; } // Get the type class CType *getTypePtr (); // Get the type const CType *getTypePtr () const; // Get the dfn CFormDfn *getDfnPtr (); // Get the dfn const CFormDfn *getDfnPtr () const; // Get type flag TEntryType getType () const; // Set as a type void setType (CFormLoader &loader, const char *filename); void setType (TEntryType type); // Set as a dfn void setDfn (CFormLoader &loader, const char *filename); // Set as a dfn pointer void setDfnPointer (); // Get element Name const std::string &getName () const; // Set element Name void setName (const char *name); // Get the filename const std::string &getFilename() const; // Get the filename extension const std::string &getFilenameExt() const; // Set the filename void setFilename (const char *def); // Set the filename extension void setFilenameExt (const char *ext); // Get default value const std::string &getDefault () const; // Set default value void setDefault (const char *def); // Set array flag void setArrayFlag (bool flag); // Get array flag bool getArrayFlag () const; private: // Entry name std::string Name; // What is the type of the element ? TEntryType TypeElement; // Is an array of this type ? bool Array; // The filename std::string Filename; // The default value for atom std::string Default; // The filename std::string FilenameExt; // Smart ptr on the type or the dfn NLMISC::CSmartPtr Type; // Smart ptr on the type or the dfn NLMISC::CSmartPtr Dfn; }; // Parent DFN class CParent { public: // The parent filename std::string ParentFilename; // The parent smart NLMISC::CSmartPtr Parent; }; void addEntry( const std::string &name ); void removeEntry( uint idx ); // ** IO functions void write (xmlDocPtr root, const char *filename); // Count parent DFN uint countParentDfn (uint32 round=0) const; // Get parent DFN void getParentDfn (std::vector &array, uint32 round=0); // Get parent DFN void getParentDfn (std::vector &array, uint32 round=0) const; // Get num parent uint getNumParent () const; // Get parent count void setNumParent (uint size); // Set a parent void setParent (uint parent, CFormLoader &loader, const char *filename); // Get a parent CFormDfn *getParent (uint parent) const; // Get a parent string const std::string &getParentFilename (uint parent) const; // Get num entry uint getNumEntry () const; // Set num entry void setNumEntry (uint size); // Get an entry const CEntry &getEntry (uint entry) const; // Get an entry CEntry &getEntry (uint entry); // Form UFormDfn bool getEntryType (uint entry, TEntryType &type, bool &array) const; bool getEntryName (uint entry, std::string &name) const; bool getEntryIndexByName (uint &entry, const std::string &name) const; bool getEntryDfn (uint entry, UFormDfn **dfn); bool getEntryByName (const std::string &name, CFormDfn::CEntry **entry); bool getEntryDfnByName (const std::string &name, UFormDfn **dfn); bool isAnArrayEntryByName (const std::string &name) const; bool getEntryType (uint entry, UType **type); uint getNumParents () const; bool getParent (uint parent, UFormDfn **parentRet); const std::string &getComment () const; bool getEntryFilename (uint entry, std::string& filename) const; bool getEntryFilenameExt (uint entry, std::string& filename) const; bool getParentFilename (uint parent, std::string &filename) const; void getDependencies (std::set &dependencies) const; // Get the sub dfn of a dfn CFormDfn *getSubDfn (uint index, uint &dfnIndex); const CFormDfn *getSubDfn (uint index, uint &dfnIndex) const; // Header CFileHeader Header; // Error handling void warning (bool exception, const char *function, const char *format, ... ) const; private: // The parents array std::vector Parents; // A vector of entries std::vector Entries; // Recursive call count mutable uint32 Round; // The form DFN filename std::string _Filename; private: // Read method called by the form loader void read (xmlNodePtr doc, CFormLoader &loader, bool forceLoad, const char *filename); }; } // NLGEORGES #endif // NL_FORM_DFN_H ================================================ FILE: code/nel/include/nel/georges/form_elm.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_FORM_ELM_H #define NL_FORM_ELM_H #include "nel/georges/u_form_elm.h" #include "nel/misc/smart_ptr.h" #include "nel/misc/rgba.h" #include "form_dfn.h" #define NLGEORGES_FIRST_ROUND 0 #define NLGEORGES_MAX_RECURSION 100 namespace NLGEORGES { class CType; class CFormDfn; class CForm; /** * Base class of form elements */ class CFormElm : public UFormElm { friend class CForm; friend class CType; friend class CFormDfn; public: // Contructor CFormElm (CForm *form, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex); // Destructor virtual ~CFormElm (); /// Reset contents virtual void clean() {} // Get the form pointer CForm *getForm () const; // Is the element used by this form ? virtual bool isUsed (const CForm *form) const; // Get the form name of the element virtual void getFormName (std::string &result, const CFormElm *child=NULL) const = 0; // From UFormElm virtual bool getNodeByName (const UFormElm **result, const char *name, TWhereIsNode *where, bool verbose, uint32 round=0) const; virtual bool getNodeByName (UFormElm **result, const char *name, TWhereIsNode *where, bool verbose, uint32 round=0); virtual bool getValueByName (std::string &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const; virtual bool getValueByName (sint8 &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const; virtual bool getValueByName (uint8 &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const; virtual bool getValueByName (sint16 &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const; virtual bool getValueByName (uint16 &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const; virtual bool getValueByName (sint32 &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const; virtual bool getValueByName (uint32 &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const; virtual bool getValueByName (float &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const; virtual bool getValueByName (double &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const; virtual bool getValueByName (bool &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const; virtual bool getValueByName (NLMISC::CRGBA &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const; virtual bool setValueByName (const char *value, const char *name, bool *created); virtual bool setValueByName (sint8 value, const char *name, bool *created); virtual bool setValueByName (uint8 value, const char *name, bool *created); virtual bool setValueByName (sint16 value, const char *name, bool *created); virtual bool setValueByName (uint16 value, const char *name, bool *created); virtual bool setValueByName (sint32 value, const char *name, bool *created); virtual bool setValueByName (uint32 value, const char *name, bool *created); virtual bool setValueByName (float value, const char *name, bool *created); virtual bool setValueByName (double value, const char *name, bool *created); virtual bool setValueByName (bool value, const char *name, bool *created); virtual bool setValueByName (NLMISC::CRGBA value, const char *name, bool *created); virtual UFormElm *getParent () const; virtual const CType *getType (); virtual bool isArray () const; virtual bool getArraySize (uint &size) const; virtual bool getArrayNode (const UFormElm **result, uint arrayIndex) const; virtual bool getArrayNode (UFormElm **result, uint arrayIndex); virtual bool getArrayNodeName (std::string &result, uint arrayIndex) const; virtual bool getArrayValue (std::string &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; virtual bool getArrayValue (sint8 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; virtual bool getArrayValue (uint8 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; virtual bool getArrayValue (sint16 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; virtual bool getArrayValue (uint16 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; virtual bool getArrayValue (sint32 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; virtual bool getArrayValue (uint32 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; virtual bool getArrayValue (float &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; virtual bool getArrayValue (double &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; virtual bool getArrayValue (bool &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; virtual bool getArrayValue (NLMISC::CRGBA &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; virtual bool isStruct () const; virtual bool isVirtualStruct () const; virtual bool getDfnName (std::string &dfnName ) const; virtual bool getStructSize (uint &size) const; virtual bool getStructNodeName (uint element, std::string &result) const; virtual bool getStructNode (uint element, const UFormElm **result) const; virtual bool getStructNode (uint element, UFormElm **result); virtual bool isAtom () const; virtual bool getValue (std::string &resultname, TEval evaluate) const; virtual bool getValue (sint8 &resultname, TEval evaluate) const; virtual bool getValue (uint8 &resultname, TEval evaluate) const; virtual bool getValue (sint16 &resultname, TEval evaluate) const; virtual bool getValue (uint16 &resultname, TEval evaluate) const; virtual bool getValue (sint32 &resultname, TEval evaluate) const; virtual bool getValue (uint32 &resultname, TEval evaluate) const; virtual bool getValue (float &resultname, TEval evaluate) const; virtual bool getValue (double &resultname, TEval evaluate) const; virtual bool getValue (bool &resultname, TEval evaluate) const; virtual bool getValue (NLMISC::CRGBA &resultname, TEval evaluate) const; virtual UFormDfn *getStructDfn () { return NULL; } // ** Convert functions inline bool convertValue (sint8 &result, const char *value) const; inline bool convertValue (uint8 &result, const char *value) const; inline bool convertValue (sint16 &result, const char *value) const; inline bool convertValue (uint16 &result, const char *value) const; inline bool convertValue (sint32 &result, const char *value) const; inline bool convertValue (uint32 &result, const char *value) const; inline bool convertValue (float &result, const char *value) const; inline bool convertValue (double &result, const char *value) const; inline bool convertValue (bool &result, const char *value) const; inline bool convertValue (NLMISC::CRGBA &result, const char *value) const; // ** Get dependencies virtual void getDependencies (std::set &dependencies) const = 0; // ** Internal node access // Create a node by name. If the node already exists, return it bool createNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn, const CFormDfn **nodeDfn, const CType **nodeType, CFormElm **node, UFormDfn::TEntryType &type, bool &array, bool &created); /** * Delete a node by name. If the node already exists, return it *Delete its parent if not used */ bool deleteNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn, const CFormDfn **nodeDfn, const CType **nodeType, CFormElm **node, UFormDfn::TEntryType &type, bool &array); // Search for a node by name bool getNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn, const CFormDfn **nodeDfn, const CType **nodeType, CFormElm **node, UFormDfn::TEntryType &type, bool &array, bool &parentVDfnArray, bool verbose, uint32 round) const; /** * Insert an array node by name * The index asked must be < the size of the array. */ bool arrayInsertNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn, const CFormDfn **nodeDfn, const CType **nodeType, CFormElm **node, UFormDfn::TEntryType &type, bool &array, bool verbose, uint arrayIndex) const; /** * Delete an array node by name * The index asked must be < the size of the array. */ bool arrayDeleteNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn, const CFormDfn **nodeDfn, const CType **nodeType, CFormElm **node, UFormDfn::TEntryType &type, bool &array, bool verbose, uint arrayIndex) const; protected: // Action to perform enum TNodeAction { Return, Create, Delete, }; /** * Is createNode == Create, (*node)->Form must be == to the form argument. * Is createNode == Return, form argument is not used, can be undefined. * * Only form, name, and action, must be defined. * Then, else (*parentDfn / indexDfn ) or *node must be defined. * Other values are for result only. */ static bool getInternalNodeByName (CForm *form, const char *name, const CFormDfn **parentDfn, uint &indexDfn, const CFormDfn **nodeDfn, const CType **nodeType, CFormElm **node, UFormDfn::TEntryType &type, bool &array, TNodeAction action, bool &created, bool &parentVDfnArray, bool verbose, uint32 round); /** * Unlink a child */ virtual void unlink (CFormElm *child); public: // Get next token, return NULL if last token static const char* tokenize (const char *name, std::string &str, uint &errorIndex, uint &code); // ** IO functions virtual xmlNodePtr write (xmlNodePtr node, const CForm *form, const char *structName = NULL, bool forceWrite = false) const = 0; protected: // The form of this node CForm *Form; // The parent node of this node CFormElm *ParentNode; // The parent DFN of this node const CFormDfn *ParentDfn; // The index in the parent DFN for this node uint ParentIndex; // Recurce Tag uint32 Round; // Error handling static void warning (bool exception, const char *formName, const char *formFileName, const char *function, const char *format, ... ); virtual void warning (bool exception, const char *function, const char *format, ... ) const; private: // Tokens enum TToken { TokenString = 0, TokenPoint, TokenArrayBegin, TokenArrayEnd, }; }; /** * Define a structure of elements * * This structure has pointers on named sub structures in Elements. * If a sub structure is empty, its pointer is NULL. */ class CFormElmStruct : public CFormElm { public: // Default constructor CFormElmStruct (CForm *form, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex); virtual ~CFormElmStruct (); // Clear sub elements void clean (); // Smart pointer on the form definition for this structure NLMISC::CSmartPtr FormDfn; // Pointer on the parent element //CFormElmStruct *Parent; // A struct element class CFormElmStructElm { public: CFormElmStructElm () { Element = NULL; } std::string Name; CFormElm* Element; }; // Build form a DFN void build (const CFormDfn *dfn); // From UFormElm bool isStruct () const; bool getStructSize (uint &size) const; bool getStructNodeName (uint element, std::string &result) const; bool getStructNode (uint element, const UFormElm **result) const; bool getStructNode (uint element, UFormElm **result); UFormDfn *getStructDfn (); // From CFormElm bool isUsed (const CForm *form) const; xmlNodePtr write (xmlNodePtr node, const CForm *form, const char *structName, bool forceWrite = false) const; void unlink (CFormElm *child); void getFormName (std::string &result, const CFormElm *child) const; void getDependencies (std::set &dependencies) const; // Call by CFormLoader void read (xmlNodePtr node, CFormLoader &loader, const CFormDfn *dfn, CForm *form); // Sub Elements std::vector Elements; // Error handling virtual void warning (bool exception, const char *function, const char *format, ... ) const; }; /** * Define an array of elements */ class CFormElmVirtualStruct : public CFormElmStruct { public: CFormElmVirtualStruct (CForm *form, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex); virtual ~CFormElmVirtualStruct() { } // The Dfn filename used by this struct std::string DfnFilename; // From UFormElm bool isVirtualStruct () const; bool getDfnName (std::string &dfnName ) const; // From CFormElm bool isUsed (const CForm *form) const; xmlNodePtr write (xmlNodePtr node, const CForm *form, const char *structName, bool forceWrite = false) const; // Call by CFormLoader void read (xmlNodePtr node, CFormLoader &loader, CForm *form); // Error handling virtual void warning (bool exception, const char *function, const char *format, ... ) const; }; /** * Define an array of elements */ class CFormElmArray : public CFormElm { public: // Default constructor CFormElmArray (CForm *form, const CFormDfn *formDfn, const CType *type, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex); virtual ~CFormElmArray (); void clean (); // Smart pointer on the form definition for this structure NLMISC::CSmartPtr FormDfn; // Pointer on the type (the smart pointer in hold by CFormDfn) const CType *Type; // From UFormElm bool isArray () const; bool getArraySize (uint &size) const; bool getArrayNode (const UFormElm **result, uint arrayIndex) const; bool getArrayNode (UFormElm **result, uint arrayIndex); bool getArrayNodeName (std::string &result, uint arrayIndex) const; bool getArrayValue (std::string &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; bool getArrayValue (sint8 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; bool getArrayValue (uint8 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; bool getArrayValue (sint16 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; bool getArrayValue (uint16 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; bool getArrayValue (sint32 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; bool getArrayValue (uint32 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; bool getArrayValue (float &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; bool getArrayValue (double &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; bool getArrayValue (bool &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; bool getArrayValue (NLMISC::CRGBA &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const; // From CFormElm xmlNodePtr write (xmlNodePtr node, const CForm *form, const char *structName, bool forceWrite = false) const; bool setParent (CFormElm *parent); void unlink (CFormElm *child); bool isUsed (const CForm *form) const; void getFormName (std::string &result, const CFormElm *child) const; void getDependencies (std::set &dependencies) const; // Call by CFormLoader // Read an array void read (xmlNodePtr node, CFormLoader &loader, CForm *form); // A struct element class CElement { public: CElement () { Element = NULL; } std::string Name; CFormElm* Element; }; // Array of elements std::vector Elements; // Error handling virtual void warning (bool exception, const char *function, const char *format, ... ) const; }; /** * Signed integer element */ class CFormElmAtom : public CFormElm { friend class CForm; friend class CFormElm; friend class CType; public: // Default constructor CFormElmAtom (CForm *form, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex); virtual ~CFormElmAtom() { } // Pointer on the parent element //CFormElmAtom *Parent; // Pointer on the type (the smart pointer in hold by CFormDfn) const CType *Type; // From CFormElm xmlNodePtr write (xmlNodePtr node, const CForm *form, const char *structName, bool forceWrite = false) const; bool setParent (CFormElm *parent); void getFormName (std::string &result, const CFormElm *child) const; void getDependencies (std::set &dependencies) const; const CType* getType (); // Call by CFormLoader void read (xmlNodePtr node, CFormLoader &loader, const CType *type, CForm *form); // From UFormElm bool isAtom () const; bool getValue (std::string &result, TEval evaluate) const; bool getValue (sint8 &result, TEval evaluate) const; bool getValue (uint8 &result, TEval evaluate) const; bool getValue (sint16 &result, TEval evaluate) const; bool getValue (uint16 &result, TEval evaluate) const; bool getValue (sint32 &result, TEval evaluate) const; bool getValue (uint32 &result, TEval evaluate) const; bool getValue (float &result, TEval evaluate) const; bool getValue (double &result, TEval evaluate) const; bool getValue (bool &result, TEval evaluate) const; bool getValue (NLMISC::CRGBA &result, TEval evaluate) const; // Set the value, the elt been used void setValue (const char *value); // Get the raw value. Does not care about any parent or default values void getValue (std::string &result) const; private: // The value std::string Value; // Error handling virtual void warning (bool exception, const char *function, const char *format, ... ) const; }; // *************************************************************************** // CFormElm inlines // *************************************************************************** inline bool CFormElm::convertValue (sint8 &result, const char *value) const { float tmp; if (NLMISC::fromString(value, tmp)) { NLMISC::clamp (tmp, -128.f, 127.f); result = (sint8)tmp; return true; } else { // Error message warning (false, "convertValue", "Can't convert the string \"%s\" in sint8.", value); } return false; } // *************************************************************************** inline bool CFormElm::convertValue (uint8 &result, const char *value) const { float tmp; if (NLMISC::fromString(value, tmp)) { NLMISC::clamp (tmp, 0.f, 255.f); result = (uint8)tmp; return true; } else { // Error message warning (false, "convertValue", "Can't convert the string \"%s\" in uint8.", value); } return false; } // *************************************************************************** inline bool CFormElm::convertValue (sint16 &result, const char *value) const { float tmp; if (NLMISC::fromString(value, tmp)) { NLMISC::clamp (tmp, -32768.f, 32767.f); result = (sint16)tmp; return true; } else { // Error message warning (false, "convertValue", "Can't convert the string \"%s\" in sint16.", value); } return false; } // *************************************************************************** inline bool CFormElm::convertValue (uint16 &result, const char *value) const { float tmp; if (NLMISC::fromString(value, tmp)) { NLMISC::clamp (tmp, 0.f, 65535.f); result = (uint16)tmp; return true; } else { // Error message warning (false, "convertValue", "Can't convert the string \"%s\" in uint16.", value); } return false; } // *************************************************************************** inline bool CFormElm::convertValue (sint32 &result, const char *value) const { float tmp; if (NLMISC::fromString(value, tmp)) { NLMISC::clamp (tmp, -2147483648.f, 2147483647.f); result = (sint32)tmp; return true; } else { // Error message warning (false, "convertValue", "Can't convert the string \"%s\" in sint32.", value); } return false; } // *************************************************************************** inline bool CFormElm::convertValue (uint32 &result, const char *value) const { float tmp; if (NLMISC::fromString(value, tmp)) { NLMISC::clamp (tmp, 0.f, 4294967295.f); result = (sint32)tmp; return true; } else { // Error message warning (false, "convertValue", "Can't convert the string \"%s\" in uint32.", value); } return false; } // *************************************************************************** inline bool CFormElm::convertValue (float &result, const char *value) const { if (NLMISC::fromString(value, result)) { return true; } else { // Error message warning (false, "convertValue", "Can't convert the string \"%s\" in float.", value); } return false; } // *************************************************************************** inline bool CFormElm::convertValue (double &result, const char *value) const { float tmp; if (NLMISC::fromString(value, tmp)) { result = tmp; return true; } else { // Error message warning (false, "convertValue", "Can't convert the string \"%s\" in double.", value); } return false; } // *************************************************************************** inline bool CFormElm::convertValue (bool &result, const char *value) const { int tmp; if (NLMISC::fromString(value, tmp)) { result = tmp != 0; return true; } else { std::string temp = NLMISC::toLower(std::string(value)); if (strcmp (temp.c_str (), "true") == 0) { result = true; return true; } if (strcmp (temp.c_str (), "false") == 0) { result = false; return true; } } // Error message warning (false, "convertValue", "Can't convert the string \"%s\" in boolean.", value); return false; } // *************************************************************************** inline bool CFormElm::convertValue (NLMISC::CRGBA &result, const char *value) const { float r, g, b; if (sscanf (value, "%f,%f,%f", &r, &g, &b) == 3) { NLMISC::clamp (r, 0.f, 255.f); NLMISC::clamp (g, 0.f, 255.f); NLMISC::clamp (b, 0.f, 255.f); result.R = (uint8)r; result.G = (uint8)g; result.B = (uint8)b; return true; } // Error message warning (false, "convertValue", "Can't convert the string \"%s\" in RGB color.", value); return false; } // *************************************************************************** } // NLGEORGES #endif // NL_FORM_ELM_H ================================================ FILE: code/nel/include/nel/georges/form_loader.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_FORM_LOADER_H #define NL_FORM_LOADER_H #include "nel/misc/types_nl.h" #include "nel/misc/smart_ptr.h" #include "nel/georges/u_form_loader.h" namespace NLGEORGES { class UForm; class CType; class CFormDfn; class CForm; /** * Georges form loader implementation * * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2002 */ class CFormLoader : public UFormLoader { public: virtual ~CFormLoader(); // From UFormLoader UForm *loadForm (const char *filename); UFormDfn *loadFormDfn (const char *filename); UType *loadFormType (const char *filename); // Load type and formDfn CType *loadType (const char *filename); CFormDfn *loadFormDfn (const char *filename, bool forceLoad); private: // Error handling virtual void warning (bool exception, const char *function, const char *format, ... ) const; typedef std::map > TTypeMap; typedef std::map > TFormDfnMap; typedef std::map > TFormMap; // Map of filename / CRefPtr TTypeMap _MapType; // Map of filename / CRefPtr TFormDfnMap _MapFormDfn; // Map of form / CRefPtr TFormMap _MapForm; }; } // NLGEORGES #endif // NL_FORM_LOADER_H /* End of form_loader.h */ ================================================ FILE: code/nel/include/nel/georges/header.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_HEADER_H #define NL_HEADER_H #include "nel/misc/types_nl.h" // Include from libxml2 #include namespace NLGEORGES { class CFileHeader { public: /// Default constructor CFileHeader (); // Form states enum TState { Modified =0, Checked, StateCount, }; /// Add a log void addLog (const char *log); /// Set the comment void setComments (const char *comments); /// Major version number uint32 MajorVersion; /// Minor version number uint32 MinorVersion; /// State of the form TState State; /// Comments of the form std::string Comments; /// Log of the form std::string Log; /// ** IO functions void read (xmlNodePtr root); void write (xmlNodePtr node) const; // Get state string static const char *getStateString (TState state); // Error handling void warning (bool exception, const char *function, const char *format, ... ) const; }; } // NLGEORGES #endif // NL_HEADER_H ================================================ FILE: code/nel/include/nel/georges/load_form.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_LOAD_FORM_H #define NL_LOAD_FORM_H #include "nel/misc/types_nl.h" #include #include #include #include "nel/misc/path.h" #include "nel/misc/file.h" #include "nel/misc/sheet_id.h" #include "nel/misc/algo.h" #include "u_form_loader.h" #include "u_form.h" /** This function is used to load values from georges sheet in a quick way. * The first time it loads the sheet and parse it with the readGeorges function * provided by the user to read the value he wants. It'll generate a packed file * that contains this values (using serialCont). The next launch, the function will * only load the packed file and if some sheet have changed, it'll automatically regenerate * the packed file. * * To use the loadForm(), you first have to create a class that will contains values for one sheet. * This class must also implements 2 functions (readGeorges() and serial()) and 1 static function (getVersion()) * * Extension file name for the packedFilename must be ".packed_sheets" * * Classical use (copy/paste this in your code): // For each sheet in the packed sheet, an instance of this class // is created and stored into an stl container. // This class must be default and copy constructable. class CContainerEntry { public: CContainerEntry () : WalkSpeed(1.3f), RunSpeed(6.0f) {} float WalkSpeed, RunSpeed; // load the values using the george sheet void readGeorges (const NLMISC::CSmartPtr &form, const NLMISC::CSheetId &sheetId) { // the form was found so read the true values from George form->getRootNode ().getValueByName (WalkSpeed, "Basics.MovementSpeeds.WalkSpeed"); form->getRootNode ().getValueByName (RunSpeed, "Basics.MovementSpeeds.RunSpeed"); } // load/save the values using the serial system void serial (NLMISC::IStream &s) { s.serial (WalkSpeed, RunSpeed); } // Event to implement any action when the sheet no longer exist. // This method is called when a sheet have been read from the packed sheet // and the associated sheet file no more exist in the directories. void removed() { // any action that is needed if the sheet no more exist. } // return the version of this class, increments this value when the content of this class changed static uint getVersion () { return 1; } }; // this structure is filled by the loadForm() function and will contain all you need std::map Container; void init () { // load the values using the george sheet or packed file and fill the container loadForm(".creature", "test.packed_sheets", Container); } * Now you can access the Container (using the CSheedId) to know the WalkSpeed and RunSpeed of all creatures. * */ /// Dictionnary entry for dependency information. /* struct TLoadFormDicoEntry { std::string Filename; uint32 ModificationDate; void serial(NLMISC::IStream &s) { s.serial(Filename); s.serial(ModificationDate); } }; */ const uint32 PACKED_SHEET_HEADER = NELID("PKSH"); const uint32 PACKED_SHEET_VERSION = 5; // This Version may be used if you want to use the serialVersion() system in loadForm() const uint32 PACKED_SHEET_VERSION_COMPATIBLE = 0; // *************************************************************************** /** This function is used to load values from georges sheet in a quick way. * \param sheetFilter a vector of string to filter the sheet in the case you need more than one filter * \param packedFilename the name of the file that this function will generate (extension must be "packed_sheets") * \param container the map that will be filled by this function */ template void loadForm (const std::vector &sheetFilters, const std::string &packedFilename, std::map &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true) { std::vector dictionnary; std::map dictionnaryIndex; std::map > dependencies; std::vector dependencyDates; // check the extension (i know that file like "foo.packed_sheetsbar" will be accepted but this check is enough...) nlassert (packedFilename.find (".packed_sheets") != std::string::npos); std::string packedFilenamePath = NLMISC::CPath::lookup(NLMISC::CFile::getFilename(packedFilename), false, false); if (packedFilenamePath.empty()) { packedFilenamePath = packedFilename; } // make sure the CSheetId singleton has been properly initialised NLMISC::CSheetId::init(updatePackedSheet); // load the packed sheet if exists try { NLMISC::CIFile ifile; ifile.setCacheFileOnOpen(true); if (!ifile.open (packedFilenamePath)) { throw NLMISC::Exception("can't open PackedSheet %s", packedFilenamePath.c_str()); } // an exception will be launch if the file is not the good version or if the file is not found //nlinfo ("loadForm(): Loading packed file '%s'", packedFilename.c_str()); // read the header ifile.serialCheck(PACKED_SHEET_HEADER); ifile.serialCheck(PACKED_SHEET_VERSION); ifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE); // Read depend block size uint32 dependBlockSize; ifile.serial(dependBlockSize); // Read the dependencies only if update packed sheet if(updatePackedSheet) { // read the dictionnary { ifile.serialCont(dictionnary); } // read the dependency data { uint32 depSize; ifile.serial(depSize); for (uint i=0; i no heavy reallocation / free else if(dependBlockSize>0) { std::vector bigBlock; bigBlock.resize(dependBlockSize); ifile.serialBuffer(&bigBlock[0], dependBlockSize); } // read the packed sheet data uint32 nbEntries; uint32 ver; ifile.serial (nbEntries); ifile.serial (ver); if(ver != T::getVersion ()) throw NLMISC::Exception("The packed sheet version in stream is different of the code"); ifile.serialCont (container); ifile.close (); } catch (const NLMISC::Exception &e) { // clear the container because it can contains partially loaded sheet so we must clean it before continue container.clear (); if (!updatePackedSheet) { if (errorIfPackedSheetNotGood) nlerror ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what()); else nlinfo ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what()); return; } else { nlinfo ("loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)", e.what()); } } // if we don't want to update packed sheet, we have nothing more to do if (!updatePackedSheet) { //nlinfo ("Don't update the packed sheet with real sheet"); return; } // retreive the date of all dependency file { for (uint i=0; i sheetIds; std::vector filenames; for (uint i = 0; i < sheetFilters.size(); i++) NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]); // if there's no file, nothing to do if (sheetIds.empty()) return; // set up the current sheet in container to remove sheet that are in the container and not in the directory anymore std::map sheetToRemove; for (typename std::map::iterator it = container.begin(); it != container.end(); it++) { sheetToRemove.insert (std::make_pair((*it).first, true)); } // check if we need to create a new .pitems or just read it uint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath); bool containerChanged = false; NLGEORGES::UFormLoader *formLoader = NULL; std::vector NeededToRecompute; for (uint k = 0; k < filenames.size(); k++) { std::string p = NLMISC::CPath::lookup (filenames[k], false, false); if (p.empty()) continue; uint32 d = NLMISC::CFile::getFileModificationDate(p); // no need to remove this sheet sheetToRemove[sheetIds[k]] = false; if( d > packedFiledate || container.find (sheetIds[k]) == container.end()) { NeededToRecompute.push_back(k); } else { // check the date of each parent nlassert(dependencies.find(sheetIds[k]) != dependencies.end()); std::vector &depends = dependencies[sheetIds[k]]; for (uint i=0; i packedFiledate) { nldebug("Dependency on %s for %s not up to date !", dictionnary[depends[i]].c_str(), sheetIds[k].toString().c_str()); NeededToRecompute.push_back(k); break; } } } } nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size()); NLMISC::TTime last = NLMISC::CTime::getLocalTime (); NLMISC::TTime start = NLMISC::CTime::getLocalTime (); NLMISC::CSmartPtr form; std::vector > cacheFormList; for (uint j = 0; j < NeededToRecompute.size(); j++) { if(NLMISC::CTime::getLocalTime () > last + 5000) { last = NLMISC::CTime::getLocalTime (); if(j>0) nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000); } // create the georges loader if necessary if (formLoader == NULL) { NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file"); formLoader = NLGEORGES::UFormLoader::createLoader (); } // cache used to retain information (to optimize time). if (form) cacheFormList.push_back (form); // Load the form with given sheet id form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ()); if (form) { // build the dependency data { std::vector depends; std::set dependFiles; form->getDependencies (dependFiles); nlassert(dependFiles.find(sheetIds[NeededToRecompute[j]].toString()) != dependFiles.end()); // remove the sheet itself from the container dependFiles.erase(sheetIds[NeededToRecompute[j]].toString()); std::set::iterator first(dependFiles.begin()), last(dependFiles.end()); for (; first != last; ++first) { const std::string filename = NLMISC::CFile::getFilename(*first); std::map::iterator findDicIt=dictionnaryIndex.find(filename); if (findDicIt!=dictionnaryIndex.end()) { depends.push_back(findDicIt->second); continue; } std::string p = NLMISC::CPath::lookup (*first, false, false); if (!p.empty()) { uint dicIndex; // add a new dictionnary entry dicIndex = (uint)dictionnary.size(); dictionnaryIndex.insert(std::make_pair(filename, (uint)dictionnary.size())); dictionnary.push_back(filename); // add the dependecy index depends.push_back(dicIndex); } } // store the dependency list with the sheet ID dependencies[sheetIds[NeededToRecompute[j]]] = depends; } // add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one typedef typename std::map::iterator TType1; typedef typename std::pair TType2; TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]],T())); (*res.first).second.readGeorges (form, sheetIds[NeededToRecompute[j]]); containerChanged = true; } } if(NeededToRecompute.size() > 0) nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size()); // free the georges loader if necessary if (formLoader != NULL) { NLGEORGES::UFormLoader::releaseLoader (formLoader); NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file"); } // we have now to remove sheets that are in the container and not exist anymore in the sheet directories for (std::map::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++) { if((*it2).second) { nlinfo ("the sheet '%s' is not in the directory, remove it from container", (*it2).first.toString().c_str()); container.find((*it2).first)->second.removed(); container.erase((*it2).first); containerChanged = true; dependencies.erase((*it2).first); } } // now, save the new container in the packedfile try { if(containerChanged) { NLMISC::COFile ofile; ofile.open(packedFilenamePath); // write the header. ofile.serialCheck(PACKED_SHEET_HEADER); ofile.serialCheck(PACKED_SHEET_VERSION); ofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE); // Write a dummy block size for now sint32 posBlockSize= ofile.getPos(); uint32 dependBlockSize= 0; ofile.serial(dependBlockSize); // write the dictionnary ofile.serialCont(dictionnary); // write the dependencies data uint32 depSize = (uint32)dependencies.size(); ofile.serial(depSize); std::map >::iterator first(dependencies.begin()), last(dependencies.end()); for (; first != last; ++first) { NLMISC::CSheetId si = first->first; ofile.serial(si); ofile.serialCont(first->second); } // Then get the dictionary + dependencies size, and write it back to posBlockSize sint32 endBlockSize= ofile.getPos(); dependBlockSize= (endBlockSize - posBlockSize) - 4; ofile.seek(posBlockSize, NLMISC::IStream::begin); ofile.serial(dependBlockSize); ofile.seek(endBlockSize, NLMISC::IStream::begin); // write the sheet data uint32 nbEntries = (uint32)sheetIds.size(); uint32 ver = T::getVersion (); ofile.serial (nbEntries); ofile.serial (ver); ofile.serialCont(container); ofile.close (); } } catch (const NLMISC::Exception &e) { nlinfo ("loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)", e.what()); } // housekeeping sheetIds.clear (); filenames.clear (); } // *************************************************************************** /** This function is used to load values from georges sheet in a quick way. * \param sheetFilter a string to filter the sheet (ie: ".item") * \param packedFilename the name of the file that this function will generate (extension must be "packed_sheets") * \param container the map that will be filled by this function */ template void loadForm (const std::string &sheetFilter, const std::string &packedFilename, std::map &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true) { std::vector vs; vs.push_back(sheetFilter); loadForm(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood); } // *************************************************************************** // variant with smart pointers, maintain with function above template void loadForm2(const std::vector &sheetFilters, const std::string &packedFilename, std::map > &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true) { std::vector dictionnary; std::map dictionnaryIndex; std::map > dependencies; std::vector dependencyDates; // check the extension (i know that file like "foo.packed_sheetsbar" will be accepted but this check is enough...) nlassert (packedFilename.find (".packed_sheets") != std::string::npos); std::string packedFilenamePath = NLMISC::CPath::lookup(NLMISC::CFile::getFilename(packedFilename), false, false); if (packedFilenamePath.empty()) { packedFilenamePath = packedFilename; } // make sure the CSheetId singleton has been properly initialised NLMISC::CSheetId::init(updatePackedSheet); // load the packed sheet if exists try { NLMISC::CIFile ifile; ifile.setCacheFileOnOpen(true); if (!ifile.open (packedFilenamePath)) { throw NLMISC::Exception("can't open PackedSheet %s", packedFilenamePath.c_str()); } // an exception will be launch if the file is not the good version or if the file is not found nlinfo ("loadForm(): Loading packed file '%s'", packedFilename.c_str()); // read the header ifile.serialCheck(PACKED_SHEET_HEADER); ifile.serialCheck(PACKED_SHEET_VERSION); sint loadFormVersion= ifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE); // Read depend block size uint32 dependBlockSize; ifile.serial(dependBlockSize); // Read the dependencies only if update packed sheet if(updatePackedSheet) { // read the dictionnary { ifile.serialCont(dictionnary); } // read the dependency data { uint32 depSize; ifile.serial(depSize); for (uint i=0; i no heavy reallocation / free else if(dependBlockSize>0) { std::vector bigBlock; bigBlock.resize(dependBlockSize); ifile.serialBuffer(&bigBlock[0], dependBlockSize); } // read the packed sheet data uint32 nbEntries; uint32 ver; ifile.serial (nbEntries); ifile.serial (ver); if(ver != T::getVersion ()) throw NLMISC::Exception("The packed sheet version in stream is different of the code"); ifile.serialPtrCont (container); ifile.close (); } catch (const NLMISC::Exception &e) { // clear the container because it can contains partially loaded sheet so we must clean it before continue container.clear (); if (!updatePackedSheet) { if (errorIfPackedSheetNotGood) nlerror ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what()); else nlinfo ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what()); return; } else { nlinfo ("loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)", e.what()); } } // if we don't want to update packed sheet, we have nothing more to do if (!updatePackedSheet) { nlinfo ("Don't update the packed sheet with real sheet"); return; } // retreive the date of all dependency file { for (uint i=0; i sheetIds; std::vector filenames; for (uint i = 0; i < sheetFilters.size(); i++) NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]); // if there's no file, nothing to do if (sheetIds.empty()) return; // set up the current sheet in container to remove sheets that are in the container and not in the directory anymore std::map sheetToRemove; for (typename std::map >::iterator it = container.begin(); it != container.end(); it++) { sheetToRemove.insert (std::make_pair((*it).first, true)); } // check if we need to create a new .pitems or just read it uint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath); bool containerChanged = false; NLGEORGES::UFormLoader *formLoader = NULL; std::vector NeededToRecompute; for (uint k = 0; k < filenames.size(); k++) { std::string p = NLMISC::CPath::lookup (filenames[k], false, false); if (p.empty()) continue; uint32 d = NLMISC::CFile::getFileModificationDate(p); // no need to remove this sheet sheetToRemove[sheetIds[k]] = false; if( d > packedFiledate || container.find (sheetIds[k]) == container.end()) { NeededToRecompute.push_back(k); } else { // check the date of each parent nlassert(dependencies.find(sheetIds[k]) != dependencies.end()); std::vector &depends = dependencies[sheetIds[k]]; for (uint i=0; i packedFiledate) { nldebug("Dependency on %s for %s not up to date !", dictionnary[depends[i]].c_str(), sheetIds[k].toString().c_str()); NeededToRecompute.push_back(k); break; } } } } nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size()); NLMISC::TTime last = NLMISC::CTime::getLocalTime (); NLMISC::TTime start = NLMISC::CTime::getLocalTime (); NLMISC::CSmartPtr form; std::vector > cacheFormList; for (uint j = 0; j < NeededToRecompute.size(); j++) { if(NLMISC::CTime::getLocalTime () > last + 5000) { last = NLMISC::CTime::getLocalTime (); if(j>0) nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000); } // create the georges loader if necessary if (formLoader == NULL) { NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file"); formLoader = NLGEORGES::UFormLoader::createLoader (); } // cache used to retain information (to optimize time). if (form) cacheFormList.push_back (form); // Load the form with given sheet id form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ()); if (form) { // build the dependency data { std::vector depends; std::set dependFiles; form->getDependencies (dependFiles); nlassert(dependFiles.find(sheetIds[NeededToRecompute[j]].toString()) != dependFiles.end()); // remove the sheet itself from the container dependFiles.erase(sheetIds[NeededToRecompute[j]].toString()); std::set::iterator first(dependFiles.begin()), last(dependFiles.end()); for (; first != last; ++first) { const std::string filename = NLMISC::CFile::getFilename(*first); std::map::iterator findDicIt=dictionnaryIndex.find(filename); if (findDicIt!=dictionnaryIndex.end()) { depends.push_back(findDicIt->second); continue; } std::string p = NLMISC::CPath::lookup (*first, false, false); if (!p.empty()) { uint dicIndex; // add a new dictionnary entry dicIndex = (uint)dictionnary.size(); dictionnaryIndex.insert(std::make_pair(filename, (NLMISC::TSStringId)dictionnary.size())); dictionnary.push_back(filename); // add the dependency index depends.push_back(dicIndex); } } // store the dependency list with the sheet ID dependencies[sheetIds[NeededToRecompute[j]]] = depends; } // add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one typedef typename std::map >::iterator TType1; typedef typename std::pair TType2; TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]], NLMISC::CSmartPtr(new T()))); (*res.first).second->readGeorges (form, sheetIds[NeededToRecompute[j]]); containerChanged = true; } } if(NeededToRecompute.size() > 0) nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size()); // free the georges loader if necessary if (formLoader != NULL) { NLGEORGES::UFormLoader::releaseLoader (formLoader); NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file"); } // we have now to remove sheets that are in the container and not exist anymore in the sheet directories for (std::map::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++) { if((*it2).second) { nlinfo ("the sheet '%s' is not in the directory, remove it from container", (*it2).first.toString().c_str()); container.find((*it2).first)->second->removed(); container.erase((*it2).first); containerChanged = true; dependencies.erase((*it2).first); } } // now, save the new container in the packedfile try { if(containerChanged) { NLMISC::COFile ofile; ofile.open(packedFilenamePath); // write the header. ofile.serialCheck(PACKED_SHEET_HEADER); ofile.serialCheck(PACKED_SHEET_VERSION); ofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE); // Write a dummy block size for now sint32 posBlockSize= ofile.getPos(); uint32 dependBlockSize= 0; ofile.serial(dependBlockSize); // write the dictionnary ofile.serialCont(dictionnary); // write the dependencies data uint32 depSize = (uint32)dependencies.size(); ofile.serial(depSize); std::map >::iterator first(dependencies.begin()), last(dependencies.end()); for (; first != last; ++first) { NLMISC::CSheetId si = first->first; ofile.serial(si); ofile.serialCont(first->second); } // Then get the dicionary + dependencies size, and write it back to posBlockSize sint32 endBlockSize= ofile.getPos(); dependBlockSize= (endBlockSize - posBlockSize) - 4; ofile.seek(posBlockSize, NLMISC::IStream::begin); ofile.serial(dependBlockSize); ofile.seek(endBlockSize, NLMISC::IStream::begin); // write the sheet data uint32 nbEntries = (uint32)sheetIds.size(); uint32 ver = T::getVersion (); ofile.serial (nbEntries); ofile.serial (ver); ofile.serialPtrCont(container); ofile.close (); } } catch (const NLMISC::Exception &e) { nlinfo ("loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)", e.what()); } // housekeeping sheetIds.clear (); filenames.clear (); } // *************************************************************************** // variant with smart pointers, maintain with function above template void loadForm2(const std::string &sheetFilter, const std::string &packedFilename, std::map &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true) { std::vector vs; vs.push_back(sheetFilter); loadForm2(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood); } // *************************************************************************** /** This function is used to load values from georges sheet in a quick way. * \param sheetFilter a vector of string to filter the sheet in the case you need more than one filter * \param packedFilename the name of the file that this function will generate (extension must be "packed_sheets") * \param container the map that will be filled by this function */ template void loadForm (const std::vector &sheetFilters, const std::string &packedFilename, std::map &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true) { std::vector dictionnary; std::map dictionnaryIndex; std::map > dependencies; std::vector dependencyDates; // check the extension (i know that file like "foo.packed_sheetsbar" will be accepted but this check is enough...) nlassert (packedFilename.find (".packed_sheets") != std::string::npos); std::string packedFilenamePath = NLMISC::CPath::lookup(packedFilename, false, false); if (packedFilenamePath.empty()) { packedFilenamePath = packedFilename; } // make sure the CSheetId singleton has been properly initialised // NLMISC::CSheetId::init(updatePackedSheet); // load the packed sheet if exists try { NLMISC::CIFile ifile; ifile.setCacheFileOnOpen(true); ifile.open (packedFilenamePath); // an exception will be launch if the file is not the good version or if the file is not found nlinfo ("loadForm(): Loading packed file '%s'", packedFilename.c_str()); // read the header ifile.serialCheck(PACKED_SHEET_HEADER); ifile.serialCheck(PACKED_SHEET_VERSION); ifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE); // Read depend block size uint32 dependBlockSize; ifile.serial(dependBlockSize); // Read the dependencies only if update packed sheet if(updatePackedSheet) { // read the dictionnary { ifile.serialCont(dictionnary); } // read the dependency data { uint32 depSize; ifile.serial(depSize); for (uint i=0; i no heavy reallocation / free else if(dependBlockSize>0) { std::vector bigBlock; bigBlock.resize(dependBlockSize); ifile.serialBuffer(&bigBlock[0], dependBlockSize); } // read the packed sheet data uint32 nbEntries; uint32 ver; ifile.serial (nbEntries); ifile.serial (ver); if(ver != T::getVersion ()) throw NLMISC::Exception("The packed sheet version in stream is different of the code"); ifile.serialCont (container); ifile.close (); } catch (const NLMISC::Exception &e) { // clear the container because it can contains partially loaded sheet so we must clean it before continue container.clear (); if (!updatePackedSheet) { if (errorIfPackedSheetNotGood) nlerror ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what()); else nlinfo ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what()); return; } else { nlinfo ("loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)", e.what()); } } // if we don't want to update packed sheet, we have nothing more to do if (!updatePackedSheet) { nlinfo ("Don't update the packed sheet with real sheet"); return; } // retreive the date of all dependency file { for (uint i=0; i sheetNames; { std::vector::const_iterator first(sheetFilters.begin()), last(sheetFilters.end()); for (; first != last; ++first) NLMISC::CPath::getFileList(*first, sheetNames); } // if there's no file, nothing to do if (sheetNames.empty()) return; // set up the current sheet in container to remove sheet that are in the container and not in the directory anymore std::map sheetToRemove; { typename std::map::iterator first(container.begin()), last(container.end()); for(; first != last; ++first) sheetToRemove.insert (make_pair(first->first, true)); } // check if we need to create a new .pitems or just read it uint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath); bool containerChanged = false; NLGEORGES::UFormLoader *formLoader = NULL; std::vector NeededToRecompute; for (uint k = 0; k < sheetNames.size(); k++) { std::string p = NLMISC::CPath::lookup (sheetNames[k], false, false); if (p.empty()) { continue; } uint32 d = NLMISC::CFile::getFileModificationDate(p); // no need to remove this sheet sheetToRemove[sheetNames[k]] = false; if( d > packedFiledate || container.find (sheetNames[k]) == container.end()) { NeededToRecompute.push_back(k); } else { // check the date of each parent nlassert(dependencies.find(sheetNames[k]) != dependencies.end()); std::vector &depends = dependencies[sheetNames[k]]; for (uint i=0; i packedFiledate) { nldebug("Dependency on %s for %s not up to date !", dictionnary[depends[i]].c_str(), sheetNames[k].c_str()); NeededToRecompute.push_back(k); break; } } } } nlinfo ("%d sheets checked, %d need to be recomputed", sheetNames.size(), NeededToRecompute.size()); NLMISC::TTime lastTime = NLMISC::CTime::getLocalTime (); NLMISC::TTime start = NLMISC::CTime::getLocalTime (); NLMISC::CSmartPtr form; for (uint j = 0; j < NeededToRecompute.size(); j++) { if(NLMISC::CTime::getLocalTime () > lastTime + 5000) { lastTime = NLMISC::CTime::getLocalTime (); if(j>0) nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(lastTime-start)/j/1000); } // create the georges loader if necessary if (formLoader == NULL) { NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file"); formLoader = NLGEORGES::UFormLoader::createLoader (); } // Load the form with given sheet id form = formLoader->loadForm (sheetNames[NeededToRecompute[j]].c_str ()); if (form) { // build the dependency data { std::vector depends; std::set dependFiles; form->getDependencies (dependFiles); nlassert(dependFiles.find(sheetNames[NeededToRecompute[j]]) != dependFiles.end()); // remove the sheet itself from the container dependFiles.erase(sheetNames[NeededToRecompute[j]]); std::set::iterator first(dependFiles.begin()), last(dependFiles.end()); for (; first != last; ++first) { std::string p = NLMISC::CPath::lookup (*first, false, false); if (!p.empty()) { // uint32 date = NLMISC::CFile::getFileModificationDate(p); uint dicIndex; std::string filename = NLMISC::CFile::getFilename(p); if (dictionnaryIndex.find(filename) == dictionnaryIndex.end()) { // add a new dictionnary entry dicIndex = (uint)dictionnary.size(); dictionnaryIndex.insert(std::make_pair(filename, (uint)dictionnary.size())); dictionnary.push_back(filename); } else { dicIndex = dictionnaryIndex.find(filename)->second; } // add the dependecy index depends.push_back(dicIndex); } } // store the dependency list with the sheet ID dependencies[sheetNames[NeededToRecompute[j]]] = depends; } // add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one typedef typename std::map::iterator TType1; typedef typename std::pair TType2; TType2 res = container.insert(std::make_pair(sheetNames[NeededToRecompute[j]],T())); (*res.first).second.readGeorges (form, sheetNames[NeededToRecompute[j]]); containerChanged = true; } } nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size()); // free the georges loader if necessary if (formLoader != NULL) { NLGEORGES::UFormLoader::releaseLoader (formLoader); NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file"); } // we have now to remove sheet that are in the container and not exist anymore in the sheet directories for (std::map::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++) { if(it2->second) { // inform the contained object that it is no more needed. container.find(it2->first)->second.removed(); container.erase(it2->first); containerChanged = true; dependencies.erase((*it2).first); } } // now, save the new container in the packedfile try { if(containerChanged) { NLMISC::COFile ofile; ofile.open(packedFilenamePath); // write the header. ofile.serialCheck(PACKED_SHEET_HEADER); ofile.serialCheck(PACKED_SHEET_VERSION); ofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE); // Write a dummy block size for now sint32 posBlockSize= ofile.getPos(); uint32 dependBlockSize= 0; ofile.serial(dependBlockSize); // write the dictionnary ofile.serialCont(dictionnary); // write the dependencies data uint32 depSize = (uint32)dependencies.size(); ofile.serial(depSize); std::map >::iterator first(dependencies.begin()), last(dependencies.end()); for (; first != last; ++first) { std::string sheetName = first->first; ofile.serial(sheetName); ofile.serialCont(first->second); } // Then get the dicionary + dependencies size, and write it back to posBlockSize sint32 endBlockSize= ofile.getPos(); dependBlockSize= (endBlockSize - posBlockSize) - 4; ofile.seek(posBlockSize, NLMISC::IStream::begin); ofile.serial(dependBlockSize); ofile.seek(endBlockSize, NLMISC::IStream::begin); // write the sheet data uint32 nbEntries = (uint32)sheetNames.size(); uint32 ver = T::getVersion (); ofile.serial (nbEntries); ofile.serial (ver); ofile.serialCont(container); ofile.close (); } } catch (const NLMISC::Exception &e) { nlinfo ("loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)", e.what()); } // housekeeping sheetNames.clear (); } // *************************************************************************** /** This function is used to load values from georges sheet in a quick way. * \param sheetFilter a string to filter the sheet (ie: ".item") * \param packedFilename the name of the file that this function will generate (extension must be "packed_sheets") * \param container the map that will be filled by this function */ template void loadForm (const std::string &sheetFilter, const std::string &packedFilename, std::map &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true) { std::vector vs; vs.push_back(sheetFilter); loadForm(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood); } // *************************************************************************** template void loadFormNoPackedSheet (const std::string &sheetFilter, std::map &container, const std::string &wildcardFilter) { std::vector vs; vs.push_back(sheetFilter); loadFormNoPackedSheet(vs, container, wildcardFilter); } // *************************************************************************** // variant with smart pointers, maintain with function above template void loadFormNoPackedSheet2 (const std::string &sheetFilter, std::map &container, const std::string &wildcardFilter) { std::vector vs; vs.push_back(sheetFilter); loadFormNoPackedSheet2(vs, container, wildcardFilter); } // *************************************************************************** /** This function is used to load values from georges sheet in a quick way. * NB: no packedsheet is given for load/write * \param sheetFilters a vector of string to filter the sheet (by extension) in the case you need more than one filter * \param wildcardFilter an additional by sheet filter (must include the extension) * \param container the map that will be filled by this function */ template void loadFormNoPackedSheet (const std::vector &sheetFilters, std::map &container, const std::string &wildcardFilter) { // make sure the CSheetId singleton has been properly initialised NLMISC::CSheetId::init(false); // build a vector of the sheetFilters sheet ids (ie: "item") std::vector sheetIds; std::vector filenames; for (uint i = 0; i < sheetFilters.size(); i++) NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]); // if there's no file, nothing to do if (sheetIds.empty()) return; // compute sheets that needs to be recomputed std::vector NeededToRecompute; for (uint k = 0; k < filenames.size(); k++) { std::string p = NLMISC::CPath::lookup (filenames[k], false, false); if (p.empty()) continue; // check if wildcardok if(!wildcardFilter.empty() && !NLMISC::testWildCard(p,wildcardFilter)) continue; NeededToRecompute.push_back(k); } nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size()); NLMISC::TTime last = NLMISC::CTime::getLocalTime (); NLMISC::TTime start = NLMISC::CTime::getLocalTime (); NLGEORGES::UFormLoader *formLoader = NULL; NLMISC::CSmartPtr form; std::vector > cacheFormList; // For all sheets need to recompute for (uint j = 0; j < NeededToRecompute.size(); j++) { if(NLMISC::CTime::getLocalTime () > last + 5000) { last = NLMISC::CTime::getLocalTime (); if(j>0) nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000); } // create the georges loader if necessary if (formLoader == NULL) { NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file"); formLoader = NLGEORGES::UFormLoader::createLoader (); } // cache used to retain information (to optimize time). if (form) cacheFormList.push_back (form); // Load the form with given sheet id form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ()); if (form) { // add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one typedef typename std::map::iterator TType1; typedef typename std::pair TType2; TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]],T())); (*res.first).second.readGeorges (form, sheetIds[NeededToRecompute[j]]); } } if(NeededToRecompute.size() > 0) nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size()); // free the georges loader if necessary if (formLoader != NULL) { NLGEORGES::UFormLoader::releaseLoader (formLoader); NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file"); } // housekeeping sheetIds.clear (); filenames.clear (); } // *************************************************************************** // variant with smart pointers, maintain with function above template void loadFormNoPackedSheet2 (const std::vector &sheetFilters, std::map > &container, const std::string &wildcardFilter) { // make sure the CSheetId singleton has been properly initialised NLMISC::CSheetId::init(false); // build a vector of the sheetFilters sheet ids (ie: "item") std::vector sheetIds; std::vector filenames; for (uint i = 0; i < sheetFilters.size(); i++) NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]); // if there's no file, nothing to do if (sheetIds.empty()) return; // compute sheets that needs to be recomputed std::vector NeededToRecompute; for (uint k = 0; k < filenames.size(); k++) { std::string p = NLMISC::CPath::lookup (filenames[k], false, false); if (p.empty()) continue; // check if wildcardok if(!wildcardFilter.empty() && !NLMISC::testWildCard(p,wildcardFilter)) continue; NeededToRecompute.push_back(k); } nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size()); NLMISC::TTime last = NLMISC::CTime::getLocalTime (); NLMISC::TTime start = NLMISC::CTime::getLocalTime (); NLGEORGES::UFormLoader *formLoader = NULL; NLMISC::CSmartPtr form; std::vector > cacheFormList; // For all sheets need to recompute for (uint j = 0; j < NeededToRecompute.size(); j++) { if(NLMISC::CTime::getLocalTime () > last + 5000) { last = NLMISC::CTime::getLocalTime (); if(j>0) nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000); } // create the georges loader if necessary if (formLoader == NULL) { NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file"); formLoader = NLGEORGES::UFormLoader::createLoader (); } // cache used to retain information (to optimize time). if (form) cacheFormList.push_back (form); // Load the form with given sheet id form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ()); if (form) { // add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one typedef typename std::map >::iterator TType1; typedef typename std::pair TType2; TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]], NLMISC::CSmartPtr(new T()))); (*res.first).second->readGeorges (form, sheetIds[NeededToRecompute[j]]); } } if(NeededToRecompute.size() > 0) nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size()); // free the georges loader if necessary if (formLoader != NULL) { NLGEORGES::UFormLoader::releaseLoader (formLoader); NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file"); } // housekeeping sheetIds.clear (); filenames.clear (); } #endif // NL_LOAD_FORM_H /* End of load_form.h */ ================================================ FILE: code/nel/include/nel/georges/type.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_TYPE_H #define NL_TYPE_H #include "nel/misc/types_nl.h" #include "nel/georges/u_type.h" #include "nel/georges/u_form_elm.h" #include "header.h" namespace NLGEORGES { class UFormElm; /** * This class is a basic type used by atomic form element. */ class CType : public UType { friend class CFormLoader; public: CType (); virtual ~CType (); // ** UI enum TUI { Edit, // Default, for all types EditSpin, // For number types NonEditableCombo, // For all types FileBrowser, // Browse file BigEdit, // Edit a huge text ColorEdit, // Edit a color IconWidget, // Draw an icon UITypeCount }; // Is a UI compatible with a type ? static bool uiCompatible (TType type, TUI ui); // ** IO functions void write (xmlDocPtr doc) const; // Header CFileHeader Header; // Type of the type UType::TType Type; // Type fo user interface TUI UIType; // Default value std::string Default; // Min value std::string Min; // Max value std::string Max; // Increment step value std::string Increment; // Evaluate a node bool getValue (std::string &result, const class CForm *form, const class CFormElmAtom *node, const class CFormDfn &parentDfn, uint parentIndex, UFormElm::TEval evaluate, uint32 *where, uint32 round, const char *formName) const; // Definitions class CDefinition { public: // Label of the definition std::string Label; // Value of the definition std::string Value; }; // Array of definition std::vector Definitions; // Get the type names static const char *getTypeName (UType::TType type); static const char *getUIName (TUI type); // From UType virtual TType getType () const; virtual const std::string &getDefault () const; virtual const std::string &getMin () const; virtual const std::string &getMax () const; virtual const std::string &getIncrement () const; virtual uint getNumDefinition () const; virtual bool getDefinition (uint index, std::string &label, std::string &value) const; virtual const std::string &getComment () const; virtual void getDependencies (std::set &dependencies) const; private: // Error handling virtual void warning (bool exception, const char *formName, const char *formFilename, const char *function, const char *format, ... ) const; virtual void warning2 (bool exception, const char *function, const char *format, ... ) const; // Type names static const char *TypeNames[]; static const char *UITypeNames[]; // CFormLoader call it void read (xmlNodePtr root); }; } // NLGEORGES #endif // NL_TYPE_H ================================================ FILE: code/nel/include/nel/georges/u_form.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_U_FORM_H #define NL_U_FORM_H #include "nel/misc/types_nl.h" #include "nel/misc/smart_ptr.h" #include namespace NLMISC { class IStream; } namespace NLGEORGES { class UFormElm; /** * This class provide an interface to access Georges form */ class UForm : public NLMISC::CRefCount { public: virtual ~UForm (); /** * Access form nodes */ /// Get a mutable pointer on the root element of the form. It is a struct node. virtual UFormElm& getRootNode () = 0; /// Get a const pointer on the root element of the form. It is a struct node. virtual const UFormElm& getRootNode () const = 0; /** Write the form in a stream. * * \param stream is the stream used to write the form */ virtual void write (NLMISC::IStream &stream) = 0; /** * Access form parents */ /// Get a mutable pointer on the root element of the form. It is a struct node. virtual uint getNumParent () const = 0; /// Get a mutable pointer on the root element of the form. It is a struct node. virtual UForm *getParentForm (uint parent) const = 0; // Get the form filename with extension virtual const std::string &getFilename () const = 0; /** * Get the comment */ virtual const std::string &getComment () const = 0; /** * Get dependency files */ virtual void getDependencies (std::set &dependencies) const = 0; }; } // NLGEORGES #endif // NL_U_FORM_H ================================================ FILE: code/nel/include/nel/georges/u_form_dfn.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_U_FORM_DFN_H #define NL_U_FORM_DFN_H #include "nel/misc/types_nl.h" #include "u_form_elm.h" #include "nel/misc/smart_ptr.h" namespace NLGEORGES { class UType; /** * Georges DFN ifle interface * * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2002 */ class UFormDfn : public NLMISC::CRefCount // Deprecated , public UFormElm { public: virtual ~UFormDfn() { } // ** Common methods // Type of dfn entry enum TEntryType { EntryType, EntryDfn, EntryVirtualDfn, }; /** * Return the number of entry in this DFN */ virtual uint getNumEntry () const = 0; /** * Return the entry type. * Doesn't look in parents DFN. * * \param entry is the entry id to get the type. * \param type will be filled with the entry type. * \param array is true if the entry is an array, else false. * \return true if successed, false if the entry doesn't exist. */ virtual bool getEntryType (uint entry, TEntryType &type, bool &array) const = 0; /** * Return the entry name * Doesn't look in parents DFN. * * \param entry is the entry id to get the dfn pointer. * \param name will be filled with the entry name. * \return true if successed, false if the entry doesn't exist. */ virtual bool getEntryName (uint entry, std::string &name) const = 0; virtual bool getEntryIndexByName (uint &entry, const std::string &name) const = 0; /** * Return the filename of the type or the DFN. * Doesn't look in parents DFN. * * \param entry is the entry id to get the dfn pointer. * \param name will be filled with the entry filename. * \return true if successed, false if the entry doesn't exist or is a virtual DFN. */ virtual bool getEntryFilename (uint entry, std::string &name) const = 0; /** * Return the filename extension used by the DFN entry. * Doesn't look in parents DFN. * * \param entry is the entry id to get the dfn pointer. * \param name will be filled with the entry filename. * \return true if successed, false if the entry doesn't exist or is a virtual DFN. */ virtual bool getEntryFilenameExt (uint entry, std::string &name) const = 0; /** * Return the entry DFN pointer * Doesn't look in parents DFN. * * \param entry is the entry id to get the dfn pointer. * \param dfn will be filled with the DFN pointer. * \return true if successed, false if the entry doesn't exist or is not a DFN. */ virtual bool getEntryDfn (uint entry, UFormDfn **dfn) = 0; /** * Return the entry DFN pointer * Doesn't look in parents DFN. * * \param name is the supposed name of the dfn. * \param dfn will be filled with the DFN pointer. * \return true if successed, false if the entry doesn't exist or is not a DFN. */ virtual bool getEntryDfnByName (const std::string &name, UFormDfn **dfn) = 0; virtual bool isAnArrayEntryByName (const std::string &name) const = 0; /** * Return the entry Type pointer * Doesn't look in parents DFN. * * \param entry is the entry id to get the dfn pointer. * \param type will be filled with the TYPE pointer. * \return true if successed, false if the entry doesn't exist or is not a Type. */ virtual bool getEntryType (uint entry, UType **type) = 0; /** * Get the number of parent DFN. * Doesn't look in parents DFN for parents. */ virtual uint getNumParents () const = 0; /** * Get a parent. * * \param entry is the entry id to get the dfn pointer. * \param parent will be filled with the parent pointer. * \return true if successed, false if the parent doesn't exist. */ virtual bool getParent (uint parent, UFormDfn **parentRet) = 0; /** * Get a parent filename. * * \param entry is the entry id to get the dfn pointer. * \param parent will be filled with the parent pointer. * \return true if successed, false if the parent doesn't exist. */ virtual bool getParentFilename (uint parent, std::string &filename) const = 0; /** * Get the comment */ virtual const std::string &getComment () const = 0; /** * Get dependency files */ virtual void getDependencies (std::set &dependencies) const = 0; }; } // NLGEORGES #endif // NL_U_FORM_DFN_H ================================================ FILE: code/nel/include/nel/georges/u_form_elm.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_U_FORM_ELM_H #define NL_U_FORM_ELM_H #include "nel/misc/types_nl.h" namespace NLMISC { class CRGBA; } namespace NLGEORGES { class UFormElm { public: // dtor virtual ~UFormElm() {} // ** Common methods /// Value evalution enum TEval { NoEval, /// The value will not be evaluated at all, the litteral value will be returned Formula, /// Eval the enumeration value, but don't evaluate the formula nor the value references Eval, /// Full evaluation of the value }; /// Where a node has been found enum TWhereIsNode { NodeForm, /// The node has been found in the form NodeParentForm, /// The node has been found in the parent form NodeDfn, /// The node is a DFN NodeType, /// The node is a Type }; /** * Return a node pointer with its name. * * \param result will be filled with the node pointer. Can be NULL if the node doesn't exist. * \param name is the form node name * \param where is a pointer on the information flag of the value. If Where is not NULL, it is filled with * the position where the node has been found. If result is NULL, where is undefined. * \return true if the result has been filled, false if the node is not referenced. * * About the node existance * * An atom node exist if its value is defined. * A struct node exist if one of its children exist. * An array node exist if one of its children exist. * If the node doesn't exist, you can't have a pointer on it with getNodeByName(). It returns NULL. * But, you can evaluate the value of non-existant atom nodes with getValueByName(). * * About the form name: * * Struct elements name must be separated by '.' * Struct indexes must be between '[' and ']' * * Exemple: * "position.x" : get the element named x in the struct named position * "entities[2].color" : get the node named color in the second element of the entities array */ virtual bool getNodeByName (const UFormElm **result, const char *name, TWhereIsNode *where = NULL, bool reserved=true, uint32 round=0) const = 0; virtual bool getNodeByName (UFormElm **result, const char *name, TWhereIsNode *where = NULL, bool reserved=true, uint32 round=0) = 0; /// Where a value has been found enum TWhereIsValue { ValueForm, /// The value has been found in the form ValueParentForm, /// The value has been found in the parent form ValueDefaultDfn, /// The value has been found in the DFN default value ValueDefaultType, /// The value has been found in the TYPE default value Dummy = 0xffffffff /// Be sure the size == sizeof(uint32) }; /** * Get a form value with its name. * The numbers are clamped to the type limit values. * * \param result is a reference on the value to fill with the result. * \param name is the form name of the value to found. * \param evaluate must be true if you want to have an evaluated value, false if you want the formula value. * \param where is a pointer on the information flag of the value. If Where is not NULL, it is filled with * the position where the value has been found. * \return true if the result has been filled, false if the value has not been found or the cast has failed or the evaluation has failed. * \see getNodeByName () */ virtual bool getValueByName (std::string &result, const char *namename, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0; virtual bool getValueByName (sint8 &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0; virtual bool getValueByName (uint8 &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0; virtual bool getValueByName (sint16 &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0; virtual bool getValueByName (uint16 &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0; virtual bool getValueByName (sint32 &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0; virtual bool getValueByName (uint32 &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0; virtual bool getValueByName (float &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0; virtual bool getValueByName (double &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0; virtual bool getValueByName (bool &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0; /// Warning, only R, G and B members are filled, not A. virtual bool getValueByName (NLMISC::CRGBA &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0; /** * Set a form value with its name. If the node doesn't exist, it is created. * * \param value is a reference on the value to set in the form. * \param name is the form name of the value to set or create. * \param where is a pointer on the information flag of the value. If Where is not NULL, it is filled with * the position where the value has been found. * \param created is a pointer on the creatation flag. If created is not NULL, it is filled with * true if the value has been created, false it the value has been filled. * \return true if the value has been set, false if the value has not been found or hasn't been created. */ virtual bool setValueByName (const char *value, const char *name, bool *created = NULL) = 0; virtual bool setValueByName (sint8 value, const char *name, bool *created = NULL) = 0; virtual bool setValueByName (uint8 value, const char *name, bool *created = NULL) = 0; virtual bool setValueByName (sint16 value, const char *name, bool *created = NULL) = 0; virtual bool setValueByName (uint16 value, const char *name, bool *created = NULL) = 0; virtual bool setValueByName (sint32 value, const char *name, bool *created = NULL) = 0; virtual bool setValueByName (uint32 value, const char *name, bool *created = NULL) = 0; virtual bool setValueByName (float value, const char *name, bool *created = NULL) = 0; virtual bool setValueByName (double value, const char *name, bool *created = NULL) = 0; virtual bool setValueByName (bool value, const char *name, bool *created = NULL) = 0; virtual bool setValueByName (NLMISC::CRGBA value, const char *name, bool *created = NULL) = 0; // ** Array element methods /// Return true if the element is an array virtual bool isArray () const = 0; /// Return true if the element is an array and fill size with the array size virtual bool getArraySize (uint &size) const = 0; /** * Get a array sub element const pointer. * If return true, fill result with the arrayIndex cell's element * Can be NULL if the node doesn't exist. */ virtual bool getArrayNode (const UFormElm **result, uint arrayIndex) const = 0; /** * Get a array sub element mutable pointer. * If return true, fill result with the arrayIndex cell's element pointer. * Can be NULL if the node doesn't exist. */ virtual bool getArrayNode (UFormElm **result, uint arrayIndex) = 0; /** * Get an array value. The node must be an array of atom element. * * \param result is a reference on the value to fill with the result. * \param arrayIndex is the array index to evaluate. * \param evaluate must be true if you want to have an evaluated value, false if you want the formula value. * \param where is a pointer on the information flag of the value. If Where is not NULL, it is filled with * the position where the value has been found. * \return true if the result has been filled, false if the value has not been found or the cast has failed or the evaluation has failed. */ virtual bool getArrayValue (std::string &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0; virtual bool getArrayValue (sint8 &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0; virtual bool getArrayValue (uint8 &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0; virtual bool getArrayValue (sint16 &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0; virtual bool getArrayValue (uint16 &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0; virtual bool getArrayValue (sint32 &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0; virtual bool getArrayValue (uint32 &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0; virtual bool getArrayValue (float &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0; virtual bool getArrayValue (double &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0; virtual bool getArrayValue (bool &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0; /// Warning, only R, G and B members are filled, not A. virtual bool getArrayValue (NLMISC::CRGBA &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0; /// Return the name of a table element. virtual bool getArrayNodeName (std::string &result, uint arrayIndex) const = 0; // ** Struct element methods /// Return true if the element is a struct or a virtual struct virtual bool isStruct () const = 0; /// Return true if the element is a virtual struct virtual bool isVirtualStruct () const = 0; /// Get the dfn filename for this virtual struct. Must be a virtual struct node. virtual bool getDfnName (std::string &dfnName ) const = 0; /// Return the struct size virtual bool getStructSize (uint &size) const = 0; /// Return the element name virtual bool getStructNodeName (uint element, std::string &result) const = 0; /// Return a const element pointer. Can be NULL if the node doesn't exist. virtual bool getStructNode (uint element, const UFormElm **result) const = 0; /// Return a mutable element pointer. Can be NULL if the node doesn't exist. virtual bool getStructNode (uint element, UFormElm **result) = 0; /// Return the struct dfn virtual class UFormDfn *getStructDfn () = 0; // ** Atom element methods /// Returns the type of the atom. NULL otherwise. virtual const class UType *getType () = 0; /// Return true if the element is an atom virtual bool isAtom () const = 0; /** * Return the atom value. * The numbers are clamped to the type limit values. * * \param result is the reference on the value to fill with result * \param evaluate must be true if you want to have an evaluated value, false if you want the formula value. */ virtual bool getValue (std::string &result, TEval evaluate = Eval) const = 0; virtual bool getValue (sint8 &result, TEval evaluate = Eval) const = 0; virtual bool getValue (uint8 &result, TEval evaluate = Eval) const = 0; virtual bool getValue (sint16 &result, TEval evaluate = Eval) const = 0; virtual bool getValue (uint16 &result, TEval evaluate = Eval) const = 0; virtual bool getValue (sint32 &result, TEval evaluate = Eval) const = 0; virtual bool getValue (uint32 &result, TEval evaluate = Eval) const = 0; virtual bool getValue (float &result, TEval evaluate = Eval) const = 0; virtual bool getValue (double &result, TEval evaluate = Eval) const = 0; virtual bool getValue (bool &result, TEval evaluate = Eval) const = 0; /// Warning, only R, G and B members are filled, not A. virtual bool getValue (NLMISC::CRGBA &result, TEval evaluate = Eval) const = 0; }; } // NLGEORGES #endif // NL_U_FORM_ELM_H ================================================ FILE: code/nel/include/nel/georges/u_form_loader.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_U_FORM_LOADER_H #define NL_U_FORM_LOADER_H #include "nel/misc/types_nl.h" namespace NLGEORGES { class UType; class UForm; class UFormDfn; /** * Georges form loader interface * * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2002 */ class UFormLoader { public: virtual ~UFormLoader() {} /** Load a form, use NMISC::CPath to find the file. * * The pointer on the form must be held in a CSmartPtr. Returns NULL if the form can't be loaded. */ virtual UForm *loadForm (const char *filename) = 0; /** Load a DFN, use NMISC::CPath to find the file. * * The pointer on the form must be held in a CSmartPtr. Returns NULL if the DFN can't be loaded. */ virtual UFormDfn *loadFormDfn (const char *filename) = 0; /** Load a type, use NMISC::CPath to find the file. * * The pointer on the form must be held in a CSmartPtr. Returns NULL if the type can't be loaded. */ virtual UType *loadFormType (const char *filename) = 0; /// Create a form loader static UFormLoader *createLoader (); /// Create a form loader static void releaseLoader (UFormLoader *loader); }; } // NLGEORGES #endif // NL_U_FORM_LOADER_H /* End of u_form_loader.h */ ================================================ FILE: code/nel/include/nel/georges/u_type.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_U_TYPE_H #define NL_U_TYPE_H #include "nel/misc/types_nl.h" #include "nel/misc/smart_ptr.h" namespace NLGEORGES { /** * Georges type interface * * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2002 */ class UType : public NLMISC::CRefCount { public: virtual ~UType() { } // ** Type enum TType { UnsignedInt=0, SignedInt, Double, String, Color, TypeCount }; /** * Get the type of this type. */ virtual TType getType () const = 0; /** * Get the default value of this type. */ virtual const std::string &getDefault () const = 0; /** * Get the min value of this type. */ virtual const std::string &getMin () const = 0; /** * Get the max value of this type. */ virtual const std::string &getMax () const = 0; /** * Get the increment value of this type. */ virtual const std::string &getIncrement () const = 0; /** * Get the definition count for this type. */ virtual uint getNumDefinition () const = 0; /** * Get a definition for this type. * * index is the index of the defnition you want to get. * If the method returns true, label will be filled with * the definition label and value will be filled with the * defnition value. * The method returns false if the index is invalid. In this * case, label and value are not changed. */ virtual bool getDefinition (uint index, std::string &label, std::string &value) const = 0; /** * Get the comments of type. */ virtual const std::string &getComment () const = 0; /** * Get dependency files */ virtual void getDependencies (std::set &dependencies) const = 0; }; } // NLGEORGES #endif // NL_U_TYPE_H /* End of u_type.h */ ================================================ FILE: code/nel/include/nel/ligo/CMakeLists.txt ================================================ FILE(GLOB HEADERS *.h) INSTALL(FILES ${HEADERS} DESTINATION include/nel/ligo COMPONENT headers) ================================================ FILE: code/nel/include/nel/ligo/ligo_config.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_LIGO_CONFIG_H #define NL_LIGO_CONFIG_H #include "nel/misc/types_nl.h" #include "primitive_class.h" #include "primitive_configuration.h" #define DEFAULT_PRIMITIVE_COLOR (CRGBA (128, 0, 0, 128)) namespace NLLIGO { class IPrimitive; class CPrimitive; /** * Ligo config file * * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2001 */ class CLigoConfig { public: CLigoConfig(); virtual ~CLigoConfig() { } /** Load the config file. Can throw some exceptions if file doesn't exist or is malformed. * * This file will try to open the file ligo class description file (XML) using the LigoClass as file name. * It will try first to load directly the file and then to lookup the file in NLMISC::CPath. */ bool readConfigFile (const char *fileName, bool parsePrimitiveComboContent); /** * This file will read the file ligo class description file (XML) using the LigoClass as file name. * It will try first to load directly the file and then to lookup the file in NLMISC::CPath. */ bool readPrimitiveClass (const char *fileName, bool parsePrimitiveComboContent); bool reloadIndexFile(const std::string &indexFileName = std::string()); /// Reset the primitive configurations void resetPrimitiveConfiguration (); /// \name Public value /// Size of a cell of the ligoscape in meter float CellSize; /// Snap precision for vertex position checking in meter float Snap; /// Zone snap shot resolution uint ZoneSnapShotRes; /// The ligo class file std::string PrimitiveClassFilename; /// \name Primitive class accessors /// Get the dynamic bit size for alias uint32 getDynamicAliasSize() const; /// Get the dynamic bit mask for alias uint32 getDynamicAliasMask() const; /// Get the static bit size for alias uint32 getStaticAliasSize() const; /// Get the static bit mask for alias uint32 getStaticAliasMask() const; /// Build an alias given a static and dynamic part uint32 buildAlias(uint32 staticPart, uint32 dynamicPart, bool warnIfOverload = true) const; /// register filename to static alias translation void registerFileToStaticAliasTranslation(const std::string &fileName, uint32 staticPart); /// get the static alias mapping (or 0 if no mapping defined) virtual uint32 getFileStaticAliasMapping(const std::string &fileName) const; /// get the filename for a static alias (or empty string for 0) const std::string &getFileNameForStaticAlias(uint32 staticAlias) const; /// Check if a file is already mapped bool isFileStaticAliasMapped(const std::string &fileName) const; /// Build a standard human readable alias string std::string aliasToString(uint32 fullAlias); /// Read a standard human readable alias string uint32 aliasFromString(std::string fullAlias); // Get a primitive class const CPrimitiveClass *getPrimitiveClass (const NLLIGO::IPrimitive &primitive) const; // Get a primitive class const CPrimitiveClass *getPrimitiveClass (const char *className) const; // Get the primitive color NLMISC::CRGBA getPrimitiveColor (const NLLIGO::IPrimitive &primitive); // Is the primitive deletable ? bool isStaticChild (const NLLIGO::IPrimitive &primitive); // Is the primitive linked to its brother primitive ? bool isPrimitiveLinked (const NLLIGO::IPrimitive &primitive); // Return the next primitive linked to 'primitive', or NULL const NLLIGO::IPrimitive *getLinkedPrimitive (const NLLIGO::IPrimitive &primitive) const; // Return the previous primitive linked to 'primitive', or NULL const NLLIGO::IPrimitive *getPreviousLinkedPrimitive (const NLLIGO::IPrimitive &primitive) const; // Is the primitive deletable ? bool isPrimitiveDeletable (const NLLIGO::IPrimitive &primitive); // Is the child primitive can be a child of the parent primitive ? bool canBeChild (const NLLIGO::IPrimitive &child, const NLLIGO::IPrimitive &parent); // Is the primitive a root primitive ? bool canBeRoot (const NLLIGO::IPrimitive &primitive); // Read a property from an XML file bool getPropertyString (std::string &result, const char *filename, xmlNodePtr xmlNode, const char *propName); // Output error message void syntaxError (const char *filename, xmlNodePtr xmlNode, const char *format, ...); virtual void errorMessage (const char *format, ... ); // Access to the config string const std::vector &getContextString () const; // Access the primitive configuration const std::vector &getPrimitiveConfiguration() const { return _PrimitiveConfigurations; } // Update the DynamicAlias bit count that was previously defined in the config file. // The _StaticAliasFileMapping is updated in order that full alias stay the same. // All previous DynamicAlias must fit in the new DynamicAliasBitCount void updateDynamicAliasBitCount(uint32 newDynamicAliasBitCount); private: // Init primitive class manager bool initPrimitiveClass (const char *filename); // The primitive class manager std::map _PrimitiveClasses; // The context strings std::vector _Contexts; // The file context look up std::map _ContextFilesLookup; // The primitive configurations std::vector _PrimitiveConfigurations; // Dynamic alias bit count uint32 _DynamicAliasBitCount; /// Name of the index file std::string _IndexFileName; // Static alias part file mapping : filename -> staticAliasPart std::map _StaticAliasFileMapping; }; } #endif // NL_LIGO_CONFIG_H /* End of ligo_config.h */ ================================================ FILE: code/nel/include/nel/ligo/primitive.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef __PRIMITIVE_H__ #define __PRIMITIVE_H__ #include "nel/misc/vector.h" #include "nel/misc/rgba.h" // Include from libxml2 #include #include namespace NLLIGO { #ifdef NL_DEBUG # define NLLIGO_DEBUG #endif /** * Ligo primitives are used to add logical geometrical gameplay information. * Ligo primitives are NODES, POINTS, PATHES or ZONES. * Ligo primitives have a CLASS. * * The primitive class defines the properties attached to the primitive * The primitive class are defined in the XML file specified in the LigoClass field of the CLigoConfig class. */ class CPrimitives; class CLigoConfig; // *************************************************************************** void Register (); // *************************************************************************** /* * This class is a property class for ligo primitive. */ class IProperty : public NLMISC::IStreamable { public: IProperty () { Default = false; } // This property is set to default bool Default; // Force class to be polymorphic virtual void foo () const = 0; }; // *************************************************************************** /* * This class is a property class for ligo primitive. * This is a simple string */ class CPropertyString : public IProperty { public: CPropertyString () {} CPropertyString (const char *str); CPropertyString (const std::string &str); CPropertyString (const char *str, bool _default); virtual ~CPropertyString () {} std::string String; NLMISC_DECLARE_CLASS (CPropertyString) virtual void serial(NLMISC::IStream &f) { f.serial(Default); f.serial(String); } // Force class to be polymorphic virtual void foo () const {} }; // *************************************************************************** /* * This class is a property class for ligo primitive. * This is a string array */ class CPropertyStringArray : public IProperty { public: CPropertyStringArray () {} virtual ~CPropertyStringArray () {} CPropertyStringArray (const std::vector &stringArray); CPropertyStringArray (const std::vector &stringArray, bool _default); std::vector StringArray; NLMISC_DECLARE_CLASS (CPropertyStringArray) virtual void serial(NLMISC::IStream &f) { f.serial(Default); f.serialCont(StringArray); } // Force class to be polymorphic virtual void foo () const {} }; // *************************************************************************** /* * This class is a property class for ligo primitive. * This is a string array */ class CPropertyColor : public IProperty { public: NLMISC::CRGBA Color; NLMISC_DECLARE_CLASS (CPropertyColor) virtual void serial(NLMISC::IStream &f) { f.serial(Default); f.serial(Color); } // Force class to be polymorphic virtual void foo () const {} // ctors CPropertyColor() {} CPropertyColor(NLMISC::CRGBA col) : Color(col) {} }; // *************************************************************************** class CPrimVector : public NLMISC::CVector { public: CPrimVector () { Selected = false; } CPrimVector (const NLMISC::CVector &v) { CVector::operator= (v); Selected = false; } void serial(NLMISC::IStream &f) { CVector::serial(f); f.serial(Selected); } bool Selected; }; // *************************************************************************** /* * This class is the base class for ligo primitive. * * Provide access to common properties. * Provide access to the primitive hierachy */ class IPrimitive : public NLMISC::IStreamable { friend class CPrimitives; public: // Deprecated // std::string Layer; // Deprecated // std::string Name; // Expended in the tree view // bool Expanded; enum { NotAnArray, AtTheEnd = 0xffffffff, }; /// \name Hierarchy IPrimitive (); virtual ~IPrimitive (); IPrimitive (const IPrimitive &node); virtual void operator= (const IPrimitive &node); /** Get the children primitive count */ uint getNumChildren () const { return (uint)_Children.size (); } /** Get a child primitive */ bool getChild (const IPrimitive *&result, uint childId) const; /** Get a child primitive */ bool getChild (IPrimitive *&result, uint childId); /** Get the parent primitive */ IPrimitive *getParent () { return _Parent; } const IPrimitive *getParent () const { return _Parent; } /** Get the primitive relative to this and the given path */ const IPrimitive *getPrimitive (const std::string &absoluteOrRelativePath) const; /** Get the id of the child, return 0xffffffff if not found */ bool getChildId (uint &childId, const IPrimitive *child) const; /** Remove and delete a child primitive */ bool removeChild (IPrimitive *child); /** Remove and delete a child primitive */ bool removeChild (uint childId); /// Remove the child primitive from the children list, don't delete it bool unlinkChild(IPrimitive *child); /** Remove and delete all children primitives */ void removeChildren (); /** * Insert a child primitive before the index. * The pointer will be deleted by the parent primitive using the ::delete operator. * return false if the index is invalid */ bool insertChild (IPrimitive *primitive, uint index = AtTheEnd); /// \name Properties /** * Get a num properties **/ uint getNumProperty () const; /** * Get a properties by its index * This method (iterate a list) is slower than getPropertyByName (look up in a map). **/ bool getProperty (uint index, std::string &property_name, const IProperty *&result) const; /** * Get a properties by its index * This method (iterate a list) is slower than getPropertyByName (look up in a map). **/ bool getProperty (uint index, std::string &property_name, IProperty *&result); /** Check the existence of a named property */ bool checkProperty(const std::string &property_name) const; /** * Add a property * If the property already exist, the method does nothing and returns false. * The pointer will be deleted by the primitive using the ::delete operator. **/ bool addPropertyByName (const char *property_name, IProperty *result); /** * Get a property with its name **/ bool getPropertyByName (const char *property_name, const IProperty *&result) const; /** * Get a property with its name **/ bool getPropertyByName (const char *property_name, IProperty *&result) const; /** * Get a string property with its name. Return false if the property is not found or is not a string property. **/ bool getPropertyByName (const char *property_name, std::string *&result) const; /** * Get a string array property with its name. Return false if the property is not found or is not a string array property. **/ bool getPropertyByName (const char *property_name, std::vector *&result) const; /** * Get a string property with its name. Return false if the property is not found or is not a string property. **/ bool getPropertyByName (const char *property_name, std::string &result) const; /** * Get a string array property with its name. Return false if the property is not found or is not a string array property. **/ bool getPropertyByName (const char *property_name, const std::vector *&result) const; /** * Get a color property with its name. Return false if the property is not found or is not a string array property. **/ bool getPropertyByName (const char *property_name, NLMISC::CRGBA &result) const; /** * Remove a property * This is method (iterate a list) is slower than removePropertyByName (look up in a map). **/ bool removeProperty (uint index); /** * Remove a property by its name **/ bool removePropertyByName (const char *property_name); /** * Remove all the properties **/ void removeProperties (); /* Init default primitive's parameters * * This method will add all the properties declared in the primitive class and create default properties. */ void initDefaultValues (CLigoConfig &config); // Read the primitive, calls initDefaultValue (CLigoConfig &config) virtual bool read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config); // Write the primitive virtual void write (xmlNodePtr xmlNode, const char *filename) const; // Get the vertices virtual uint getNumVector () const = 0; virtual const CPrimVector *getPrimVector () const = 0; virtual CPrimVector *getPrimVector () = 0; // Make a copy virtual IPrimitive *copy () const = 0; // used for fast binary save/load (exploitation mode) void serial(NLMISC::IStream &f); // shortcut to getPropertyByName("name", ret); return ret; std::string getName() const; const std::string &getUnparsedProperties() const; void setUnparsedProperties(const std::string &unparsedProperties) const; private: // callback called just after the node is attach under a parent virtual void onLinkToParent() {} // callback called just before the node is removed from it's parent virtual void onUnlinkFromParent() {} /// Callback called just after an ancestor is linked virtual void onBranchLink() {} /// Callback called just before an ancestor is unlinked virtual void onBranchUnlink() {} /// Callback called when the primitive is updated, giving a chance to track the primitive's modifications during the loading virtual void onModifyPrimitive(CPrimitives &/* primitives */) const {} // internal recusive call void branchLink(); void branchUnlink(); // Update child Id void updateChildId (uint index); // Child id uint32 _ChildId; // Parent IPrimitive *_Parent; // Children std::vector _Children; // Single properties std::map _Properties; // Editor specific properties (unparsed) mutable std::string _UnparsedProperties; #ifdef NLLIGO_DEBUG std::string _DebugClassName; std::string _DebugPrimitiveName; #endif }; // *************************************************************************** // Simple primitive node class CPrimNode : public IPrimitive { public: // \name From IClassable NLMISC_DECLARE_CLASS (CPrimNode) protected: // void operator= (const CPrimNode &node); // Get the vertices virtual uint getNumVector () const; virtual const CPrimVector *getPrimVector () const; virtual CPrimVector *getPrimVector (); // Read the primitive virtual bool read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config); // \name From IPrimitive virtual IPrimitive *copy () const; }; // *************************************************************************** class CPrimPoint : public IPrimitive { public: CPrimPoint () { Angle = 0; } CPrimVector Point; float Angle; // Angle on OZ, CCW public: void serial (NLMISC::IStream &f); // void operator= (const CPrimPoint &node); // \name From IClassable NLMISC_DECLARE_CLASS (CPrimPoint); protected: // Get the vertices virtual uint getNumVector () const; virtual const CPrimVector *getPrimVector () const; virtual CPrimVector *getPrimVector (); // Read the primitive virtual bool read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config); // Write the primitive virtual void write (xmlNodePtr xmlNode, const char *filename) const; // \name From IPrimitive virtual IPrimitive *copy () const; }; // *************************************************************************** class CPrimPath : public IPrimitive { public: std::vector VPoints; public: void serial (NLMISC::IStream &f); // void operator= (const CPrimPath &node); // \name From IClassable NLMISC_DECLARE_CLASS (CPrimPath); protected: // Get the vertices virtual uint getNumVector () const; virtual const CPrimVector *getPrimVector () const; virtual CPrimVector *getPrimVector (); // Read the primitive virtual bool read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config); // Write the primitive virtual void write (xmlNodePtr xmlNode, const char *filename) const; // \name From IPrimitive virtual IPrimitive *copy () const; }; // *************************************************************************** class CPrimZone : public IPrimitive { public: std::vector VPoints; static float getSegmentDist(const NLMISC::CVector v, const NLMISC::CVector &p1, const NLMISC::CVector &p2, NLMISC::CVector &nearPos); public: bool contains (const NLMISC::CVector &v) const { return CPrimZone::contains(v, VPoints); } bool contains(const NLMISC::CVector &v, float &distance, NLMISC::CVector &nearPos, bool isPath) const { return CPrimZone::contains(v, VPoints, distance, nearPos, isPath); } // void operator= (const CPrimZone &node); void serial (NLMISC::IStream &f); // Returns true if the vector v is inside of the patatoid static bool contains (const NLMISC::CVector &v, const std::vector &points); // Returns true if the vector v is inside of the patatoid and set the distance of the nearest segment and the position of the nearest point. static bool contains (const NLMISC::CVector &v, const std::vector &points, float &distance, NLMISC::CVector &nearPos, bool isPath); // Returns true if the vector v is inside of the patatoid static bool contains (const NLMISC::CVector &v, const std::vector &points); // Returns true if the vector v is inside of the patatoid and set the distance of the nearest segment and the position of the nearest point. static bool contains (const NLMISC::CVector &v, const std::vector &points, float &distance, NLMISC::CVector &nearPos, bool isPath); /// Returns the barycenter of the zone (warning, it may be outside of the zone if it is not convex). Returns CVector::Null if there is no vertex. NLMISC::CVector getBarycentre() const; /// Returns the smallest axis-aligned box containing the zone (z is always set to 0) void getAABox( NLMISC::CVector& cornerMin, NLMISC::CVector& cornerMax ) const; /// Return the area of the axis-aligned box containing the zone float getAreaOfAABox() const; // \name From IClassable NLMISC_DECLARE_CLASS (CPrimZone); protected: // Get the vertices virtual uint getNumVector () const; virtual const CPrimVector *getPrimVector () const; virtual CPrimVector *getPrimVector (); // Read the primitive virtual bool read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config); // Write the primitive virtual void write (xmlNodePtr xmlNode, const char *filename) const; // \name From IPrimitive virtual IPrimitive *copy () const; }; // *************************************************************************** /** This primitive type is used to handle unique alias across a primitive file. * Usage of this primitive imply the setting of the appropriate 'ligo context' * before reading or copy/pasting alias. */ class CPrimAlias : public IPrimitive { friend class CPrimitives; /// The 'dynamic' part of the alias uint32 _Alias; /// The primitive container class CPrimitives *_Container; // Needed overloads (not used) virtual uint getNumVector () const { return 0; }; virtual const CPrimVector *getPrimVector () const { return NULL; } virtual CPrimVector *getPrimVector () { return NULL; } virtual void onBranchLink(); // callback called just before the node is removed from it's parent virtual void onBranchUnlink(); void regenAlias(); public: // \name From IClassable NLMISC_DECLARE_CLASS (CPrimAlias); // private default constructor CPrimAlias(); // copy constructor needed CPrimAlias(const CPrimAlias &other); ~CPrimAlias(); // return the dynamic part of the alias uint32 getAlias() const; // Return the full alias, merge of the static and dynamic part uint32 getFullAlias() const; // Read the primitive virtual bool read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config); // Write the primitive virtual void write (xmlNodePtr xmlNode, const char *filename) const; // Create a copy of this primitive virtual IPrimitive *copy () const; // serial for binary save virtual void serial (NLMISC::IStream &f); }; // *************************************************************************** /* This class is deprecated. */ class CPrimRegion { public: std::string Name; std::vector VPoints; std::vector VZones; std::vector VPaths; std::vector VHidePoints; std::vector VHideZones; std::vector VHidePaths; public: void serial (NLMISC::IStream &f); }; // *************************************************************************** /** * This class is a ligo primitives set */ class CPrimitives { public: CPrimitives (); CPrimitives (const CPrimitives &other); ~CPrimitives (); // Operator copy CPrimitives& operator= (const CPrimitives &other); // Convert from old format to the new one void convert (const CPrimRegion ®ion); // Read the primitive bool read (xmlNodePtr xmlNode, const char *filename, CLigoConfig &config); // Write the primitive void write (xmlDocPtr xmlNode, const char *filename) const; // Write the primitive void write (xmlNodePtr root, const char *filename) const; // serial the primitive. Used for binary files. void serial(NLMISC::IStream &f); // Root primitive hierarchy CPrimNode *RootNode; // get the static alias part for this primitive uint32 getAliasStaticPart(); // set the static alias part for this primitive void setAliasStaticPart(uint32 staticPart); // Build an alias by combining the static and dynamic part uint32 buildFullAlias(uint32 dynamicPart); // Generate a new unique alias (dynamic part only) uint32 genAlias(IPrimitive *prim, uint32 preferedAlias = 0); // Reserve an alias and store it in the used alias list (dynamic part only) // void reserveAlias(uint32 dynamicAlias); // Remove an alias from the list of alias in use (dynamic part only) void releaseAlias(IPrimitive *prim, uint32 dynamicAlias); // Force the assignation of the specified alias to the primitive. If another primitive // already hold the alias, this other primitive is assigned a new alias. void forceAlias(CPrimAlias *prim, uint32 alias); // get the last generated alias value (for debug only) uint32 getLastGeneratedAlias(); // Return the primitive indexed by the given alias (ie, it doesn't return the alias primitive, but its first parent) IPrimitive *getPrimitiveByAlias(uint32 primAlias); // Build the complete list of indexed primitive (ie all primitive that have a primalias child) void buildPrimitiveWithAliasList(std::map &result); private: // Conversion internal methods void convertAddPrimitive (IPrimitive *child, const IPrimitive *prim, bool hidden); void convertPrimitive (const IPrimitive *prim, bool hidden); /// Optional context information CLigoConfig *_LigoConfig; /// Static part alias mapping (can be 0 if no mapping is defined) uint32 _AliasStaticPart; /// Last generated Alias, used to compute the next alias uint32 _LastGeneratedAlias; /// List of alias in use in the primitive (dynamic part only) std::map _AliasInUse; // Store the filename // This allows to retrieve the static alias when reloading from binary file std::string _Filename; }; // *************************************************************************** /** Singleton to manage special loading feature related to * unique alias assignment */ class CPrimitiveContext { static CPrimitiveContext *_Instance; // private ctor CPrimitiveContext(); public: // get the singleton reference static CPrimitiveContext &instance() { if (!_Instance) { _Instance = new CPrimitiveContext; } return *_Instance; } /// The current ligo configuration file. CLigoConfig *CurrentLigoConfig; /// The current primitives container. CPrimitives *CurrentPrimitive; }; } // namespace NLLIGO #endif // __PRIMITIVE_H__ ================================================ FILE: code/nel/include/nel/ligo/primitive_class.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_PRIMITIVE_CLASS_H #define NL_PRIMITIVE_CLASS_H #include "nel/misc/types_nl.h" #include "nel/misc/rgba.h" #include #include // Include from libxml2 #include namespace NLLIGO { class IPrimitive; class IProperty; class CLigoConfig; /** * Class of primitive * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2002 */ class CPrimitiveClass { public: // Type of the primitive enum TType { Node, Point, Path, Bitmap, Zone, Alias } Type; /// Constructor CPrimitiveClass (); /// Class name std::string Name; /// Filename extension (for type File) std::string FileExtension; /// File type (for type File) std::string FileType; /// Color NLMISC::CRGBA Color; /// Auto init ? bool AutoInit; /// Deletable ? bool Deletable; /// Collision ? bool Collision; /// Link children ? bool LinkBrothers; /// Show arrow ? bool ShowArrow; /// Numberize on copy ? bool Numberize; /// Is primitive visible ? bool Visible; /// Init parameters class CInitParameters { // A default value class CDefaultValue { public: std::string Name; bool GenID; bool operator== (const CDefaultValue &other) const { return (Name == other.Name) && (GenID == other.GenID); } bool operator< (const CDefaultValue &other) const { if (Name < other.Name) return true; else if (Name == other.Name) { return (GenID < other.GenID); } else return false; } }; public: /// Parameter name std::string Name; /// Default value std::vector DefaultValue; }; // Parameter description class CParameter : public CInitParameters { public: CParameter () {} CParameter (const NLLIGO::IProperty &property, const char *propertyName); bool operator== (const CParameter &other) const; bool operator< (const CParameter &other) const; // Type enum TType { Boolean, ConstString, String, StringArray, ConstStringArray, } Type; /// Is parameter visible ? bool Visible; // Is a filename bool Filename; // Make a look up ? bool Lookup; /// Is parameter read only ? bool ReadOnly; // File extension std::string FileExtension; // Autonaming std::string Autoname; // Folder std::string Folder; // Size of multi line view uint WidgetHeight; // Sort entry in combo box bool SortEntries; // Editable bool Editable; // Display horizontal slider in multiline edit box bool DisplayHS; // Combobox value class CConstStringValue { public: bool operator== (const CConstStringValue &other) const; bool operator< (const CConstStringValue &other) const; std::vector Values; std::vector PrimitivePath; void appendFilePath (std::vector &pathList) const; void appendPrimPath (std::vector &pathList, const std::vector &relativePrimPaths) const; void getPrimitivesForPrimPath (std::vector &relativePrimPaths, const std::vector &startPrimPath) const; }; // Map of combobox value per context std::map ComboValues; /// Get the autoname translation bool translateAutoname (std::string &result, const IPrimitive &primitive, const CPrimitiveClass &primitiveClass) const; // Get a default value bool getDefaultValue (std::string &result, const IPrimitive &primitive, const CPrimitiveClass &primitiveClass, std::string *fromWhere = NULL) const; bool getDefaultValue (std::vector &result, const IPrimitive &primitive, const CPrimitiveClass &primitiveClass, std::string *fromWhere = NULL) const; }; /// Parameters std::vector Parameters; // Child class CChild { public: /// Static child name std::string Name; /// Child class name std::string ClassName; /// Init parameters std::vector Parameters; }; // Static Children std::vector StaticChildren; // Dynamic Children std::vector DynamicChildren; // Generated Children std::vector GeneratedChildren; // Read bool read (xmlNodePtr primitiveNode, const char *filename, const char *className, std::set &contextStrings, std::map &contextFilesLookup, NLLIGO::CLigoConfig &config, bool parsePrimitiveComboContent); }; } // NLLIGO #endif // NL_PRIMITIVE_CLASS_H /* End of primitive_class.h */ ================================================ FILE: code/nel/include/nel/ligo/primitive_configuration.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_PRIMITIVE_CONFIGURATION_H #define NL_PRIMITIVE_CONFIGURATION_H #include "nel/misc/types_nl.h" #include "nel/misc/rgba.h" #include // Include from libxml2 #include namespace NLLIGO { class CLigoConfig; class IPrimitive; /** * Ligo primitive configuration description. * * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2001 */ class CPrimitiveConfigurations { public: // The name of the matching values std::string Name; // The configuration color NLMISC::CRGBA Color; // Matching pairs class CMatchGroup { public: std::vector > Pairs; }; // The pair of name / value parameter to match std::vector MatchPairs; // Read from a xml tree bool read (xmlNodePtr configurationNode, const char *filename, const char *name, class CLigoConfig &config); // Test if this primitive belong this configuration bool belong (const IPrimitive &primitive) const; }; } #endif // NL_PRIMITIVE_CONFIGURATION_H /* End of ligo_config.h */ ================================================ FILE: code/nel/include/nel/ligo/primitive_utils.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef PRIMITIVE_UTIL_H #define PRIMITIVE_UTIL_H #include "primitive.h" #include "nel/misc/i_xml.h" #include "nel/misc/o_xml.h" #include "nel/misc/file.h" #include "nel/misc/path.h" #include #include #include namespace NLLIGO { typedef std::vector TPrimitiveSet; /** Default predicate for primitive enumerator. * This predicate test the class name of each primitive against a * given class name. */ struct TPrimitiveClassPredicate : public std::unary_function { TPrimitiveClassPredicate(const std::string &className) : ClassName(className) {} bool operator () (const IPrimitive *prim) const { std::string *s; if (prim->getPropertyByName("class", s) && *s == ClassName) return true; return false; } /// The primitive class name to check const std::string ClassName; }; /** Predicate for primitive enumerator. * This predicate test the name of each primitive against a * given name. */ struct TPrimitiveNamePredicate { TPrimitiveNamePredicate(const std::string &name) : Name(name) {} bool operator () (const IPrimitive *prim) const { std::string *s; if (prim->getPropertyByName("name", s) && *s == Name) return true; return false; } /// The primitive name to check const std::string Name; }; /** Predicate for primitive enumerator. * This predicate test the class name and name of the primitive. */ struct TPrimitiveClassAndNamePredicate { TPrimitiveClassAndNamePredicate(const std::string &className, const std::string &name) : ClassName(className), Name(name) {} bool operator () (const IPrimitive *prim) const { std::string *s; if (prim->getPropertyByName("class", s) && *s == ClassName) { if (prim->getPropertyByName("name", s) && *s == Name) return true; } return false; } /// The primitive class name to check const std::string ClassName; /// The primitive name to check const std::string Name; }; /** Predicate for primitive enumerator. * This predicate test the string value of a given property */ struct TPrimitivePropertyPredicate { TPrimitivePropertyPredicate(const std::string &propName, const std::string &value) : PropName(propName), PropValue(value) {} bool operator () (const IPrimitive *prim) const { std::string *s; if (prim->getPropertyByName(PropName.c_str(), s) && *s == PropValue) return true; return false; } /// The property name const std::string PropName; /// The property value const std::string PropValue; }; /** The primitive enumerator class is used to iterate over primitive node that * match a given predicate. * The primitive are tested recursively starting at an arbitrary node in the * primitive tree. * Application code just need to call getNextMatch until it return NULL indicating * there is no more node that match the predicate. */ template class CPrimitiveEnumerator { public: /** Construct a primitive enumerator. * startPrim is the primitive where the enumeration start. Even if the startPrimitive * is not at the root of the primitive tree, the enumerator will not * try to parse the parent of startPrim. * predicate is the functor predicate. Each node is tested against the bool operator()(IPrimitive *) * method of the predicate. If the predicate return true, then the node is returned by getNextMatch. */ CPrimitiveEnumerator(IPrimitive *startPrim, Pred &predicate) : _StartPrim(startPrim), _Predicate(predicate), _CurrentPrim(startPrim) { // mark the root node as non checked _IndexStack.push_back(std::numeric_limits::max()); } /** Each call to this method will return a primitive pointer that match * the predicate functor. * Return NULL when there is no more primitive matching the predicate. */ IPrimitive *getNextMatch() { while (!_IndexStack.empty()) { if (_IndexStack.back() == std::numeric_limits::max()) { _IndexStack.back() = 0; // we need to check the current node. if (_Predicate(_CurrentPrim)) { // this one match ! return _CurrentPrim; } } if (_IndexStack.back() < _CurrentPrim->getNumChildren()) { IPrimitive *child; if (_CurrentPrim->getChild(child, _IndexStack.back()++)) { // go down into this node _IndexStack.push_back(std::numeric_limits::max()); _CurrentPrim = child; } } else { // no more child to test, pop one level _IndexStack.pop_back(); _CurrentPrim = _CurrentPrim->getParent(); } } // no more match return NULL; } private: /// The root primitive for enumeration IPrimitive *_StartPrim; /// The predicate functor Pred _Predicate; /// The current primitive IPrimitive *_CurrentPrim; /// for each recursion level, keep the index of the currently explored child. std::vector _IndexStack; }; /** Build a primitive set that match the predicate * This class makes use of the CPrimitiveEnumerator class to iterate * on each valid node and fill the result primitive set. */ template class CPrimitiveSet { public: void buildSet(IPrimitive *startPrimitive, Pred &predicate, TPrimitiveSet &result) { CPrimitiveEnumerator enumerator(startPrimitive, predicate); IPrimitive *p; while ((p = enumerator.getNextMatch()) != NULL) result.push_back(p); } }; /** Filter a primitive set against a predicate. * Useful to refine a primitive set with another predicate. */ template class CPrimitiveSetFilter { public: void filterSet(const std::vector &source, Pred &predicate, TPrimitiveSet &result) { std::vector::const_iterator first(source.begin()), last(source.end()); for (; first != last; ++first) { if (predicate(*first)) result.push_back(*first); } } }; /** Utility function that load an xml primitive file into a CPrimitives object. * This function deal with file IO and XML parsing call. * Return false if the loading fail for some reason, true otherwise. */ inline bool loadXmlPrimitiveFile(CPrimitives &primDoc, const std::string &fileName, CLigoConfig &ligoConfig) { try { NLMISC::CIFile fileIn(fileName); NLMISC::CIXml xmlIn; xmlIn.init (fileIn); // Read it return primDoc.read (xmlIn.getRootNode (), NLMISC::CFile::getFilename(fileName).c_str(), ligoConfig); } catch(const NLMISC::Exception &e) { nlwarning("Error reading input file '%s': '%s'", fileName.c_str(), e.what()); return false; } } /** Utility function that save a CPrimitives object into an xml file. * This function deal with file IO and XML parsing call. * Return false if the saving fail for some reason, true otherwise. */ inline bool saveXmlPrimitiveFile(CPrimitives &primDoc, const std::string &fileName) { try { NLMISC::COFile fileOut(fileName); // xmlDocPtr xmlDoc = xmlNewDoc((xmlChar*)("1.0"));; NLMISC::COXml xmlOut; xmlOut.init (&fileOut); // NLMISC::CIXml xmlOut; // xmlOut.init (fileOut); // Read it primDoc.write(xmlOut.getDocument(), fileName.c_str()); xmlOut.flush (); fileOut.close(); return true; // return xmlSaveFile(fileName.c_str(), xmlDoc) != -1; } catch(const NLMISC::Exception &e) { nlwarning("Error writing output file '%s': '%s'", fileName.c_str(), e.what()); return false; } } /** Utility function to look for the first child of a primitive node that * match the predicate. * Return NULL if none of the child match the predicate. * There is no way to get the next matching child using this function, * you must use filterPrimitiveChilds to do this. */ template IPrimitive *getPrimitiveChild(IPrimitive *parent, Pred &predicate) { for (uint i=0; igetNumChildren(); ++i) { IPrimitive *child; if (parent->getChild(child, i) && predicate(child)) { return child; } } return NULL; } /** Utility function to look for the first parent of a primitive node that * match the predicate. * Return NULL if none of the parent match the predicate. */ template IPrimitive *getPrimitiveParent(IPrimitive *prim, Pred &predicate) { IPrimitive *parent = prim->getParent(); while (parent) { if (predicate(parent)) return parent; parent = parent->getParent(); } return NULL; } /** Utility function that fill a primitive set with all the child nodes * that match the predicate. */ template void filterPrimitiveChilds(IPrimitive *parent, Pred &predicate, TPrimitiveSet &result) { for (uint i=0; igetNumChildren(); ++i) { IPrimitive *child; if (parent->getChild(child, i) && predicate(child)) result.push_back(child); } } /** Build a string that represent the path to a node * Note that the reverse operation does not guaranty to * return a unique node because there is no name * uniqueness constraint in the primitive system. */ std::string buildPrimPath(const IPrimitive *prim); /** Return a set of primitive that match a given path*/ void selectPrimByPath(IPrimitive *rootNode, const std::string &path, TPrimitiveSet &result); } // namespace NLLIGO #endif // #define PRIMITIVE_UTIL_H ================================================ FILE: code/nel/include/nel/ligo/zone_bank.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_ZONE_BANK_H #define NL_ZONE_BANK_H #include "nel/misc/types_nl.h" #include "nel/misc/stream.h" #include #include namespace NLLIGO { // Categories that MUST exist // (zone) // (size) // (material) or (transname + transtype + transnum) // All categories are string but some categories are particular string: // zone is any string // size is two number separated by a 'x' // material is any string // transname is two string (of materials separated by a '-') // transnum is a number // transtype is a string among (flat, cornera, cornerb) // *************************************************************************** /// No category of the type given found #define STRING_NO_CAT_TYPE "< NOCATTYPE >" // *************************************************************************** class CZoneBankElement { // Category stuff // The key is the Type of the category (Ex: "material", "size", ...) // The second element is the value (Ex: "Grass", "2x2", ...) std::map _CategoriesMap; // In this list the category type and value must be unique and 2 categories MUST // appears : "zone" (The zone name) and "size" (*x* (ex:4x4 3x1 etc...)) // Some categories used in WorldEditor : "material", "transition" uint8 _SizeX, _SizeY; std::vector _Mask; static std::string _NoCatTypeFound; // = STRING_NO_CAT_TYPE public: CZoneBankElement (); // Set the mask of the zone bank element void setMask (const std::vector &mask, uint8 sizeX, uint8 sizeY); void addCategory (const std::string &CatType, const std::string &CatValue); const std::string &getName (); // Return the value of the "zone" category const std::string &getSize (); uint8 getSizeX () { return _SizeX; } uint8 getSizeY () { return _SizeY; } const std::vector &getMask () { return _Mask; } /// Return the CatValue or STRING_NO_CAT_TYPE if no category of that type found const std::string &getCategory(const std::string &CatType); /// Convert size in the categories to _SizeX, _SizeY void convertSize (); void serial (NLMISC::IStream &f); friend class CZoneBank; }; // *************************************************************************** class CZoneBank { std::map _ElementsMap; std::vector _Selection; public: // Debug stuff beg // --------------- void debugInit(const std::string &sPath); void debugSaveInit(CZoneBankElement &zbeTmp, const std::string &fileName); // --------------- // Debug stuff end void reset (); /// Initialize the zone bank with all files present in the path given (note pathName must not end with '\\') bool initFromPath (const std::string &pathName, std::string &error); /// Load an element in the current directory bool addElement (const std::string &elementName, std::string &error); void getCategoriesType (std::vector &CategoriesType); void getCategoryValues (const std::string &CategoryType, std::vector &CategoryValues); CZoneBankElement *getElementByZoneName (const std::string &ZoneName); // Selection void resetSelection (); void addOrSwitch (const std::string &CategoryType, const std::string &CategoryValue); void addAndSwitch (const std::string &CategoryType, const std::string &CategoryValue); void getSelection (std::vector &SelectedElements); }; // *************************************************************************** } // namespace NLLIGO // *************************************************************************** #endif // NL_ZONE_BANK_H /* End of zone_bank.h */ ================================================ FILE: code/nel/include/nel/ligo/zone_region.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef __ZONE_REGION_H__ #define __ZONE_REGION_H__ // *************************************************************************** #include "nel/misc/stream.h" #include #include namespace NLLIGO { // *************************************************************************** #define STRING_OUT_OF_BOUND "< OOB >" #define STRING_UNUSED "< UNUSED >" // *************************************************************************** struct SPiece { sint32 w, h; // Max 255x255 std::vector Tab; void rotFlip (uint8 rot, uint8 flip); }; // *************************************************************************** class CZoneRegion { public: CZoneRegion (); void serial (NLMISC::IStream &f); void resize (sint32 newMinX, sint32 newMaxX, sint32 newMinY, sint32 newMaxY); void basicSet (sint32 x, sint32 y, sint32 PosX, sint32 PosY, const std::string &ZoneName); // Accessors const std::string &getName (sint32 x, sint32 y) const; uint8 getPosX (sint32 x, sint32 y) const; uint8 getPosY (sint32 x, sint32 y) const; uint8 getRot (sint32 x, sint32 y) const; uint8 getFlip (sint32 x, sint32 y) const; uint8 getCutEdge (sint32 x, sint32 y, uint8 pos) const; // pos==0 -> getUpCE, pos==1 -> getDownCE, ... uint32 getDate (sint32 x, sint32 y, uint8 lowOrHigh) const; // lowOrHigh == 0 -> low std::string getSharingMatNames (sint32 x, sint32 y, uint edge); uint8 getSharingCutEdges (sint32 x, sint32 y, uint edge); // Accessors bool setName (sint32 x, sint32 y, const std::string &newValue); bool setPosX (sint32 x, sint32 y, uint8 newValue); bool setPosY (sint32 x, sint32 y, uint8 newValue); bool setRot (sint32 x, sint32 y, uint8 newValue); bool setFlip (sint32 x, sint32 y, uint8 newValue); bool setSharingMatNames (sint32 x, sint32 y, uint edge, const std::string &newValue); bool setSharingCutEdges (sint32 x, sint32 y, uint edge, uint8 newValue); sint32 getMinX () const { return _MinX; }; sint32 getMaxX () const { return _MaxX; }; sint32 getMinY () const { return _MinY; }; sint32 getMaxY () const { return _MaxY; }; void setMinX (sint32 newValue) { _MinX = newValue; }; void setMaxX (sint32 newValue) { _MaxX = newValue; }; void setMinY (sint32 newValue) { _MinY = newValue; }; void setMaxY (sint32 newValue) { _MaxY = newValue; }; protected: // An element of the grid struct SZoneUnit { std::string ZoneName; uint8 PosX, PosY; // Position in a large piece uint8 Rot, Flip; // Rot 0-0deg, 1-90deg, 2-180deg, 3-270deg, Flip 0-false, 1-true // Work Data : For transition [2 3] std::string SharingMatNames[4]; // [0 1] uint8 SharingCutEdges[4]; // 0-Up, 1-Down, 2-Left, 3-Right (value [0-2]) SZoneUnit (); void serial (NLMISC::IStream &f); const SZoneUnit&operator= (const SZoneUnit&zu); }; struct SZoneUnit2 : public SZoneUnit { uint32 DateLow; uint32 DateHigh; SZoneUnit2 (); void serial (NLMISC::IStream &f); const SZoneUnit2&operator= (const SZoneUnit2&zu); const SZoneUnit2&operator= (const SZoneUnit&zu); }; static std::string _StringOutOfBound; protected: std::vector _Zones; sint32 _MinX, _MinY; sint32 _MaxX, _MaxY; }; } // namespace NLLIGO #endif // __ZONE_REGION_H__ ================================================ FILE: code/nel/include/nel/logic/CMakeLists.txt ================================================ FILE(GLOB HEADERS *.h) INSTALL(FILES ${HEADERS} DESTINATION include/nel/logic COMPONENT headers) ================================================ FILE: code/nel/include/nel/logic/logic_condition.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef LOGIC_CONDITION_H #define LOGIC_CONDITION_H #include "nel/misc/types_nl.h" #include "nel/misc/stream.h" #include "nel/misc/o_xml.h" #include "nel/misc/i_xml.h" namespace NLLOGIC { class CLogicStateMachine; class CLogicConditionNode; /** * CLogicComparisonBlock * * \author Stephane Coutelas * \author Nevrax France * \date 2001 */ class CLogicComparisonBlock { /// state machine managing this comparison block CLogicStateMachine * _LogicStateMachine; public: /// variable name std::string VariableName; /// comparison operator std::string Operator; /// comparand sint64 Comparand; /** * Default constructor */ CLogicComparisonBlock() { _LogicStateMachine = 0; VariableName = "no_name"; Operator = ">"; Comparand = 0; } /** * Set the logic state machine * * \param logicStateMachine is the state machine containing this block */ void setLogicStateMachine( CLogicStateMachine * logicStateMachine ); /** * Test the condition * * \return true if this condition is fulfiled, false else */ bool testLogic(); /** * serial */ //void serial(class NLMISC::IStream &f) throw(NLMISC::EStream); void write (xmlNodePtr node) const; void read (xmlNodePtr node); }; /** * CLogicConditionLogicBlock * * \author Stephane Coutelas * \author Nevrax France * \date 2001 */ class CLogicConditionLogicBlock { /// state machine managing this logic block CLogicStateMachine * _LogicStateMachine; public: /// all condition logic block types enum TLogicConditionLogicBlockType { NOT = 0, COMPARISON, SUB_CONDITION, }; /// type of this condition block TLogicConditionLogicBlockType Type; /// name of the sub-condition std::string SubCondition; /// comparison block CLogicComparisonBlock ComparisonBlock; /** * Default constructor */ CLogicConditionLogicBlock() { Type = SUB_CONDITION; SubCondition = "no_condition"; } /** * Return info about the type of the block * * \return true if this block is a NOT block */ bool isNotBlock() const { return (Type == NOT); } /** * Set the logic state machine * * \param logicStateMachine is the state machine containing this block */ void setLogicStateMachine( CLogicStateMachine * logicStateMachine ); /** * Test the condition * * \return true if this condition is fulfiled, false else */ bool testLogic(); /** * Fill a set with all the variables name referenced by this condition * * \param condVars a set to store the variable names */ void fillVarSet( std::set& condVars ); /** * serial */ //void serial(class NLMISC::IStream &f) throw(NLMISC::EStream); void write (xmlNodePtr node) const; void read (xmlNodePtr node); }; /** * CLogicConditionNode * * \author Stephane Coutelas * \author Nevrax France * \date 2001 */ class CLogicConditionNode { /// state machine managing this logic block CLogicStateMachine * _LogicStateMachine; public: /// all condition node types enum TConditionNodeType { TERMINATOR = 0, LOGIC_NODE }; /// type of this condition node TConditionNodeType Type; // if this node is a logical node : /// condition logic node CLogicConditionLogicBlock LogicBlock; /// condition nodes std::vector _Nodes; /** * Default constructor */ CLogicConditionNode() { _LogicStateMachine = 0; Type = TERMINATOR; } /** * Set the logic state machine * * \param logicStateMachine is the state machine containing this block */ void setLogicStateMachine( CLogicStateMachine * logicStateMachine ); /** * add a node in the subtree * * \param node is the new node to add */ void addNode( CLogicConditionNode * node ); /** * Test the condition * * \return true if this condition is fulfiled, false else */ bool testLogic(); /** * Fill a set with all the variables name referenced by this condition * * \param condVars is a set to store the variable names */ void fillVarSet( std::set& condVars ); /** * serial */ //void serial(class NLMISC::IStream &f) throw(NLMISC::EStream); /** * Destructor */ ~CLogicConditionNode(); void write (xmlNodePtr node) const; void read (xmlNodePtr node); }; /** * CLogicCondition * * \author Stephane Coutelas * \author Nevrax France * \date 2001 */ class CLogicCondition { /// condition name std::string _ConditionName; public: /// condition tree std::vector Nodes; /** * CLogicCondition */ CLogicCondition() { _ConditionName = "no_condition"; } /** * Set the logic state machine * * \param logicStateMachine is the state machine containing this block */ void setLogicStateMachine( CLogicStateMachine * logicStateMachine ); /** * Set the condition's name * * \param name is the condition's name */ void setName( std::string name ) { _ConditionName = name; } /** * Get the condition's name * * \return the condition's name */ std::string getName() const { return _ConditionName; } /** * Add a condition node * * \param node is the new node to add */ void addNode( CLogicConditionNode node ) { Nodes.push_back( node ); } /** * Test the condition * * \return true if this condition is fulfiled, false else */ bool testLogic(); /** * Fill a set with all the variables name referenced by this condition * * \param condVars is a set to store the variable names */ void fillVarSet( std::set& condVars ); /** * serial */ //void serial(class NLMISC::IStream &f) throw(NLMISC::EStream); void write (xmlNodePtr node) const; void read (xmlNodePtr node); }; } // NLLOGIC #endif //LOGIC_CONDITION ================================================ FILE: code/nel/include/nel/logic/logic_event.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef LOGIC_EVENT_H #define LOGIC_EVENT_H #include "nel/misc/types_nl.h" #include "nel/misc/stream.h" #include "nel/misc/entity_id.h" #include "nel/misc/o_xml.h" #include "nel/misc/i_xml.h" //#include "game_share/sid.h" namespace NLLOGIC { class CLogicStateMachine; /** * CLogicEventMessage * * \author Stephane Coutelas * \author Nevrax France * \date 2001 */ class CLogicEventMessage { public: /// true if the message has to be sent bool ToSend; /// true if the message has been sent bool Sent; /// message destination std::string Destination; /// message destination id NLMISC::CEntityId DestinationId; /// message id std::string MessageId; /// message arguments std::string Arguments; /** * Default constructor */ CLogicEventMessage() { ToSend = false; Sent = false; Destination = "no_destination"; MessageId = "no_id"; DestinationId.setType( 0xfe ); DestinationId.setCreatorId( 0 ); DestinationId.setDynamicId( 0 ); Arguments = "no_arguments"; } /** * serial */ //void serial(NLMISC::IStream &f) throw(NLMISC::EStream); void write (xmlNodePtr node, const char *subName = "") const; void read (xmlNodePtr node, const char *subName = ""); }; /** * CLogicEventAction * * \author Stephane Coutelas * \author Nevrax France * \date 2001 */ class CLogicEventAction { public: /// true if this action consist in a state change, false if it's a message bool IsStateChange; /// state name for state change std::string StateChange; /// event message CLogicEventMessage EventMessage; /** * Default constructor */ CLogicEventAction() { IsStateChange = false; } /** * This message will be sent as soon as the dest id will be given */ void enableSendMessage(); /** * serial */ //void serial(NLMISC::IStream &f) throw(NLMISC::EStream); void write (xmlNodePtr node) const; void read (xmlNodePtr node); }; /** * CLogicEvent * * \author Stephane Coutelas * \author Nevrax France * \date 2001 */ class CLogicEvent { /// state machine managing this event CLogicStateMachine * _LogicStateMachine; public: /// condition name std::string ConditionName; /// event action CLogicEventAction EventAction; /** * Default constructor */ CLogicEvent() { _LogicStateMachine = 0; ConditionName = "no_condition"; } /** * Reset this event */ void reset(); /** * Set the logic state machine * * \param logicStateMachine is the state machine containing this block */ void setLogicStateMachine( CLogicStateMachine * logicStateMachine ); /** * Test the condition * * \return true if condition is fulfiled */ bool testCondition(); /** * serial */ //void serial(class NLMISC::IStream &f) throw(NLMISC::EStream); void write (xmlNodePtr node) const; void read (xmlNodePtr node); }; } // NLLOGIC #endif //LOGIC_EVENT ================================================ FILE: code/nel/include/nel/logic/logic_state.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef LOGIC_STATE_H #define LOGIC_STATE_H #include "nel/misc/types_nl.h" #include "nel/misc/stream.h" #include "nel/misc/entity_id.h" #include "nel/misc/o_xml.h" #include "nel/misc/i_xml.h" #include "nel/net/service.h" //#include "game_share/sid.h" #include "logic_event.h" namespace NLLOGIC { class CLogicStateMachine; /// map destination names to destination sid typedef std::map TSIdMap; /** * CLogicState * * \author Stephane Coutelas * \author Nevrax France * \date 2001 */ class CLogicState { public: /// state name std::string _StateName; /// entry messages std::vector _EntryMessages; /// exit messages std::vector _ExitMessages; /// logic std::vector _Events; /// state machine containing this state CLogicStateMachine * _LogicStateMachine; /// messages to send by the service std::multimap _MessagesToSend; public: /** * Default constructor */ CLogicState(); /** * Set the state machine which contains this state * * \param logicStateMachine is the state machine containing this block */ void setLogicStateMachine( CLogicStateMachine * logicStateMachine ); /** * set the state name * * \param name is the new state's name */ void setName( std::string name ) { _StateName = name; } /** * get the state name * * \return the state's name */ std::string getName() { return _StateName; } /** * Add an event * * \param event is the event to add */ void addEvent( CLogicEvent event ); /** * Associate message destination name with sid * * \param sIdMap is the map associating destination name with a destination id */ void addSIdMap( const TSIdMap& sIdMap ); /** * Test the conditions of this state */ void processLogic(); /** * Get the messages to send * * \param msgs is the map associating all the message to send with their destination id */ void getMessagesToSend( std::multimap& msgs ); /** * send the entry messages */ void enterState(); /** * send the exit messages */ void exitState(); /** * Try to send the entry messages */ void trySendEntryMessages(); /** * Try to send the event messages */ void trySendEventMessages(); /** * Fill a map associating all the referenced var in the state with the id of service managing them * (debug purpose) */ void fillVarMap( std::multimap& stateMachineVariables ); /** * serial */ //void serial(NLMISC::IStream &f) throw(NLMISC::EStream); void write (xmlNodePtr node) const; void read (xmlNodePtr node); }; } // NLLOGIC #endif //LOGIC_STATE ================================================ FILE: code/nel/include/nel/logic/logic_state_machine.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef LOGIC_STATE_MACHINE_H #define LOGIC_STATE_MACHINE_H #include "logic_state.h" #include "logic_variable.h" #include "logic_condition.h" #include "nel/misc/o_xml.h" #include "nel/misc/i_xml.h" #include "nel/net/service.h" #include #include #include namespace NLLOGIC { void xmlCheckNodeName (xmlNodePtr &node, const char *nodeName); std::string getXMLProp (xmlNodePtr node, const char *propName); /** * CLogicStateMachine * * \author Stephane Coutelas * \author Nevrax France * \date 2001 */ class CLogicStateMachine { /// variables std::map _Variables; /// counters std::map _Counters; /// conditions used in this state machine std::map _Conditions; /// states std::map _States; /// name of the current state std::string _CurrentState; /// name of this sate machine std::string _Name; public: const std::map &getVariables () { return _Variables; } const std::map &getCounters () { return _Counters; } const std::map &getConditions () { return _Conditions; } const std::map &getStates () { return _States; } /** * Default constructor */ CLogicStateMachine() { _Name = "no_name"; } /** * Set the state machine name * * \param name is the name of state machine */ void setName( const std::string& name ) { _Name = name; } /** * Get the state machine name * * \return the name of this state machine */ std::string getName() const { return _Name; } /** * Set the current state * * \param stateName is the name of the state to give focus to */ void setCurrentState( std::string stateName ); /** * call the addSIdMap() method for each sate machines * * \param sIdMap is the map associating destination name with a destination id */ void addSIdMap( const TSIdMap& sIdMap ); /** * call the processLogic method for each sate machines */ void processLogic(); /** * Get the self-addressed message * * \param msgs is the list used to store the self-addressed messages */ void getSelfAddressedMessages( std::list& msgs ); /** * Add a variable in the state machine * * \param var is the new variable to add in this state machine */ void addVariable( CLogicVariable var ) { _Variables.insert( std::make_pair(var.getName(),var) ); } /** * Get the variable * * \param varName is the name of the variable to get * \param var is the variable to get * \return true if the variable has been found, false if not */ bool getVariable( std::string& varName, CLogicVariable& var ); /** * Add a counter in the state machine * * \param counter is the new counter to add in this state machine */ void addCounter( CLogicCounter counter ) { _Counters.insert( std::make_pair(counter.getName(),counter) ); } /** * Add a condition in the state machine * * \param condition is the new condition to add in this state machine */ void addCondition( CLogicCondition condition ); /** * Get the condition * * \param condName is the name of the condition to get * \param cond is the condition to get * \return true if the condition has been found, false if not */ bool getCondition( const std::string& condName, CLogicCondition& cond ); /** * Get the messages to send * * \param msgs is the list used to store the messages to send */ void getMessagesToSend( std::multimap& msgs ); /** * Add a state to the state machine * * \param state is the new state to add in this state machine */ void addState( CLogicState logicState ); /** * modify a variable * * \param varName is the name of the variable to modify * \param modifOperator can be one of these operators :"SET"("set"),"ADD"("add"),"SUB"("sub"),"MUL"("mul"),"DIV"("div") * \param value is the value to use along with the modificator */ void modifyVariable( std::string varName, std::string modifOperator, sint64 value ); /** * serial */ //void serial( NLMISC::IStream &f ) throw(NLMISC::EStream); /** * Display the variables */ void displayVariables(); /** * Display the states */ void displayStates(); /** * Set the verbose mode for a variable * * \param varName is the name of the variable * \param b is true to activate the verbose mode, false else */ void setVerbose( std::string varName, bool b ); void write (xmlDocPtr doc) const; void read (xmlNodePtr node); }; } // NLLOGIC #endif //LOGIC_SYSTEM ================================================ FILE: code/nel/include/nel/logic/logic_variable.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef LOGIC_VARIABLE_H #define LOGIC_VARIABLE_H #include "nel/misc/types_nl.h" #include "nel/misc/stream.h" #include "nel/misc/o_xml.h" #include "nel/misc/i_xml.h" namespace NLLOGIC { /** * CLogicVariable * * \author Stephane Coutelas * \author Nevrax France * \date 2001 */ class CLogicVariable { protected: /// variable value sint64 _Value; /// variable name std::string _Name; /// true if verbose mode is active bool _Verbose; public: /** * Default constructor */ CLogicVariable(); /** * Set the variable name * * \param name is the name of the variable */ void setName( std::string name ) { _Name = name; } /** * Get the variable name * * \return the name of the variable */ std::string getName() const { return _Name; } /** * Set the variable value * * \param value is the new value of the variable */ void setValue( sint64 value ); /** * Get the variable value * * \return the variable's value */ sint64 getValue() const { return _Value; } /** * Set the verbose mode active or inactive * * \param varName is the name of the variable * \param b is true to activate the verbose mode, false else */ void setVerbose( bool b ) { _Verbose = b; } /** * Apply modifications on a variable * * \param op can be one of these operators :"SET"("set"),"ADD"("add"),"SUB"("sub"),"MUL"("mul"),"DIV"("div") * \param value is the value to use along with the modificator */ void applyModification( std::string op, sint64 value ); /** * update the variable */ virtual void processLogic(); /** * serial */ //virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream); virtual void write (xmlNodePtr node) const; virtual void read (xmlNodePtr node); }; /** * CLogicCounter * * \author Stephane Coutelas * \author Nevrax France * \date 2001 */ class CLogicCounter : public CLogicVariable { uint _TickCount; public: /// counter running mode enum TLogicCounterRule { STOP_AT_LIMIT = 0, LOOP, SHUTTLE, DOWN_UP, // bounce at low end, stop at high end UP_DOWN, // bounce at high end, stop at low end }; /// counter running state enum TLogicCounterRunningMode { STOPPED = 0, RUN, REWIND, FAST_FORWARD, }; /// period between inc( measured in game ticks ) CLogicVariable Period; /// time offset to apply with period CLogicVariable Phase; /// regular increment value( normally 1 or -1 ) CLogicVariable Step; /// lower limit for counter CLogicVariable LowLimit; /// higher limit for counter CLogicVariable HighLimit; /// running mode CLogicVariable Mode; /// running state CLogicVariable Control; /** * Default constructor */ CLogicCounter(); /** * update the counter */ void update(); /** * check the counter value according to the running mode */ void manageRunningMode(); /** * serial */ //void serial(NLMISC::IStream &f) throw(NLMISC::EStream); virtual void write (xmlNodePtr node) const; virtual void read (xmlNodePtr node); }; } // NLLOGIC #endif //LOGIC_VARIABLE ================================================ FILE: code/nel/include/nel/misc/CMakeLists.txt ================================================ FILE(GLOB HEADERS *.h) INSTALL(FILES ${HEADERS} DESTINATION include/nel/misc COMPONENT headers) ================================================ FILE: code/nel/include/nel/misc/aabbox.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_AABBOX_H #define NL_AABBOX_H #include "types_nl.h" #include "vector.h" #include "plane.h" #include "common.h" #include "stream.h" #include "bsphere.h" namespace NLMISC { class CMatrix; // *************************************************************************** /** * An Axis Aligned Bounding Box. * Note: Center/HalfSize set to private, to have same manipulation for CAABBox and CAABBoxExt. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CAABBox { protected: /// The center of the bbox. CVector Center; /// The size/2 of the bbox. CVector HalfSize; public: /// Empty bbox Constructor. (for AABBoxExt::getRadius() correctness). CAABBox() : Center(0,0,0), HalfSize(0,0,0) {} /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ /// \name Builds. // @{ void setCenter(const CVector ¢er) {Center= center;} void setHalfSize(const CVector &hs) {HalfSize= hs;} /// Set the size of the bbox (ie 2* the halfSize). void setSize(const CVector &s) {HalfSize= s/2;} /// Build the bbox, with a min/max style bbox. void setMinMax(const CVector &bmin, const CVector &bmax) { Center= (bmin+bmax)/2; HalfSize= bmax-Center; } /** extend the bbox so it contains v. * Warning!! By default, a bbox is the vector 0,0,0. So set the first vertex with setCenter() or else the bbox will * be the extension of v and (0,0,0)... */ void extend(const CVector &v); //@} /// \name Gets. // @{ CVector getMin() const {return Center-HalfSize;} CVector getMax() const {return Center+HalfSize;} void getMin(CVector &ret) const {ret= Center-HalfSize;} void getMax(CVector &ret) const {ret= Center+HalfSize;} const CVector &getCenter() const {return Center;} const CVector &getHalfSize() const {return HalfSize;} /// Return the size of the bbox. CVector getSize() const {return HalfSize*2;} void getSize(CVector &ret) const {ret= HalfSize*2;} /// Return the radius of the bbox. float getRadius() const {return HalfSize.norm();} // @} /// \name Clip // @{ /// Is the bbox partially in front of the plane?? bool clipFront(const CPlane &p) const; /// Is the bbox partially in back of the plane?? bool clipBack(const CPlane &p) const; /// Does the bbox include this point. bool include(const CVector &a) const; /// Does the bbox include entirely this bbox. bool include(const CAABBox &box) const; /// Does the bbox intersect the bbox box. bool intersect(const CAABBox &box) const; /// Does the bbox intersect the triangle ABC. bool intersect(const CVector &a, const CVector &b, const CVector &c) const; /// Does the bbox instersect the sphere s bool intersect(const CBSphere &s) const; /// Does the bbox instersect the segment AB bool intersect(const CVector &a, const CVector &b) const; /// clip the segment by the bbox. return false if don't intersect. a and b are modified. bool clipSegment(CVector &a, CVector &b) const; // @} /// \name Misc // @{ /// Build the equivalent polytope of planes. void makePyramid(CPlane planes[6]) const; /** * Compute the union of 2 bboxs, that is the aabbox that contains the 2 others. * Should end up in NLMISC */ static CAABBox computeAABBoxUnion(const CAABBox &b1, const CAABBox &b2); /** * Compute the intersection of 2 bboxs. * NB: this methods suppose the intersection exist, and doesn't check it (use intersect() to check). * If !intersect, *this is still modified and the result bbox is big shit. */ void computeIntersection(const CAABBox &b1, const CAABBox &b2); /** Apply a matrix on an aabbox * \return an aabbox, bigger or equal to parameter, after the matrix multiplication */ static CAABBox transformAABBox(const CMatrix &mat, const CAABBox &box); // @} void serial(NLMISC::IStream &f); }; // *************************************************************************** /** * An Extended Axis Aligned Bouding Box. Sphere Min/Max Radius is stored for improved clip test. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CAABBoxExt : private CAABBox { protected: float RadiusMin, RadiusMax; void updateRadius() { // The bounding sphere. RadiusMax= CAABBox::getRadius(); // The including sphere. RadiusMin= NLMISC::minof((float)fabs(HalfSize.x), (float)fabs(HalfSize.y), (float)fabs(HalfSize.z)); } public: /// Empty bbox Constructor CAABBoxExt() {RadiusMin= RadiusMax=0;} /// Constructor from a normal BBox. CAABBoxExt(const CAABBox &o) {RadiusMin= RadiusMax=0; *this=o;} /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ /// \name Builds. // @{ void setCenter(const CVector ¢er) {Center= center;} void setHalfSize(const CVector &hs) {HalfSize= hs; updateRadius();} void setSize(const CVector &s) {HalfSize= s/2; updateRadius();} /// Build the bbox, with a min/max style bbox. void setMinMax(const CVector &bmin, const CVector &bmax) { Center= (bmin+bmax)/2; HalfSize= bmax-Center; updateRadius(); } CAABBoxExt &operator=(const CAABBox &o) {Center= o.getCenter(); HalfSize= o.getHalfSize(); updateRadius(); return (*this);} //@} /// \name Gets. // @{ CVector getMin() const {return CAABBox::getMin();} CVector getMax() const {return CAABBox::getMax();} const CVector &getCenter() const {return Center;} const CVector &getHalfSize() const {return HalfSize;} /// Return the size of the bbox. CVector getSize() const {return HalfSize*2;} /// Return the (stored!!) radius of the bbox. float getRadius() const {return RadiusMax;} /// Return a simple Axis Aligned Bounding Box (no radius inside) CAABBox getAABBox() const { CAABBox box; box.setCenter(getCenter()); box.setHalfSize(getHalfSize()); return box; } // @} /// \name Clip // @{ /// Is the bbox partially in front of the plane?? p MUST be normalized. bool clipFront(const CPlane &p) const; /// Is the bbox partially in back of the plane?? p MUST be normalized. bool clipBack(const CPlane &p) const; /// Does the bbox intersect the bbox box. bool intersect(const CAABBoxExt &box) const {return CAABBox::intersect(box);} /// Does the bbox intersect the triangle ABC. bool intersect(const CVector &a, const CVector &b, const CVector &c) const {return CAABBox::intersect(a,b,c);} // @} void serial(NLMISC::IStream &f); }; } // NLMISC #endif // NL_AABBOX_H /* End of aabbox.h */ ================================================ FILE: code/nel/include/nel/misc/algo.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_ALGO_H #define NL_ALGO_H #include "types_nl.h" #include #include #include "ucstring.h" namespace NLMISC { // *************************************************************************** // blend between 2 values // NB: like 'toString' or 'swap', this function is intended to be specialised for other types (CRGBA ...) template T blend(const T &v0, const T &v1, const U &blendFactor) { return blendFactor * v1 + ((U) 1 - blendFactor) * v0; } // *************************************************************************** // add a delta to a value until it reaches the wanted target. Value is clamped to the target inline void incrementalBlend(float &value, float target, float absDelta) { nlassert(absDelta >= 0.f); if (value < target) { value += absDelta; if (value > target) value = target; } else if (target < value) { value -= absDelta; if (value < target) value = target; } } // *************************************************************************** /** bilinear of 4 values * v3 v2 * +-----+ * | | * | | * +-----+ * v0 v1 * * * T * ^ * | * | * +---> S */ template T computeBilinear(const T &v0, const T &v1, const T &v2, const T &v3, const U &s, const U &t) { T h0 = t * v3 + ((U) 1 - t) * v0; T h1 = t * v2 + ((U) 1 - t) * v1; return s * h1 + ((U) 1 - s) * h0; } // *************************************************************************** /** Select all points crossed by the line [(x0,y0) ; (x1,y1)] * Not the same than brensenham */ void drawFullLine (float x0, float y0, float x1, float y1, std::vector > &result); // *************************************************************************** /** Select points on the line [(x0,y0) ; (x1,y1)] */ void drawLine (float x0, float y0, float x1, float y1, std::vector > &result); // *************************************************************************** /** Search the lower_bound in a sorted array of Value, in growing order (0, 1, 2....). * operator<= is used to perform the comparison. * It return the first element such that array[id]<=key * If not possible, 0 is returned * NB: but 0 may still be a good value, so you must check whether or not 0 means "Not found", or "Id 0". */ template uint searchLowerBound(const T *array, uint arraySize, const T &key) { uint start=0; uint end= arraySize; // find lower_bound by dichotomy while(end-1>start) { uint pivot= (end+start)/2; // return the lower_bound, ie return first start with array[pivot]<=key if(array[pivot] <= key) start= pivot; else end= pivot; } return start; } // *************************************************************************** /** Search the lower_bound in a sorted array of Value, in growing order (0, 1, 2....). * operator<= is used to perform the comparison. * It returns the first element such that array[id]<=key * If not possible, 0 is returned * NB: but 0 may still be a good value, so you must check whether or not 0 means "Not found", or "Id 0". */ template uint searchLowerBound(const std::vector &array, const T &key) { uint size= (uint)array.size(); if(size==0) return 0; else return searchLowerBound(&array[0], size, key); } // *************************************************************************** /** Clamp a sint in 0..255. Avoid cond jump. */ static inline void fastClamp8(sint &v) { #if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM) // clamp v in 0..255 (no cond jmp) __asm { mov esi, v mov eax, [esi] mov ebx, eax // clamp to 0. add eax, 0x80000000 sbb ecx, ecx not ecx and ebx, ecx // clamp to 255. add eax, 0x7FFFFF00 sbb ecx, ecx or ebx, ecx and ebx, 255 // store mov [esi], ebx } #else clamp(v, 0, 255); #endif } // *************************************************************************** /** return true if the string strIn verify the wildcard string wildCard. * eg: * testWildCard("azert", "*")== true * testWildCard("azert", "??er*")== true * testWildCard("azert", "*er*")== true * testWildCard("azert", "azert*")== true * Undefined result if s has some '*', * return false if wildcard has some "**" or "*?" * NB: case-sensitive */ bool testWildCard(const char *strIn, const char *wildCard); bool testWildCard(const std::string &strIn, const std::string &wildCard); // *************************************************************************** /** From a string with some separators, build a vector of string. * eg: splitString("hello|bye|||bee", "|", list) return 3 string into list: "hello", "bye" and "bee". */ void splitString(const std::string &str, const std::string &separator, std::vector &retList); void splitUCString(const ucstring &ucstr, const ucstring &separator, std::vector &retList); // *************************************************************************** /// In a string or ucstring, find a substr and replace it with another. return true if replaced template bool strFindReplace(T &str, const T &strFind, const U &strReplace) { typename T::size_type pos= str.find(strFind); if(pos != T::npos) { str.replace(pos, strFind.size(), T(strReplace) ); return true; } else return false; } template bool strFindReplace(T &str, const char *strFind, const U &strReplace) { T tempStr(strFind); return strFindReplace(str, tempStr, strReplace); } // set flags in a bit set template inline void setFlags(T &dest, U mask, bool on) { if (on) { dest = (T) (dest | (T) mask); } else { dest = (T) (dest & ~((T) mask)); } } //DoubleRound(1.234,2) = 1.23 //DoubleRound(1.234,0) = 1.0 //DoubleRound(123.4,-1) = 120.0 inline double DoubleRound(double dVal, short iPlaces) { double dRetval; double dMod = 0.0000001; if (dVal<0.0) dMod=-0.0000001; dRetval=dVal; dRetval+=(5.0/pow(10.0,iPlaces+1.0)); dRetval*=pow(10.0,iPlaces); dRetval=floor(dRetval+dMod); dRetval/=pow(10.0,iPlaces); return (dRetval); } } // NLMISC #endif // NL_ALGO_H /* End of algo.h */ ================================================ FILE: code/nel/include/nel/misc/app_context.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef APP_CONTEXT_H #define APP_CONTEXT_H #include "nel/misc/types_nl.h" #include namespace NLMISC { class CLog; class CMemDisplayer; class CMsgBoxDisplayer; /** Interface definition for nel context. * Any application wide data can be accessed thru this interface. * * The NeL context is a mean to allow dynamic library loading in NeL. * In order to make all NeL application safe, it is mandatory to declare * a NeL context at startup of any application (first instruction of the * main() or WinMain() is good practice). * Note that for NLNET::IService oriented application, service framwork * already provide the application context. * * \author Boris 'SoniX' Boucher * \date 2005 */ class INelContext { static INelContext ** _getInstance(); public: /// Access to the context singleton static INelContext &getInstance(); static bool isContextInitialised(); virtual ~INelContext(); //@name Singleton registry //@{ /** Return the pointer associated to a given singleton name * If the name is not present, return NULL. */ virtual void *getSingletonPointer(const std::string &singletonName) =0; /** Register a singleton pointer. */ virtual void setSingletonPointer(const std::string &singletonName, void *ptr) =0; /** Release a singleton pointer */ virtual void releaseSingletonPointer(const std::string &singletonName, void *ptr) =0; //@} //@name Global debugging object //@{ virtual CLog *getErrorLog() =0; virtual void setErrorLog(CLog *errorLog) =0; virtual CLog *getWarningLog() =0; virtual void setWarningLog(CLog *warningLog) =0; virtual CLog *getInfoLog() =0; virtual void setInfoLog(CLog *infoLog) =0; virtual CLog *getDebugLog() =0; virtual void setDebugLog(CLog *debugLog) =0; virtual CLog *getAssertLog() =0; virtual void setAssertLog(CLog *assertLog) =0; virtual CMemDisplayer *getDefaultMemDisplayer() =0; virtual void setDefaultMemDisplayer(CMemDisplayer *memDisplayer) =0; virtual CMsgBoxDisplayer *getDefaultMsgBoxDisplayer() =0; virtual void setDefaultMsgBoxDisplayer(CMsgBoxDisplayer *msgBoxDisplayer) =0; virtual bool getDebugNeedAssert() =0; virtual void setDebugNeedAssert(bool needAssert) =0; virtual bool getNoAssert() =0; virtual void setNoAssert(bool noAssert) =0; virtual bool getAlreadyCreateSharedAmongThreads() =0; virtual void setAlreadyCreateSharedAmongThreads(bool b) =0; virtual bool isWindowedApplication() = 0; virtual void setWindowedApplication(bool b = true) = 0; //@} protected: /// Called by derived class to finalize initialisation of context void contextReady(); static INelContext *_NelContext; }; /** This class implement the context interface for the application module * That means that this class will really hold the data. * \author Boris 'SoniX' Boucher * \date 2005 */ class CApplicationContext : public INelContext { public: CApplicationContext(); virtual void *getSingletonPointer(const std::string &singletonName); virtual void setSingletonPointer(const std::string &singletonName, void *ptr); virtual void releaseSingletonPointer(const std::string &singletonName, void *ptr); virtual CLog *getErrorLog(); virtual void setErrorLog(CLog *errorLog); virtual CLog *getWarningLog(); virtual void setWarningLog(CLog *warningLog); virtual CLog *getInfoLog(); virtual void setInfoLog(CLog *infoLog); virtual CLog *getDebugLog(); virtual void setDebugLog(CLog *debugLog); virtual CLog *getAssertLog(); virtual void setAssertLog(CLog *assertLog); virtual CMemDisplayer *getDefaultMemDisplayer(); virtual void setDefaultMemDisplayer(CMemDisplayer *memDisplayer); virtual CMsgBoxDisplayer *getDefaultMsgBoxDisplayer(); virtual void setDefaultMsgBoxDisplayer(CMsgBoxDisplayer *msgBoxDisplayer); virtual bool getDebugNeedAssert(); virtual void setDebugNeedAssert(bool needAssert); virtual bool getNoAssert(); virtual void setNoAssert(bool noAssert); virtual bool getAlreadyCreateSharedAmongThreads(); virtual void setAlreadyCreateSharedAmongThreads(bool b); virtual bool isWindowedApplication(); virtual void setWindowedApplication(bool b); private: /// Singleton registry typedef std::map TSingletonRegistry; TSingletonRegistry _SingletonRegistry; CLog *ErrorLog; CLog *WarningLog; CLog *InfoLog; CLog *DebugLog; CLog *AssertLog; CMemDisplayer *DefaultMemDisplayer; CMsgBoxDisplayer *DefaultMsgBoxDisplayer; bool DebugNeedAssert; bool NoAssert; bool AlreadyCreateSharedAmongThreads; bool WindowedApplication; }; /** This class implements the context interface for the a library module. * All it contains is forward call to the application context instance. * \author Boris 'SoniX' Boucher * \date 2005 */ class CLibraryContext : public INelContext { public: CLibraryContext (INelContext &applicationContext); virtual void *getSingletonPointer(const std::string &singletonName); virtual void setSingletonPointer(const std::string &singletonName, void *ptr); virtual void releaseSingletonPointer(const std::string &singletonName, void *ptr); virtual CLog *getErrorLog(); virtual void setErrorLog(CLog *errorLog); virtual CLog *getWarningLog(); virtual void setWarningLog(CLog *warningLog); virtual CLog *getInfoLog(); virtual void setInfoLog(CLog *infoLog); virtual CLog *getDebugLog(); virtual void setDebugLog(CLog *debugLog); virtual CLog *getAssertLog(); virtual void setAssertLog(CLog *assertLog); virtual CMemDisplayer *getDefaultMemDisplayer(); virtual void setDefaultMemDisplayer(CMemDisplayer *memDisplayer); virtual CMsgBoxDisplayer *getDefaultMsgBoxDisplayer(); virtual void setDefaultMsgBoxDisplayer(CMsgBoxDisplayer *msgBoxDisplayer); virtual bool getDebugNeedAssert(); virtual void setDebugNeedAssert(bool needAssert); virtual bool getNoAssert(); virtual void setNoAssert(bool noAssert); virtual bool getAlreadyCreateSharedAmongThreads(); virtual void setAlreadyCreateSharedAmongThreads(bool b); virtual bool isWindowedApplication(); virtual void setWindowedApplication(bool b); private: /// Pointer to the application context. INelContext *_ApplicationContext; }; //@name Singleton utility //@{ /** Some utility macro to build singleton compatible with * the dynamic loading of library * This macro must be put inside the singleton class * definition. * Warning : this macro change the current access right, it end up with * private access right. */ #define NLMISC_SAFE_SINGLETON_DECL(className) \ private:\ /* declare private constructors*/ \ /*className () {}*/\ className (const className &) {}\ /* the local static pointer to the singleton instance */ \ static className *_Instance; \ public:\ static className &getInstance() \ { \ if (_Instance == NULL) \ { \ /* the nel context MUST be initialised */ \ nlassertex(NLMISC::INelContext::isContextInitialised(), ("You are trying to access a safe singleton without having initialized a NeL context. The simplest correction is to add 'NLMISC::CApplicationContext myApplicationContext;' at the very beginning of your application.")); \ void *ptr = NLMISC::INelContext::getInstance().getSingletonPointer(#className); \ if (ptr == NULL) \ { \ /* allocate the singleton and register it */ \ _Instance = new className; \ NLMISC::INelContext::getInstance().setSingletonPointer(#className, _Instance); \ } \ else \ { \ _Instance = reinterpret_cast(ptr); \ } \ } \ return *_Instance; \ } \ private: /** The same as above, but generate a getInstance method that * return a pointer instead of a reference */ #define NLMISC_SAFE_SINGLETON_DECL_PTR(className) \ private:\ /* declare private constructors*/ \ /*className () {}*/\ className (const className &) {}\ /* the local static pointer to the singleton instance */ \ static className *_Instance; \ public:\ static className *getInstance() \ { \ if (_Instance == NULL) \ { \ /* the nel context MUST be initialised */ \ nlassertex(NLMISC::INelContext::isContextInitialised(), ("You are trying to access a safe singleton without having initialized a NeL context. The simplest correction is to add 'NLMISC::CApplicationContext myApplicationContext;' at the very beginning of your application.")); \ void *ptr = NLMISC::INelContext::getInstance().getSingletonPointer(#className); \ if (ptr == NULL) \ { \ /* allocate the singleton and register it */ \ _Instance = new className; \ NLMISC::INelContext::getInstance().setSingletonPointer(#className, _Instance); \ } \ else \ { \ _Instance = reinterpret_cast(ptr); \ } \ } \ return _Instance; \ } \ private: /** This macro is the complement of the previous one. * It must be put in a cpp file to implement the static * property of the singleton. */ #define NLMISC_SAFE_SINGLETON_IMPL(className) className *className::_Instance = NULL; /// Function type for library entry point typedef void (*TInitLibraryFunc)(INelContext &applicationContext); /** An helper macro to build the dll entry point easily. */ #define NLMISC_LIBRARY_ENTRY \ void libraryEntryImp(NLMISC::INelContext &applicationContext) \ { \ nlassert(!NLMISC::INelContext::isContextInitialised() || &applicationContext == &(NLMISC::INelContext::getInstance())); \ \ if (!NLMISC::INelContext::isContextInitialised()) \ { \ new CLibraryContext(applicationContext); \ } \ } \ extern "C" \ { \ NLMISC_LIB_EXPORT TInitLibraryFunc libraryEntry = libraryEntryImp; \ } \ class CLibrary; /// helper function to init newly loaded nel library void initNelLibrary(CLibrary &lib); } // namespace NLMISC #endif //APP_CONTEXT_H ================================================ FILE: code/nel/include/nel/misc/array_2d.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_ARRAY_2D_H #define NL_ARRAY_2D_H #include "nel/misc/rect.h" #include "nel/misc/stream.h" #include "nel/misc/traits_nl.h" namespace NLMISC { /** A simple 2D array. * * Access is done using the () operator * * Example : * * CArray2D myArray; * myArray.init(10, 10, 0); // fill with zero's * myArray(5, 5) = 1; * * \author Nicolas Vizerie * \author Nevrax France * \date 2005 */ template class CArray2D { public: typedef typename std::vector TArrayContainer; typedef typename TArrayContainer::iterator iterator; typedef typename TArrayContainer::const_iterator const_iterator; CArray2D() : _Width(0), _Height(0) {} void init(uint width, uint height); void init(uint width, uint height, const T &defaultValue); bool empty() const { return _Array.empty(); } void clear(); iterator begin() { return _Array.begin(); } iterator end() { return _Array.end(); } const_iterator begin() const { return _Array.begin(); } const_iterator end() const { return _Array.end(); } bool isIn(sint x, sint y) const { return x >= 0 && y >= 0 && x < (sint) _Width && y < (sint) _Height; } // access element by column/row T &operator()(uint x, uint y) { #ifdef NL_DEBUG nlassert(x < _Width); nlassert(y < _Height); #endif return _Array[x + y * _Width]; } // access element by column/row (const version) const T &operator()(uint x, uint y) const { #ifdef NL_DEBUG nlassert(x < _Width); nlassert(y < _Height); #endif return _Array[x + y * _Width]; } // Return width of array uint getWidth() const { return _Width; } // Return height of array uint getHeight() const { return _Height; } /** Move array content of the given offset. No wrapping is applied * Example : move(1, 0) will move the array of one column to the left. The latest column is lost. The first column remains unchanged */ void move(sint offsetX, sint offsetY); // Move a part of the array. Values are clamped as necessary void moveSubArray(sint dstX, sint dstY, sint srcX, sint srcY, sint width, sint height); // Blit content from another array void blit(const CArray2D &src, sint srcX, sint srcY, sint srcWidth, sint srcHeight, sint dstX, sint dstY); // get an iterator to the start of a row iterator beginRow(uint row) { nlassert(row < _Height); return _Array.begin() + row * _Width; } const_iterator beginRow(uint row) const { nlassert(row < _Height); return _Array.begin() + row * _Width; } iterator endRow(uint row) { nlassert(row < _Height); return _Array.begin() + (row + 1) * _Width; } const_iterator endRow(uint row) const { nlassert(row < _Height); return _Array.begin() + (row + 1) * _Width; } // get an iterator at the given position iterator getIteratorAt(uint x, uint y) { #ifdef NL_DEBUG nlassert(x < _Width); nlassert(y < _Height); #endif return _Array.begin() + x + (y * _Width); } // Get a const iterator at the given position const_iterator getIteratorAt(uint x, uint y) const { #ifdef NL_DEBUG nlassert(x < _Width); nlassert(y < _Height); #endif return _Array.begin() + x + (y * _Width); } /** See which part of array should be updated after its content has been displaced by the given offset (by a call to move for example). * Example: getUpdateRects(0, 1, result) will result the first row as a result */ void getUpdateRects(sint moveOffsetX, sint moveOffsetY, std::vector &rectsToUpdate); // See which parts of array will be discarded if the array is displaced by the given offset void getDiscardRects(sint moveOffsetX, sint moveOffsetY, std::vector &discardedRects); // void serial(NLMISC::IStream &f) throw(NLMISC::EStream); private: TArrayContainer _Array; uint _Width; uint _Height; private: inline void checkRect(const NLMISC::CRect &r) const { nlassert(r.X >= 0 && r.X < (sint32) _Width); nlassert(r.Y >= 0 && r.Y < (sint32) _Height); nlassert(r.X + r.Width >= 0 && r.X + (sint32) r.Width <= (sint32) _Width); nlassert(r.Y + r.Height >= 0 && r.Y + (sint32) r.Height <= (sint32) _Height); } }; //********************************************************************************* template void CArray2D::clear() { _Array.clear(); _Width = _Height = 0; } //********************************************************************************* template void CArray2D::serial(NLMISC::IStream &f) throw(NLMISC::EStream) { f.serialCont(_Array); uint32 width = _Width; uint32 height = _Height; f.serial(width); f.serial(height); _Width = width; _Height = height; } //********************************************************************************* template void CArray2D::getUpdateRects(sint moveOffsetX, sint moveOffsetY, std::vector &rectsToUpdate) { rectsToUpdate.clear(); if (moveOffsetX < 0) // moved right ? { // the width to update uint width = std::min((uint) moveOffsetX, _Width); // the grid moved top or bottom, exclude this part sint height = _Height - abs(moveOffsetY); if (height > 0) { // complete column on the right rectsToUpdate.push_back(NLMISC::CRect((sint32) (_Width - width), (sint32) (std::max(- moveOffsetY, 0)), (uint32) width, (uint32) height)); #ifdef NL_DEBUG checkRect(rectsToUpdate.back()); #endif } } else if (moveOffsetX > 0) // moved left ? { // the width to update uint width = std::min((uint) (- moveOffsetX), _Width); // the grid moved top or bottom. sint height = _Height - abs(moveOffsetY); if (height > 0) { // complete column on the right rectsToUpdate.push_back(NLMISC::CRect(0, (sint32) std::max(- moveOffsetY, 0), (uint32) width, (uint32) height)); #ifdef NL_DEBUG checkRect(rectsToUpdate.back()); #endif } } // update top or bottom part if (moveOffsetY < 0) { sint height = std::min((uint) moveOffsetY, _Height); rectsToUpdate.push_back(NLMISC::CRect(0, _Height - height, _Width, height)); #ifdef NL_DEBUG checkRect(rectsToUpdate.back()); #endif } else if (moveOffsetY > 0) { sint height = std::min((uint) (- moveOffsetY), _Height); rectsToUpdate.push_back(NLMISC::CRect(0, 0, _Width, height)); #ifdef NL_DEBUG checkRect(rectsToUpdate.back()); #endif } } //********************************************************************************* template void CArray2D::getDiscardRects(sint moveOffsetX, sint moveOffsetY,std::vector &discardedRects) { getUpdateRects(- moveOffsetX, - moveOffsetY, discardedRects); } //********************************************************************************* template void CArray2D::moveSubArray(sint dstX, sint dstY, sint srcX, sint srcY, sint width, sint height) { if (srcX >= (sint) getWidth()) return; if (srcY >= (sint) getHeight()) return; if (dstX >= (sint) getWidth()) return; if (dstY >= (sint) getHeight()) return; if (srcX < 0) { width += srcX; if (width <= 0) return; srcX = 0; } if (srcY < 0) { height += srcY; if (height <= 0) return; srcY = 0; } if (srcX + width > (sint) getWidth()) { width = getWidth() - srcX; } if (srcY + height > (sint) getHeight()) { height = getHeight() - srcY; } if (dstX < 0) { width += dstX; if (width < 0) return; srcX -= dstX; dstX = 0; } if (dstY < 0) { height += dstY; if (height < 0) return; srcY -= dstY; dstY = 0; } if (dstX + width > (sint) getWidth()) { width = getWidth() - dstX; } if (dstY + height > (sint) getHeight()) { height = getHeight() - dstY; } #ifdef NL_DEBUG nlassert(width > 0); nlassert(height > 0); nlassert(srcX >= 0 && srcX < (sint) getWidth()); nlassert(srcY >= 0 && srcY < (sint) getHeight()); #endif if (dstY < srcY) { const_iterator src = getIteratorAt(srcX, srcY); iterator dst = getIteratorAt(dstX, dstY); do { if (CTraits::SupportRawCopy) { // type support fast copy ::memcpy(&(*dst), &(*src), sizeof(T) * width); } else { std::copy(src, src + width, dst); } src += _Width; dst += _Width; } while(--height); } else if (dstY > srcY) { // copy from top to bottom const_iterator src = getIteratorAt(srcX, srcY + height - 1); iterator dst = getIteratorAt(dstX, dstY + height - 1); do { if (CTraits::SupportRawCopy) { // type support fast copy ::memcpy(&(*dst), &(*src), sizeof(T) * width); } else { std::copy(src, src + width, dst); } src -= _Width; dst -= _Width; } while(--height); } else { const_iterator src = getIteratorAt(srcX, srcY); iterator dst = getIteratorAt(dstX, dstY); if (dstX < srcX) { do { if (CTraits::SupportRawCopy) { // type support fast copy ::memmove(&(*dst), &(*src), sizeof(T) * width); } else { std::reverse_copy(src, src + width, dst); } src += _Width; dst += _Width; } while(--height); } else { do { if (CTraits::SupportRawCopy) { // type support fast copy ::memcpy(&(*dst), &(*src), sizeof(T) * width); } else { std::copy(src, src + width, dst); } src += _Width; dst += _Width; } while(--height); } } } //********************************************************************************* template void CArray2D::blit(const CArray2D &src, sint srcX, sint srcY, sint srcWidth, sint srcHeight, sint dstX, sint dstY) { if (&src == this) { moveSubArray(dstX, dstY, srcX, srcY, srcWidth, srcHeight); return; } // clip x if (srcX < 0) { srcWidth += srcX; if (srcWidth <= 0) return; dstX -= srcX; srcX = 0; } if (srcX + srcWidth > (sint) src.getWidth()) { srcWidth = src.getWidth() - srcX; if (srcWidth <= 0) return; } if (dstX < 0) { srcWidth += dstX; if (srcWidth <= 0) return; srcX -= dstX; dstX = 0; } if (dstX + srcWidth > (sint) getWidth()) { srcWidth = getWidth() - dstX; if (srcWidth <= 0) return; } // clip y if (srcY < 0) { srcHeight += srcY; if (srcHeight <= 0) return; dstY -= srcY; srcY = 0; } if (srcY + srcHeight > (sint) src.getHeight()) { srcHeight = src.getHeight() - srcY; if (srcHeight <= 0) return; } if (dstY < 0) { srcHeight += dstY; if (srcHeight <= 0) return; srcY -= dstY; dstY = 0; } if (dstY + srcHeight > (sint) getHeight()) { srcHeight = getHeight() - dstY; if (srcHeight <= 0) return; } const T *srcBase = (const T *) &src._Array[0]; const T *srcPtr = &(srcBase[srcX + srcY * src.getWidth()]); const T *srcEndPtr = srcPtr + srcHeight * src.getWidth(); T *destBase = (T *) &_Array[0]; T *destPtr = &(destBase[dstX + dstY * getWidth()]); while (srcPtr != srcEndPtr) { if (CTraits::SupportRawCopy) { memcpy(destPtr, srcPtr, sizeof(T) * srcWidth); } else { std::copy(srcPtr, srcPtr + srcWidth, destPtr); } srcPtr += src.getWidth(); destPtr += getWidth(); } } //********************************************************************************* template void CArray2D::move(sint offsetX, sint offsetY) { moveSubArray(offsetX, offsetY, 0, 0, _Width, _Height); } //********************************************************************************* template void CArray2D::init(uint width, uint height) { _Array.resize(width * height); _Width = width; _Height = height; } //********************************************************************************* template void CArray2D::init(uint width,uint height, const T &defaultValue) { _Array.resize(width * height, defaultValue); _Width = width; _Height = height; } } // NLMISC #endif ================================================ FILE: code/nel/include/nel/misc/async_file_manager.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_ASYNC_FILE_MANAGER_H #define NL_ASYNC_FILE_MANAGER_H #include "types_nl.h" #include "task_manager.h" namespace NLMISC { /** * CAsyncFileManager is a class that manage file loading in a seperate thread * \author Matthieu Besson * \author Nevrax France * \date 2002 */ class CAsyncFileManager : public CTaskManager { NLMISC_SAFE_SINGLETON_DECL(CAsyncFileManager); CAsyncFileManager() {} public: // Must be called instead of constructing the object // static CAsyncFileManager &getInstance (); // NB: release the singleton, but assert if there is any pending loading tasks. // Each system that use the async file manager should ensure it has no more pending task in it static void terminate (); // Do not use these methods with the bigfile manager void loadFile (const std::string &fileName, uint8 **pPtr); void loadFiles (const std::vector &vFileNames, const std::vector &vPtrs); void signal (bool *pSgn); // Signal a end of loading for a group of "mesh or file" added void cancelSignal (bool *pSgn); /** * CCancelCallback is an interface that is used in call to CAsyncFileManager::cancelLoad. * This class contains one method that is called for each task in the async file loader. * If the method returns true, then the task is removed and cancelLoad return. * \author Boris Boucher * \author Nevrax France * \date 10/2002 */ class ICancelCallback { public: virtual ~ICancelCallback() {} virtual bool callback(const IRunnable *prunnable) const =0; }; /// Add a load task in the CAsyncFileManager task list. void addLoadTask(IRunnable *ploadTask); /** Call this method to cancel a programmed load. * \return False if the task either already ended or running. */ bool cancelLoadTask(const ICancelCallback &cancelCallBack); private: // CAsyncFileManager (); // Singleton mode -> access it with the getInstance function // static CAsyncFileManager *_Singleton; // All the tasks // ------------- // Load a file class CFileLoad : public IRunnable { std::string _FileName; uint8 **_ppFile; public: CFileLoad (const std::string& sFileName, uint8 **ppFile); void run (void); void getName (std::string &result) const; }; // Load multiple files class CMultipleFileLoad : public IRunnable { std::vector _FileNames; std::vector _Ptrs; public: CMultipleFileLoad (const std::vector &vFileNames, const std::vector &vPtrs); void run (void); void getName (std::string &result) const; }; // Signal class CSignal : public IRunnable { public: bool *Sgn; public: CSignal (bool *pSgn); void run (void); void getName (std::string &result) const; }; }; } // NLMISC #endif // NL_ASYNC_FILE_MANAGER_H /* End of async_file_manager.h */ ================================================ FILE: code/nel/include/nel/misc/base64.h ================================================ #ifndef NL_BASE64_H #define NL_BASE64_H #include "types_nl.h" #include namespace NLMISC { std::string base64_encode( std::string const& ); std::string base64_decode( std::string const& ); }; // namespace NLMISC #endif // NL_BASE64_H /* End of base64.h */ ================================================ FILE: code/nel/include/nel/misc/big_file.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BIG_FILE_H #define NL_BIG_FILE_H #include "types_nl.h" #include "tds.h" #include "singleton.h" namespace NLMISC { /** * Big file management * \author Matthieu Besson * \author Nevrax France * \date 2002 */ const uint32 BF_ALWAYS_OPENED = 0x00000001; const uint32 BF_CACHE_FILE_ON_OPEN = 0x00000002; // *************************************************************************** class CBigFile { NLMISC_SAFE_SINGLETON_DECL(CBigFile); CBigFile() {} ~CBigFile() {} public: // release memory static void releaseInstance(); // Retrieve the global instance // static CBigFile &getInstance (); // Add a big file to the manager bool add (const std::string &sBigFileName, uint32 nOptions); // get path of all added bigfiles void getBigFilePaths(std::vector &bigFilePaths); // Remove a big file from the manager void remove (const std::string &sBigFileName); // true if a bigFile is added bool isBigFileAdded(const std::string &sBigFileName) const; // return name of Big File std::string getBigFileName(const std::string &sBigFileName) const; // List all files in a bigfile void list (const std::string &sBigFileName, std::vector &vAllFiles); // Remove all big files added void removeAll (); /** Signal that the current thread has ended : all file handles "permanently" allocated for that thread * can be released then, preventing them from accumulating. */ void currentThreadFinished(); // Used by CIFile to get information about the files within the big file FILE* getFile (const std::string &sFileName, uint32 &rFileSize, uint32 &rBigFileOffset, bool &rCacheFileOnOpen, bool &rAlwaysOpened); // Used by Sound to get information for async loading of mp3 in .bnp. Return false if file not found in registered bnps bool getFileInfo (const std::string &sFileName, uint32 &rFileSize, uint32 &rBigFileOffset); // Used for CPath only for the moment ! char *getFileNamePtr(const std::string &sFileName, const std::string &sBigFileName); // *************** private: class CThreadFileArray; friend class CThreadFileArray; // A ptr to a file. struct CHandleFile { FILE *File; CHandleFile() : File(NULL) { } }; // A class which return a FILE * handle per Thread. class CThreadFileArray { public: CThreadFileArray(); // Allocate a FileId for a BNP. uint32 allocate(); // Given a BNP File Id, return its FILE* handle for the current thread. CHandleFile &get(uint32 index); void currentThreadFinished(); private: // Do it this way because a few limited TDS is possible (64 on NT4) CTDS _TDS; // The array is grow only!! uint32 _CurrentId; }; // A BNPFile header struct BNPFile { BNPFile() : Name(NULL), Size(0), Pos(0) { } char *Name; uint32 Size; uint32 Pos; }; struct CBNPFileComp { bool operator()(const BNPFile &f, const BNPFile &s ) { return strcmp( f.Name, s.Name ) < 0; } }; // A BNP structure struct BNP { BNP() : FileNames(NULL) { } // FileName of the BNP. important to open it in getFile() (for other threads or if not always opened). std::string BigFileName; // map of files in the BNP. char *FileNames; std::vector Files; // Since many seek may be done on a FILE*, each thread should have its own FILE opened. uint32 ThreadFileId; bool CacheFileOnOpen; bool AlwaysOpened; }; private: // CBigFile(); // Singleton mode -> access it with the getInstance function // static CBigFile *_Singleton; // This is an array of CHandleFile, unique to each thread CThreadFileArray _ThreadFileArray; std::map _BNPs; // common for getFile and getFileInfo bool getFileInternal (const std::string &sFileName, BNP *&zeBnp, BNPFile *&zeBnpFile); }; } // NLMISC #endif // NL_BIG_FILE_H /* End of big_file.h */ ================================================ FILE: code/nel/include/nel/misc/bit_mem_stream.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BIT_MEM_STREAM_H #define NL_BIT_MEM_STREAM_H #include "types_nl.h" #include "mem_stream.h" namespace NLMISC { /* In debugging stage, should be defined. In stable stage, undefine it! * Works along with the verboseAllTraffic command */ #ifndef NL_NO_DEBUG # ifdef NL_OS_WINDOWS # define LOG_ALL_TRAFFIC # else # undef LOG_ALL_TRAFFIC # endif #endif #ifdef LOG_ALL_TRAFFIC extern bool VerboseAllTraffic; #define serialAndLog1( v ) \ _serialAndLog( #v, v ); #define serialAndLog2( v, s ) \ _serialAndLog( #v, v, s ); #define serialBitAndLog( v ) \ _serialBitAndLog( #v, v ); #define serialAdaptAndLog( argstr, b, type ) \ uint32 ub=0; \ if ( isReading() ) \ { \ _serialAndLog( argstr, ub, sizeof(type)*8 ); \ b = (type)ub; \ } \ else \ { \ ub = (uint32)b; \ _serialAndLog( argstr, ub, sizeof(type)*8 ); \ } #ifdef NL_LITTLE_ENDIAN #define serialAdapt64AndLog( argstr, b ) \ _serialAndLog( argstr, *((uint32*)(&b)), 32 ); \ _serialAndLog( argstr, *((uint32*)(&b)+1), 32 ); #else #define serialAdapt64AndLog( argstr, b ) \ serialAndLog( argstr, *((uint32*)(&b)+1), 32); \ serialAndLog( argstr, *((uint32*)(&b)), 32); #endif #else #define serialAndLog1 serial #define serialAndLog2 serial #define serialBitAndLog serialBit #endif #define serialAdapt( b, type ) \ uint32 ub=0; \ if ( isReading() ) \ { \ serial( ub, sizeof(type)*8 ); \ b = (type)ub; \ } \ else \ { \ ub = (uint32)b; \ serial( ub, sizeof(type)*8 ); \ } #ifdef NL_LITTLE_ENDIAN #define serialAdapt64( b ) \ serial( *((uint32*)(&b)), 32); \ serial( *((uint32*)(&b)+1), 32); #else #define serialAdapt64( b ) \ serial( *((uint32*)(&b)+1), 32); \ serial( *((uint32*)(&b)), 32); #endif class CBitSet; /* * Item of CBMSDbgInfo */ struct TBMSSerialInfo { enum TSerialType { B, U, U64, F, BF, Buffer, NbSerialTypes }; TBMSSerialInfo( uint32 bitpos, uint32 bitsize, TSerialType type, const char *symbol ) { nlassert( bitpos < 800000 ); BitPos = bitpos; BitSize = bitsize; Type = type; Symbol = symbol; } uint32 BitPos; uint32 BitSize; TSerialType Type; const char *Symbol; }; extern const char * SerialTypeToCStr [ TBMSSerialInfo::NbSerialTypes ]; typedef std::vector< TBMSSerialInfo > TBMSSerialInfoList; /* * Data members struct for CBMSDbgInfo */ struct TBMSDbgInfoData { /// Constructor TBMSDbgInfoData() : List(), CurrentBrowsedItem(0), NextSymbol(NULL), AddEventIsEnabled(true) {} /// Vector of serial items TBMSSerialInfoList List; /// Current browsed item in the list (valid only from beginEventBrowsing() until clear() or addSerial()/addPoke()) uint32 CurrentBrowsedItem; /// Symbol of next event const char *NextSymbol; /// Flag to enable/disable addSerial() and addPoke() (because CBitMemStream::getSerialItem() must not add events in the list) bool AddEventIsEnabled; }; class CBitMemStream; /* * Debug details about what was serialised (sizeof is only one pointer if not explicitely initialised) */ class CBMSDbgInfo { public: #ifdef NL_DEBUG /// Constructor CBMSDbgInfo() : _DbgData(NULL) { init(); } #else /// Constructor CBMSDbgInfo() {} #endif #ifdef NL_DEBUG /// Copy constructor CBMSDbgInfo( const CBMSDbgInfo& src ) : _DbgData(NULL) { init(); operator=( src ); } /// Operator= CBMSDbgInfo& operator=( const CBMSDbgInfo& src ) { *_DbgData = *src._DbgData; return *this; } /// Destructor ~CBMSDbgInfo() { delete _DbgData; _DbgData = NULL; } #endif void swap(CBMSDbgInfo &other) { #ifdef NL_DEBUG std::swap(_DbgData, other._DbgData); #else nlunreferenced(other); #endif } /// Add a serial event at the end void addSerial( uint32 bitpos, uint32 size, TBMSSerialInfo::TSerialType type ) { #ifdef NL_DEBUG if ( ! _DbgData->AddEventIsEnabled ) { _DbgData->NextSymbol = NULL; return; } TBMSSerialInfo serialItem( bitpos, size, type, _DbgData->NextSymbol ); _DbgData->List.push_back( serialItem ); _DbgData->NextSymbol = NULL; #else nlunreferenced(bitpos); nlunreferenced(size); nlunreferenced(type); #endif } /// Add a serial event in the middle void addPoke( uint32 bitpos, uint32 size, TBMSSerialInfo::TSerialType type ) { #ifdef NL_DEBUG if ( ! _DbgData->AddEventIsEnabled ) { _DbgData->NextSymbol = NULL; return; } TBMSSerialInfo serialItem( bitpos, size, type, _DbgData->NextSymbol ); /// Find where to add it bool found = false; TBMSSerialInfoList::iterator itl; for ( itl=_DbgData->List.begin(); itl!=_DbgData->List.end(); ++itl ) { if ( (*itl).BitPos == bitpos ) { // Found, replace reserved by poked (*itl) = serialItem; found = true; break; } } if ( ! found ) { nlwarning( "Missing reserve() corresponding to poke()" ); } _DbgData->NextSymbol = NULL; #else nlunreferenced(bitpos); nlunreferenced(size); nlunreferenced(type); #endif } /// Set the symbol for the next event that will be added (optional) void setSymbolOfNextSerialEvent( const char *symbol ) { #ifdef NL_DEBUG _DbgData->NextSymbol = symbol; #else nlunreferenced(symbol); #endif } /// Clear void clear() { #ifdef NL_DEBUG _DbgData->List.clear(); #endif } /// Begin a browsing session of serial events, addSerial()/addPoke() is now disabled void beginEventBrowsing() { #ifdef NL_DEBUG _DbgData->CurrentBrowsedItem = 0; _DbgData->AddEventIsEnabled = false; #endif } /// End a browsing session of serial events, and reenable addSerial()/addPoke() void endEventBrowsing() { #ifdef NL_DEBUG _DbgData->AddEventIsEnabled = true; #endif } /// Return an eventId of serial event, or "" (and eventId -1) if nothing found at the specified bitpos std::string getEventIdAtBitPos( uint32 bitpos, sint32 *eventId ) { #ifdef NL_DEBUG if ( _DbgData->CurrentBrowsedItem < _DbgData->List.size() ) { if ( bitpos == _DbgData->List[_DbgData->CurrentBrowsedItem].BitPos ) // works only with a vector! { *eventId = (sint32)_DbgData->CurrentBrowsedItem; ++_DbgData->CurrentBrowsedItem; return toString( "(%u)", _DbgData->CurrentBrowsedItem - 1 ); } //nlassert( bitpos < (*_List)[_CurrentBrowsedItem].BitPos ); // occurs if stream overflow } #else nlunreferenced(bitpos); #endif *eventId = -1; return std::string(); } /// Return full info about a serial event, or "" if eventId is -1 std::string getEventLegendAtBitPos( CBitMemStream& bms, sint32 eventId ); private: #ifdef NL_DEBUG /// Explicit init void init() { _DbgData = new TBMSDbgInfoData(); } /// List of serials TBMSDbgInfoData *_DbgData; #endif }; /** * Bit-oriented memory stream * * How output mode works: * In CMemStream, _BufPos points to the end of the stream, where to write new data. * In CBitMemStream, _BufPos points to the last byte of the stream, where to write new data. * Then _FreeBits tells the number of bits not used in this byte (i.e. (8-_FreeBits) is the * number of bits already filled inside this byte). * The minimum buffer size is 1: when nothing has been written yet, the position is at beginning * and _FreeBits is 8. * * How input mode works: * Same as in CMemStream, but some bits may be free in the last byte (the information about * how many is not stored in the CBitMemStream object, the reader needs to know the format of * the data it reads). * * \author Olivier Cado * \author Nevrax France * \date 2001, 2003 */ class CBitMemStream : public CMemStream { public: /// Constructor CBitMemStream( bool inputStream=false, uint32 defaultcapacity=32 ); /// Copy constructor CBitMemStream( const CBitMemStream& other ); /// Assignment operator CBitMemStream& operator=( const CBitMemStream& other ) { CMemStream::operator=( other ); _FreeBits = other._FreeBits; _DbgInfo = other._DbgInfo; return *this; } // Echange status and memory data void swap(CBitMemStream &other); /** * Set the position at the beginning. In output mode, the method ensures the buffer * contains at least one blank byte to write to. * * If you are using the stream only in output mode, you can use this method as a faster version * of clear() *if you don't serialize pointers*. */ virtual void resetBufPos() { // This is ensured in CMemStream::CMemStream() and CMemStream::clear() //if ( (!isReading()) && _Buffer.empty() ) /// _Buffer.resize( 8 ); // at least 8 bytes nlassert( ! ((!isReading()) && _Buffer.getBuffer().empty()) ); CMemStream::resetBufPos(); if ( !isReading() ) // *_BufPos = 0; // partial prepareNextByte() *(_Buffer.getBufferWrite().getPtr()+_Buffer.Pos) = 0; _FreeBits = 8; _DbgInfo.clear(); } /** Returns the length (size) of the message, in bytes. * If isReading(), it is the number of bytes that can be read, * otherwise it is the number of bytes that have been written * (the last byte may not be full, it may have free bits, see * also getPosInBit()). */ virtual uint32 length() const { if ( isReading() ) { return lengthR(); } else { if ( _FreeBits == 8 ) return lengthS(); else return lengthS() + 1; } } /// Transforms the message from input to output or from output to input virtual void invert() { if ( ! isReading() ) { // ++_BufPos; // write->read: extend to keep the last byte inside the payload ++_Buffer.Pos; // write->read: extend to keep the last byte inside the payload } CMemStream::invert(); if ( ! isReading() ) { #ifdef NL_DEBUG // nlassert( _BufPos == _Buffer.getPtr()+_Buffer.size() ); nlassert( _Buffer.Pos == _Buffer.getBuffer().size() ); #endif // --_BufPos; // read->write: set the position on the last byte, not at the end as in CMemStream::invert() --(_Buffer.Pos); // read->write: set the position on the last byte, not at the end as in CMemStream::invert() } // Keep the same _FreeBits } /// Clears the message virtual void clear() { CMemStream::clear(); resetBufPos(); } /// Returns the number of bit from the beginning of the buffer (in bit) sint32 getPosInBit() const { // return (_BufPos - _Buffer.getPtr() + 1)*8 - _FreeBits; return (_Buffer.Pos + 1)*8 - _FreeBits; } /// Returns the stream as a string with 0 and 1. void displayStream( const char *title="", CLog *log = NLMISC::DebugLog ); /// See doc in CMemStream::fill() void fill( const uint8 *srcbuf, uint32 len ) { _FreeBits = 8; _DbgInfo.clear(); CMemStream::fill( srcbuf, len ); } /// See doc in CMemStream::bufferToFill() virtual uint8 *bufferToFill( uint32 msgsize ) { _FreeBits = 8; _DbgInfo.clear(); return CMemStream::bufferToFill( msgsize ); } /// Append the contents of a bitmemstream at the end of our bitmemstream (precondition: !isReading()) void append( const CBitMemStream& newBits ); /// Serialize a buffer virtual void serialBuffer(uint8 *buf, uint len); /// Serialize one bit virtual void serialBit( bool& bit ); #ifdef LOG_ALL_TRAFFIC void _serialAndLog( const char *argstr, uint32& value, uint nbits ); void _serialAndLog( const char *argstr, uint64& value, uint nbits ); void _serialBitAndLog( const char *argstr, bool& bit ); #endif /** * Serialize only the nbits lower bits of value (nbits range: [1..32]) * When using this method, always leave resetvalue to true. */ void serial( uint32& value, uint nbits, bool resetvalue=true ) { _DbgInfo.addSerial( getPosInBit(), nbits, TBMSSerialInfo::U ); internalSerial( value, nbits, resetvalue ); } /** * Serialize only the nbits lower bits of 64-bit value (nbits range: [1..64]) */ void serial( uint64& value, uint nbits ) { _DbgInfo.addSerial( getPosInBit(), nbits, TBMSSerialInfo::U64 ); internalSerial( value, nbits ); } /** * Same as CMemStream::reserve(). Warning, the return value is a byte pos (not bitpos)! * Consider using reserveBits() instead. */ sint32 reserve( uint byteLen ); /** * In a output bit stream, serialize nbits bits (no matter their value). * Works even if the number of bits to add is larger than 64. See also poke() and pokeBits(). */ void reserveBits( uint nbits ); /* * Rewrite the nbbits lowest bits of a value at the specified position bitpos of the current output bit stream. * * Preconditions: * - bitpos+nbbits <= the current length in bit of the stream. * - The bits poked must have been reserved by reserveBits() (i.e. set to 0) */ void poke( uint32 value, uint bitpos, uint nbits ); /** * Rewrite the bitfield at the specified position bitpos of the current output bit stream. * The size of the bitfield is *not* written into the stream (unlike serialCont()). * Precondition: bitpos+bitfield.size() <= the current length in bit of the stream. See also reserveBits(). */ void pokeBits( const NLMISC::CBitSet& bitfield, uint bitpos ); /** * Read bitfield.size() bits from the input stream to fill the bitfield. * It means you have to know the size and to resize the bitfield yourself. */ void readBits( NLMISC::CBitSet& bitfield ); /// Display the bits of the stream just before the specified bitpos (or current pos if -1) void displayLastBits( sint nbits, sint bitpos=-1, NLMISC::CLog *log=NLMISC::DebugLog ); /// Return a string showing the serial item std::string getSerialItem( const TBMSSerialInfo& serialItem ); /// Template serialisation (should take the one from IStream) template void serial(T &obj) { obj.serial(*this); } // CMemStream::serialCont() will call CBitMemStream's virtual serialBuffer() template void serialCont(std::vector &cont) {CMemStream::serialCont(cont);} template void serialCont(std::list &cont) {CMemStream::serialCont(cont);} template void serialCont(std::deque &cont) {CMemStream::serialCont(cont);} template void serialCont(std::set &cont) {CMemStream::serialCont(cont);} template void serialCont(std::multiset &cont) {CMemStream::serialCont(cont);} template void serialCont(std::map &cont) {CMemStream::serialCont(cont);} template void serialCont(std::multimap &cont) {CMemStream::serialCont(cont);} /*template void serial(T0 &a, T1 &b) { serial(a); serial(b);} template void serial(T0 &a, T1 &b, T2 &c) { serial(a); serial(b); serial(c);} template void serial(T0 &a, T1 &b, T2 &c, T3 &d) { serial(a); serial(b); serial(c); serial(d);} template void serial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e) { serial(a); serial(b); serial(c); serial(d); serial(e);} template void serial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e, T5 &f) { serial(a); serial(b); serial(c); serial(d); serial(e); serial(f);}*/ /** \name Base type serialisation. * Those method are a specialisation of template method "void serial(T&)". */ //@{ /* #define serialAdapt64( b, type ) \ uint32 ubl=0, ubh=0; \ if ( isReading() ) \ { \ serial( ubh, sizeof(uint32)*8 ); \ serial( ubl, sizeof(uint32)*8 ); \ b = (((type)ubh)<<32)+ubl; \ } \ else \ { \ ubh = (uint32)(b>>32); \ ubl = (uint32)(b); \ serial( ubh, sizeof(uint32)*8 ); \ serial( ubl, sizeof(uint32)*8 ); \ } */ #ifdef LOG_ALL_TRAFFIC void _serialAndLog(const char *argstr, uint8 &b) { serialAdaptAndLog( argstr, b, uint8 ); } void _serialAndLog(const char *argstr, sint8 &b) { serialAdaptAndLog( argstr, b, sint8 ); } void _serialAndLog(const char *argstr, uint16 &b) { serialAdaptAndLog( argstr, b, uint16 ); } void _serialAndLog(const char *argstr, sint16 &b) { serialAdaptAndLog( argstr, b, sint16 ); } void _serialAndLog(const char *argstr, uint32 &b) { serialAdaptAndLog( argstr, b, uint32 ); } void _serialAndLog(const char *argstr, sint32 &b) { serialAdaptAndLog( argstr, b, sint32 ); } void _serialAndLog(const char *argstr, uint64 &b) { serialAdapt64AndLog( argstr, b ); } void _serialAndLog(const char *argstr, sint64 &b) { serialAdapt64AndLog( argstr, b ); } void _serialAndLog(const char *argstr, float &b); void _serialAndLog(const char *argstr, double &b) { serialAdapt64AndLog( argstr, b ); } void _serialAndLog(const char *argstr, bool &b) { _serialBitAndLog( argstr, b ); } #ifndef NL_OS_CYGWIN virtual void _serialAndLog(const char *argstr, char &b) { serialAdaptAndLog( argstr, b, char ); } #endif #endif virtual void serial(uint8 &b) { serialAdapt( b, uint8 ); } virtual void serial(sint8 &b) { serialAdapt( b, sint8 ); } virtual void serial(uint16 &b) { serialAdapt( b, uint16 ); } virtual void serial(sint16 &b) { serialAdapt( b, sint16 ); } virtual void serial(uint32 &b) { serialAdapt( b, uint32 ); } virtual void serial(sint32 &b) { serialAdapt( b, sint32 ); } virtual void serial(uint64 &b) { serialAdapt64( b ); } virtual void serial(sint64 &b) { serialAdapt64( b ); } virtual void serial(float &b); virtual void serial(double &b) { serialAdapt64( b ); } virtual void serial(bool &b) { serialBit( b ); } #ifndef NL_OS_CYGWIN virtual void serial(char &b) { serialAdapt( b, char ); } #endif virtual void serial(std::string &b); virtual void serial(ucstring &b); virtual void serial(CBitMemStream &b) { serialMemStream(b); } virtual void serialMemStream(CMemStream &b); //@} /// Specialisation of serialCont() for vector virtual void serialCont(std::vector &cont) { serialVector(cont); } /// Specialisation of serialCont() for vector virtual void serialCont(std::vector &cont) { serialVector(cont); } /// Specialisation of serialCont() for vector virtual void serialCont(std::vector &cont); protected: /** * Helper for serial(uint32,uint) */ void internalSerial( uint32& value, uint nbits, bool resetvalue=true ); /** * Helper for serial(uint64,uint) */ void internalSerial( uint64& value, uint nbits ) { if ( nbits > 32 ) { if ( isReading() ) { // Reset and read MSD uint32 msd = 0; internalSerial( msd, nbits-32 ); value = (uint64)msd << 32; // Reset and read LSD internalSerial( (uint32&)value, 32 ); } else { // Write MSD uint32 msd = (uint32)(value >> 32); internalSerial( msd, nbits-32 ); // Write LSD internalSerial( (uint32&)value, 32 ); } } else { if ( isReading() ) { // Reset MSB (=0 is faster than value&=0xFFFFFFFF) value = 0; } // Read or write LSB internalSerial( (uint32&)value, nbits ); } } /** * Prepare next byte for writing. * * Preconditions: * - See the preconditions of increaseBufferIfNecessary() and pointNextByte() * * Postconditions: * - See the postconditions of increaseBufferIfNecessary() and pointNextByte() * - The new pointed byte is 0 */ void prepareNextByte() { pointNextByte(); increaseBufferIfNecessary(); // *_BufPos = 0; *(_Buffer.getBufferWrite().getPtr() + _Buffer.Pos) = 0; } /** * Point the beginning of the byte after _BufPos * * Preconditions * - The last written byte, at pos _BufPos, is fully written (but _FreeBits may not be updated yet) * * Postconditions * - The pos was incremented by 1, _FreeBits is 8 */ void pointNextByte() { #ifdef NL_DEBUG nlassert( !isReading() ); #endif _FreeBits = 8; // ++_BufPos; ++_Buffer.Pos; } /** * Increase the size of the buffer if necessary (outpout bit stream) * * Preconditions: * - The stream is in output mode (!isReading()) * - resetBufPos() must have been called since construction * - getPos() <= _Buffer.size() * * Postconditions: * - getPos() < _Buffer.size() */ void increaseBufferIfNecessary() { #ifdef NL_DEBUG // nlassert( (!isReading()) && (!_Buffer.empty()) ); nlassert( (!isReading()) && (!_Buffer.getBuffer().empty()) ); // nlassert( _BufPos <= _Buffer.getPtr() + _Buffer.size() ); nlassert( _Buffer.Pos <= _Buffer.getBuffer().size() ); #endif // uint32 bytepos = _BufPos - _Buffer.getPtr(); // uint32 bytepos = _BufPos; // if ( bytepos == _Buffer.size() ) if ( _Buffer.Pos == _Buffer.getBuffer().size() ) { // _Buffer.resize( bytepos * 2 ); _Buffer.getBufferWrite().resize( _Buffer.Pos * 2 ); // _BufPos = _Buffer.getPtr() + bytepos; // don't change the pos but update pointer (needed because the buffer may have moved when reallocating) } } /** * Helper for poke(), to write a value inside an output stream (works because reserveBits sets to 0) * Warning: if _FreeBits == 8, increments _BufPos. */ void serialPoke( uint32 value, uint nbits ); /// Number of bits unused at the current pos. If 8, means the current pos if full and we need to increment the pos! uint _FreeBits; // From 8 downto 1 /// Debug details about what was serialised CBMSDbgInfo _DbgInfo; }; /// Display a part of a bitmemstream void displayBitStream( const CBitMemStream& msg, sint beginbitpos, sint endbitpos, NLMISC::CLog *log=NLMISC::DebugLog ); /* * Return full info about a serial event, or "" if eventId is -1 */ inline std::string CBMSDbgInfo::getEventLegendAtBitPos( CBitMemStream& bms, sint32 eventId ) { #ifdef NL_DEBUG if ( eventId != -1 ) { nlassert( eventId < (sint32)_DbgData->List.size() ); TBMSSerialInfo& serialItem = _DbgData->List[eventId]; // works only with a vector! return toString( "(%d) BitPos %3u Type %s BitSize %2u Value %s %s\n", eventId, serialItem.BitPos, SerialTypeToCStr[serialItem.Type], serialItem.BitSize, bms.getSerialItem( serialItem ).c_str(), (serialItem.Symbol!=NULL)?serialItem.Symbol:"" ); } #else nlunreferenced(bms); nlunreferenced(eventId); #endif return std::string(); } } // NLMISC #endif // NL_BIT_MEM_STREAM_H /* End of bit_mem_stream.h */ ================================================ FILE: code/nel/include/nel/misc/bit_set.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BIT_SET_H #define NL_BIT_SET_H #include "types_nl.h" #include "stream.h" namespace NLMISC { // Size in bit of base word. #define NL_BITLEN (4*8) #define NL_BITLEN_SHIFT 5 // *************************************************************************** /** * A BitSet, to test / set flags quickly. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CBitSet { public: /* *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * ***********************************************/ /// \name Object. //@{ CBitSet(); CBitSet(uint numBits); CBitSet(const CBitSet &bs); ~CBitSet(); CBitSet &operator=(const CBitSet &bs); //@} /// \name Basics. //@{ /// Resize the bit array. All Bits are reseted. void resize (uint numBits); /// Resize the bit array. Bits are not reseted. New bits are set with value. void resizeNoReset (uint numBits, bool value=false); /// Clear the bitarray so size() return 0. void clear(); /// Return size of the bit array. uint size() const { return NumBits; } /// Set a bit to 0 or 1. void set(sint bitNumber, bool value) { nlassert(bitNumber>=0 && bitNumber> NL_BITLEN_SHIFT]|= mask ; else Array[bitNumber >> NL_BITLEN_SHIFT]&= ~mask; } /// Get the value of a bit. bool get(sint bitNumber) const { nlassert(bitNumber>=0 && bitNumber> NL_BITLEN_SHIFT] & mask) != 0; } /// Get the value of a bit. bool operator[](sint bitNumber) const { return get(bitNumber); } /// Set a bit to 1. void set(sint bitNumber) {set(bitNumber, true);} /// Set a bit to 0. void clear(sint bitNumber) {set(bitNumber, false);} /// Set all bits to 1. void setAll(); /// Set all bits to 0. void clearAll(); //@} /// \name Bit operations. //@{ /// Return The bitarray NOTed. CBitSet operator~() const; /** * Return this ANDed with bs. * The result BitSet is of size of \c *this. Any missing bits into bs will be considered as 0. */ CBitSet operator&(const CBitSet &bs) const; /** * Return this ORed with bs. * The result BitSet is of size of \c *this. Any missing bits into bs will be considered as 0. */ CBitSet operator|(const CBitSet &bs) const; /** * Return this XORed with bs. * The result BitSet is of size of \c *this. Any missing bits into bs will be considered as 0. */ CBitSet operator^(const CBitSet &bs) const; /// NOT the BitArray. void flip(); /** * AND the bitArray with bs. * The bitset size is not changed. Any missing bits into bs will be considered as 0. */ CBitSet &operator&=(const CBitSet &bs); /** * OR the bitArray with bs. * The bitset size is not changed. Any missing bits into bs will be considered as 0. */ CBitSet &operator|=(const CBitSet &bs); /** * XOR the bitArray with bs. * The bitset size is not changed. Any missing bits into bs will be considered as 0. */ CBitSet &operator^=(const CBitSet &bs); //@} /// \name Bit comparisons. //@{ /** * Compare two BitSet not necessarely of same size. The comparison is done on N bits, where N=min(this->size(), bs.size()) * \return true if the N common bits of this and bs are the same. false otherwise. */ bool compareRestrict(const CBitSet &bs) const; /// Compare two BitSet. If not of same size, return false. bool operator==(const CBitSet &bs) const; /// operator!=. bool operator!=(const CBitSet &bs) const; /// Return true if all bits are set. false if size()==0. bool allSet(); /// Return true if all bits are cleared. false if size()==0. bool allCleared(); //@} /// Serialize void serial(NLMISC::IStream &f); /// Return the raw vector const std::vector& getVector() const { return Array; } /// Write an uint32 into the bit set (use with caution, no check) void setUint( uint32 srcValue, uint i ) { Array[i] = srcValue; } /// Return a string representing the bitfield with 1 and 0 (from left to right) std::string toString() const; private: std::vector Array; sint NumBits; uint32 MaskLast; // Mask for the last uint32. }; } #endif // NL_BIT_SET_H /* End of bit_set.h */ ================================================ FILE: code/nel/include/nel/misc/bitmap.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BITMAP_H #define NL_BITMAP_H #include "types_nl.h" #include "rgba.h" #include "debug.h" #include #include "object_vector.h" namespace NLMISC { class IStream; //------------------ DDS STUFFS -------------------- #ifndef NL_MAKEFOURCC #define NL_MAKEFOURCC(ch0, ch1, ch2, ch3) \ ((uint32)(uint8)(ch0) | ((uint32)(uint8)(ch1) << 8) | \ ((uint32)(uint8)(ch2) << 16) | ((uint32)(uint8)(ch3) << 24 )) #endif const uint32 DDS_HEADER = NL_MAKEFOURCC('D', 'D', 'S', ' '); const uint32 DXT_HEADER = NL_MAKEFOURCC('D', 'X', 'T', '\0'); const uint32 PNG_HEADER = NL_MAKEFOURCC(0x89, 'P', 'N', 'G'); const uint32 JPG_HEADER = NL_MAKEFOURCC(0xff, 0xd8, 0xff, 0xe0); // dwLinearSize is valid #define DDSD_LINEARSIZE 0x00080000l //---------------- END OF DDS STUFFS ------------------ const uint8 MAX_MIPMAP = 16; /** * Class Bitmap * * \author Stephane Coutelas * \author Nevrax France * \date 2000 */ /* *** IMPORTANT ******************** * *** IF YOU MODIFY THE STRUCTURE OF THIS CLASS, PLEASE INCREMENT IDriver::InterfaceVersion TO INVALIDATE OLD DRIVER DLL * ********************************** */ class CBitmap { protected : CObjectVector _Data[MAX_MIPMAP]; // The number of mipmaps. base image IS a mipmap. 1 means a base image with no mipmaping. uint8 _MipMapCount; bool _LoadGrayscaleAsAlpha; uint32 _Width; uint32 _Height; // don't forget to update operator=() and swap() if adding a data member private : /** * blend 2 integers between 0 and 255 . * \param n0 first integer * \param n1 second integer * \param coef coefficient for the first integer (must be in [0,256]) */ uint32 blend(uint32 &n0, uint32 &n1, uint32 coef0); /** * Read a DDS from an IStream. * The bitmap is readen as a set of bytes and stocked compressed. * Width and Height are multiple of 4. * \param IStream The stream must be in reading mode. * \return image depth * \throw EDDSBadHeader : surface is header is not valid. */ uint8 readDDS(NLMISC::IStream &f, uint mipMapSkip); /** * Read a TGA from an IStream. * TGA pictures can be in 24 or 32 bits, RLE or uncompressed * \param f IStream (must be a reading stream) * \return image depth if succeed, 0 else */ uint8 readTGA( NLMISC::IStream &f); /** * Read a PNG from an IStream. * PNG pictures can be in 24 or 32 bits * \param f IStream (must be a reading stream) * \return image depth if succeed, 0 else */ uint8 readPNG( NLMISC::IStream &f ); /** * Read a JPG from an IStream. * JPG pictures can be in 24 * \param f IStream (must be a reading stream) * \return image depth if succeed, 0 else */ uint8 readJPG( NLMISC::IStream &f ); /** * Change bitmap format * * about DXTC1 to DXTC5 : * Does nothing if the format is not DXTC1 * about alpha encoding : * alpha0 == alpha1 * code(x,y) == 7 for every (x,y) * * about luminance to alpha and alpha to luminance : * the buffer keeps unchanged * */ ///@{ bool convertToDXTC5(); bool convertToRGBA(); bool luminanceToRGBA(); bool alphaToRGBA(); bool alphaLuminanceToRGBA(); bool convertToLuminance(); bool rgbaToLuminance(); bool alphaToLuminance(); bool alphaLuminanceToLuminance(); bool convertToAlpha(); bool rgbaToAlpha(); bool luminanceToAlpha(); bool alphaLuminanceToAlpha(); bool convertToAlphaLuminance(); bool rgbaToAlphaLuminance(); bool luminanceToAlphaLuminance(); bool alphaToAlphaLuminance(); ///@} /** * Decompress bitmap compressed with S3TC DXT1 algorithm. * \param alpha if alpha is true there's alpha. */ bool decompressDXT1(bool alpha); /** * Decompress bitmap compressed with S3TC DXT3 algorithm. * \throw EAllocationFailure : can't allocate memory. */ bool decompressDXT3(); /** * Decompress bitmap compressed with S3TC DXT3 algorithm. * \throw EAllocationFailure : can't allocate memory. */ bool decompressDXT5(); /** * Extracting RGBA infos from a 16bits word. (used by S3TC decompression) * \param color a 16bits integer * \param r a CRGBA */ static void uncompress(uint16 color, NLMISC::CRGBA &); /** * The resample function * \param pSrc CRGBA array * \param pDest CRGBA array for storing resampled texture * \param nSrcWidth original width * \param nSrcHeight original height * \param nDestWidth width after resample * \param nDestHeight height after resample */ void resamplePicture32 (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest, sint32 nSrcWidth, sint32 nSrcHeight, sint32 nDestWidth, sint32 nDestHeight); /** * The FAST resample function : works only when reducing the size by two * and when the image is square * \param pSrc CRGBA array * \param pDest CRGBA array for storing resampled texture * \param nSrcWidth original width * \param nSrcHeight original height * \param nDestWidth width after resample * \param nDestHeight height after resample */ void resamplePicture32Fast (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest, sint32 nSrcWidth, sint32 nSrcHeight, sint32 nDestWidth, sint32 nDestHeight); /** * Quadratic interpolator * \return the interpolation in (x,y) of the values (xy**) */ float getColorInterp (float x, float y, float xy00, float xy01, float xy10, float xy11) const; /// name DXTC single texel read //@{ static CRGBA getDXTCColorFromBlock(const uint8 *block, sint x, sint y); CRGBA getDXTC1Texel(sint x, sint y, uint32 numMipMap) const; CRGBA getDXTC3Texel(sint x, sint y, uint32 numMipMap) const; CRGBA getDXTC5Texel(sint x, sint y, uint32 numMipMap) const; //@} CRGBA getRGBAPixel(sint x, sint y, uint32 numMipMap /*=0*/) const; // Make a dummy from a bitfield void makeDummyFromBitField(const uint8 bitmap[1024]); // Flip DXTC void flipHDXTCBlockColor(uint8 *bitColor, uint32 w); void flipVDXTCBlockColor(uint8 *bitColor, uint32 h); void flipHDXTCBlockAlpha3(uint8 *bitColor, uint32 w); void flipVDXTCBlockAlpha3(uint8 *bitColor, uint32 h); void flipHDXTCBlockAlpha5(uint8 *bitColor, uint32 w); void flipVDXTCBlockAlpha5(uint8 *bitColor, uint32 h); void flipDXTC(bool vertical); void flipDXTCMipMap(bool vertical, uint mm, uint type); public: enum TType { RGBA=0, Luminance, Alpha, AlphaLuminance, DXTC1, DXTC1Alpha, DXTC3, DXTC5, DsDt, ModeCount, DonTKnow=0xffffffff } PixelFormat; static const uint32 bitPerPixels[ModeCount]; static const uint32 DXTC1HEADER; static const uint32 DXTC3HEADER; static const uint32 DXTC5HEADER; // don't forget to update operator=() and swap() if adding a data member CBitmap() { _MipMapCount = 1; _Width = 0; _Height = 0; PixelFormat = RGBA; _LoadGrayscaleAsAlpha = true; } virtual ~CBitmap() { } // swap 2 bitmaps contents void swap(CBitmap &other); /** * Read a bitmap(TGA, JPEG, PNG or DDS) from an IStream. * Bitmap supported are DDS (DXTC1, DXTC1 with Alpha, DXTC3, DXTC5), PNG, JPEG and * uncompressed TGA (24 and 32 bits). * \param IStream The stream must be in reading mode. * \param mipMapSkip if the file is a DDS with mipMap. N=mipMapSkip mipmaps are skipped. * \return image depth (24 or 32), or 0 if load failed * \throw ESeekFailed : seek has failed */ uint8 load(NLMISC::IStream &f, uint mipMapSkip=0); /** * Determinate the bitmap size from a bitmap(TGA or DDS) from an IStream. load just header of the file. * Bitmap supported are DDS (DXTC1, DXTC1 with Alpha, DXTC3, DXTC5), PNG, JPEG and * uncompressed TGA (24 and 32 bits). * NB: at the end, f is seeked to begin. * \param IStream The stream must be in reading mode. * \param width the width of the image. 0 if fails. * \param height the height of the image. 0 if fails. * \throw ESeekFailed : seek has failed */ static void loadSize(NLMISC::IStream &f, uint32 &width, uint32 &height); /** same than other loadSize(), but with a pathName. * \see loadSize() */ static void loadSize(const std::string &path, uint32 &retWidth, uint32 &retHeight); /** * Make a dummy "?" texture. Useful for file not found. Mode is rgba. */ void makeDummy(); /** * Make a dummy "2" texture. Useful for file not power of 2. Mode is rgba. */ void makeNonPowerOf2Dummy(); /** * Return the pixels buffer of the image, or of one of its mipmap. * Return a reference of an array in pixel format get with getPixelFormat(). * \return CObjectVector& RGBA pixels */ ///@{ CObjectVector& getPixels(uint32 numMipMap = 0) { //nlassert (numMipMap<=_MipMapCount); return _Data[numMipMap]; } const CObjectVector& getPixels(uint32 numMipMap = 0) const { //nlassert (numMipMap<=_MipMapCount); return _Data[numMipMap]; } /** Gain ownership of this texture datas. As a result, the bitmap is reseted (put in the same state than when ctor is called, e.g a single mipmap with null size) * The CObjectVector objects that contains the bitmap (one per mipmap) datas are 'swapped' with those in the array provided by the caller. * NB : The user must provide at least min(getMipMapCount(), maxMipMapCount) entries in the array * \param mipmapArray Array of mipmap that receive the bitmap datas * \param maxMipMapCount Max number of mipmap to be copied in the destination array. */ void unattachPixels(CObjectVector *mipmapDestArray, uint maxMipMapCount = MAX_MIPMAP); ///@} /** * Convert bitmap to another type * conversion to rgba always work. No-op if already rgba. * \param type new type for the bitmap * \return true if conversion succeeded, false else */ bool convertToType (TType type); /** * Return the format of pixels stored at the present time in the object buffer. * \return Pixel format (rgba luminance alpha alphaLuminance dxtc1 dxtc1Alpha dxtc3 dxtc5) */ TType getPixelFormat() const { return PixelFormat; } /** * Return the image width, or a mipmap width. * \param mipMap mipmap level * \return image width (0 if mipmap not found) */ virtual uint32 getWidth(uint32 numMipMap = 0) const; /** * Return the image height, or a mipmap height. * \param mipMap mipmap level * \return image height (0 if mipmap not found) */ virtual uint32 getHeight(uint32 numMipMap = 0) const; /** * Return the size (in pixels) of the image: <=> getHeight()*getWidth(). * \param mipMap mipmap level * \return image size (0 if mipmap not found) */ uint32 getSize(uint32 numMipMap = 0) const; /** * Return the number of mipmaps. Level0 is a mipmap... * \return number of mipmaps. 0 if no image at all. 1 if no mipmaping (for the base level). */ uint32 getMipMapCount() const { return _MipMapCount; } // Compute the number of mipmap needed for that bitmap (independently from the current number of mipmaps that have been set) uint32 computeNeededMipMapCount() const; /** * Rotate a bitmap in CCW mode. * * \see releaseMipMaps(). */ void rotateCCW(); /** * Build the mipmaps of the bitmap if they don't exist. * Work only in RGBA mode... * \see releaseMipMaps(). */ void buildMipMaps(); /** * Release the mipmaps of the bitmap if they exist. * Work for any mode. * \see buildMipMaps(). */ void releaseMipMaps(); /** * Reset the buffer. Mipmaps are deleted and bitmap is not valid anymore. * * \param type is the new type used for this texture */ void reset(TType type=RGBA); /** * Resample the bitmap. If mipmaps exist they are deleted, then rebuilt * after resampling. * \param nNewWidth width after resample * \param nNewHeight height after resample */ void resample (sint32 nNewWidth, sint32 nNewHeight); /** * Resize the bitmap. If mipmaps exist they are deleted and not rebuilt. * This is not a crop. Pixels are lost after resize. * * \param nNewWidth width after resize * \param nNewHeight height after resize * \param newType is the new type of the bitmap. If don_t_know, keep the same pixel format that before. * \param resetTo0 by default the vector are filled by 0. set false to gain performances. */ void resize (sint32 nNewWidth, sint32 nNewHeight, TType newType=DonTKnow, bool resetTo0= true); /** ADVANCED USE * Resize a single mipmap level. resize() should have been called before. * This is not a crop. Pixels are lost after resize. * No validity check is made. It is the user responsabitility fo setup correct mipmap size. * * \param numMipMap id of the mipmap * \param nNewWidth width after resize * \param nNewHeight height after resize * \param resetTo0 by default the vector are filled by 0. set false to gain performances. */ void resizeMipMap (uint32 numMipMap, sint32 nNewWidth, sint32 nNewHeight, bool resetTo0= true); /** ADVANCED USE * To use in conjunction with resizeMipMap. Setup the correct total number of mipmap * No validity check is made. It is the user responsabitility fo setup correct mipmap count. */ void setMipMapCount(uint32 mmc); /** * Write a TGA (24 or 32 bits) from the object pixels buffer. * If the current pixel format is not rgba then the method does nothing * If the pixel format is Alpha then we save in 8 bpp * \param f IStream (must be a reading stream) * \param d depth : 8 or 16 or 24 or 32 (0 for automatic) * \param upsideDown if true, the bitmap will be saved with the upside down * \return true if succeed, false else */ bool writeTGA(NLMISC::IStream &f, uint32 d=0, bool upsideDown = false); /** * Write a PNG (24 or 32 bits) from the object pixels buffer. * If the current pixel format is not rgba then the method does nothing * If the pixel format is Alpha then we save in 8 bpp * \param f IStream (must be a reading stream) * \param d depth : 8 or 16 or 24 or 32 (0 for automatic) * \return true if succeed, false else */ bool writePNG(NLMISC::IStream &f, uint32 d=0); /** * Write a JPG from the object pixels buffer. * If the current pixel format is not rgba then the method does nothing * If the pixel format is Alpha then we save in 8 bpp * \param f IStream (must be a reading stream) * \param quality 0=very bad quality 100=best quality * \return true if succeed, false else */ bool writeJPG(NLMISC::IStream &f, uint8 quality = 80); /** * Tell the bitmap to load grayscale bitmap as alpha or luminance format. * * \param loadAsAlpha is true to load grayscale bitmaps as alpha. false to load grayscale bitmaps as luminance. * default value is true. */ void loadGrayscaleAsAlpha (bool loadAsAlpha) { _LoadGrayscaleAsAlpha=loadAsAlpha; } /** * Tell if the bitmap loads grayscale bitmap as alpha or luminance format. * * \return true if the bitmap loads grayscale bitmaps as alpha, false if it loads grayscale bitmaps as luminance. */ bool isGrayscaleAsAlpha () const { return _LoadGrayscaleAsAlpha; } /** * Perform a simple blit from the source to this bitmap at the (x, y) pos * The dimension of the original bitmap are preserved * For now, this texture and the source must have the same format * With DXTC format, the dest coordinates must be a multiple of 4 * mipmap are not rebuild when present * IMPORTANT : copy to self is not handled correctly * \return true if the params were corrects and if the blit occurs. In debug build there's an assertion */ bool blit(const CBitmap *src, sint32 x, sint32 y) ; /** * Extended version of blit. The destinaion of the blit is 'this' bitmap * Source and dest rect are clamped as necessary. * For now, only RGBA is uspported (an asertion occurs otherwise) * mipmap are not updated. * IMPORTANT : copy to self is not handled correctly */ void blit(const CBitmap &src, sint srcX, sint srcY, sint srcWidth, sint srcHeight, sint destX, sint destY); /** * Get the color in the bitmap for the first mipmap * The mipmaps must be built. If not just return the bilinear at the given point. * NB: coordinates are clamped. * \param tiled If false coordinate are clamped, else the bitmap is considered to tile */ CRGBAF getColor (float x, float y) const; // Get Color with optional tiling on axis CRGBAF getColor (float x, float y, bool tileU, bool tileV) const; /** Get the pixel at the given coorrdinate. * Works in RGBA and DXTC modes. * Outside of the bitmap it returns Black (or if mipmap is not found) */ CRGBA getPixelColor(sint x, sint y, uint32 numMipMap = 0) const; /** * Horizontal flip (all the columns are flipped) * Works only with RGBA, and DXTC formats (only if w/h is a power of 2) */ void flipH(); /** * Vertical flip (all the rows are flipped) * Works only with RGBA, and DXTC formats (only if w/h is a power of 2) */ void flipV(); /** * Rotation of the bitmap of 90 degree in clockwise */ void rot90CW(); /** * Rotation of the bitmap of 90 degree in counter clockwise */ void rot90CCW(); /** Set this bitmap as the result of the blend bewteen 2 bitmap * REQUIRE : - Bm0 and Bm1 should have the same size. * - Both bitmap should be convertible to RGBA pixel format. * The result is a RGBA bitmap. * NB: this just works with the first mipmaps * \param factor The blend factor. 0 means the result is equal to Bm0, 256 means the result is equal to Bm1 * \param inputBitmapIsMutable when true, bitmap can be converted in place when needed (no copy done) */ void blend(CBitmap &Bm0, CBitmap &Bm1, uint16 factor, bool inputBitmapIsMutable = false); void getData(uint8*& extractData); void getDibData(uint8*& extractData); CBitmap& operator= (const CBitmap& from) { if (&from == this) return *this; for (uint i=0; i!=MAX_MIPMAP; ++i) { _Data[i] = from._Data[i]; // requires more than a surface copy } _MipMapCount = from._MipMapCount; _LoadGrayscaleAsAlpha = from._LoadGrayscaleAsAlpha; _Width = from._Width; _Height = from._Height; PixelFormat = from.PixelFormat; return *this; } }; } // NLMISC #endif // NL_BITMAP_H /* End of bitmap.h */ ================================================ FILE: code/nel/include/nel/misc/block_memory.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BLOCK_MEMORY_H #define NL_BLOCK_MEMORY_H #include "types_nl.h" #include #include #include "debug.h" #include "mutex.h" namespace NLMISC { // *************************************************************************** /// See CBlockMemory::Purge extern bool NL3D_BlockMemoryAssertOnPurge; // =true. // *************************************************************************** /** * Block memory allocation * * This memory manager is a fast memory allocator, doing same thing as new/delete. It works by blocks. Blocks are always * allocated, never deleted. Allocation/free are in O(1). * * Elements with sizeof(T) class CBlockMemory { public: /// Constructor CBlockMemory(uint blockSize= 16) { nlassert(blockSize); _BlockSize= blockSize; _EltSize= std::max((uint)sizeof(T), (uint)sizeof(void*)); _NextFreeElt= NULL; _NAllocatedElts= 0; } // just copy setup from other blockMemory, don't copy data! CBlockMemory(const CBlockMemory &other) { _BlockSize= other._BlockSize; // if other block is rebinded, don't copy its rebinded size. _EltSize= (uint)std::max(sizeof(T), sizeof(void*)); // No elts allocated _NextFreeElt= NULL; _NAllocatedElts= 0; } /** purge() */ ~CBlockMemory() { purge(); } /// allocate an element. ctor is called. T* allocate() { _Mutex.enter(); // if not enough memory, aloc a block. if(!_NextFreeElt) { _Blocks.push_front(CBlock()); buildBlock(*_Blocks.begin()); // new free elt points to the beginning of this block. _NextFreeElt= (*_Blocks.begin()).Data; #ifdef NL_DEBUG // if debug, must decal for begin check. _NextFreeElt= (uint32*)_NextFreeElt + 1; #endif } // choose next free elt. nlassert(_NextFreeElt); T* ret= (T*)_NextFreeElt; // update _NextFreeElt, so it points to the next free element. _NextFreeElt= *(void**)_NextFreeElt; // construct the allocated element. if( __ctor_dtor__ ) new (ret) T; // some simple Check. #ifdef NL_DEBUG uint32 *checkStart= (uint32*)(void*)ret-1; uint32 *checkEnd = (uint32*)((uint8*)(void*)ret+_EltSize); nlassert( *checkStart == CheckDeletedIdent); nlassert( *checkEnd == CheckDeletedIdent); // if ok, mark this element as allocated. *checkStart= CheckAllocatedIdent; *checkEnd = CheckAllocatedIdent; #endif _NAllocatedElts++; _Mutex.leave(); return ret; } /// delete an element allocated with this manager. dtor is called. NULL is tested. void free(T* ptr) { if(!ptr) return; _Mutex.enter(); // some simple Check. nlassert(_NAllocatedElts>0); #ifdef NL_DEBUG uint32 *checkStart= (uint32*)(void*)ptr-1; uint32 *checkEnd = (uint32*)((uint8*)(void*)ptr+_EltSize); nlassert( *checkStart == CheckAllocatedIdent); nlassert( *checkEnd == CheckAllocatedIdent); // if ok, mark this element as deleted. *checkStart = *checkEnd = uint32(CheckDeletedIdent); #endif // destruct the element. if( __ctor_dtor__ ) ptr->~T(); // just append this freed element to the list. *(void**)ptr= _NextFreeElt; _NextFreeElt= (void*) ptr; _NAllocatedElts--; _Mutex.leave(); } /** delete all blocks, freeing all memory. It is an error to purge() or delete a CBlockMemory, while elements * still remains!! You must free your elements with free(). * NB: you can disable this assert if you set NL3D_BlockMemoryAssertOnPurge to false * (good to quit a program quickly without uninitialize). */ void purge () { _Mutex.enter(); if(NL3D_BlockMemoryAssertOnPurge) { nlassert(_NAllocatedElts==0); } while(_Blocks.begin()!=_Blocks.end()) { releaseBlock(*_Blocks.begin()); _Blocks.erase(_Blocks.begin()); } _NextFreeElt= NULL; _NAllocatedElts= 0; _Mutex.leave(); } // ******************** public: // This is to be used with CSTLBlockAllocator only!!! It changes the size of an element!! void __stl_alloc_changeEltSize(uint eltSize) { _Mutex.enter(); // must not be used with object ctor/dtor behavior. nlassert(__ctor_dtor__ == false); // format size. eltSize= std::max((uint)eltSize, (uint)sizeof(void*)); // if not the same size as before if(_EltSize!= eltSize) { // verify that rebind is made before any allocation!! nlassert(_Blocks.empty()); // change the size. _EltSize= eltSize; } _Mutex.leave(); }; // This is to be used with CSTLBlockAllocator only!!! uint __stl_alloc_getEltSize() const { return _EltSize; } private: /// size of a block. uint _BlockSize; /// size of an element in the block. uint _EltSize; /// number of elements allocated. sint _NAllocatedElts; /// next free element. void *_NextFreeElt; /// Must be ThreadSafe (eg: important for 3D PointLight and list of transform) CFastMutex _Mutex; /// a block. struct CBlock { /// The data allocated. void *Data; }; /// list of blocks. std::list _Blocks; /// For debug only, check ident. enum TCheckIdent { CheckAllocatedIdent= 0x01234567, CheckDeletedIdent= 0x89ABCDEF }; private: void buildBlock(CBlock &block) { uint i; uint32 nodeSize= _EltSize; #ifdef NL_DEBUG // must allocate more size for mem checks in debug. nodeSize+= 2*sizeof(uint32); #endif // allocate. block.Data = (void*)new uint8 [_BlockSize * nodeSize]; // by default, all elements are not allocated, build the list of free elements. void *ptr= block.Data; #ifdef NL_DEBUG // if debug, must decal for begin check. ptr= (uint32*)ptr + 1; #endif for(i=0; i<_BlockSize-1; i++) { // next elt. void *next= (uint8*)ptr + nodeSize; // points to the next element in this array. *(void**)ptr= next; // next. ptr= next; } // last element points to NULL. *(void**)ptr= NULL; // If debug, must init all check values to CheckDeletedIdent. #ifdef NL_DEBUG ptr= block.Data; // must decal for begin check. ptr= (uint32*)ptr + 1; // fill all nodes. for(i=0; i<_BlockSize; i++) { uint32 *checkStart= (uint32*)ptr-1; uint32 *checkEnd = (uint32*)((uint8*)ptr+_EltSize); // mark this element as deleted. *checkStart = *checkEnd = uint32(CheckDeletedIdent); // next elt. ptr= (uint8*)ptr + nodeSize; } #endif } void releaseBlock(CBlock &block) { delete [] ((uint8*)block.Data); } }; } // NLMISC #endif // NL_BLOCK_MEMORY_H /* End of block_memory.h */ ================================================ FILE: code/nel/include/nel/misc/bsphere.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BSPHERE_H #define NL_BSPHERE_H #include "types_nl.h" #include "vector.h" #include "plane.h" #include "matrix.h" namespace NLMISC { /** * A bounding Sphere. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CBSphere { public: CVector Center; float Radius; /// Empty Constructor. CBSphere() {} /// Constructor. CBSphere(const CVector & center, float radius) : Center(center), Radius(radius) {} /// \name transform // @{ /** compute res= mat * this. NB: radius is maximized, taking max of the 3 axis of the matrix. * NB: this may be false if the matrix is not orthogonal... */ void applyTransform(const CMatrix &mat, CBSphere &res); // @} /// \name Clip // @{ /// Is the bbox partially in front of the plane?? p MUST be normalized. bool clipFront(const CPlane &p) const; /// Is the bbox partially in back of the plane?? p MUST be normalized. bool clipBack(const CPlane &p) const; // @} /// Does the sphere include this point? bool include(const CVector &p) const; /// Does the sphere include TOTALY this sphere? bool include(const CBSphere &s) const; /// Does the sphere intersect the other? bool intersect(const CBSphere &s) const; /// Build the union of the 2 sphere ans set to *this. work if this==s1 || this==s2. void setUnion(const CBSphere &sa, const CBSphere &sb); }; } // NLMISC #endif // NL_BSPHERE_H /* End of bsphere.h */ ================================================ FILE: code/nel/include/nel/misc/buf_fifo.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BUF_FIFO_H #define NL_BUF_FIFO_H #include "types_nl.h" #include #include "time_nl.h" #include "mem_stream.h" #include "command.h" namespace NLMISC { #undef BUFFIFO_TRACK_ALL_BUFFERS /** * This class is a dynamic size FIFO that contains variable size uint8 buffer. * It's used in the layer1 network for storing temporary messages. * You can resize the internal FIFO buffer if you know the average size * of data you'll put in it. It have the same behavior as STL so if the * buffer is full the size will be automatically increase by 2. * * TODO: Add a method getMsgNb() that will return the number of messages in queue. * For acceptable performance, it would need to store the current number instead * of browsing the blocks. * * \code CBufFIFO fifo; fifo.resize(10000); vector vec; vec.resize(rand()%256); memset (&(vec[0]), '-', vec.size()); // push the vector fifo.push(vec); // display the fifo fifo.display(); vector vec2; // get the vector fifo.pop(vec2); * \endcode * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CBufFIFO { public: CBufFIFO (); ~CBufFIFO (); /// Push 'buffer' in the head of the FIFO void push (const std::vector &buffer) { push (&buffer[0], (uint32)buffer.size()); } void push (const NLMISC::CMemStream &buffer) { push (buffer.buffer(), buffer.length()); } void push (const uint8 *buffer, uint32 size); /// Concate and push 'buffer1' and buffer2 in the head of the FIFO. The goal is to avoid a copy void push (const std::vector &buffer1, const std::vector &buffer2); /// Get the buffer in the tail of the FIFO and put it in 'buffer' void front (std::vector &buffer); void front (NLMISC::CMemStream &buffer); void front (uint8 *&buffer, uint32 &size); /// This function returns the last byte of the front message /// It is used by the network to know a value quickly without doing front() uint8 frontLast (); /// Pop the buffer in the tail of the FIFO void pop (); /// Set the size of the FIFO buffer in byte void resize (uint32 size); /// Return true if the FIFO is empty bool empty () { return _Empty; } /// Erase the FIFO void clear (); /// Returns the size of the FIFO uint32 size (); /// display the FIFO to stdout (used to debug the FIFO) void display (); /// display the FIFO statistics (speed, nbcall, etc...) to stdout void displayStats (CLog *log = InfoLog); private: typedef uint32 TFifoSize; // pointer to the big buffer uint8 *_Buffer; // size of the big buffer uint32 _BufferSize; // true if the bufffer is empty bool _Empty; // head of the FIFO uint8 *_Head; // tail of the FIFO uint8 *_Tail; // pointer to the rewinder of the FIFO uint8 *_Rewinder; // return true if we can put size bytes on the buffer // return false if we have to resize bool canFit (uint32 size); // statistics of the FIFO uint32 _BiggestBlock; uint32 _SmallestBlock; uint32 _BiggestBuffer; uint32 _SmallestBuffer; uint32 _Pushed ; uint32 _Fronted; uint32 _Resized; TTicks _PushedTime; TTicks _FrontedTime; TTicks _ResizedTime; #ifdef BUFFIFO_TRACK_ALL_BUFFERS typedef std::set TAllBuffers; // All the buffer for debug output static TAllBuffers _AllBuffers; // WARNING: not mutexed, can produce some crashes! #endif NLMISC_CATEGORISED_COMMAND_FRIEND(misc, dumpAllBuffers); }; } // NLMISC #endif // NL_BUF_FIFO_H /* End of buf_fifo.h */ ================================================ FILE: code/nel/include/nel/misc/callback.h ================================================ /* Copyright (c) 2009-2014, Jan BOON All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef NLMISC_CALLBACK_H #define NLMISC_CALLBACK_H #include // STL includes // NeL includes #include // Project includes namespace NLMISC { #define NLMISC_CALLBACK_TEMPLATE \ /** \ * \brief NLMISC_CALLBACK_ARGS_CLASS \ * \date 2009-03-03 18:09GMT \ * \author Jan BOON \ * Callback template \ */ \ template \ class NLMISC_CALLBACK_ARGS_CLASS \ { \ /* Very simple reference counting callback base */ \ class CCallbackBase \ { \ public: \ CCallbackBase() : m_RefCount(0) \ { \ \ } \ \ virtual ~CCallbackBase() \ { \ nlassert(!m_RefCount); \ } \ \ void refAdd() \ { \ ++m_RefCount; \ } \ \ void refRemove() \ { \ --m_RefCount; \ if (!m_RefCount) \ delete this; \ } \ \ virtual TReturn callback(NLMISC_CALLBACK_ARGS_DECL) = 0; \ \ virtual bool equals(const CCallbackBase *callbackBase) = 0; \ \ /* disable copy */ \ CCallbackBase(const CCallbackBase &); \ CCallbackBase &operator=(const CCallbackBase &); \ \ private: \ uint m_RefCount; \ }; \ \ typedef TReturn TCallbackFunction(NLMISC_CALLBACK_ARGS_DECL); \ class CCallbackFunction : public CCallbackBase \ { \ public: \ CCallbackFunction(TCallbackFunction *callbackFunction) : m_CallbackFunction(callbackFunction) \ { \ nlassert(m_CallbackFunction); \ } \ \ virtual ~CCallbackFunction() \ { \ m_CallbackFunction = NULL; \ } \ \ virtual TReturn callback(NLMISC_CALLBACK_ARGS_DECL) \ { \ return m_CallbackFunction(NLMISC_CALLBACK_ARGS_IMPL); \ } \ \ virtual bool equals(const CCallbackBase *callbackBase) \ { \ const CCallbackFunction *callbackFunction = \ dynamic_cast(callbackBase); \ if (!callbackFunction) return false; \ return m_CallbackFunction == callbackFunction->m_CallbackFunction; \ } \ \ private: \ TCallbackFunction *m_CallbackFunction; \ }; \ \ template \ class CCallbackMethod : public CCallbackBase \ { \ typedef TReturn (TClass::*TCallbackMethod)(NLMISC_CALLBACK_ARGS_DECL); \ public: \ CCallbackMethod(TClass *callbackObject, TCallbackMethod callbackMethod) : m_CallbackObject(callbackObject), m_CallbackMethod(callbackMethod) \ { \ nlassert(m_CallbackObject); \ nlassert(m_CallbackMethod); \ } \ \ virtual ~CCallbackMethod() \ { \ m_CallbackObject = NULL; \ m_CallbackMethod = NULL; \ } \ \ virtual TReturn callback(NLMISC_CALLBACK_ARGS_DECL) \ { \ return (m_CallbackObject->*m_CallbackMethod)(NLMISC_CALLBACK_ARGS_IMPL); \ } \ \ virtual bool equals(const CCallbackBase *callbackBase) \ { \ const CCallbackMethod *callbackMethod = \ dynamic_cast(callbackBase); \ if (!callbackMethod) return false; \ return m_CallbackObject == callbackMethod->m_CallbackObject \ && m_CallbackMethod == callbackMethod->m_CallbackMethod; \ } \ \ private: \ TClass *m_CallbackObject; \ TCallbackMethod m_CallbackMethod; \ }; \ \ public: \ CCallback() : m_CallbackBase(NULL) \ { \ \ } \ \ CCallback(TCallbackFunction *callbackFunction) : m_CallbackBase(new CCallbackFunction(callbackFunction)) \ { \ nlassert(m_CallbackBase); \ m_CallbackBase->refAdd(); \ } \ \ template \ CCallback(TClass *callbackObject, TReturn (TClass::*callbackMethod)(NLMISC_CALLBACK_ARGS_DECL)) : m_CallbackBase(new CCallbackMethod(callbackObject, callbackMethod)) \ { \ nlassert(m_CallbackBase); \ m_CallbackBase->refAdd(); \ } \ \ CCallback(const CCallback &callback) \ { \ m_CallbackBase = callback.m_CallbackBase; \ if (m_CallbackBase) \ m_CallbackBase->refAdd(); \ } \ \ CCallback &operator=(const CCallback &callback) \ { \ if (m_CallbackBase != callback.m_CallbackBase) \ { \ if (m_CallbackBase) \ m_CallbackBase->refRemove(); \ m_CallbackBase = callback.m_CallbackBase; \ if (m_CallbackBase) \ m_CallbackBase->refAdd(); \ } \ return *this; \ } \ \ ~CCallback() \ { \ if (m_CallbackBase) \ { \ m_CallbackBase->refRemove(); \ m_CallbackBase = NULL; \ } \ } \ \ TReturn callback(NLMISC_CALLBACK_ARGS_DECL) \ { \ nlassert(m_CallbackBase); \ return m_CallbackBase->callback(NLMISC_CALLBACK_ARGS_IMPL); \ } \ \ TReturn operator()(NLMISC_CALLBACK_ARGS_DECL) \ { \ nlassert(m_CallbackBase); \ return m_CallbackBase->callback(NLMISC_CALLBACK_ARGS_IMPL); \ } \ \ bool valid() const \ { \ return m_CallbackBase != NULL; \ } \ \ operator bool() const \ { \ return m_CallbackBase != NULL; \ } \ \ bool operator==(const CCallback &callback) \ { \ return m_CallbackBase->equals(callback.m_CallbackBase); \ } \ \ private: \ CCallbackBase *m_CallbackBase; \ \ }; /* class CCallback */ \ template class CCallback; #define NLMISC_CALLBACK_ARGS_CLASS CCallback #define NLMISC_CALLBACK_ARGS_TYPENAME #define NLMISC_CALLBACK_ARGS_DECL #define NLMISC_CALLBACK_ARGS_IMPL NLMISC_CALLBACK_TEMPLATE #undef NLMISC_CALLBACK_ARGS_CLASS #undef NLMISC_CALLBACK_ARGS_TYPENAME #undef NLMISC_CALLBACK_ARGS_DECL #undef NLMISC_CALLBACK_ARGS_IMPL #define NLMISC_CALLBACK_ARGS_CLASS CCallback #define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA #define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA #define NLMISC_CALLBACK_ARGS_IMPL argsA NLMISC_CALLBACK_TEMPLATE #undef NLMISC_CALLBACK_ARGS_CLASS #undef NLMISC_CALLBACK_ARGS_TYPENAME #undef NLMISC_CALLBACK_ARGS_DECL #undef NLMISC_CALLBACK_ARGS_IMPL #define NLMISC_CALLBACK_ARGS_CLASS CCallback #define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB #define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB #define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB NLMISC_CALLBACK_TEMPLATE #undef NLMISC_CALLBACK_ARGS_CLASS #undef NLMISC_CALLBACK_ARGS_TYPENAME #undef NLMISC_CALLBACK_ARGS_DECL #undef NLMISC_CALLBACK_ARGS_IMPL #define NLMISC_CALLBACK_ARGS_CLASS CCallback #define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC #define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC #define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC NLMISC_CALLBACK_TEMPLATE #undef NLMISC_CALLBACK_ARGS_CLASS #undef NLMISC_CALLBACK_ARGS_TYPENAME #undef NLMISC_CALLBACK_ARGS_DECL #undef NLMISC_CALLBACK_ARGS_IMPL #define NLMISC_CALLBACK_ARGS_CLASS CCallback #define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD #define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD #define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD NLMISC_CALLBACK_TEMPLATE #undef NLMISC_CALLBACK_ARGS_CLASS #undef NLMISC_CALLBACK_ARGS_TYPENAME #undef NLMISC_CALLBACK_ARGS_DECL #undef NLMISC_CALLBACK_ARGS_IMPL #define NLMISC_CALLBACK_ARGS_CLASS CCallback #define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE #define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE #define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE NLMISC_CALLBACK_TEMPLATE #undef NLMISC_CALLBACK_ARGS_CLASS #undef NLMISC_CALLBACK_ARGS_TYPENAME #undef NLMISC_CALLBACK_ARGS_DECL #undef NLMISC_CALLBACK_ARGS_IMPL #define NLMISC_CALLBACK_ARGS_CLASS CCallback #define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE, typename TArgsF #define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE, TArgsF argsF #define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE, argsF NLMISC_CALLBACK_TEMPLATE #undef NLMISC_CALLBACK_ARGS_CLASS #undef NLMISC_CALLBACK_ARGS_TYPENAME #undef NLMISC_CALLBACK_ARGS_DECL #undef NLMISC_CALLBACK_ARGS_IMPL #define NLMISC_CALLBACK_ARGS_CLASS CCallback #define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE, typename TArgsF, typename TArgsG #define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE, TArgsF argsF, TArgsG argsG #define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE, argsF, argsG NLMISC_CALLBACK_TEMPLATE #undef NLMISC_CALLBACK_ARGS_CLASS #undef NLMISC_CALLBACK_ARGS_TYPENAME #undef NLMISC_CALLBACK_ARGS_DECL #undef NLMISC_CALLBACK_ARGS_IMPL #undef NLMISC_CALLBACK_ARGS_CLASSNAME #undef NLMISC_CALLBACK_TEMPLATE } /* namespace NLMISC */ #endif /* #ifndef NLMISC_CALLBACK_H */ /* end of file */ ================================================ FILE: code/nel/include/nel/misc/cdb.h ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef CDB_H #define CDB_H // misc #include "types_nl.h" #include "smart_ptr.h" #include "string_mapper.h" #include "sstring.h" #include namespace NLMISC { class IProgressCallback; class CBitMemStream; class CCDBNodeLeaf; class CCDBNodeBranch; class CCDBBankHandler; /** * Interface to manage a database node, can contain a unique property or a set of property * \author Stephane Coutelas * \author Nevrax France * \date 2002 */ class ICDBNode : public CRefCount { //----------------------------------------------------------------------- // end of IDBNode interface // start of CDB sub-class definitions public: enum EPropType { UNKNOWN = 0, // Unsigned I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31, I32, I33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47, I48, I49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63, I64, // Signed S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31, S32, S33, S34, S35, S36, S37, S38, S39, S40, S41, S42, S43, S44, S45, S46, S47, S48, S49, S50, S51, S52, S53, S54, S55, S56, S57, S58, S59, S60, S61, S62, S63, S64, TEXT, Nb_Prop_Type }; /** * observer interface to a database property * \author Nicolas Brigand * \author Nevrax France * \date 2002 */ class IPropertyObserver : public CRefCount { public : virtual ~IPropertyObserver() {} virtual void update(ICDBNode* node ) = 0; }; /** * Text id * \author Stephane Coutelas * \author Nevrax France * \date 2002 */ class CTextId { public: /** * Default constructor */ CTextId(): _Idx(0) {} /** * Init this text id from a string */ explicit CTextId( const std::string& str ): _Idx(0) { const std::string &s = str; uint32 i, j; for (i=0,j=0; i+j=size()) return empty; else return _Ids[idx]; } private: std::vector _Ids; mutable uint _Idx; }; //----------------------------------------------------------------------- // end of CDB sub-class definitions //----------------------------------------------------------------------- // IDBNode interface definition public : /** * destructor */ virtual ~ICDBNode() {} /** * Build the structure of the database from a file * \param f is the stream */ virtual void init( xmlNodePtr node, IProgressCallback &progressCallBack, bool mapBanks=false, CCDBBankHandler *bankHandler = NULL ) = 0; /** * Save a backup of the database * \param id is the text id of the property/grp * \param f is the stream */ virtual void write( CTextId& id, FILE * f) = 0; /** * Update the database from a stream coming from the FE * \param gc the server gameCycle of this update. Any outdated update are aborted * \param f : the stream. */ virtual void readDelta( TGameCycle gc, CBitMemStream & f ) = 0; /** * Get a node . Create it if it does not exist yet * \param id : the CTextId identifying the node */ virtual ICDBNode * getNode( const CTextId& id, bool bCreate = true )=0 ; /** * Get a node * \param idx is the node index */ virtual ICDBNode * getNode( uint16 idx ) = 0; /** * Get a node index * \param node is a pointer to the node * \param index is a reference that receive the result * \return true if the node was found */ virtual bool getNodeIndex( ICDBNode* node , uint & index) = 0; /** * Return the value of a property (the update flag is set to false) * \param id is the text id of the property/grp * \param name is the name of the property * \return the value of the property */ virtual sint64 getProp( CTextId& id ) = 0; /** * Set the value of a property (the update flag is set to true) * \param id is the text id of the property/grp * \param name is the name of the property * \param value is the value of the property * \return bool : 'true' if property found. */ virtual bool setProp( CTextId& id, sint64 value ) = 0; /// Reset all leaf data from this point virtual void resetData(TGameCycle gc, bool forceReset=false) = 0; /** * Clear the node and his children */ virtual void clear() = 0; /** * add an observer to a property * \param observer : pointer to an observer * \param id text id identifying the property * \return false if the node doesn't exist */ virtual bool addObserver(IPropertyObserver* observer, CTextId& id) = 0; /** remove an obsever * \param observer : pointer to an observer * \param id text id identifying the property * \return false if the node or observer doesn t exist */ virtual bool removeObserver(IPropertyObserver* observer, CTextId& id) = 0; /** * Inform a node of its parenthood */ virtual void setParent(CCDBNodeBranch * /* parent */) { nlassertex(0,("setParent() not overloaded for given node type!")); } /** * get the parent of a node */ virtual CCDBNodeBranch* getParent() { nlassertex(0,("getParent() not overloaded for given node type!")); return NULL; } /** * get the name of this node */ const std::string * getName() const { return &_DBSM->localUnmap(_Name); } /** * get the full name of this node separator is ':' (ie UI:INTERFACE:REDSTUFF) * This will not return the fullname with the ROOT ! */ std::string getFullName(); /// Count the leaves virtual uint countLeaves() const = 0; /// Find the leaf which count is specified (if found, the returned value is non-null and count is 0) virtual CCDBNodeLeaf *findLeafAtCount( uint& count ) = 0; /// Set the atomic branch flag (when all the modified nodes of a branch should be tranmitted at the same time) void setAtomic( bool atomicBranch ) { _AtomicFlag = atomicBranch; } /// Return true if the branch has the atomic flag bool isAtomic() const { return _AtomicFlag; } // test if the node is a leaf virtual bool isLeaf() const = 0; /// Debug purpose virtual void display (const std::string &/* prefix */){} /// Return the string id corresponding to the argument static TStringId getStringId(const std::string& nodeName) { if (_DBSM == NULL) _DBSM = CStringMapper::createLocalMapper(); return _DBSM->localMap(nodeName); } /// Return a pointer to the string corresponding to the argument static const std::string *getStringFromId(TStringId nodeStringId) { if (_DBSM == NULL) _DBSM = CStringMapper::createLocalMapper(); return &_DBSM->localUnmap(nodeStringId); } /// release string mapper static void releaseStringMapper(); static bool isDatabaseVerbose(){ return verboseDatabase; } static void setVerboseDatabase( bool b ){ verboseDatabase = b; } protected: /// Constructor ICDBNode() : _AtomicFlag(false) { if (_DBSM == NULL) _DBSM = CStringMapper::createLocalMapper(); _Name = CStringMapper::emptyId(); } /// Constructor ICDBNode (const std::string &name) : _AtomicFlag(false) { if (_DBSM == NULL) _DBSM = CStringMapper::createLocalMapper(); _Name = _DBSM->localMap(name); //_NameDbg = name; } // utility to build full name efficiently (without reallocating the string at each parent level) void _buildFullName(CSString &fullName); /// Atomic flag: is the branch an atomic group, or is the leaf a member of an atomic group bool _AtomicFlag : 1; /// Name of the node TStringId _Name; //std::string _NameDbg; static CStringMapper *_DBSM; static bool verboseDatabase; }; } #endif // CDB_H ================================================ FILE: code/nel/include/nel/misc/cdb_bank_handler.h ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef CDB_BANK_HANDLER #define CDB_BANK_HANDLER #include #include "nel/misc/types_nl.h" namespace NLMISC{ /** @brief Manages the bank names and mappings of the CDB it's associated with Banks are numeric identifiers for the top-level branches of the CDB. They are used for saving bandwidth, because the local CDBs are updated with deltas, that identify the updatable top-level branch with this id. The CCDBBankHandler manages the mapping of banks to their names, unified (node) index, and the other way around. */ class CCDBBankHandler{ public: /** @brief The class' constructor @param maxbanks the maximum number of banks we need to handle */ CCDBBankHandler( uint maxbanks ); /// Very surprisingly this is the destructor ~CCDBBankHandler(){} /** @brief Returns the unified (node) index for the specified bank Id. @param bank The bank whose uid we need. @return Returns an uid or static_cast< uint >( -1 ) on failure. */ uint getUIDForBank( uint bank ) const; /** @brief Returns the bank Id for the specified unified (node) index. @param uid The unified (node) index we need to translate to bank Id. @return Returns a bank Id. */ uint getBankForUID( uint uid ) const{ return _UnifiedIndexToBank[ uid ]; } /// Returns the last unified (node) index we mapped. uint getLastUnifiedIndex() const{ return _CDBLastUnifiedIndex; } /** @brief Returns the number of bits used to store the number of nodes that belong to this bank. @param bank The banks whose id bits we need. @return Returns the number of bits used to store the number of nodes that belong to this bank. */ uint getFirstLevelIdBits( uint bank ) const{ return _FirstLevelIdBitsByBank[ bank ]; } /** @brief Returns the name of the specified bank. @param bank The id of the bank we need the name of. @return Returns the name of the specified bank. */ std::string getBankName( uint bank ) const{ return _CDBBankNames[ bank ]; } /** @brief Looks up the bank Id of the bank name specified. @param name The name of the bank whose Id we need. @return Returns the id of the bank, or static_cast< uint >( -1 ) on fail. */ uint getBankByName( const std::string &name ) const; /** @brief Maps the specified bank name to a unified (node) index and vica versa. @param bankName Name of the bank to map. */ void mapNodeByBank( const std::string &bankName ); /** @brief Loads the known bank names from an array ( the order decides the bank Id ). @param strings The array of the banks names. @param size The size of the array. */ void fillBankNames( const char **strings, uint size ); /// Resets the node to bank mapping vector void resetNodeBankMapping(){ _UnifiedIndexToBank.clear(); } /// Resets all maps, and sets _CDBLastUnifiedIndex to 0. void reset(); uint getUnifiedIndexToBankSize() const{ return _UnifiedIndexToBank.size(); } /// Calculates the number of bits used to store the number of nodes that belong to the banks. void calcIdBitsByBank(); /** @brief Looks up the unified (node) index of a bank node. @param bank The bank id of the node we are looking up. @param index The index of the node within the bank. @return Returns the unified (node) index of the specified bank node. */ uint getServerToClientUIDMapping( uint bank, uint index ) const{ return _CDBBankToUnifiedIndexMapping[ bank ][ index ]; } /** @brief Resizes the bank holders. WARNING: Resets data contained. @param newSize - The new maximum number of banks. */ void resize( uint newSize ); private: /// Mapping from server database index to client database index (first-level nodes) std::vector< std::vector< uint > > _CDBBankToUnifiedIndexMapping; /// Mapping from client database index to bank IDs (first-level nodes) std::vector< uint > _UnifiedIndexToBank; /// Last index mapped uint _CDBLastUnifiedIndex; /// Number of bits for first-level branches, by bank std::vector< uint > _FirstLevelIdBitsByBank; /// Names of the CDB banks std::vector< std::string > _CDBBankNames; /// The number of banks used uint maxBanks; }; } #endif ================================================ FILE: code/nel/include/nel/misc/cdb_branch.h ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef CDB_BRANCH_H #define CDB_BRANCH_H #include "cdb.h" #define NL_CDB_OPTIMIZE_PREDICT 1 namespace NLMISC{ /** * Database Node which contains a set of properties * \author Stephane Coutelas * \author Nevrax France * \date 2002 */ class CCDBNodeBranch : public ICDBNode { public: class ICDBDBBranchObserverHandle { public: virtual ~ICDBDBBranchObserverHandle(){} virtual ICDBNode* owner() = 0; virtual IPropertyObserver* observer() = 0; virtual bool observesLeaf( const std::string &leafName ) = 0; virtual bool inList( uint list ) = 0; virtual void addToFlushableList() = 0; virtual void removeFromFlushableList( uint list ) = 0; virtual void removeFromFlushableList() = 0; }; // default constructor CCDBNodeBranch(const std::string &name) : ICDBNode(name) { _Parent = NULL; _IdBits = 0; _Sorted = false; } /** * Build the structure of the database from a file * \param f is the stream */ void init( xmlNodePtr node, class IProgressCallback &progressCallBack, bool mapBanks=false, CCDBBankHandler *bankHandler = NULL ); /** * Add a new sub node * \param node is the new subnode * \param nodeName is the name of the node */ void attachChild( ICDBNode * node, std::string nodeName ); /** * Get a node . Create it if it does not exist yet * \param id : the CTextId identifying the node */ ICDBNode * getNode (const CTextId& id, bool bCreate=true); /** * Get a node. Return NULL if out of bounds (no warning) * \param idx is the node index */ ICDBNode * getNode( uint16 idx ); /** * Get a node index * \param node is a pointer to the node */ virtual bool getNodeIndex( ICDBNode* node , uint& index) { index=0; for ( std::vector::const_iterator it = _Nodes.begin(); it != _Nodes.end(); it++) { if (*it == node) return true; index++; } return false; } // return the child with the given node id, creating it if requested CCDBNodeLeaf *getLeaf( const char *id, bool bCreate ); CCDBNodeLeaf *getLeaf( const std::string &id, bool bCreate ) { return getLeaf(id.c_str(), bCreate); } /** * Save a backup of the database * \param id is the text id of the property/grp * \param f is the stream */ void write( CTextId& id, FILE * f); /// Update the database from the delta, but map the first level with the bank mapping (see _CDBBankToUnifiedIndexMapping) void readAndMapDelta( TGameCycle gc, CBitMemStream& s, uint bank, CCDBBankHandler *bankHandler ); /// Update the database from a stream coming from the FE void readDelta( TGameCycle gc, CBitMemStream & f ); /** * Return the value of a property (the update flag is set to false) * \param id is the text id of the property/grp * \param name is the name of the property * \return the value of the property */ sint64 getProp( CTextId& id ); /** * Set the value of a property (the update flag is set to true) * \param id is the text id of the property/grp * \param name is the name of the property * \param value is the value of the property * \return bool : 'true' if property found. */ bool setProp( CTextId& id, sint64 value ); /// Clear the node and his children void clear(); void resetNode( TGameCycle gc, uint node ) { if( node > _Nodes.size() ) return; _Nodes[ node ]->resetData( gc ); } /// Reset all leaf data from this point void resetData(TGameCycle gc, bool forceReset=false) { for ( uint i=0; i!=_Nodes.size(); ++i ) { _Nodes[i]->resetData(gc, forceReset); } } /** * Destructor */ virtual ~CCDBNodeBranch() { clear(); } // the parent node for a branch (NULL by default) virtual void setParent(CCDBNodeBranch *parent) { _Parent=parent; } virtual CCDBNodeBranch* getParent() { return _Parent; } //get the number of nodes uint16 getNbNodes() { return (uint16)_Nodes.size(); } /// Count the leaves virtual uint countLeaves() const; /// Find the leaf which count is specified (if found, the returned value is non-null and count is 0) virtual CCDBNodeLeaf *findLeafAtCount( uint& count ); virtual void display (const std::string &prefix); void removeNode (const CTextId& id); /** * add an observer to a property * \param observer : pointer to an observer * \param id text id identifying the property * \return false if the node doen t exist */ virtual bool addObserver(IPropertyObserver* observer, CTextId& id); /** remove an obsever * \param observer : pointer to an observer * \return false if the node or observer doesn t exist */ virtual bool removeObserver(IPropertyObserver* observer, CTextId& id); // Add an observer to this branch. It will be notified of any change in the sub-leaves /** * Add observer to all sub-leaves, except if a positive filter is set: * If positiveLeafNameFilter is non-empty, only changes to leaves having names found in it * will be notified (this is equivalent to creating a sub-branch containing only the specified leaves * and setting a branch observer on it, except you don't need to change your database paths * and update large amounts of code!). */ void addBranchObserver( ICDBDBBranchObserverHandle* handle, const std::vector& positiveLeafNameFilter=std::vector()); /** * Easy version of addBranchObserver() (see above). * Examples of dbPathFromThisNode: * "" -> this node * "FOO:BAR" -> sub-branch "BAR" of "FOO" which is a sub-branch of this node */ void addBranchObserver( ICDBDBBranchObserverHandle *handle, const char *dbPathFromThisNode, const char **positiveLeafNameFilter=NULL, uint positiveLeafNameFilterSize=0); // Remove observer from all sub-leaves bool removeBranchObserver(IPropertyObserver* observer); /// Easy version of removeBranchObserver() (see above and see easy version of addBranchObserver()) void removeBranchObserver(const char *dbPathFromThisNode, ICDBNode::IPropertyObserver& observer); virtual bool isLeaf() const { return false; } // mark this branch and parent branch as 'modified'. This is usually called by sub-leaves void onLeafChanged( TStringId leafName ); /// Find a subnode at this level ICDBNode * find (const std::string &nodeName); protected: typedef std::list< ICDBDBBranchObserverHandle* > TObserverHandleList; CCDBNodeBranch *_Parent; /// database subnodes not sorted std::vector _Nodes; /// subnodes sorted by name std::vector _NodesByName; // number of bits required to stock my children's ids uint8 _IdBits : 7; bool _Sorted : 1; // observers for this node or branch TObserverHandleList observerHandles; /// called by clear void removeAllBranchObserver(); #if NL_CDB_OPTIMIZE_PREDICT CRefPtr _PredictNode; #endif }; } #endif // CDB_BRANCH_H ================================================ FILE: code/nel/include/nel/misc/cdb_branch_observing_handler.h ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef CDB_BRANCH_OBS_HNDLR #define CDB_BRANCH_OBS_HNDLR #include "nel/misc/cdb_branch.h" namespace NLMISC{ /** @brief Manages the CDB branch observers. When a leaf's data changes, it notifies the branch, which then marks the observers as notifiable. The marked observers can then be notified and flushed on request. */ class CCDBBranchObservingHandler{ enum{ MAX_OBS_LST = 2 }; public: CCDBBranchObservingHandler(); ~CCDBBranchObservingHandler(); /// Notifies the observers, and flushes the list void flushObserverCalls(); void reset(); void addBranchObserver( CCDBNodeBranch *branch, ICDBNode::IPropertyObserver *observer, const std::vector< std::string >& positiveLeafNameFilter ); void addBranchObserver( CCDBNodeBranch *branch, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer, const char **positiveLeafNameFilter, uint positiveLeafNameFilterSize ); void removeBranchObserver( CCDBNodeBranch *branch, ICDBNode::IPropertyObserver* observer ); void removeBranchObserver( CCDBNodeBranch *branch, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer ); ///Observer for branch observer flush events. class IBranchObserverCallFlushObserver : public CRefCount{ public: virtual ~IBranchObserverCallFlushObserver(){} virtual void onObserverCallFlush() = 0; }; private: void triggerFlushObservers(); public: void addFlushObserver( IBranchObserverCallFlushObserver *observer ); void removeFlushObserver( IBranchObserverCallFlushObserver *observer ); private: /** @brief Handle to a branch observer. The handle stores the owner branch, the observer and remembers if it's marked for notifying the observer. Also it manages adding/removing itself to/from the marked observer handles list, which is handled by CCDBBranchObservingHandler. */ class CCDBDBBranchObserverHandle : public CCDBNodeBranch::ICDBDBBranchObserverHandle{ public: CCDBDBBranchObserverHandle( ICDBNode::IPropertyObserver *observer, CCDBNodeBranch *owner, CCDBBranchObservingHandler *handler ); ~CCDBDBBranchObserverHandle(); ICDBNode* owner(){ return _owner; } ICDBNode::IPropertyObserver* observer(){ return _observer; } bool observesLeaf( const std::string &leafName ); bool inList( uint list ); void addToFlushableList(); void removeFromFlushableList( uint list ); void removeFromFlushableList(); private: bool _inList[ MAX_OBS_LST ]; std::vector< std::string > _observedLeaves; CCDBNodeBranch *_owner; NLMISC::CRefPtr< ICDBNode::IPropertyObserver > _observer; CCDBBranchObservingHandler *_handler; }; std::list< CCDBNodeBranch::ICDBDBBranchObserverHandle* > flushableObservers[ MAX_OBS_LST ]; CCDBNodeBranch::ICDBDBBranchObserverHandle *currentHandle; uint currentList; std::vector< IBranchObserverCallFlushObserver* > flushObservers; }; } #endif ================================================ FILE: code/nel/include/nel/misc/cdb_check_sum.h ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CDB_CHECK_SUM_H #define NL_CDB_CHECK_SUM_H #include "types_nl.h" #include namespace NLMISC{ /** * class implementing check sum for the client database * these check sum can be used to ensure that linked properties have all been modified * \author Nicolas Brigand * \author Nevrax France * \date 2002 */ class CCDBCheckSum { public: ///constructor CCDBCheckSum(); //clear the sum void clear() { _Sum = 0; }; ///add an uint8 to the sum void add(uint8 el); ///add a value to the check sum template void add(const T & el) { T value = el; for (uint8 i=0; i< sizeof(T); i++) { uint8 tmp = (uint8)(value & 0xFF); add(tmp); value >>=8; } } ///add a vector to the sum template void addVector(const std::vector & vect) { for (typename std::vector::const_iterator it = vect.begin(); it != vect.end(); it++) add(*it); } uint32 getSum() { return _Sum; } private: ///the checsum result uint32 _Sum; ///the following values are used in the check algorithm uint32 _Factor; uint32 _Const1; uint32 _Const2; }; } #endif // NL_CDB_CHECK_SUM_H /* End of cdb_check_sum.h */ ================================================ FILE: code/nel/include/nel/misc/cdb_leaf.h ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef CDB_LEAF_H #define CDB_LEAF_H #include "cdb.h" #include "cdb_branch.h" #include "time_nl.h" #include "rgba.h" namespace NLMISC{ /** * Database node which contains a unique property * \author Stephane Coutelas * \author Nevrax France * \date 2002 */ class CCDBNodeLeaf : public ICDBNode { public: // flush all observers calls for modified nodes static void flushObserversCalls(); /// Return the value of the property. inline sint64 getValue64() { return _Property; } /// Set the value of the property (set '_Changed' flag with 'true'). void setValue64 (sint64 prop); inline sint32 getValue32() { return *((sint32*)&_Property); } void setValue32 (sint32 prop); inline sint16 getValue16() { return *((sint16*)&_Property); } void setValue16 (sint16 prop); inline sint8 getValue8() { return *((sint8*)&_Property); } void setValue8 (sint8 prop); inline bool getValueBool() { return (_Property!=(sint64)0 ); } void setValueBool (bool prop); inline CRGBA getValueRGBA() { CRGBA col; col.R = (uint8)(_Property&0xff); col.G = (uint8)((_Property>>8)&0xff); col.B = (uint8)((_Property>>16)&0xff); col.A = (uint8)((_Property>>24)&0xff); return col; } void setValueRGBA (const CRGBA &color); /// Return the value of the property before the database change inline sint64 getOldValue64() { return _oldProperty; } inline sint32 getOldValue32() { return *((sint32*)&_oldProperty); } inline sint16 getOldValue16() { return *((sint16*)&_oldProperty); } inline sint8 getOldValue8() { return *((sint8*)&_oldProperty); } inline bool getOldValueBool() { return (_oldProperty!=(sint64)0 ); } /// Return the type of the property. inline const EPropType &type() const {return _Type;} /// Set the property Type. inline void type(const EPropType &t) {_Type = t;} /// Return 'true' if the property changed since last call. inline const bool &changed() const {return _Changed;} /// Set the property flag to known if the property changed since last call. inline void changed(const bool &c) {_Changed = c;} /** * Default constructor */ CCDBNodeLeaf(const std::string &name) : ICDBNode(name) { _Parent=0; _Property = 0; _oldProperty = 0; _Type = UNKNOWN; _Changed = false; _LastChangeGC = 0; } /** * Build the structure of the database from a file * \param f is the stream */ void init( xmlNodePtr node, IProgressCallback &progressCallBack, bool mapBanks=false, CCDBBankHandler *bankHandler = NULL ); /** * Get a node * \param idx is the node index */ ICDBNode * getNode( uint16 idx ); /** * Get a node . Create it if it does not exist yet * \param id : the CTextId identifying the node */ ICDBNode * getNode (const CTextId& id, bool bCreate); /** * Get a node index * \param node is a pointer to the node */ virtual bool getNodeIndex( ICDBNode* /* node */, uint& /* index */) { return false; } /** * Save a backup of the database * \param id is the text id of the property/grp * \param f is the stream */ void write( CTextId& id, FILE * f); /** * Update the database from a stream coming from the FE * \param f : the stream. */ void readDelta(TGameCycle gc, CBitMemStream & f ); /** * Return the value of a property (the update flag is set to false) * \param id is the text id of the property/grp * \param name is the name of the property * \return the structure of the property */ sint64 getProp( CTextId& id ); /** * Set the value of a property (the update flag is set to true) * \param id is the text id of the property/grp * \param name is the name of the property * \param value is the value of the property * \return bool : 'false' if id is too long. */ bool setProp( CTextId& id, sint64 value ); /** * Set the value of a property, only if gc>=_LastChangeGC */ bool setPropCheckGC(TGameCycle gc, sint64 value); /// Reset all leaf data from this point void resetData(TGameCycle gc, bool forceReset=false); /** * Clear the node and his children */ void clear(); // the parent node for a branch (NULL by default) virtual void setParent(CCDBNodeBranch* parent) { _Parent=parent; } //get the node parent virtual CCDBNodeBranch *getParent() { return _Parent; } /// Count the leaves virtual uint countLeaves() const { return 1; } /// Find the leaf which count is specified (if found, the returned value is non-null and count is 0) virtual CCDBNodeLeaf *findLeafAtCount( uint& count ) { if ( count == 0 ) return this; else { --count; return NULL; } } /// Debug purpose virtual void display(const std::string &prefix); virtual bool isLeaf() const { return true; } /** * add an observer to a property * \param observer : pointer to an observer * \param id text id identifying the property * \return false if the node doen t exist */ virtual bool addObserver(IPropertyObserver* observer, CTextId& id); /** remove an obsever * \param observer : pointer to an observer * \param id text id identifying the property * \return false if the node or observer doesn t exist */ virtual bool removeObserver(IPropertyObserver* observer, CTextId& id); /// get the last change GameCycle (server tick) for this value TGameCycle getLastChangeGC() const {return _LastChangeGC;} private: CCDBNodeBranch * _Parent; /// property value sint64 _Property; sint64 _oldProperty; /// property type EPropType _Type; /// true if this value has changed bool _Changed; /// gamecycle (servertick) of the last change for this value. /// change are made in readDelta only for change >= _LastChangeGC TGameCycle _LastChangeGC; /// observers to call when the value really change std::vector _Observers; private: void notifyObservers(); }; //////////////////// // INLINE MEMBERS // //////////////////// } #endif // CDB_LEAF_H ================================================ FILE: code/nel/include/nel/misc/cdb_manager.h ================================================ // Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef CDB_MANAGER_H #define CDB_MANAGER_H #include "nel/misc/cdb_branch.h" #include "nel/misc/cdb_leaf.h" #include "nel/misc/cdb_bank_handler.h" #include "nel/misc/cdb_branch_observing_handler.h" namespace NLMISC{ /// Class that encapsulates the separate CDB components class CCDBManager{ public: /** The constructor @param maxBanks - The maximum number of banks to be used */ CCDBManager( const char *rootNodeName, uint maxBanks ); ~CCDBManager(); /** Returns the specified leaf node from the database. @param name The name of the leaf node. @param create Specifies if the node should be created if it doesn't exist yet. */ CCDBNodeLeaf* getDbLeaf( const std::string &name, bool create = true ); /** Returns the specified branch node from the database. @param name The name of the branch. */ CCDBNodeBranch* getDbBranch( const std::string &name ); /** Deletes the specified database node. @param name The name of the database node. */ void delDbNode( const std::string &name ); /** Adds an observer to a branch of the database. @param branchName The name of the branch we want to observe @param observer The observer we want to add @param positiveLeafNameFilter A vector of strings containing the names of the leaves we want to observe */ void addBranchObserver( const char *branchName, ICDBNode::IPropertyObserver *observer, const std::vector< std::string >& positiveLeafNameFilter = std::vector< std::string >() ); /** Adds an observer to a branch of the database. @param branch The branch we want to observe @param observer The observer we want to add @param positiveLeafNameFilter A vector of strings containing the names of the leaves we want to observe */ void addBranchObserver( CCDBNodeBranch *branch, ICDBNode::IPropertyObserver *observer, const std::vector< std::string >& positiveLeafNameFilter = std::vector< std::string >() ); /** Adds an observer to a branch of the database. @param branchName The name of the branch we start from @param dbPathFromThisNode The path to the branch we want to observe @param observer The observer we want to add @param positiveLeafNameFilter An array of strings containing the names of the leaves we want to observe @param positiveLeafNameFilterSize The size of the array */ void addBranchObserver( const char *branchName, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer, const char **positiveLeafNameFilter = NULL, uint positiveLeafNameFilterSize = 0 ); /** Adds an observer to a branch of the database. @param branch The branch we start from @param dbPathFromThisNode The path to the branch we want to observe @param observer The observer we want to add @param positiveLeafNameFilter An array of strings containing the names of the leaves we want to observe @param positiveLeafNameFilterSize The size of the array */ void addBranchObserver( CCDBNodeBranch *branch, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer, const char **positiveLeafNameFilter, uint positiveLeafNameFilterSize ); /** Removes an observer from a branch in the database. @param branchName The name of the branch @param observer The observer we want to remove */ void removeBranchObserver( const char *branchName, ICDBNode::IPropertyObserver* observer ); /** Removes an observer from a branch in the database. @param branch The branch @param observer The observer we want to remove */ void removeBranchObserver( CCDBNodeBranch *branch, ICDBNode::IPropertyObserver* observer ); /** Removes an observer from a branch in the database. @param branchName The name of the branch we start from @param dbPathFromThisNode The path to the branch we want to observe from the starting branch @param observer The observer we want to remove */ void removeBranchObserver( const char *branchName, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer ); /** Removes an observer from a branch in the database. @param branchName The name of the branch we start from @param dbPathFromThisNode The path to the branch we want to observe from the starting branch @param observer The observer we want to remove */ void removeBranchObserver( CCDBNodeBranch *branch, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer ); /** Adds a branch observer call flush observer. ( These are notified after the branch observers are notified ) @param observer The observer */ void addFlushObserver( CCDBBranchObservingHandler::IBranchObserverCallFlushObserver *observer ); /** Removes a branch observer call flush observer. @param observer The observer */ void removeFlushObserver( CCDBBranchObservingHandler::IBranchObserverCallFlushObserver *observer ); /** Notifies the observers whose observed branches were updated. */ void flushObserverCalls(); /** Resets the specified bank. @param gc GameCycle ( no idea what it is exactly, probably some time value ) @param bank The banks we want to reset */ void resetBank( uint gc, uint bank ); /** @brief Resizes the bank holders. WARNING: Resets data contained. @param newSize - The new maximum number of banks. */ void resizeBanks( uint newSize ); protected: CCDBBankHandler bankHandler; CCDBBranchObservingHandler branchObservingHandler; CRefPtr< CCDBNodeBranch > _Database; }; } #endif ================================================ FILE: code/nel/include/nel/misc/check_fpu.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CHECK_FPU_H #define NL_CHECK_FPU_H namespace NLMISC { class CFpuChecker { private: static int _RefFpuCtrl; void check(); void dumpFpu(int value); public: CFpuChecker(); ~CFpuChecker(); }; } // Enable define. Normal State is 0, to save CPU speed. #define NL_CHECK_FPU_CONTROL_WORD 0 // Use those Macros #if NL_CHECK_FPU_CONTROL_WORD #define FPU_CHECKER NLMISC::CFpuChecker __fpc__; #define FPU_CHECKER_ONCE { NLMISC::CFpuChecker __fpc__; } #else #define FPU_CHECKER #define FPU_CHECKER_ONCE #endif #endif // NL_CHECK_FPU_H ================================================ FILE: code/nel/include/nel/misc/class_id.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CLASS_ID_H #define NL_CLASS_ID_H #include "types_nl.h" namespace NLMISC { // *************************************************************************** /** * A unique id to specify Object by a uint64. * The Deriver should use a Max-like Id generator, to identify his own object. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CClassId { uint64 Uid; public: static const CClassId Null; public: CClassId() {Uid=0;} CClassId(uint32 a, uint32 b) {Uid= ((uint64)a<<32) | b;} CClassId(uint64 a) {Uid=a;} bool operator==(const CClassId &o) const {return Uid==o.Uid;} bool operator!=(const CClassId &o) const {return Uid!=o.Uid;} bool operator<=(const CClassId &o) const {return Uid<=o.Uid;} bool operator>=(const CClassId &o) const {return Uid>=o.Uid;} bool operator<(const CClassId &o) const {return Uid(const CClassId &o) const {return Uid>o.Uid;} //CClassId& operator=(const CClassId &o) { Uid = o.Uid; return *this;} operator uint64() const {return Uid;} }; /** * Class to be used as a hash traits for a hash_map accessed by CClassId * Ex: CHashMap< CClassId, CMyData, CClassIdHashMapTraits> _MyHashMap; */ class CClassIdHashMapTraits { public: enum { bucket_size = 4, min_buckets = 8, }; inline size_t operator() ( const CClassId& classId ) const { return ((((uint64)classId >> 32)|0xFFFFFFFF) ^ (((uint64)classId|0xFFFFFFFF) & 0xFFFFFFFF)); } bool operator() (const CClassId &classId1, const CClassId &classId2) const { return classId1 < classId2; } }; } #endif // NL_CLASS_ID_H /* End of class_id.h */ ================================================ FILE: code/nel/include/nel/misc/class_registry.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CLASS_REGISTRY_H #define NL_CLASS_REGISTRY_H #include "types_nl.h" #include "common.h" #include #include #include namespace NLMISC { // ====================================================================================================== /** * Class Registry Exception. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ struct ERegistry : public Exception { ERegistry() : Exception( "Registry error" ) {} ERegistry( const std::string& str ) : Exception( str ) {} }; struct ERegisteredClass : public ERegistry { ERegisteredClass() : ERegistry( "Class already registered" ) {} }; struct EUnregisteredClass : public ERegistry { EUnregisteredClass() : ERegistry( "Class not registered" ) {} EUnregisteredClass(const std::string &className) : ERegistry( std::string("Class not registered : ") + className ) {} }; // ====================================================================================================== /** * An Object Streamable interface. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class IClassable { public: virtual std::string getClassName() =0; virtual ~IClassable() {} }; // ====================================================================================================== /** * The Class registry where we can instanciate IClassable objects from their names. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CClassRegistry { public: /// Inits the ClassRegistry (especially RegistredClasses) static void init(); /// release memory static void release(); /// Register your class for future Instanciation. static void registerClass(const std::string &className, IClassable* (*creator)(), const std::string &typeidCheck) throw(ERegistry); /// Create an object from his class name. static IClassable *create(const std::string &className) throw(ERegistry); /// check if the object has been correctly registered. Must be used for debug only, and Must compile with RTTI. static bool checkObject(IClassable* obj); private: struct CClassNode { std::string TypeIdCheck; IClassable* (*Creator)(); }; typedef CHashMap TClassMap; static TClassMap *RegistredClasses; }; /// Useful Macros. #define NLMISC_DECLARE_CLASS(_class_) \ virtual std::string getClassName() {return #_class_;} \ static NLMISC::IClassable *creator() {return new _class_;} #define NLMISC_REGISTER_CLASS(_class_) NLMISC::CClassRegistry::registerClass(#_class_, _class_::creator, typeid(_class_).name()); } // namespace NLMISC. #endif // NL_STREAM_H /* End of stream.h */ ================================================ FILE: code/nel/include/nel/misc/cmd_args.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CMD_ARGS_H #define NL_CMD_ARGS_H // // Includes // #include #include "nel/misc/types_nl.h" #include "nel/misc/sstring.h" namespace NLMISC { class CCmdArgs { public: /// Sets the command line and init _Args variable. You must call this before calling main() void setArgs (int argc, const char **argv); /// Sets the command line and init _Args variable. You must call this before calling main() void setArgs (const char *args); /// Returns arguments of the program pass from the user to the program using parameters (ie: "myprog param1 param2") const NLMISC::CVectorSString &getArgs () const { return _Args; } /// Returns true if the argument if present in the command line (ie: haveArg('p') will return true if -p is in the command line) bool haveArg (char argName) const; /** Returns the parameter linked to an option * getArg('p') will return toto if -ptoto is in the command line * getArg('p') will return C:\Documents and Settings\toto.tmp if -p"C:\Documents and Settings\toto.tmp" is in the command line * It'll thrown an Exception if the argName is not found */ std::string getArg (char argName) const; /// return true if named long arg is present on the commandline /// eg haveLongArg("toto") returns true if "--toto" or "--toto=xxx" can be found on commandline bool haveLongArg (const char* argName) const; /// returns the value associated with the given named argument /// both "--toto=xxx" and "--toto xxx" are acceptable /// quotes round arguments are stripped std::string getLongArg (const char* argName) const; protected: /// Array of arguments pass from the command line NLMISC::CVectorSString _Args; }; // class CCmdArgs }; // NAMESPACE NLMISC #endif // NL_CMD_ARGS_H ================================================ FILE: code/nel/include/nel/misc/co_task.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CO_TASK_H #define NL_CO_TASK_H #include "types_nl.h" //#include namespace NLMISC { #if defined (NL_OS_WINDOWS) # define NL_WIN_CALLBACK CALLBACK #elif defined (NL_OS_UNIX) # define NL_WIN_CALLBACK #endif // Default to 8KB stack for tasks const unsigned int NL_TASK_STACK_SIZE = 8*1024; // forward def for platform specific data struct TCoTaskData; /** The coroutine task class encapsulate the coroutines detail and provide * an easy to use simple master/slave coroutine model. * The concept is that the main thread is the 'master' (or parent) coroutine * and that the task is run by a slave coroutine. * Therefore, you can 'start' the task, 'yield' the focus from the task to it's * parent, 'resume' the task from the parent, check for termination of the task, * and/or wait for it. * * Note that for safety reasons, the CCoTask do not provide mean to for * the termination of the task. Like for threads, 'killing' a task while * destroy the task stack without calling destructor of any object create * on the stack. This can lead to memory leaks or atomic destruction of * earth (if used inside an ICBM control program). * So, as a rule of thumb, (valid for thread as well), you should always * design your code so your coroutines are cleanly terminated before * your program end. * * If you don't know about coroutines, a short description follow : * * Coroutines are some sort of multi-threading * * Coroutines are not preemptive, it's the application code that choose * task swapping point * * thus, coroutines don't need heavy synchronization (like mutex) * * coroutines are said to be lighter than thread during context switch * * coroutines don't replace preemptives threads, they have their own application domain * * * Please note that this class is really simple (compared to what can be done with coroutines) * but match the need for a very simple mean to have two task running side by side with * predefined sync point. * You can build the same think using thread and mutex, but it will be a lot more complex * to build and debug. * * A simple sample : * CMyTask : public CCoTask * { * public: * void run() * { * for (uint i=0; i<7; ++i) * { * printf("CoTask : %i\n", i) * // leave control to parent task * yield(); * } * } * }; * * uint main() * { * CMyTask task; * // start the task, block until task terminate or call 'yield' * task.resume(); * * for (uint i=0; i<5; ++i) * { * printf("Main : %i\n", i); * // let the task run a bit * task.resume(); * } * * // wait for task completion * task.wait(); * } * * This little proggy will output the following : * *********** Output ************* * CoTask : 1 * Main : 1 * CoTask : 2 * Main : 2 * CoTask : 3 * Main : 3 * CoTask : 4 * Main : 4 * CoTask : 5 * CoTask : 6 * *********** End of output ******** * * */ class CCoTask { /// Flag stating if the task is started or not bool _Started; /// Flag statig if the task should terminate as soon as possible bool _TerminationRequested; /// Flag stating if the task is finished (run() have returned) bool _Finished; /// Pointer on internal platform specific data TCoTaskData *_PImpl; friend struct TCoTaskData; /// Coroutine bootstrap function void start(); public: /** Get the current task object. * Return NULL if the current thread context is not in a CCoTask coroutine */ static CCoTask *getCurrentTask(); /** Constructor with stack size for the task. * The default stack size is 8 KB because it sound cool and because * I found many coroutine code that use a 8 KB stack. * If you need to start many (more than some 10th) tasks with very * little stack usage, you could reduce you coroutine memory overhead * by lowering the stack size. */ CCoTask(uint stackSize = NL_TASK_STACK_SIZE); /** Destructor. If the task is running, set the termination requested flag * and resume the task until it terminate. * If you task is badly designed, your destructor will never return, waiting * indefinitely for the task to terminate. */ virtual ~CCoTask(); /* Start or resume task execution. * If called from the current task context, do nothing (execution continue in the * current task) */ void resume(); /// to call from the task, yield execution focus to parent task void yield(); /** Check if task is started. * A task is not started until you call resume(). */ bool isStarted() { return _Started; } /// check for task completion bool isFinished() { return _Finished; } /// parent task ask for task ending (run function should check this and terminate asap) void requestTerminate(); /** check if termination request have been called (mainly used by task user code * to check for terminating the task on request). */ bool isTerminationRequested() { return _TerminationRequested; } /** Called by parent task, wait until the task terminate. Note obviously that this call can lead to an * infinite wait if the task function is not willing to terminate itself. */ void wait(); /** the run method to implement by the derived class. This is where * you put the co routine code. * Coroutine terminate when this method return. */ virtual void run() =0; /** Wait (using 'yield') until some amount of time (in milliseconds) has ellapsed, or until termination is requested. * This should be called inside this task 'run()', else an assertion is raised */ void sleep(uint milliseconds); }; } // namespace NLMISC #endif // NL_CO_TASK_H ================================================ FILE: code/nel/include/nel/misc/command.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_COMMAND_H #define NL_COMMAND_H #include "types_nl.h" #include "twin_map.h" #include #include #include #include //#include #include #include "stream.h" #include "config_file.h" #include "log.h" namespace NLMISC { /** WARNING: * This is standard Unix linker behavior: object files * that are not referenced from outside are discarded. The * file in which you run your constructor is thus simply * thrown away by the linker, which explains why the constructor * is not run. */ /** * Create a function that can be call in realtime. * * Example: * \code // I want to create a function that computes the square of the parameter and display the result NLMISC_COMMAND(square,"display the square of the parameter","") { // check args, if there s not the right number of parameter, return bad if(args.size() != 1) return false; // get the value uint32 val; fromString(args[0], val); // display the result on the displayer log.displayNL("The square of %d is %d", val, val*val); return true; } * \endcode * * Please use the same casing than for the function (first letter in lower case and after each word first letter in upper case) * ie: myFunction, step, orderByName, lookAtThis * * System extended by Sadge July 2004 * - NLMISC_CATEGORISED_COMMAND now takes a 4th 'category' parameter which is used by 'help' system to organise cmmands * - All default commands added by NeL are categorised as "nel" * - All commands created using the NLMISC_COMMAND macro are are categorised as "commands" * * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ #define NLMISC_COMMAND(__name,__help,__args) NLMISC_CATEGORISED_COMMAND(commands,__name,__help,__args) #define NLMISC_CATEGORISED_COMMAND(__category,__name,__help,__args) \ struct __category##_##__name##Class: public NLMISC::ICommand \ { \ __category##_##__name##Class() : NLMISC::ICommand(#__category,#__name,__help,__args) { } \ virtual bool execute(const std::string &rawCommandString, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human); \ }; \ __category##_##__name##Class __category##_##__name##Instance; \ bool __category##_##__name##Class::execute(const std::string &rawCommandString, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human) /** Helper to declare a command as friend of a class. * Useful when you want to declare debug command that access private class method or data. */ #define NLMISC_COMMAND_FRIEND(__name) friend struct commands_##__name##Class #define NLMISC_CATEGORISED_COMMAND_FRIEND(__category,__name) friend struct __category##_##__name##Class /** * Create a function that can be call in realtime. Don't use this class directly but use the macro NLMISC_COMMAND * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class ICommand { public: /// Constructor ICommand(const char *categoryName, const char *commandName, const char *commandHelp, const char *commandArgs); virtual ~ICommand(); // quiet means that we don't display anything else than the value // human means that we want the value in a human readable if possible virtual bool execute(const std::string &rawCommandString, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human = true) = 0; std::string CategoryName; std::string HelpString; std::string CommandArgs; // is it a variable or a classic command? enum TType { Unknown, Command, Variable }; TType Type; // static members typedef std::map TCommand; // typedef std::set TCategorySet; static TCommand *LocalCommands; // static TCategorySet *LocalCategories; // static TCommand *LocalCommands; static bool LocalCommandsInit; /// Executes the command and display output to the log /// \param quiet true if you don't want to display the "executing the command ..." static bool execute (const std::string &commandWithArgs, NLMISC::CLog &log, bool quiet = false, bool human = true); /** Command name completion. * Case-sensitive. Displays the list after two calls with the same non-unique completion. * Completes commands used with prefixes (such as "help " for example) as well. */ static void expand (std::string &commandName, NLMISC::CLog &log=*InfoLog); static void serialCommands (IStream &f); /// returns true if the command exists static bool exists (std::string const &commandName); /// if the string begin with an upper case, it s a variable, otherwise, it s a command static bool isCommand (const std::string &str); /// Retrieve the interface over command object for the given command name. static ICommand *getCommand(const std::string &commandName); const std::string &getName () const { return _CommandName; } /** declare a command to "enable control char". By default all commands "enable control char" * * eg: if enableControlCharForCommand("region", false) is called, then the command: * * region hello; "i am busy" \never disturb me please * * won't treat '"', '\' and ';' as special control character. * Thus the final list of args will be (separated by '/' here for clarity): * * hello;/"i/am/busy"/\never/disturb/me/please */ static void enableControlCharForCommand(const std::string &commandName, bool state); /// see enableControlCharForCommand() static bool isControlCharForCommandEnabled(const std::string &commandName); protected: std::string _CommandName; }; /** Struct to host data for one object command * \author Boris 'SoniX' Boucher * \author Nevrax France * \date 2005 */ struct TCommandHandlerInfo { /// The help string of the command std::string CommandHelp; /// The argument required for the command std::string CommandArgs; /// A comparison operator need for STL container storage bool operator ==(const TCommandHandlerInfo &other) const { return (CommandHelp == other.CommandHelp) && (CommandArgs == other.CommandArgs); } }; /** Struct to host data for all the commands of an object class * \author Boris 'SoniX' Boucher * \author Nevrax France * \date 2005 */ struct TCommandHandlerClassInfo { /// Number of instance of object of this class uint32 InstanceCount; /// The list of command available on this class of object. typedef std::map TCommandsInfo; TCommandsInfo _Commands; /// Constructor. TCommandHandlerClassInfo() : InstanceCount(0) {} }; /** Base class for command handler. * Command handler are a mean to build object that support NeL commands * _Commands are associated to object class and invoked to named instance. * Each named instance must have a unique name (whatever it's class). * Unlike NeL global commands, object commands are invoked in the context * of the object instance. * * In order to write an object that support commands, you must devive from * template CCommandsHandler. The class ICommandsHandler * is used by the command registry to handle any type of object. * * \author Boris 'SoniX' Boucher * \author Nevrax France * \date 2005 */ class ICommandsHandler { /// Store the class name after handler registration const std::string *_ClassName; public: ICommandsHandler(); /** The derived class call this method to register the instance in * the command registry. * Before calling this method, the object is not available for * commands invocation. */ void registerCommandsHandler(); /** The derived class call this method to unregister the instance in * the command registry. * After this call, the object is no more liste in named object * list nor it can receive command invocation. * You can later re-register the object. */ void unregisterCommandsHandler(); virtual const std::string &getCommandHandlerClassName() const =0; /** This methods implemented by CCommandHandler is used by the * command registry to retrieve the name of the object instance. */ virtual const std::string &getCommandHandlerName() const =0; /** This methods implemented by CCommandHandler is used by the * command registry to build the list of available commands * on the object class. */ virtual void fillCommandsHandlerList(TCommandHandlerClassInfo::TCommandsInfo &commandList) =0; /** Virtual destructor to unregister the object instance. * When all the instance of a given class are deleted, * the associated command an class information are * removed from the command registry. */ virtual ~ICommandsHandler(); /** This methods implemented by CCommandHandler is used by the * command registry to start a command execution. */ virtual bool execute(const std::string &rawCommandString, const std::string &commandName, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human = true) =0; }; template struct TCommandHandler : public TCommandHandlerInfo { typedef bool (T::*TCommand)(const std::string &rawCommandString, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human); TCommand CommandHandler; }; /** Template class used as base for derivation of object that support commands. * To declare your object supporting commands, you must * derive from this class with your class type as template parameter. * * e.g : * class CMyClass : public CCommandsHandler * { * }; * * To easily generate the command table, NeL provide some macros : * * class CMyClass : public CCommandsHandler * { * public: * * NLMISC_COMMAND_HANDLER_TABLE_BEGIN(CMyClass) * NLMISC_COMMAND_HANDLER_ADD(CMyClass, theCommand1, "help", "args") * NLMISC_COMMAND_HANDLER_ADD(CMyClass, theCommand2, "other help", "other args") * NLMISC_COMMAND_HANDLER_TABLE_END * * NLMISC_CLASS_COMMAND_DECL(theCommand1) * { * // put yout code here * } * * NLMISC_CLASS_COMMAND_DECL(theCommand2) * { * // put yout code here * } * }; * * You can also derive a class and add some more commands in the * derived class by using NLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN: * * class CMyDerivedClass : public CMyClass * { * NLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(CMyClass) * NLMISC_COMMAND_HANDLER_ADD(CMyClass, addedCommand, "help", "args") * NLMISC_COMMAND_HANDLER_TABLE_END * * NLMISC_CLASS_COMMAND_DECL(addedCommand) * { * // put yout code here * } * }; * * \author Boris 'SoniX' Boucher * \author Nevrax France * \date 2005 */ //template //class CCommandsHandler : public ICommandsHandler //{ //public: // /** Constructor, used to initialise the class name in the interface class */ //// CCommandsHandler() //// : ICommandsHandler(T::getCommandHandlerClassName()) //// { //// } //// // /** Virtual pure method used by execute to retrieve the method pointer. // * This method will be automatically implemented by the NLMISC_COMMAND_HANDLER_TABLE_BEGIN // * macro utility. // */ //// virtual TCommand getCommandHandler(const std::string &commandName) =0; // // /** Execute a command. // * Return false if no command of the name exist. // */ //// bool execute(const std::string &rawCommandString, const std::string &commandName, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human = true) //// { //// TCommand cmd = getCommandHandler(commandName); //// if (cmd != NULL) //// { //// T* tp = static_cast(this); //// return (tp->*cmd)(rawCommandString, args, log, quiet, human); //// } //// else //// { //// log.displayNL("Command on object '%s' : unknow command '%s'", //// getCommandHandlerName().c_str(), //// commandName.c_str()); //// return false; //// } //// } //}; /** Macro to start a command handler table. * Use it inside the class declaration. */ #define NLMISC_COMMAND_HANDLER_TABLE_BEGIN(className) \ /* Typedef a method pointer on the template class. */ \ /* This type is the type of the command handler method.*/ \ /* It have the same signature as global NeL commands. */ \ typedef bool (className::*TCommand)(const std::string &rawCommandString, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human); \ \ /** Typedef for a container for command handler table. */ \ typedef std::map > TCommandsTable; \ \ virtual const std::string &getCommandHandlerClassName() const\ { \ static std::string className(#className); \ return className; \ } \ TCommand className##_getCommandHandler(const std::string &commandName) \ { \ TCommandsTable commandTable = className##_getCommandsHandlerTable(); \ TCommandsTable::iterator it = commandTable.find(commandName); \ \ if (it != commandTable.end()) \ { \ /** ok, we have the command handler*/ \ return it->second.CommandHandler; \ } \ else \ return NULL; \ } \ virtual bool execute(const std::string &rawCommandString, const std::string &commandName, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human) \ { \ TCommand cmd = className##_getCommandHandler(commandName); \ if (cmd != NULL) \ { \ if (!quiet)\ log.displayNL("Execute command: %s", rawCommandString.c_str()); \ return (this->*cmd)(rawCommandString, args, log, quiet, human); \ } \ else \ { \ log.displayNL("Command on object '%s' : unknow command '%s'", \ getCommandHandlerName().c_str(), \ commandName.c_str()); \ return false; \ } \ } \ virtual void fillCommandsHandlerList(NLMISC::TCommandHandlerClassInfo::TCommandsInfo &commandList) \ { \ const TCommandsTable &commandTable = className##_getCommandsHandlerTable(); \ TCommandsTable::const_iterator first(commandTable.begin()), last(commandTable.end()); \ for (; first != last; ++first) \ { \ commandList.insert(std::make_pair(first->first, first->second)); \ } \ } \ \ const TCommandsTable &className##_getCommandsHandlerTable() \ { \ static bool initialized = false; \ static TCommandsTable commandsTable; \ \ if (!initialized) \ { \ initialized = true; \ /** Macro to add a handler in the handler table. * Use this macro between NLMISC_COMMAND_HANDLER_TABLE_BEGIN and * NLMISC_COMMAND_HANDLER_TABLE_END macros. * * The command name must match a method of the class with * a command signature. * You can easily declare command method using the macro * NLMISC_CLASS_COMMAND_DECL * */ #define NLMISC_COMMAND_HANDLER_ADD(className, theCommandName, theCommandHelp, theCommandArgs) \ { \ NLMISC::TCommandHandler ch; \ ch.CommandArgs = theCommandArgs; \ ch.CommandHelp = theCommandHelp; \ ch.CommandHandler = &className::cmdHandler_##theCommandName; \ commandsTable.insert(std::make_pair(std::string(#theCommandName), ch)); \ } \ /** Macro to end the command handler table. * Must be put after the last command handler adding. */ #define NLMISC_COMMAND_HANDLER_TABLE_END \ } \ return commandsTable; \ } \ /** Macro to add commands in a class that derive from a class * that already declare a command handler table. * the most derivative class will override base class commands * if they have the same name. */ #define NLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(className, baseClassName) \ typedef bool (className::*TCommand)(const std::string &rawCommandString, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human); \ typedef std::map > TCommandsTable; \ virtual const std::string &getCommandHandlerClassName() const\ { \ static std::string className(#className); \ return className; \ } \ TCommand className##_getCommandHandler(const std::string &commandName) \ { \ TCommandsTable commandTable = className##_getCommandsHandlerTable(); \ TCommandsTable::iterator it = commandTable.find(commandName); \ \ if (it != commandTable.end()) \ { \ /* ok, we have the command handler*/ \ return it->second.CommandHandler; \ } \ else \ { \ return NULL;\ } \ } \ virtual bool execute(const std::string &rawCommandString, const std::string &commandName, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human) \ { \ TCommand cmd = className##_getCommandHandler(commandName); \ if (cmd != NULL) \ { \ return (this->*cmd)(rawCommandString, args, log, quiet, human); \ } \ else \ { \ /* try with the base class */ \ return baseClassName::execute(rawCommandString, commandName, args, log, quiet, human);\ } \ } \ virtual void fillCommandsHandlerList(NLMISC::TCommandHandlerClassInfo::TCommandsInfo &commandList) \ { \ const TCommandsTable &commandTable = className##_getCommandsHandlerTable(); \ TCommandsTable::const_iterator first(commandTable.begin()), last(commandTable.end()); \ for (; first != last; ++first) \ { \ commandList.insert(std::make_pair(first->first, first->second)); \ } \ /* call base class to complete the command table */ \ baseClassName::fillCommandsHandlerList(commandList); \ } \ \ const TCommandsTable &className##_getCommandsHandlerTable() \ { \ static bool initialized = false; \ static TCommandsTable commandsTable; \ \ if (!initialized) \ { \ initialized = true; \ // A macro to declare or implement inline the command method #define NLMISC_CLASS_COMMAND_DECL(commandName) \ bool cmdHandler_##commandName(const std::string &rawCommandString, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human) // A macro to implement the command method in a cpp (you still need to declare it in the class scope using the previous macro) #define NLMISC_CLASS_COMMAND_IMPL(className, commandName) \ bool className::cmdHandler_##commandName(const std::string &rawCommandString, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human) // A macro to recall a base class command implementation #define NLMISC_CLASS_COMMAND_CALL_BASE(baseClassName, commandName)\ baseClassName::cmdHandler_##commandName(rawCommandString, args, log, quiet, human) /** The command registry is a singleton that hold all available * commands. * It bridge the legacy global commands and variable with * the object commands. * * All the legacy static call made on ICommand are now forwarded * directly to this class (e.g. IService::execute) * * This class is modeled after the safe singlton pattern, * so it is safe to use in a dynamicaly loaded library * program. * * \author Boris 'SoniX' Boucher * \author Nevrax France * \date 2005 */ class CCommandRegistry { // this class is a safe singleton (dll friendly) NLMISC_SAFE_SINGLETON_DECL(CCommandRegistry); CCommandRegistry() {} NLMISC_CATEGORISED_COMMAND_FRIEND(nel, help); friend void cbVarChanged (CConfigFile::CVar &var); friend class ICommand; friend class ICommandsHandler; friend class INelContext; typedef std::map TCommand; typedef std::set TCategorySet; /// List of commands categories TCategorySet _Categories; /// List of available command TCommand _Commands; typedef CTwinMap TCommandsHandlers; /// Registry for commands handlers named instance TCommandsHandlers _CommandsHandlers; typedef std::map TCommandsHandlersClass; /// Registry for commands name and handler class TCommandsHandlersClass _CommandsHandlersClass; std::set _CommandsDisablingControlChar; /// Used by ICommand to register themselves void registerCommand(ICommand *command); /// Used by ICommand to unregister themselves void unregisterCommand(ICommand *command); public: /// Called by command handlers to register themselves. void registerNamedCommandHandler(ICommandsHandler *handler, const std::string &className); /// Called by command handlers to unregister themselves. void unregisterNamedCommandHandler(ICommandsHandler *handler, const std::string &className); /// Executes the command and display output to the log /// \param quiet true if you don't want to display the "executing the command ..." bool execute (const std::string &commandWithArgs, NLMISC::CLog &log, bool quiet = false, bool human = true); /** Command name completion. * Case-sensitive. Displays the list after two calls with the same non-unique completion. * Completes commands used with prefixes (such as "help " for example) as well. */ void expand (std::string &commandName, NLMISC::CLog &log=*InfoLog); void serialCommands (IStream &f); /// returns true if the command exists bool exists (std::string const &commandName); /// Return true if a named command handler with that name is registered bool isNamedCommandHandler(const std::string &handlerName); /// if the string begin with an upper case, it s a variable, otherwise, it s a command bool isCommand (const std::string &str); /// Retrieve the interface over command object for the given command name. ICommand *getCommand(const std::string &commandName); /** declare a command to "enable control char". By default all commands "enable control char" * * eg: if enableControlCharForCommand("region", false) is called, then the command: * * region hello; "i am busy" \never disturb me please * * won't treat '"', '\' and ';' as special control character. * Thus the final list of args will be (separated by '/' here for clarity): * * hello;/"i/am/busy"/\never/disturb/me/please */ void enableControlCharForCommand(const std::string &commandName, bool state); /// see enableControlCharForCommand() bool isControlCharForCommandEnabled(const std::string &commandName); // initialisation for IVariable management (variable are an extension of commands) void initVariables(NLMISC::CConfigFile &configFile); }; /** This class is only used to serialize easily a command for the admin service for example */ struct CSerialCommand { CSerialCommand () : Name (""), Type(ICommand::Unknown) { } CSerialCommand (std::string n, ICommand::TType t) : Name (n), Type(t) { } std::string Name; ICommand::TType Type; void serial (IStream &f) { f.serial (Name); f.serialEnum (Type); } }; } // NLMISC #endif // NL_COMMAND_H /* End of command.h */ ================================================ FILE: code/nel/include/nel/misc/common.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_COMMON_H #define NL_COMMON_H #include "types_nl.h" #include #include #include #include #include #include #include #include #include #include #ifdef NL_OS_WINDOWS # include # include #else # include # include #endif #include "string_common.h" #ifdef NL_OS_WINDOWS struct nameHWND__; typedef struct HWND__ *HWND; typedef HWND nlWindow; #define EmptyWindow NULL #elif defined(NL_OS_MAC) // TODO This should be NSView*, but then we would need to include Cocoa.h // and compile with "-x objective-c++" ... everything including this file. typedef void* nlWindow; #define EmptyWindow NULL #elif defined(NL_OS_UNIX) typedef int nlWindow; #define EmptyWindow 0 #endif /// This namespace contains all miscellaneous classes used by other modules namespace NLMISC { /** Read the time stamp counter. Supports only Intel architectures for now */ #ifdef NL_CPU_INTEL inline uint64 rdtsc() { uint64 ticks; # ifdef NL_OS_WINDOWS # ifdef NL_NO_ASM ticks = uint64(__rdtsc()); # else // We should use the intrinsic code now. ticks = uint64(__rdtsc()); __asm rdtsc __asm mov DWORD PTR [ticks], eax __asm mov DWORD PTR [ticks + 4], edx # endif // NL_NO_ASM # else __asm__ volatile(".byte 0x0f, 0x31" : "=a" (ticks.low), "=d" (ticks.high)); # endif // NL_OS_WINDOWS return ticks; } #endif // NL_CPU_INTEL /** breakable statement, used to allow break call inside parenthesis. */ #define breakable \ switch(1) case 1: default: /** Pi constant in double format. */ const double Pi = 3.1415926535897932384626433832795; // retrieve size of a static array #define sizeofarray(v) (sizeof(v) / sizeof((v)[0])) /** Return a float random inside the interval [0,mod] */ inline float frand(float mod) { double r = (double) rand(); r/= (double) RAND_MAX; return (float)(r * mod); } /** Return -1 if f<0, 0 if f==0, 1 if f>1 */ inline sint fsgn(double f) { if(f<0) return -1; else if(f>0) return 1; else return 0; } /** Return the square of a number */ template inline T sqr(const T &v) { return v * v; } /** Force v to be inside the interval [min,max]. Warning: implicit cast are made if T,U or V are different. */ template inline void clamp(T &v, const U &min, const V &max) { v = (v < min) ? min : v; v = (v > max) ? max : v; } /** MIN/MAX extended functions. */ template inline T minof(const T& a, const T& b, const T& c) {return std::min(std::min(a,b),c);} template inline T minof(const T& a, const T& b, const T& c, const T& d) {return std::min(minof(a,b,c),d);} template inline T minof(const T& a, const T& b, const T& c, const T& d, const T& e) {return std::min(minof(a,b,c,d),e);} template inline T maxof(const T& a, const T& b, const T& c) {return std::max(std::max(a,b),c);} template inline T maxof(const T& a, const T& b, const T& c, const T& d) {return std::max(maxof(a,b,c),d);} template inline T maxof(const T& a, const T& b, const T& c, const T& d, const T& e) {return std::max(maxof(a,b,c,d),e);} /** \c contReset take a container like std::vector or std::deque and put his size to 0 like \c clear() but free all buffers. * This function is useful because \c resize(), \c clear(), \c erase() or \c reserve() methods never realloc when the array size come down. * \param a is the container to reset. */ template inline void contReset (T& a) { a.~T(); new (&a) T; } /** Return the value maximized to the next power of 2 of v. * Example: * raiseToNextPowerOf2(8) is 8 * raiseToNextPowerOf2(5) is 8 */ uint raiseToNextPowerOf2 (uint v); /** Return the power of 2 of v. * Example: * getPowerOf2(8) is 3 * getPowerOf2(5) is 3 */ uint getPowerOf2 (uint v); /** Return \c true if the value is a power of 2. */ bool isPowerOf2 (sint32 v); /** Converts from degrees to radians */ inline float degToRad( float deg ) { return deg * (float)Pi / 180.0f; } /** Converts from radians to degrees */ inline float radToDeg( float rad ) { return rad * 180.0f / (float)Pi; } /** Return true if double is a valid value (not inf nor nan) */ inline double isValidDouble (double v) { #ifdef NL_OS_WINDOWS return _finite(v) && !_isnan(v); #else #ifdef _STLPORT_VERSION return !isnan(v) && !isinf(v); #else return !std::isnan(v) && !std::isinf(v); #endif #endif } /** Convert a string in lower case. * \param str a string to transform to lower case */ std::string toLower ( const std::string &str ); void toLower ( char *str ); char toLower ( const char ch ); // convert only one character /** Convert a string in upper case. * \param a string to transform to upper case */ std::string toUpper ( const std::string &str); void toUpper ( char *str); // Remove all the characters <= 32 (tab, space, new line, return, vertical tab etc..) at the beginning and at the end of a string template T trim (const T &str) { typename T::size_type start = 0; const typename T::size_type size = str.size(); while (start < size && str[start] <= 32) start++; typename T::size_type end = size; while (end > start && str[end-1] <= 32) end--; return str.substr (start, end-start); } // remove spaces at the end of the string template T trimRightWhiteSpaces (const T &str) { typename T::size_type end = str.size(); while (end > 0 && str[end-1] == ' ') end--; return str.substr (0, end); } ////////////////////////////////////////////////////////////////////////// // **** DEPRECATED *****: PLEASE DON'T USE THESE METHODS BUT FUNCTIONS ABOVE toLower() and toUpper() ////////////////////////////////////////////////////////////////////////// inline std::string &strlwr ( std::string &str ) { str = toLower(str); return str; } inline std::string strlwr ( const std::string &str ) { return toLower(str); } inline char *strlwr ( char *str ) { toLower(str); return str; } inline std::string &strupr ( std::string &str ) { str = toUpper(str); return str; } inline std::string strupr ( const std::string &str ) { return toUpper(str); } inline char *strupr ( char *str ) { toUpper(str); return str; } /** Compare 2 C-Style strings without regard to case * \return 0 if strings are equal, < 0 if lhs < rhs, > 0 if lhs > rhs * * On Windows, use stricmp * On GNU/Linux, create stricmp using strcasecmp and use stricmp */ #ifndef NL_OS_WINDOWS inline int stricmp(const char *lhs, const char *rhs) { return strcasecmp(lhs, rhs); } inline int strnicmp(const char *lhs, const char *rhs, size_t n) { return strncasecmp(lhs, rhs, n); } #endif inline sint nlstricmp(const char *lhs, const char *rhs) { return stricmp(lhs, rhs); } inline sint nlstricmp(const std::string &lhs, const std::string &rhs) { return stricmp(lhs.c_str(), rhs.c_str()); } inline sint nlstricmp(const std::string &lhs, const char *rhs) { return stricmp(lhs.c_str(),rhs); } inline sint nlstricmp(const char *lhs, const std::string &rhs) { return stricmp(lhs,rhs.c_str()); } /** Signed 64 bit fseek. Same interface as fseek */ int nlfseek64( FILE *stream, sint64 offset, int origin ); // Retrieve position in a file, same interface as ftell sint64 nlftell64(FILE *stream); /** * Base class for all NeL exception. * It enables to construct simple string at the ctor. */ class Exception : public std::exception { protected: std::string _Reason; public: Exception(); Exception(const std::string &reason); Exception(const char *format, ...); virtual ~Exception() throw() {} virtual const char *what() const throw(); }; /** * Portable Sleep() function that suspends the execution of the calling thread for a number of milliseconds. * Note: the resolution of the timer is system-dependant and may be more than 1 millisecond. */ void nlSleep( uint32 ms ); /// Returns Process Id (note: on Linux, Process Id is the same as the Thread Id) #ifdef NL_OS_WINDOWS # define getpid _getpid #endif /// Returns Thread Id (note: on Linux, Process Id is the same as the Thread Id) size_t getThreadId(); /// Returns a readable string from a vector of bytes. unprintable char are replaced by '?' std::string stringFromVector( const std::vector& v, bool limited = true ); /// Convert a string into an sint64 (same as atoi() function but for 64 bits intergers) sint64 atoiInt64 (const char *ident, sint64 base = 10); /// Convert an sint64 into a string (same as itoa() function but for 64 bits intergers) char* itoaInt64 (sint64 number, char *str, sint64 base = 10); /// Convert a number in bytes into a string that is easily readable by an human, for example 105123 -> "102kb" std::string bytesToHumanReadable (const std::string &bytes); std::string bytesToHumanReadable (uint64 bytes); /// Convert a human readable into a bytes, for example "102kb" -> 105123 uint32 humanReadableToBytes (const std::string &str); /// Convert a time into a string that is easily readable by an human, for example 3600 -> "1h" std::string secondsToHumanReadable (uint32 time); /// Get a bytes or time in string format and convert it in seconds or bytes uint32 fromHumanReadable (const std::string &str); /// Add digit grouping seperator to if value >= 10 000. Assumes input is numerical string. std::string formatThousands(const std::string& s); /// This function executes a program in the background and returns instantly (used for example to launch services in AES). /// The program will be launched in the current directory bool launchProgram (const std::string &programName, const std::string &arguments); /// This function kills a program using his pid (on unix, it uses the kill() POSIX function) bool killProgram(uint32 pid); /// This function kills a program using his pid with abort signal (on unix, it uses the kill() POSIX function) bool abortProgram(uint32 pid); /** Returns a string corresponding to the class T in string format. * Example: * string num = toString (1234); // num = "1234"; */ /*acetemplate std::string toString (const T &t) { std::stringstream ss; ss << t; return ss.str(); } */ /** Returns a string corresponding to the format and parameter (like printf). * Example: * string hexnum = toString ("%x", 255); // hexnum = "ff"; */ /*#ifdef NL_OS_WINDOWS inline std::string _toString (const char *format, ...) #else inline std::string toString (const char *format, ...) #endif { std::string Result; NLMISC_CONVERT_VARGS (Result, format, NLMISC::MaxCStringSize); return Result; } #ifdef NL_OS_WINDOWS CHECK_TYPES(std::string toString, return _toString) #endif // NL_OS_WINDOWS #ifdef NL_OS_UNIX inline std::string toString (const uint8 &t) { std::stringstream ss; ss << (unsigned int)t; return ss.str(); } inline std::string toString (const sint8 &t) { std::stringstream ss; ss << (unsigned int)t; return ss.str(); } #endif // NL_OS_UNIX */ /** Explode a string (or ucstring) into a vector of string with *sep* as separator. If sep can be more than 1 char, in this case, * we find the entire sep to separator (it s not a set of possible separator) * * \param skipEmpty if true, we don't put in the res vector empty string */ template void explode (const T &src, const T &sep, std::vector &res, bool skipEmpty = false) { std::string::size_type oldpos = 0, pos; res.clear (); do { pos = src.find (sep, oldpos); T s; if(pos == std::string::npos) s = src.substr (oldpos); else s = src.substr (oldpos, (pos-oldpos)); if (!skipEmpty || !s.empty()) res.push_back (s); oldpos = pos+sep.size(); } while(pos != std::string::npos); } /* All the code above is used to add our types (uint8, ...) in the stringstream (used by the toString() function). * So we can use stringstream operator << and >> with all NeL simple types (except for ucchar and ucstring) */ /* #ifdef NL_OS_WINDOWS #if _MSC_VER < 1300 // visual or older (on visual .NET, we don't need to do that) #define NLMISC_ADD_BASIC_ISTREAM_OPERATOR(__type,__casttype) \ template \ std::basic_istream<_CharT, _Traits>& __cdecl \ operator>>(std::basic_istream<_CharT, _Traits>& __is, __type& __z) \ { \ __casttype __z2 = (__casttype) __z; \ __is.operator>>(__z2); \ __z = (__type) __z2; \ return __is; \ } \ \ template \ std::basic_ostream<_CharT, _Traits>& __cdecl \ operator<<(std::basic_ostream<_CharT, _Traits>& __os, const __type& __z) \ { \ std::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __tmp; \ __tmp << (__casttype) __z; \ return __os << __tmp.str(); \ } NLMISC_ADD_BASIC_ISTREAM_OPERATOR(uint8, unsigned int); NLMISC_ADD_BASIC_ISTREAM_OPERATOR(sint8, signed int); NLMISC_ADD_BASIC_ISTREAM_OPERATOR(uint16, unsigned int); NLMISC_ADD_BASIC_ISTREAM_OPERATOR(sint16, signed int); NLMISC_ADD_BASIC_ISTREAM_OPERATOR(uint32, unsigned int); NLMISC_ADD_BASIC_ISTREAM_OPERATOR(sint32, signed int); #endif // _MSC_VER < 1300 template std::basic_istream<_CharT, _Traits>& __cdecl operator>>(std::basic_istream<_CharT, _Traits>& __is, uint64& __z) { __z = 0; bool neg = false; char c; do { __is >> c; } while (isspace(c)); if (c == '-') { neg = true; __is >> c; } while (isdigit(c)) { __z *= 10; __z += c-'0'; __is >> c; if (__is.fail()) break; } if (neg) __z = 0; return __is; } template std::basic_ostream<_CharT, _Traits>& __cdecl operator<<(std::basic_ostream<_CharT, _Traits>& __os, const uint64& __z) { std::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __res; if (__z == 0) { __res << '0'; } else { std::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __tmp; uint64 __z2 = __z; while (__z2 != 0) { __tmp << (char)((__z2%10)+'0'); __z2 /= 10; } uint __s = __tmp.str().size(); for (uint i = 0; i < __s; i++) __res << __tmp.str()[__s - 1 - i]; } return __os << __res.str(); } template std::basic_istream<_CharT, _Traits>& __cdecl operator>>(std::basic_istream<_CharT, _Traits>& __is, sint64& __z) { __z = 0; bool neg = false; char c; do { __is >> c; } while (isspace(c)); if (c == '-') { neg = true; __is >> c; } while (isdigit(c)) { __z *= 10; __z += c-'0'; __is >> c; if (__is.fail()) break; } if (neg) __z = -__z; return __is; } template std::basic_ostream<_CharT, _Traits>& __cdecl operator<<(std::basic_ostream<_CharT, _Traits>& __os, const sint64& __z) { std::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __res; if (__z == 0) { __res << '0'; } else { sint64 __z2 = __z; if (__z2 < 0) { __res << '-'; } std::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __tmp; while (__z2 != 0) { if (__z2 < 0) { __tmp << (char)((-(__z2%10))+'0'); } else { __tmp << (char)((__z2%10)+'0'); } __z2 /= 10; } uint __s = __tmp.str().size(); for (uint i = 0; i < __s; i++) __res << __tmp.str()[__s - 1 - i]; } return __os << __res.str(); } #endif // NL_OS_WINDOWS */ class CLog; /// Display the bits (with 0 and 1) composing a byte (from right to left) void displayByteBits( uint8 b, uint nbits, sint beginpos, bool displayBegin, NLMISC::CLog *log ); /// Display the bits (with 0 and 1) composing a number (uint32) (from right to left) void displayDwordBits( uint32 b, uint nbits, sint beginpos, bool displayBegin, NLMISC::CLog *log ); /// this wrapping is due to a visual bug when calling isprint with big value /// example of crash with VC6 SP4: int a = isprint(0x40e208); #ifdef NL_OS_WINDOWS inline int nlisprint(int c) { if(c>255||c<0) return 0; return isprint(c); } #else #define nlisprint isprint #endif // Open an url in a browser bool openURL (const char *url); // Open a document bool openDoc (const char *document); // AntiBug method that return an epsilon if x==0, else x inline float favoid0(float x) { if(x==0) return 0.00001f; return x; } inline double davoid0(double x) { if(x==0) return 0.00001; return x; } // AntiBug method that return 1 if x==0, else x template inline T iavoid0(T x) { if(x==0) return 1; return x; } } // NLMISC #endif // NL_COMMON_H ================================================ FILE: code/nel/include/nel/misc/config_file.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CONFIG_FILE_H #define NL_CONFIG_FILE_H #include "types_nl.h" #include "common.h" #include "debug.h" #include "log.h" #include #include #include namespace NLMISC { /** * CConfigFile class. Useful when you want to have a configuration file with variables. * It manages integers, real (double), and string basic types. A variable can be an array of * basic type. In this case, all elements of the array must have the same type. * * If you setup the global callback before loading, it'll be called after the load() function. * * Example: *\code * try * { * CConfigFile cf; * * // Load and parse "test.txt" file * cf.load ("test.txt"); * * // Attach a callback to the var1 variable. When the var1 will change, this cvar1cb function will be called * cf.setCallback ("var1", var1cb); * * // Get the foo variable (suppose it's a string variable) * CConfigFile::CVar &foo = cf.getVar ("foo"); * * // Display the content of the variable * printf ("foo = %s\n", foo.asString ().c_str ()); * * // Get the bar variable (suppose it's an array of int) * CConfigFile::CVar &bar = cf.getVar ("bar"); * * // Display the content of all the elements of the bar variable * printf ("bar have %d elements : \n", bar.size ()); * for (int i = 0; i < bar.size (); i++) * printf ("%d ", bar.asInt (i)); * printf("\n"); * } * catch (const EConfigFile &e) * { * // Something goes wrong... catch that * printf ("%s\n", e.what ()); * } *\endcode * * Example of config file: *\code * // one line comment * / * big comment * on more than one line * / * * var1 = 123; // var1 type:int, value:123 * var2 = "456.25"; // var2 type:string, value:"456.25" * var3 = 123.123; // var3 type:real, value:123.123 * * // the resulting type is type of the first left value * var4 = 123.123 + 2; // var4 type:real, value:125.123 * var5 = 123 + 2.1; // var5 type:int, value:125 * * var6 = (-112+1) * 3 - 14; // var6 type:int, value:-347 * * var7 = var1 + 1; // var7 type:int, value:124 * * var8 = var2 + 10; // var8 type:string, value:456.2510 (convert 10 into a string and concat it) * var9 = 10.15 + var2; // var9 type:real, value:466.4 (convert var2 into a real and add it) * * var10 = { 10.0, 51.1 }; // var10 type:realarray, value:{10.0,51.1} * var11 = { "str1", "str2", "str3" }; // var11 type:stringarray, value:{"str1", "str2", "str3"} * * var12 = { 10+var1, var1-var7 }; // var12 type:intarray, value:{133,-1} *\endcode * * Operators are '+', '-', '*', '/'. * You can't use operators on a array variable, for example, you can't do \cvar13=var12+1. * If you have 2 variables with the same name, the first value will be remplaced by the second one. * * \bug if you terminate the config file with a comment without carriage returns it'll generate an exception, add a carriage returns * * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ class CConfigFile { public: /** * CVar class. Used by CConfigFile. A CVar is returned when you want to have a variable. * * Example: see the CConfigFile example * * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ struct CVar { public: CVar () : Type(T_UNKNOWN), Root(false), Comp(false), FromLocalFile(true), SaveWrap(6) {} /// \name Access to the variable content. //@{ /// Get the content of the variable as an integer int asInt (int index=0) const; /// Get the content of the variable as a double double asDouble (int index=0) const; /// Get the content of the variable as a float float asFloat (int index=0) const; /// Get the content of the variable as a STL string std::string asString (int index=0) const; /// Get the content of the variable as a boolean bool asBool (int index=0) const; //@} /// \name Set the variable content. /// If the index is the size of the array, the value will be append at the end. //@{ /// Set the content of the variable as an integer void setAsInt (int val, int index=0); /// Set the content of the variable as a double void setAsDouble (double val, int index=0); /// Set the content of the variable as a float void setAsFloat (float val, int index=0); /// Set the content of the variable as a STL string void setAsString (const std::string &val, int index=0); /// Force the content of the variable to be a single integer void forceAsInt (int val); /// Force the content of the variable to be a single double void forceAsDouble (double val); /// Force the content of the variable to be a single string void forceAsString (const std::string &val); /// Set the content of the aray variable as an integer void setAsInt (const std::vector &vals); /// Set the content of the aray variable as a double void setAsDouble (const std::vector &vals); /// Set the content of the aray variable as a float void setAsFloat (const std::vector &vals); /// Set the content of the aray variable as a string void setAsString (const std::vector &vals); //@} bool operator== (const CVar& var) const; bool operator!= (const CVar& var) const; // add this variable with var void add (const CVar &var); // Get the size of the variable. It's the number of element of the array or 1 if it's not an array. uint size () const; /// \name Internal use //@{ static const char *TypeName[]; enum TVarType { T_UNKNOWN, T_INT, T_STRING, T_REAL, T_BOOL }; std::string Name; TVarType Type; bool Root; // true if this var comes from the root document. false else. bool Comp; // true if the parser found a 'complex' var (ie an array) bool FromLocalFile; // Used during cfg parsing. True if the var has been created from the currently parsed cfg std::vector IntValues; std::vector RealValues; std::vector StrValues; int SaveWrap; void (*Callback)(CVar &var); //@} }; CConfigFile() : _Callback(NULL) {} virtual ~CConfigFile (); /// Get a variable with the variable name CVar &getVar (const std::string &varName); /// Get a variable pointer with the variable name, without throwing exception. Return NULL if not found. CVar *getVarPtr (const std::string &varName); /// Get the variable count. uint getNumVar () const; /// Get a variable. CVar *getVar (uint varId); /// Add a variable. If the variable already exists, return it. CVar *insertVar (const std::string &varName, const CVar &varToCopy); /// Return true if the variable exists, false otherwise bool exists (const std::string &varName); /// load and parse the file void load (const std::string &fileName, bool lookupPaths = false); /// save the config file void save () const; /// Clear all the variable array (including information on variable callback etc) void clear (); /// set to 0 or "" all variable in the array (but not destroy them) void clearVars (); /// Returns true if the file has been loaded bool loaded(); /// Returns the number of variables in the configuration uint32 getVarCount(); /// reload and reparse the file void reparse (bool lookupPaths = false); /// display all variables with nlinfo (debug use) void display () const; /// display all variables with nlinfo (debug use) void display (CLog *log) const; /// set a callback function that is called when the config file is modified void setCallback (void (*cb)()); /// set a callback function to a variable, it will be called when this variable is modified void setCallback (const std::string &VarName, void (*cb)(CConfigFile::CVar &var)); /// contains the variable names that getVar() and getVarPtr() tried to access but not present in the cfg std::vector UnknownVariables; /// returns the config file name std::string getFilename () const { return FileNames[0]; } /// set the time between 2 file checking (default value is 1 second) /// \param timeout time in millisecond, if timeout=0, the check will be made each "frame" static void setTimeout (uint32 timeout); /// Internal use only static void checkConfigFiles (); private: /// Internal use only void (*_Callback)(); /// Internal use only std::vector _Vars; // contains the configfilename (0) and roots configfilenames // std::string _FileName; // std::vector _LastModified; // contains the configfilename (0) and roots configfilenames std::vector FileNames; std::vector LastModified; static uint32 _Timeout; static std::vector *_ConfigFiles; }; struct EConfigFile : public Exception { EConfigFile() { _Reason = "Unknown Config File Exception";} }; struct EBadType : public EConfigFile { EBadType (const std::string &varName, int varType, int wantedType) { static char str[NLMISC::MaxCStringSize]; smprintf (str, NLMISC::MaxCStringSize, "Bad variable type, variable \"%s\" is a %s and not a %s", varName.c_str (), CConfigFile::CVar::TypeName[varType], CConfigFile::CVar::TypeName[wantedType]); _Reason = str; nlinfo("CF: Exception will be launched: %s", _Reason.c_str()); } }; struct EBadSize : public EConfigFile { EBadSize (const std::string &varName, int varSize, int varIndex) { static char str[NLMISC::MaxCStringSize]; smprintf (str, NLMISC::MaxCStringSize, "Trying to access to the index %d but the variable \"%s\" size is %d", varIndex, varName.c_str (), varSize); _Reason = str; nlinfo("CF: Exception will be launched: %s", _Reason.c_str()); } }; struct EUnknownVar : public EConfigFile { EUnknownVar (const std::string &filename, const std::string &varName) { static char str[NLMISC::MaxCStringSize]; smprintf (str, NLMISC::MaxCStringSize, "variable \"%s\" not found in file \"%s\"", varName.c_str (), filename.c_str()); _Reason = str; nlinfo("CF: Exception will be launched: %s", _Reason.c_str()); } }; struct EParseError : public EConfigFile { EParseError (const std::string &fileName, int currentLine) { static char str[NLMISC::MaxCStringSize]; smprintf (str, NLMISC::MaxCStringSize, "Parse error on the \"%s\" file, line %d", fileName.c_str (), currentLine); _Reason = str; nlinfo("CF: Exception will be launched: %s", _Reason.c_str()); } }; struct EFileNotFound : public EConfigFile { EFileNotFound (const std::string &fileName) { static char str[NLMISC::MaxCStringSize]; smprintf (str, NLMISC::MaxCStringSize, "File \"%s\" not found", fileName.c_str ()); _Reason = str; } }; } // NLMISC #endif // NL_CONFIG_FILE_H /* End of config_file.h */ ================================================ FILE: code/nel/include/nel/misc/contiguous_block_allocator.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CONTIGUOUS_BLOCK_ALLOCATOR_H #define NL_CONTIGUOUS_BLOCK_ALLOCATOR_H #include "types_nl.h" namespace NLMISC { /** One of the simplest scheme of allocation around, but very useful in some situations. * This allocator is just provided with a single block of memory at start (possibly of size 0). Each alloc get a new block in that big block, by * simply advancing a pointer. When not enough space is available, the default stl allocator is used. * When a block is deallocated, nothing happens, unless the block was allocated using the default stl allocator is used, in which case deallocate() is called. * * The typical use is when an object makes a lot of allocations at init, but in a predictable way, and if it doesn't make alloc / realloc * later. In this case the caller can measure the amount of memory needed to create the object, and can create this allocator with the good amount of * memory. Subsequent allocations will then be very fast even for very differently sized blocks, with no fragmentation inside the allocated block * and no memory overhead per allocated bloc. * * Obviously, if the quantity of memory to be allocated can't be predicted (or if no max bytes can be forseen), then other allocators may * be best suited. * * \author Nicolas Vizerie * \author Nevrax France * \date 2004 * */ class CContiguousBlockAllocator { public: // ctor CContiguousBlockAllocator(); // dtor ~CContiguousBlockAllocator(); // Init the allocator with the given size. Previous allocations become invalid, so when calling init again, the user must have // freed all memory he allocated void init(uint numBytes = 0); // synonymous to init(0) void release() { init(0); } // allocated a block of n bytes void *alloc(uint numBytes); // deallocate a block void free(void *block, uint numBytes); // compute the total number of bytes allocated since init // NB : freed block are not subtracted from that total !! uint getNumAllocatedBytes() const { return _NumAllocatedBytes; } #ifdef NL_DEBUG // get number of calls to alloc since last init uint getNumAlloc() const { return _NumAlloc; } // get number of calls to free since last init uint getNumFree() const { return _NumFree; } #endif private: uint8 *_BlockStart; uint8 *_BlockEnd; uint8 *_NextAvailablePos; uint _NumAllocatedBytes; std::allocator _DefaultAlloc; #ifdef NL_DEBUG uint _NumAlloc; uint _NumFree; #endif }; } #endif ================================================ FILE: code/nel/include/nel/misc/cpu_time_stat.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CPU_TIME_STAT_H #define NL_CPU_TIME_STAT_H #include #include #include namespace NLMISC { /** * Utility class to read cpu time information from /proc/stat and /cpu/pid/stat * Allows accurate timing measures for both cpu and process (at least at OS timing accuracy) * Call peekMeasures() once in a while (once a second, for instance, to avoid to much load) * then call each getCPU... and getProcess... methods to get instant CPU or Process load. * * \author Benjamin Legros * \author Nevrax France * \date 2004 */ class CCPUTimeStat { public: CCPUTimeStat(); /** * Get absolute ticks value for the whole cpu set * e.g. a foursome of cpu will all tell their ticks through these numbers */ static bool getCPUTicks(uint64& user, uint64& nice, uint64& system, uint64& idle, uint64& iowait); /// Get absolute ticks values for a specific pid static bool getPIDTicks(uint64& utime, uint64& stime, uint64& cutime, uint64& cstime, uint pid); /// \name Measure peeking and reading // @{ /// Peek measure void peekMeasures(); enum TMeasureType { Instant, Mean, Peak }; /** * Get Overall CPU Load * Call this method to know the overall server CPU usage (0=min, 1=max) * All processes running on the same machine will return approximately * the same value */ float getCPULoad(TMeasureType type = Instant) const { return _CPUUser.get(type)+_CPUSystem.get(type)+_CPUNice.get(type)+_CPUIOWait.get(type); } /** * Get overall load for this process (children excluded) * Call this method to know the CPU usage for this process (0=min, 1=max) * Please note that quadriprocessor machines will show maximum of 0.25 per process * (0.5 for a biprocessor). * Children of a process are processes that have been launched from this process * (that is, this process is marked as parent of the child process, see ppid, fork() and/or exec()) * Unused but by the AES (all launched services are children of the AES) */ float getProcessLoad(TMeasureType type = Instant) const { return _PIDUTime.get(type)+_PIDSTime.get(type); } // @} /** \name Detailed measures * These methods allow you to check precisely what consumes cpu power, * (user processes/kernel/nice processes...) */ // @{ /// Get User Load float getCPUUserLoad(TMeasureType type = Instant) const { return _CPUUser.get(type); } /// Get System Load float getCPUSystemLoad(TMeasureType type = Instant) const { return _CPUSystem.get(type); } /// Get Nice Load float getCPUNiceLoad(TMeasureType type = Instant) const { return _CPUNice.get(type); } /// Get Nice Load float getCPUIOWaitLoad(TMeasureType type = Instant) const { return _CPUIOWait.get(type); } /// Get User load for this process (children excluded) float getProcessUserLoad(TMeasureType type = Instant) const { return _PIDUTime.get(type); } /// Get Sytem load for this process (children excluded) float getProcessSystemLoad(TMeasureType type = Instant) const { return _PIDSTime.get(type); } /// Get User load for this process (children included) float getProcessCUserLoad(TMeasureType type = Instant) const { return _PIDCUTime.get(type); } /// Get Sytem load for this process (children included) float getProcessCSystemLoad(TMeasureType type = Instant) const { return _PIDCSTime.get(type); } /// Get overall load for this process (children included) float getProcessCLoad(TMeasureType type = Instant) const { return _PIDCUTime.get(type)+_PIDCSTime.get(type); } // @} private: struct CTickStat { CTickStat() : Tick(0), Diff(0), Load(0.0f) { } uint64 Tick; uint32 Diff; float Load; typedef std::deque > TLoadQueue; TLoadQueue LoadQueue; void computeDiff(uint64 newTick) { Diff = (uint32)(newTick-Tick); Tick = newTick; } void computeLoad(uint32 total, const NLMISC::TTime& ctime) { Load = (float)Diff / (float)total; while (!LoadQueue.empty() && ctime-LoadQueue.front().first > 60000) LoadQueue.pop_front(); LoadQueue.push_back(std::make_pair(ctime, Load)); } float get(TMeasureType type) const { if (type == Peak) return getPeakLoad(); else if (type == Mean) return getMeanLoad(); else return Load; } float getPeakLoad() const { float peak = 0.0f; uint i; for (i=0; i peak) peak = LoadQueue[i].second; return peak; } float getMeanLoad() const { if (LoadQueue.empty()) return 0.0f; float t = 0.0f; uint i; for (i=0; i // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_DEBUG_H #define NL_DEBUG_H #include "common.h" #include "log.h" #include "mutex.h" #include "mem_displayer.h" #include "displayer.h" #include "app_context.h" #include #include namespace NLMISC { #ifdef ASSERT_THROW_EXCEPTION #define ASSERT_THROW_EXCEPTION_CODE(exp) ASSERT_THROW_EXCEPTION_CODE_EX(exp, #exp) #define ASSERT_THROW_EXCEPTION_CODE_EX(exp, str) if(!(exp)) throw NLMISC::Exception(str" returns false"); #else #define ASSERT_THROW_EXCEPTION_CODE(exp) #define ASSERT_THROW_EXCEPTION_CODE_EX(exp, str) #endif /** Imposter class to wrap all global access to the nel context for backward compatibility * Yoyo note: This was a template before, hence with inline. * We removed the inline because there was a hard compilation bug * in plugin max under some compiler which caused operator-> to crash.... (don't understand why grrrr) * Btw the method is optimized like this (1 call instead of 3 (and one with virtual)) because we added a local cache (_Log) * Thus it is much better like this. */ class CImposterLog { private: typedef CLog *(INelContext::*TAccessor)(); // Method to access the Log TAccessor _Accessor; public: CImposterLog(TAccessor accessor); CLog* operator -> (); operator CLog*(); CLog &operator ()(); }; // // Externals // // NOTE: The following are all NULL until createDebug() has been called at least once // NOTE2: You must not use this class before the main() (not inside a static class ctor) extern CImposterLog ErrorLog; extern CImposterLog WarningLog; extern CImposterLog InfoLog; extern CImposterLog DebugLog; extern CImposterLog AssertLog; extern CMemDisplayer *DefaultMemDisplayer; extern CMsgBoxDisplayer *DefaultMsgBoxDisplayer; // // Functions // // internal use only void createDebug (const char *logPath = NULL, bool logInFile = true, bool eraseLastLog = false); /// Do not call this, unless you know what you're trying to do (it kills debug)! void destroyDebug(); // call this if you want to change the dir of the log.log file void changeLogDirectory(const std::string &dir); // call this if you want to get the dir of the log.log file std::string getLogDirectory(); // internal breakpoint window void enterBreakpoint (const char *message); // if true, the assert generates an assert // if false, the assert just displays a warning and continue void setAssert (bool assert); // Beep (Windows only, no effect elsewhere) void beep( uint freq, uint duration ); typedef std::string (*TCrashCallback)(); // this function enables user application to add information in the log when a crash occurs void setCrashCallback(TCrashCallback crashCallback); // For Crash report window. allow to know if a crash has already raised in the application bool isCrashAlreadyReported(); void setCrashAlreadyReported(bool state); // This very amazing macro __FUNCTION__ doesn't exist on VC6, map it to NULL #ifdef NL_COMP_VC6 # define __FUNCTION__ NULL #endif // Macros /// Utility macro used by NL_MACRO_TO_STR to concatenate macro in text message. #define NL_MACRO_TO_STR_SUBPART(x) #x /** Use this macro to concatenate macro such * You can use this macro to build '#pragma message' friendly macro * or to make macro definition into string * eg : #define M1 foo * #define MESSAGE "the message is "NL_MACRO_TO_STR(M1) * #pragma message(MESSAGE) * printf(NL_MACRO_TO_STR(M1)); */ #define NL_MACRO_TO_STR(x) NL_MACRO_TO_STR_SUBPART(x) /** the two following macros help to build compiler message using #pragma message * on visual C++. * The macro generate a message formated like the visual C++ compiler message. * NL_LOC_MSG generate informative message and * NL_LOC_WRN generate warning message not differentiable to genuine Visual C++ warning. * The two message allow automatic source access with F4 or double click in * output window. * * usage : #pragma message( NL_LOC_MGS "your message" ) * * Note : If you want to concatenate another macro to your message, you * can append using the NL_MACRO_TO_STR macro like in * #define CLASS_NAME TheClassName * #pragma message( NL_LOC_MGS "The class name is " NL_MACRO_TO_STR(CLASS_NAME)) * Note 2 : To show a warning under GCC, use #warning "Your warning here", * see nel/net/net_manager.h for an example on how to use these correctly. */ #define NL_LOC_MSG __FILE__"(" NL_MACRO_TO_STR(__LINE__) ") : Message: " #define NL_LOC_WRN __FILE__"(" NL_MACRO_TO_STR(__LINE__) ") : Warning Msg: " /** * \def nldebug(exp) * Log a debug string. You don't have to put the final new line. It will be automatically append at the end of the string. * * Example: *\code void function(sint type) { // display the type value. nldebug("type is %d", type); } *\endcode */ #ifdef NL_NO_DEBUG # if defined(NL_COMP_VC) && NL_COMP_VC_VERSION >= 71 # define nldebug __noop # else # define nldebug 0&& # endif #else // NL_NO_DEBUG extern bool DisableNLDebug; # define nldebug if (NLMISC::DisableNLDebug) {} else (NLMISC::createDebug(), NLMISC::INelContext::getInstance().getDebugLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::INelContext::getInstance().getDebugLog())->displayNL #endif // NL_NO_DEBUG /** * \def nlinfo(exp) * Same as nldebug but it will be display in debug and in release mode. */ #ifdef NL_NO_DEBUG # if defined(NL_COMP_VC) && NL_COMP_VC_VERSION >= 71 # define nlinfo __noop # else # define nlinfo 0&& # endif #else // NL_NO_DEBUG # define nlinfo (NLMISC::createDebug(), NLMISC::INelContext::getInstance().getInfoLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::INelContext::getInstance().getInfoLog())->displayNL #endif // NL_NO_DEBUG /** * \def nlwarning(exp) * Same as nlinfo but you have to call this macro when something goes wrong but it's not a fatal error, the program could continue. * * Example: *\code void function(char *str) { // display the type value. if (str==NULL) { nlwarning("in function(), str should not be NULL, assume it's an empty string"); str=""; } } *\endcode */ #ifdef NL_NO_DEBUG # if defined(NL_COMP_VC) && NL_COMP_VC_VERSION >= 71 # define nlwarning __noop # else # define nlwarning 0&& # endif #else // NL_NO_DEBUG # define nlwarning (NLMISC::createDebug(), NLMISC::INelContext::getInstance().getWarningLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::INelContext::getInstance().getWarningLog())->displayNL #endif // NL_NO_DEBUG /** * \def nlerror(exp) * Same as nlinfo but you have to call it when you have a fatal error, this macro display the text and \b exit the application * automatically. nlerror must be in a try/catch because it generates an EFatalError exception to exit the application. * *\code void function(char *filename) { FILE *fp = fopen (filename, "r"); if (fp==NULL) { nlerror("file not found"); } } *\endcode */ #define nlerror (NLMISC::createDebug (), NLMISC::INelContext::getInstance().getErrorLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::nlFatalError) /** * \def nlerrornoex(exp) * Same as nlerror but it doesn't generate any exceptions. It's used only in very specific case, for example, when you * call a nlerror in a catch block (look the service.cpp) */ #define nlerrornoex (NLMISC::createDebug (), NLMISC::INelContext::getInstance().getErrorLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::nlError) /** * \def nlassert(exp) * Try the assertion of \c exp. In release mode, nlassert do \b *nothing*. In debug mode, If \c exp is true, nothing happen, * otherwise, the program stop on the assertion line. * * Example: *\code void function(char *string) { // the string must not be NULL. nlassert(string!=NULL); } *\endcode */ /** * \def nlassertonce(exp) * Same behaviour as nlassert but the assertion will be test on time only. It's useful when you are under an inner loop and * you don't want to flood log file for example. * * Example: *\code for (int i = 0; i < Vect.size(); i++) { // all string must not be NULL, but if it's happen, log only the first time. nlassertonce(Vect[i].string!=NULL); } *\endcode */ /** * \def nlassertex(exp,str) * Same behaviour as nlassert but add a user defined \c str variables args string that will be display with the assert message. * Very useful when you can't debug directly on your computer. * * Example: *\code void function(sint type) { // the \c type must be between 0 and 15. nlassertex(type>=0&&type<=16, ("type was %d", type)); // it'll display something like "assertion failed line 10 of test.cpp: type>=&&type<=16, type was 423555463" } *\endcode */ /** * \def nlverify(exp) * Same behaviour as nlassert but the \c exp will be executed in release mode too (but not tested). * * Example: *\code // Load a file and assert if the load failed. This example will work \b only in debug mode because in release mode, // nlassert do nothing, the load function will not be called... nlassert(load("test.tga")); // If you want to do that anyway, you could call nlverify. In release mode, the assertion will not be tested but // the \c load function will be called. nlverify(load("test.tga")); // You can also do this: bool res = load ("test.tga")); assert(res); *\endcode */ /** * \def nlverifyonce(exp) * Same behaviour as nlassertonce but it will execute \c exp in debug and release mode. */ /** * \def nlverifyex(exp,str) * Same behaviour as nlassertex but it will execute \c exp in debug and release mode. */ /** * \def nlstop * It stop the application at this point. It's exactly the same thing as "nlassert(false)". * Example: *\code switch(type) { case 1: ... break; case 2: ... break; default: nlstop; // it should never happen... } *\endcode */ /** * \def nlstoponce * Same as nlassertonce(false); */ /** * \def nlstopex(exp) * Same as nlassertex(false,exp); */ // removed because we always check assert (even in release mode) #if defined (NL_OS_WINDOWS) && defined (NL_DEBUG) #if defined (NL_OS_WINDOWS) #define NLMISC_BREAKPOINT __debugbreak(); #else #define NLMISC_BREAKPOINT abort() #endif // Internal, don't use it (make smaller assert code) extern bool _assert_stop(bool &ignoreNextTime, sint line, const char *file, const char *funcName, const char *exp); extern void _assertex_stop_0(bool &ignoreNextTime, sint line, const char *file, const char *funcName, const char *exp); extern bool _assertex_stop_1(bool &ignoreNextTime); // removed because we always check assert (even in release mode) #if defined(NL_DEBUG) #ifdef NL_NO_DEBUG # define nlassert(exp) if(false) # define nlassertonce(exp) if(false) # define nlassertex(exp, str) if(false) # define nlverify(exp) { exp; } # define nlverifyonce(exp) { exp; } # define nlverifyex(exp, str) { exp; } #else // NL_NO_DEBUG # ifdef NL_OS_UNIX // Linux set of asserts is reduced due to that there is no message box displayer #define nlassert(exp) \ do { \ if (!(exp)) { \ NLMISC::createDebug (); \ NLMISC::INelContext::getInstance().getAssertLog()->setPosition (__LINE__, __FILE__, __FUNCTION__); \ NLMISC::INelContext::getInstance().getAssertLog()->displayNL ("\"%s\" ", #exp); \ NLMISC_BREAKPOINT; \ } \ } while(0) #define nlassertonce(exp) nlassert(exp) #define nlassertex(exp, str) \ do { \ if (!(exp)) { \ NLMISC::createDebug (); \ NLMISC::INelContext::getInstance().getAssertLog()->setPosition (__LINE__, __FILE__, __FUNCTION__); \ NLMISC::INelContext::getInstance().getAssertLog()->displayNL ("\"%s\" ", #exp); \ NLMISC::INelContext::getInstance().getAssertLog()->displayRawNL str; \ NLMISC_BREAKPOINT; \ } \ } while(0) #define nlverify(exp) nlassert(exp) #define nlverifyonce(exp) nlassert(exp) #define nlverifyex(exp, str) nlassertex(exp, str) # else // NL_OS_UNIX #define nlassert(exp) \ do { \ static bool ignoreNextTime = false; \ bool _expResult_ = (exp) ? true : false; \ if (!ignoreNextTime && !_expResult_) { \ if(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp)) \ NLMISC_BREAKPOINT; \ } \ ASSERT_THROW_EXCEPTION_CODE_EX(_expResult_, #exp) \ } while(0) #define nlassertonce(exp) \ do { \ static bool ignoreNextTime = false; \ if (!ignoreNextTime && !(exp)) { \ ignoreNextTime = true; \ if(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp)) \ NLMISC_BREAKPOINT; \ } \ } while(0) #define nlassertex(exp, str) \ do { \ static bool ignoreNextTime = false; \ bool _expResult_ = (exp) ? true : false; \ if (!ignoreNextTime && !_expResult_) { \ NLMISC::_assertex_stop_0(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp); \ NLMISC::INelContext::getInstance().getAssertLog()->displayRawNL str; \ if(NLMISC::_assertex_stop_1(ignoreNextTime)) \ NLMISC_BREAKPOINT; \ } \ ASSERT_THROW_EXCEPTION_CODE_EX(_expResult_, #exp) \ } while(0) #define nlverify(exp) \ do { \ static bool ignoreNextTime = false; \ bool _expResult_ = (exp) ? true : false; \ if (!_expResult_ && !ignoreNextTime) { \ if(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp)) \ NLMISC_BREAKPOINT; \ } \ ASSERT_THROW_EXCEPTION_CODE_EX(_expResult_, #exp) \ } while(0) #define nlverifyonce(exp) \ do { \ static bool ignoreNextTime = false; \ bool _expResult_ = (exp) ? true : false; \ if (!_expResult_ && !ignoreNextTime) { \ ignoreNextTime = true; \ if(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp)) \ NLMISC_BREAKPOINT; \ } \ } while(0) #define nlverifyex(exp, str) \ do { \ static bool ignoreNextTime = false; \ bool _expResult_ = (exp) ? true : false; \ if (!_expResult_ && !ignoreNextTime) { \ NLMISC::_assertex_stop_0(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp); \ NLMISC::INelContext::getInstance().getAssertLog()->displayRawNL str; \ if(NLMISC::_assertex_stop_1(ignoreNextTime)) \ NLMISC_BREAKPOINT; \ } \ ASSERT_THROW_EXCEPTION_CODE_EX(_expResult_, #exp) \ } while(0) # endif // NL_OS_UNIX #endif // NL_NO_DEBUG #define nlunreferenced(identifier) (void)identifier #define nlstop \ do { \ static bool ignoreNextTime = false; \ if (!ignoreNextTime) { \ if(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, NULL)) \ NLMISC_BREAKPOINT; \ } \ ASSERT_THROW_EXCEPTION_CODE(false) \ } while(0) #define nlstoponce \ do { \ static bool ignoreNextTime = false; \ if (!ignoreNextTime) { \ ignoreNextTime = true; \ if(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, NULL)) \ NLMISC_BREAKPOINT; \ } \ } while(0) #define nlstopex(str) \ do { \ static bool ignoreNextTime = false; \ if (!ignoreNextTime) { \ NLMISC::_assertex_stop_0(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, NULL); \ NLMISC::INelContext::getInstance().getAssertLog()->displayRawNL str; \ if(NLMISC::_assertex_stop_1(ignoreNextTime)) \ NLMISC_BREAKPOINT; \ } \ } while(0) struct EFatalError : public Exception { EFatalError() : Exception( "nlerror() called" ) {} }; class ETrapDebug : public Exception { }; // undef default assert to force people to use nlassert() instead of assert() // if NL_MAP_ASSERT is set we map assert to nlassert instead of removing it // this makes it compatible with zeroc's ICE network library #ifdef NL_MAP_ASSERT # ifdef assert # undef assert # define assert nlassert # endif #else # ifdef assert # undef assert # define assert(a) you_must_not_use_assert___use_nl_assert___read_debug_h_file # endif #endif /// Get the call stack and set it with result void getCallStack(std::string &result, sint skipNFirst = 0); /// Get the call stack and the logs and set it with result void getCallStackAndLog (std::string &result, sint skipNFirst = 0); /** * safe_cast<>: this is a function which nlassert() a dynamic_cast in Debug, and just do a static_cast in release. * So slow check is made in debug, but only fast cast is made in release. */ template inline T safe_cast(U o) { // NB: must check debug because assert may still be here in release #ifdef NL_DEBUG nlassert(dynamic_cast(o)); #endif return static_cast(o); } /** * type_cast<>: this is a function which nlassert() a dynamic_cast in Debug, and just do a static_cast in release. * So slow check is made in debug, but only fast cast is made in release. * Differs from safe_cast by allowinf NULL objets. (ask Stephane LE DORZE for more explanations). */ template inline T type_cast(U o) { // NB: must check debug because assert may still be here in release #ifdef NL_DEBUG if (o) nlassert(dynamic_cast(o)); #endif // optimization made to check pointer validity before address translation. (hope it works on linux). if ((size_t)(static_cast((U)0x0400)) == (size_t)((U)0x0400)) { return static_cast(o); } else { return (o==0)?0:static_cast(o); } } /** Compile time assertion */ #ifdef NL_ISO_CPP0X_AVAILABLE # define nlctassert(cond) static_assert(cond, "Compile time assert in "#cond) #else # define nlctassert(cond) (void)sizeof(uint[(cond) ? 1 : 0]) #endif /** * Allow to verify an object was accessed before its destructor call. * For instance, it could be used to check if the user take care of method call return. * ex: * CMustConsume foo() * { * ... * return ErrorInvalidateType; // part of TErrorCode enum. * } * Exclusive implementation samples: * TerrorCode code=foo().consumeValue(); // Good! * foo().consume(); // Good! * TerrorCode code=foo(); // Mistake! * foo(); // Will cause an assert at next ending brace during execution time. * TerrorCode code=foo().Value(); // Will cause an assert at next ending brace during execution time. * (ask Stephane LE DORZE for more explanations). */ // Need a breakpoint in the assert / verify macro extern bool DebugNeedAssert; // Internal process, don't use it extern bool NoAssert; template class CMustConsume { public: CMustConsume(const T &val) : Value(val) #if !FINAL_VERSION , Consumed(false) #endif { } ~CMustConsume() { #if !FINAL_VERSION nlassert(Consumed == true); #endif } // Get the value without validating the access. const T &value() const { return Value; } operator const T &() const { #if !FINAL_VERSION Consumed = true; #endif return Value; } // Get the value and validate the access. const T &consumeValue() const { #if !FINAL_VERSION Consumed = true; #endif return Value; } // Only consume the access. void consume() const { #if !FINAL_VERSION Consumed = true; #endif } private: T Value; #if !FINAL_VERSION mutable bool Consumed; #endif }; /// Data for instance counting struct TInstanceCounterData { sint32 _InstanceCounter; sint32 _DeltaCounter; const char *_ClassName; bool _Touched; TInstanceCounterData(const char *className); ~TInstanceCounterData(); }; // forward declaration for members of CInstanceCounterManager class CInstanceCounterLocalManager; // The singleton used to display the instance counter class CInstanceCounterManager { // NLMISC_SAFE_SINGLETON_DECL(CInstanceCounterManager); private: /* declare private constructors*/ CInstanceCounterManager () {} CInstanceCounterManager (const CInstanceCounterManager &) {} /* the local static pointer to the singleton instance */ static CInstanceCounterManager *_Instance; public: static CInstanceCounterManager &getInstance() { if (_Instance == NULL) { /* the nel context MUST be initialised */ // nlassert(NLMISC::NelContext != NULL); void *ptr = NLMISC::INelContext::getInstance().getSingletonPointer("CInstanceCounterManager"); if (ptr == NULL) { /* allocate the singleton and register it */ _Instance = new CInstanceCounterManager; NLMISC::INelContext::getInstance().setSingletonPointer("CInstanceCounterManager", _Instance); } else { _Instance = reinterpret_cast(ptr); } } return *_Instance; } private: public: std::string displayCounters() const; void resetDeltaCounter(); uint32 getInstanceCounter(const std::string &className) const; sint32 getInstanceCounterDelta(const std::string &className) const; private: friend class CInstanceCounterLocalManager; void registerInstaceCounterLocalManager(CInstanceCounterLocalManager *localMgr); void unregisterInstaceCounterLocalManager(CInstanceCounterLocalManager *localMgr); // static CInstanceCounterManager *_Instance; std::set _InstanceCounterMgrs; }; // // Local instance counter // class CInstanceCounterLocalManager { public: static CInstanceCounterLocalManager &getInstance() { if (_Instance == NULL) { _Instance = new CInstanceCounterLocalManager; } return *_Instance; } static void releaseInstance() { if (_Instance != NULL) { delete _Instance; _Instance = NULL; } } void registerInstanceCounter(TInstanceCounterData *counter) { _InstanceCounters.insert(counter); } void unregisterInstanceCounter(TInstanceCounterData *counter); ~CInstanceCounterLocalManager() { CInstanceCounterManager::getInstance().unregisterInstaceCounterLocalManager(this); } private: friend class CInstanceCounterManager; friend class INelContext; CInstanceCounterLocalManager() { } void registerLocalManager() { CInstanceCounterManager::getInstance().registerInstaceCounterLocalManager(this); } static CInstanceCounterLocalManager *_Instance; std::set _InstanceCounters; }; /** Utility to count instance of class. * This class is designed to be lightweight and to trace * the number of instance of 'tagged' class. * Commands are provided to display the actual number * of object of each class and to compute delta * between two call of the displayer. * Usage is simple, you just have to put a macro * inside the class definition to trace it's allocation * and a macro in the implementation file. * The macro only add a compiler minimum size for member * struct of 0 octets (witch can be 0 or 1 octet, compiler * dependent). * usage : * * In the header : * class foo // This is the class we want to count instance * { * NL_INSTANCE_COUNTER_DECL(foo); * } * In the cpp : * NL_INSTANCE_COUNTER_IMPL(foo); */ #define NL_INSTANCE_COUNTER_DECL(className) \ public: \ struct className##InstanceCounter \ { \ className##InstanceCounter() \ { \ _InstanceCounterData._InstanceCounter++; \ _InstanceCounterData._Touched = true; \ } \ className##InstanceCounter(const className##InstanceCounter &/* other */) \ { \ _InstanceCounterData._InstanceCounter++; \ _InstanceCounterData._Touched = true; \ } \ \ ~className##InstanceCounter()\ { \ _InstanceCounterData._InstanceCounter--; \ } \ static sint32 getInstanceCounter() \ { \ return _InstanceCounterData._InstanceCounter; \ } \ static sint32 getInstanceCounterDelta() \ { \ return _InstanceCounterData._InstanceCounter - _InstanceCounterData._DeltaCounter; \ } \ static NLMISC::TInstanceCounterData _InstanceCounterData; \ }; \ \ className##InstanceCounter _##className##InstanceCounter; \ private: /// The macro to make the implementation of the counter #define NL_INSTANCE_COUNTER_IMPL(className) NLMISC::TInstanceCounterData className::className##InstanceCounter::_InstanceCounterData(#className); /// An utility macro to get the instance counter for a class #define NL_GET_LOCAL_INSTANCE_COUNTER(className) className::className##InstanceCounter::getInstanceCounter() #define NL_GET_INSTANCE_COUNTER(className) NLMISC::CInstanceCounterManager::getInstance().getInstanceCounter(#className) /// An utility macro to get the delta since the last counter reset. #define NL_GET_LOCAL_INSTANCE_COUNTER_DELTA(className) className::className##InstanceCounter::getInstanceCounterDelta() #define NL_GET_INSTANCE_COUNTER_DELTA(className) NLMISC::CInstanceCounterManager::getInstance().getInstanceCounterDelta(#className) // // Following are internal functions, you should never use them // /// Never use this function (internal use only) void nlFatalError (const char *format, ...); /// Never use this function but call the nlerror macro (internal use only) void nlError (const char *format, ...); #define NL_CRASH_DUMP_FILE "nel_debug.dmp" // Standard API to retrieve error code and test for windows or unix platform /// Return the last error code generated by a system call int getLastError(); /// Return a readable text according to the error code submited std::string formatErrorMessage(int errorCode); //------------------------------------------------------------------------------------------------- // A handy 'nldebug', 'nlinfo' & 'nlwarning' override system //------------------------------------------------------------------------------------------------- // // The system includes a set of object classes // To override one or more of the standard NeL log channels one simply instantiates the appropriate class // with the new log channel as a parameter. // The log channel in question will revert to its previous value on destruction of the override object // // Usage Example: // // void doSomething() // { // nlinfo("bla"); // nlwarning("bla"); // } // // NLMISC_COMMAND(bla,"bla","bla") // { // CNLLogOverride(&log); // doSomething(); // return true; // } // //------------------------------------------------------------------------------------------------- class CNLDebugOverride { public: CNLDebugOverride(NLMISC::CLog *debugLog) { nlassert(debugLog!=NULL); _OldValue=NLMISC::DebugLog; nlassert(_OldValue!=NULL); NLMISC::INelContext::getInstance().setDebugLog(debugLog); } ~CNLDebugOverride() { NLMISC::INelContext::getInstance().setDebugLog(_OldValue); } private: // prohibit copy CNLDebugOverride(const CNLDebugOverride&); NLMISC::CLog *_OldValue; }; //------------------------------------------------------------------------------------------------- class CNLInfoOverride { public: CNLInfoOverride(NLMISC::CLog *infoLog) { nlassert(infoLog!=NULL); _OldValue=NLMISC::InfoLog; nlassert(_OldValue!=NULL); NLMISC::INelContext::getInstance().setInfoLog(infoLog); } ~CNLInfoOverride() { NLMISC::INelContext::getInstance().setInfoLog(_OldValue); } private: // prohibit copy CNLInfoOverride(const CNLInfoOverride&); NLMISC::CLog *_OldValue; }; //------------------------------------------------------------------------------------------------- class CNLWarningOverride { public: CNLWarningOverride(NLMISC::CLog *warningLog) { nlassert(warningLog!=NULL); _OldValue=NLMISC::WarningLog; nlassert(_OldValue!=NULL); NLMISC::INelContext::getInstance().setWarningLog(warningLog); } ~CNLWarningOverride() { NLMISC::INelContext::getInstance().setWarningLog(_OldValue); } private: // prohibit copy CNLWarningOverride(const CNLWarningOverride&); NLMISC::CLog *_OldValue; }; //------------------------------------------------------------------------------------------------- class CNLLogOverride { public: CNLLogOverride(NLMISC::CLog *commonLog): _DebugLog(commonLog), _InfoLog(commonLog), _WarningLog(commonLog) {} private: CNLDebugOverride _DebugLog; CNLInfoOverride _InfoLog; CNLWarningOverride _WarningLog; }; //------------------------------------------------------------------------------------------------- class CNLSmartLogOverride { public: CNLSmartLogOverride(NLMISC::CLog *commonLog): _DebugLog(commonLog==NLMISC::InfoLog?NLMISC::DebugLog:commonLog), _InfoLog(commonLog), _WarningLog(commonLog==NLMISC::InfoLog?NLMISC::WarningLog:commonLog) {} private: CNLDebugOverride _DebugLog; CNLInfoOverride _InfoLog; CNLWarningOverride _WarningLog; }; } // NLMISC #endif // NL_DEBUG_H /* End of debug.h */ ================================================ FILE: code/nel/include/nel/misc/di_event_emitter.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_DI_EVENT_EMITTER_H #define NL_DI_EVENT_EMITTER_H #include "types_nl.h" #ifdef NL_OS_WINDOWS #define DIRECTINPUT_VERSION 0x0800 #include "input_device_server.h" #include "input_device_manager.h" #include "event_emitter.h" #include "smart_ptr.h" #include "events.h" #include "rect.h" #include "game_device.h" #define NOMINMAX #include #include namespace NLMISC { class CWinEventEmitter; class CDIKeyboard; class CDIMouse; struct IMouseDevice; struct IKeyboardDevice; // struct EDirectInput : public EInputDevice { EDirectInput(const char *reason) : EInputDevice(reason) {} }; // struct EDirectInputLibNotFound : public EDirectInput { EDirectInputLibNotFound() : EDirectInput("can't found the direct input dll") {} }; // struct EDirectInputInitFailed : public EDirectInput { EDirectInputInitFailed() : EDirectInput("Direct input initialization failed") {} }; // struct EDirectInputCooperativeLevelFailed : public EDirectInput { EDirectInputCooperativeLevelFailed() : EDirectInput("Direct Input Device Cooperative level couldn't be set") {} }; // Class to represent Direct Inputs events struct CDIEvent : public IInputDeviceEvent { virtual bool operator < (const IInputDeviceEvent &ide) const { // just compare the dates return Datas.dwTimeStamp < (safe_cast(&ide))->Datas.dwTimeStamp; } DIDEVICEOBJECTDATA Datas; }; /** * This manage events by using DirectInput8. * This should be polled regularly. * This can be mixed with a CWinEmitter (for example, you may have mouse using direct input, and keyboard using standard messages) * \author Nicolas Vizerie * \author Nevrax France * \date 2002 */ class CDIEventEmitter : public IEventEmitter, public IInputDeviceManager { public: /** Build a Direct Input Event Emitter object. An exception containing the reason is thrown if the initialization failed. * The obtained object must be released by deleting it. * \param hinst the instance of the application. * \param hwnd the main window of the application. * \param we A windows eventsemitter. Can be NULL. Needed if you want to mix WIN32 events and Direct Input events * (for example, a Direct Input Mouse and a Win32 Keyboard) */ static CDIEventEmitter *create(HINSTANCE hinst, HWND hwnd, CWinEventEmitter *we); ~CDIEventEmitter(); public: /// This poll the direct input state, directly storing the result in the given server, or keeping the result in internal server if NULL. void poll(CEventServer *server = NULL); ///\name From IDeviceManager, access to devices //@{ // Test if a mouse has been created (by a call to getMouseDeivce) virtual bool isMouseCreated() { return _Mouse != NULL; } /** Create the mouse device if needed (one active at a time for that object, repeated calls returns the same pointer) and get an interface on it. An exception if thrown if it couldn't be obtained. * If this object has a pointer on a win32 emiter, Win32 mouse messages are replaced by this mouse messages. */ virtual IMouseDevice *getMouseDevice(bool hardware) throw(EInputDevice); /// remove the direct input mouse virtual void releaseMouse(); /** Create the keyboard device if needed (one active at a time for that object, repeated calls returns the same pointer) and get an interface on it. * If this object has a pointer on a win32 emiter, Win32 keyboard messages are replaced by this keyboard messages. * NB: A direct input has no notion of localization or key combinations. See keyboard_device.h for more infos */ virtual IKeyboardDevice *getKeyboardDevice() throw(EInputDevice); /// remove the direct input keyboard virtual void releaseKeyboard(); // Enumerates current game devices (gamepads, joystick etc.). The result is stored in the given vector virtual void enumerateGameDevice(TDeviceDescVect &descs) throw(EInputDevice); // Create the given game device from its instance name. It also means that it will begin to sends inputs virtual IGameDevice *createGameDevice(const std::string &instanceName) throw(EInputDevice); // Release the given game device virtual void releaseGameDevice(IGameDevice *); //@} /// from IEventEmitter virtual void submitEvents(CEventServer &server, bool allWindows); virtual void emulateMouseRawMode(bool enable); // Build a TMouseButton value from the current buttons state TMouseButton buildButtonsFlags() const; // Build a TMouseButton value (but with no mouse values) TMouseButton buildKeyboardButtonFlags() const { return (TMouseButton) (buildButtonsFlags() & (ctrlButton|shiftButton|altButton)); } //================================================================ //================================================================ //================================================================ private: typedef HRESULT (WINAPI * TPDirectInput8Create) (HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID* ppvOut, LPUNKNOWN punkOuter); // Private internal server message, used to stored all messages internally before to dispatch them, when no server is supplied to poll(... class CDIEventServer : CEventServer { friend class CDIEventEmitter; public: void setServer (CEventServer *server) { _Server = server; } private: bool pumpEvent(CEvent *event) { CEventServer::pumpEvent(event); _Server->postEvent (event); return false; } private: CEventServer *_Server; }; private: HWND _hWnd; TMouseButton _ButtonsFlags; NLMISC::CRefPtr _WE; static HMODULE _DirectInputLibHandle; static TPDirectInput8Create _PDirectInput8Create; static uint _NumCreatedInterfaces; private: static bool loadLib(); static void unloadLib(); //==== private: CDIEventServer _InternalServer; CInputDeviceServer _DeviceServer; IDirectInput8 *_DInput8; CDIMouse *_Mouse; CDIKeyboard *_Keyboard; private: CDIEventEmitter(HWND hwnd, CWinEventEmitter *we); }; } // NLMISC #endif // NL_WINDOWS #endif // NL_DX_EVENT_EMITTER_H /* End of dx_event_emitter.h */ ================================================ FILE: code/nel/include/nel/misc/diff_tool.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef DIFF_TOOL_H #define DIFF_TOOL_H #include "i18n.h" namespace STRING_MANAGER { const ucstring nl("\r\n"); struct TStringInfo { std::string Identifier; ucstring Text; ucstring Text2; mutable ucstring Comments; uint64 HashValue; }; struct TStringDiffContext { typedef std::vector::iterator iterator; const std::vector &Addition; std::vector &Reference; std::vector &Diff; TStringDiffContext(const std::vector &addition, std::vector &reference, std::vector &diff) : Addition(addition), Reference(reference), Diff(diff) { } }; struct TClause { std::string Identifier; ucstring Conditions; ucstring Text; ucstring Comments; uint64 HashValue; }; struct TPhrase { std::string Identifier; ucstring Parameters; mutable ucstring Comments; std::vector Clauses; uint64 HashValue; }; struct TPhraseDiffContext { typedef std::vector::iterator iterator; const std::vector &Addition; std::vector &Reference; std::vector &Diff; TPhraseDiffContext(const std::vector &addition, std::vector &reference, std::vector &diff) : Addition(addition), Reference(reference), Diff(diff) { } }; struct TWorksheet { typedef std::vector TRow; typedef std::vector TData; TData Data; uint ColCount; TWorksheet() : ColCount(0) { } std::vector::iterator begin() { return Data.begin(); } std::vector::iterator end() { return Data.end(); } std::vector::const_iterator begin() const { return Data.begin(); } std::vector::const_iterator end() const { return Data.end(); } void push_back(const TRow &row) { Data.push_back(row); } std::vector::iterator insert(std::vector::iterator pos, const TRow &value) { return Data.insert(pos, value); } std::vector::iterator erase(std::vector::iterator it) { return Data.erase(it); } TRow &back() { return Data.back(); } TRow &operator [] (uint index) { return Data[index]; } const TRow &operator [] (uint index) const { return Data[index]; } uint size() const { return (uint)Data.size(); } void insertColumn(uint colIndex) { nlassert(colIndex <= ColCount); for (uint i=0; i oldColIndex) { // the dst is after the src, no problem with index insertColumn(newColIndex); copyColumn(oldColIndex, newColIndex); eraseColumn(oldColIndex); } else { // the dst is before the src, need to take the column insertion into account insertColumn(newColIndex); copyColumn(oldColIndex+1, newColIndex); eraseColumn(oldColIndex+1); } } void setColCount(uint count) { if (count != ColCount) { for (uint i=0; ioperator[](colIndex) == colValue) { rowIndex = (uint)(first - Data.begin()); return true; } } return false; } void setData(uint rowIndex, uint colIndex, const ucstring &value) { nlassertex(rowIndex < Data.size(), ("TWorksheet::setData: bad row index: rowIndex(%u) is out of range (max=%u)", rowIndex, Data.size())); nlassertex(colIndex < ColCount, ("TWorksheet::setData: bad column index: colIndex(%u) is not less than ColCount(%u) ar rowIndex(%u)", colIndex, ColCount, rowIndex)); Data[rowIndex][colIndex] = value; } const ucstring &getData(uint rowIndex, uint colIndex) const { nlassertex(rowIndex < Data.size(), ("TWorksheet::getData: bad row index: rowIndex(%u) is out of range (max=%u)", rowIndex, Data.size())); nlassertex(colIndex < ColCount, ("TWorksheet::getData: bad column index: colIndex(%u) is not less than ColCount(%u) at rowIndex(%u)", colIndex, ColCount, rowIndex)); return Data[rowIndex][colIndex]; } void setData(uint rowIndex, const ucstring &colName, const ucstring &value) { nlassertex(rowIndex > 0, ("TWorksheet::setData: rowIndex(%u) must be greater then 0 !", rowIndex)); nlassertex(rowIndex < Data.size(), ("TWorksheet::setData: rowIndex(%u) is out of range (max=%u)", rowIndex, Data.size())); TWorksheet::TRow::iterator it = std::find(Data[0].begin(), Data[0].end(), ucstring(colName)); nlassertex(it != Data[0].end(), ("TWorksheet::setData: invalid colName: can't find the column named '%s' at row %u", colName.toString().c_str(), rowIndex)); Data[rowIndex][it - Data[0].begin()] = value; } const ucstring &getData(uint rowIndex, const ucstring &colName) const { nlassertex(rowIndex > 0, ("TWorksheet::getData: bad row index: rowIndex(%u) must be greater then 0 !", rowIndex)); nlassertex(rowIndex < Data.size(), ("TWorksheet::getData: bad row index: rowIndex(%u) is out of range (max=%u)", rowIndex, Data.size())); TWorksheet::TRow::const_iterator it = std::find(Data[0].begin(), Data[0].end(), ucstring(colName)); nlassertex(it != Data[0].end(), ("TWorksheet::getData: invalid colName: can't find the column named '%s' at row %u", colName.toString().c_str(), rowIndex)); return Data[rowIndex][it - Data[0].begin()]; } }; struct TGetWorksheetIdentifier { std::string operator()(const TWorksheet &container, uint index) const { return container.getData(index, 1).toString(); } }; struct TGetWorksheetHashValue { uint64 operator()(const TWorksheet &container, uint index) const { return NLMISC::CI18N::stringToHash(container.getData(index, ucstring("*HASH_VALUE")).toString()); } }; struct TTestWorksheetItem : public std::unary_function { ucstring Identifier; TTestWorksheetItem(const std::string &identifier) : Identifier(identifier) {} bool operator () (const TWorksheet::TRow &row) const { return row[1] == Identifier; } }; struct TWordsDiffContext { typedef TWorksheet::TData::iterator iterator; const TWorksheet &Addition; TWorksheet &Reference; TWorksheet &Diff; TWordsDiffContext(const TWorksheet &addition, TWorksheet &reference, TWorksheet &diff) : Addition(addition), Reference(reference), Diff(diff) { } }; template struct TGetIdentifier { std::string operator()(const std::vector &container, uint index) const { return container[index].Identifier; } }; template struct TGetHashValue { uint64 operator()(const std::vector &container, uint index) const { return container[index].HashValue; } }; template struct TTestItem : public std::unary_function { std::string Identifier; TTestItem(const std::string &identifier) : Identifier(identifier) {} bool operator () (const ItemType &item) const { return item.Identifier == Identifier; } }; /** * ItemType must have a property named Identifier that uniquely * identify each item. * ItemType must have a property named HashValue that is used * to determine the change between context.Addition and context.Reference vector. */ template , class GetHashValue = TGetHashValue, class TestItem = TTestItem > class CMakeDiff { public: struct IDiffCallback { virtual void onEquivalent(uint addIndex, uint refIndex, Context &context) = 0; virtual void onAdd(uint addIndex, uint refIndex, Context &context) = 0; virtual void onRemove(uint addIndex, uint refIndex, Context &context) = 0; virtual void onChanged(uint addIndex, uint refIndex, Context &context) = 0; virtual void onSwap(uint newIndex, uint refIndex, Context &context) = 0; }; void makeDiff(IDiffCallback *callback, Context &context, bool skipFirstRecord = false) { #ifdef NL_DEBUG // compile time checking // Context::iterator testIt; #endif GetIdentifier getIdentifier; GetHashValue getHashValue; // compare the context.Reference an context.Addition file, remove any equivalent strings. uint addCount, refCount; if (skipFirstRecord) { addCount = 1; refCount = 1; } else { addCount = 0; refCount=0; } while (addCount < context.Addition.size() || refCount < context.Reference.size()) { bool equal = true; if (addCount != context.Addition.size() && refCount != context.Reference.size()) { equal = getHashValue(context.Addition, addCount) == getHashValue(context.Reference, refCount); } // vector::iterator it; if (addCount == context.Addition.size() || ( !equal && find_if(context.Addition.begin(), context.Addition.end(), TestItem(getIdentifier(context.Reference, refCount))) == context.Addition.end() ) ) { // this can only be removal callback->onRemove(addCount, refCount, context); context.Reference.erase(context.Reference.begin()+refCount); // ++refCount; } else if (refCount == context.Reference.size() || ( !equal && find_if(context.Reference.begin(), context.Reference.end(), TestItem(getIdentifier(context.Addition, addCount))) == context.Reference.end() ) ) { // this can only be context.Addition callback->onAdd(addCount, refCount, context); context.Reference.insert(context.Reference.begin()+refCount, context.Addition[addCount]); ++refCount; ++addCount; } else if (getIdentifier(context.Addition, addCount) != getIdentifier(context.Reference, refCount)) { // swap two element. // Context::iterator it = find_if(context.Reference.begin(), context.Reference.end(), TestItem(getIdentifier(context.Addition, addCount))); // if (it == context.Reference.end()) if (find_if( context.Reference.begin(), context.Reference.end(), TestItem(getIdentifier(context.Addition, addCount))) == context.Reference.end()) { // context.Addition callback->onAdd(addCount, refCount, context); context.Reference.insert(context.Reference.begin()+refCount, context.Addition[addCount]); ++refCount; ++addCount; } else { // nlassert(it != context.Reference.begin()+refCount); uint index = (uint)(find_if(context.Reference.begin(), context.Reference.end(), TestItem(getIdentifier(context.Addition, addCount))) - context.Reference.begin()); // callback->onSwap(it - context.Reference.begin(), refCount, context); callback->onSwap(index, refCount, context); // std::swap(*it, context.Reference[refCount]); std::swap(context.Reference[index], context.Reference[refCount]); } } else if (getHashValue(context.Addition, addCount) != getHashValue(context.Reference, refCount)) { // changed element callback->onChanged(addCount, refCount, context); ++refCount; ++addCount; } else { // same entry callback->onEquivalent(addCount, refCount, context); addCount++; refCount++; } } } }; typedef CMakeDiff TStringDiff; typedef CMakeDiff TPhraseDiff; typedef CMakeDiff TWorkSheetDiff; uint64 makePhraseHash(const TPhrase &phrase); bool parseHashFromComment(const ucstring &comments, uint64 &hashValue); bool loadStringFile(const std::string filename, std::vector &stringInfos, bool forceRehash, ucchar openMark = '[', ucchar closeMark = ']', bool specialCase = false); ucstring prepareStringFile(const std::vector &strings, bool removeDiffComments, bool noDiffInfo = false); bool readPhraseFile(const std::string &filename, std::vector &phrases, bool forceRehash); bool readPhraseFileFromString(ucstring const& doc, const std::string &filename, std::vector &phrases, bool forceRehash); ucstring tabLines(uint nbTab, const ucstring &str); ucstring preparePhraseFile(const std::vector &phrases, bool removeDiffComments); bool loadExcelSheet(const std::string filename, TWorksheet &worksheet, bool checkUnique = true); bool readExcelSheet(const ucstring &text, TWorksheet &worksheet, bool checkUnique = true); void makeHashCode(TWorksheet &sheet, bool forceRehash); ucstring prepareExcelSheet(const TWorksheet &worksheet); } // namespace STRING_MANAGER #endif // DIFF_TOOL_H ================================================ FILE: code/nel/include/nel/misc/displayer.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_DISPLAYER_H #define NL_DISPLAYER_H #include "types_nl.h" #include #include "log.h" namespace NLMISC { class CMutex; /** * Displayer interface. Used to specialize a displayer to display a string. * \ref log_howto * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ class IDisplayer { public: /// Constructor IDisplayer(const char *displayerName = ""); /// Destructor virtual ~IDisplayer(); /// Display the string where it does. void display( const CLog::TDisplayInfo& args, const char *message ); /// This is the identifier for a displayer, it is used to find or remove a displayer std::string DisplayerName; protected: /// Method to implement in the derived class virtual void doDisplay( const CLog::TDisplayInfo& args, const char *message) = 0; // Return the header string with date (for the first line of the log) static const char *HeaderString (); public: /// Convert log type to string static const char *logTypeToString (CLog::TLogType logType, bool longFormat = false); /// Convert the current date to human string static const char *dateToHumanString (); /// Convert date to "2000/01/14 10:05:17" string static const char *dateToHumanString (time_t date); /// Convert date to "784551148" string (time in second from 1975) static const char *dateToComputerString (time_t date); private: CMutex *_Mutex; }; /** * Std displayer. Put string to stdout. * \ref log_howto * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ class CStdDisplayer : virtual public IDisplayer { public: CStdDisplayer (const char *displayerName = "") : IDisplayer (displayerName) {} protected: /// Display the string to stdout and OutputDebugString on Windows virtual void doDisplay ( const CLog::TDisplayInfo& args, const char *message ); }; /** * File displayer. Put string into a file. * \ref log_howto * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ class CFileDisplayer : virtual public IDisplayer { public: /// Constructor CFileDisplayer (const std::string &filename, bool eraseLastLog = false, const char *displayerName = "", bool raw = false); CFileDisplayer (); ~CFileDisplayer (); /// Set Parameter of the displayer if not set at the ctor time void setParam (const std::string &filename, bool eraseLastLog = false); protected: /// Put the string into the file. virtual void doDisplay ( const CLog::TDisplayInfo& args, const char *message ); private: std::string _FileName; FILE *_FilePointer; bool _NeedHeader; uint _LastLogSizeChecked; bool _Raw; }; /** * Message Box displayer. Put string into a message box. * \ref log_howto * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ class CMsgBoxDisplayer : virtual public IDisplayer { public: CMsgBoxDisplayer (const char *displayerName = "") : IDisplayer (displayerName), IgnoreNextTime(false) {} bool IgnoreNextTime; protected: /// Put the string into the file. virtual void doDisplay ( const CLog::TDisplayInfo& args, const char *message ); }; } #endif // NL_DISPLAYER_H /* End of displayer.h */ ================================================ FILE: code/nel/include/nel/misc/dummy_window.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_DUMMY_WINDOW_H #define NL_DUMMY_WINDOW_H #include "nel/misc/types_nl.h" #ifdef NL_OS_WINDOWS // for win32 os only #ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif #ifndef _WIN32_WINDOWS # define _WIN32_WINDOWS 0x0410 #endif #ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0400 #endif #ifndef WINVER # define WINVER 0x0400 #endif #ifndef NOMINMAX # define NOMINMAX #endif #include namespace NLMISC { /** A simple invisible win32 window, with an optional message handling function. * Possible uses include : * - Creating an icon in the tray (require a window to be passed) * - Creating a message queue (in order to use an IPC mechanism such as WM_COPYDATA) * - etc. * * \author Nicolas Vizerie * \author Nevrax France * \date 2007 */ class CDummyWindow { public: CDummyWindow(); /** Init a dummy window, with an optional message handling procedure * \return true on success */ bool init(HINSTANCE hInstance, WNDPROC winProc = NULL); // release this window void release(); ~CDummyWindow(); // Get this window handle HWND getWnd() const { return _HWnd; } private: HWND _HWnd; }; } // NLMISC #endif // NL_OS_WINDOWS #endif ================================================ FILE: code/nel/include/nel/misc/dynloadlib.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_DYNLIBLOAD_H #define NL_DYNLIBLOAD_H #include "types_nl.h" #include #include #ifdef NL_OS_WINDOWS struct HINSTANCE__; typedef struct HINSTANCE__ *HINSTANCE; typedef HINSTANCE HMODULE; /* HMODULEs can be used in place of HINSTANCEs */ #else # include #endif namespace NLMISC { /// Define the os specific type for dynamic library module handler #if defined (NL_OS_WINDOWS) typedef HMODULE NL_LIB_HANDLE; #elif defined (NL_OS_UNIX) typedef void* NL_LIB_HANDLE; #else # error "You must define the module type on this platform" #endif #ifdef NL_OS_WINDOWS // MSCV need explicit tag to export or import symbol for a code module #define NL_LIB_EXPORT __declspec(dllexport) #define NL_LIB_IMPORT __declspec(dllimport) #else // other systems don't bother with this kind of detail, they export any 'extern' symbol (almost all functions) #define NL_LIB_EXPORT #define NL_LIB_IMPORT #endif /// Generic dynamic library loading function. NL_LIB_HANDLE nlLoadLibrary(const std::string &libName); /// Generic dynamic library unloading function. bool nlFreeLibrary(NL_LIB_HANDLE libHandle); /// Generic dynamic library symbol address lookup function. void *nlGetSymbolAddress(NL_LIB_HANDLE libHandle, const std::string &symbolName); // Compilation mode specific suffixes #ifdef NL_OS_WINDOWS # ifdef NL_DEBUG_INSTRUMENT const std::string nlLibSuffix("_di"); # elif defined(NL_DEBUG) const std::string nlLibSuffix("_d"); # elif defined(NL_RELEASE) const std::string nlLibSuffix("_r"); # else # error "Unknown compilation mode, can't build suffix" # endif #elif defined (NL_OS_UNIX) const std::string nlLibSuffix; // empty #else # error "You must define the lib suffix for your platform" #endif // Utility macro to export a module entry point as a C pointer to a C++ class or function #define NL_LIB_EXPORT_SYMBOL(symbolName, classOrFunctionName, instancePointer) \ extern "C" \ { \ NL_LIB_EXPORT classOrFunctionName *symbolName = (classOrFunctionName*)instancePointer; \ }; /* * * \author Boris Boucher * \author Nevrax France * \date 2004 */ class CLibrary { /// Dynamic library handle NL_LIB_HANDLE _LibHandle; /// Loaded library name std::string _LibFileName; /** When a module handle is assigned to the instance, this * flag state whether the CLibrary will free the library or not * when it is deleted. */ bool _Ownership; /** This points to the 'pure' nel library interface. * This means that the library export an entry point called * 'NeLLibraryEntry' that points to a INelLibrary interface. * This interface is used by the CLibrary class to * manage efficiently the library and to give * library implementors some hooks on library management. */ class INelLibrary *_PureNelLibrary; /// Lib paths static std::vector _LibPaths; /// Private copy constructor, not authorized CLibrary (const CLibrary &other); // Private assignment operator CLibrary &operator =(const CLibrary &other); public: CLibrary(); /** Assign a existing module handler to a new dynamic library instance * Note that you cannot use 'pure nel library' this way. */ CLibrary(NL_LIB_HANDLE libHandle, bool ownership); /// Load the specified library and take ownership by default CLibrary(const std::string &libName, bool addNelDecoration, bool tryLibPath, bool ownership = true); /// Destructor, free the library if the object have ownership virtual ~CLibrary(); /** Load the specified library. * The method assert if a module is already assigned or loaded * If addNelDecoration is true, the standard Nel suffix and library extention or prefix are * added to the lib name (with is just a base name). * If tryLibPath is true, then the method will try to find the required * library in the added library files (in order of addition). * Return true if the library load ok. */ bool loadLibrary(const std::string &libName, bool addNelDecoration, bool tryLibPath, bool ownership = true); /** Unload (free) the assigned/loaded library. * The object must have ownership over the library or the call will assert. * After this call, you can recall loadLibrary. */ void freeLibrary(); /** Get the address a the specified procedure in the library * Return NULL is the proc is not found, * Assert if the library is not load or assigned. */ void *getSymbolAddress(const std::string &symbolName); /// Get the name of the loaded library std::string getLibFileName() { return _LibFileName; } /// Check whether a library is effectively loaded bool isLibraryLoaded(); /** Check if the loaded library is a pure library * Return false if the library is not pure * or if the library is not loaded. */ bool isLibraryPure(); /** Return the pointer on the pure nel library interface. * Return NULL if isLibraryPure() is false. */ class INelLibrary *getNelLibraryInterface(); /** Build a NeL standard library name according to platform and compilation mode setting. * aka : adding decoration one base lib name. * e.g : 'mylib' become 'mylib_rd.dll' on Windows ReleaseDebug mode or * 'libmylib.so' on unix system. */ static std::string makeLibName(const std::string &baseName); /** Remove NeL standard library name decoration according to platform and compilation mode setting. * e.g : 'mylib_rd.dll' on windows ReleaseDebug mode become 'mylib' */ static std::string cleanLibName(const std::string &decoratedName); /** Add a list of library path * @see loadLibrary for a discusion about lib path */ static void addLibPaths(const std::vector &paths); /** Add a library path * @see loadLibrary for a discusion about lib path */ static void addLibPath(const std::string &path); }; /** Interface class for 'pure Nel' library module. * This interface is used to expose a standard * entry point for dynamically loaded library * and to add some hooks for library implementor * over library loading/unloading. */ class INelLibrary { friend class CLibrary; /// this counter keep tracks of how many time the library have been loaded in the same process. uint32 _LoadingCounter; /// The library context class CLibraryContext *_LibContext; /** Called by CLibrary after a successful loadLibrary * Note : this methods MUST be virtual to ensure * that the code executed is the one from * the loaded library. */ virtual void _onLibraryLoaded(class INelContext &nelContext); /** Called by the CLibrary class before unloading the library. * Note : this methods MUST be virtual to ensure * that the code executed is the one from * the loaded library. */ virtual void _onLibraryUnloaded(); public: INelLibrary() : _LoadingCounter(0), _LibContext(NULL) {} virtual ~INelLibrary(); /// Return the loading counter value uint32 getLoadingCounter(); /** Called after each loading of the library. * firstTime is true if this is the first time that * this library is loaded in the current process. * If the process load more than once the same * library, subsequent call to this method will * have firstTime false. * Implement this method to initialize think or whatever. */ virtual void onLibraryLoaded(bool firstTime) =0; /** Called after before each unloading of the library. * lastTime is true if the library will be effectively * unmapped from the process memory. * If the library have been loaded more than once, * then lastTime is false, indicating that the * library will still be in the process memory * space after the call. */ virtual void onLibraryUnloaded(bool lastTime) =0; }; #define NLMISC_PURE_LIB_ENTRY_POINT NelLibraryEntry #define NLMISC_DECL_PURE_LIB(className) \ className _PureLibraryEntryInstance; \ NL_LIB_EXPORT_SYMBOL( NLMISC_PURE_LIB_ENTRY_POINT, NLMISC::INelLibrary, &_PureLibraryEntryInstance) } // NLMISC #endif // NL_DYNLIBLOAD_H ================================================ FILE: code/nel/include/nel/misc/eid_translator.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_EID_TRANSLATOR_H #define NL_EID_TRANSLATOR_H #include #include #include #include #include "types_nl.h" #include "entity_id.h" #include "ucstring.h" #include "command.h" namespace NLMISC { class CEntityIdTranslator { NLMISC_SAFE_SINGLETON_DECL_PTR(CEntityIdTranslator); public: /** Descriptor for an entity in the translator */ struct CEntity { CEntity () : EntityNameStringId(0), EntitySlot(-1), ShardId(0), UId(std::numeric_limits::max()), Online(false) { } CEntity (const ucstring &entityName, uint32 uid, const std::string &userName, sint8 entitySlot, uint32 shardId =0) : EntityName(entityName), EntityNameStringId(0), EntitySlot(entitySlot), ShardId(shardId), UId(uid), UserName(userName), Online(false) { } /// The display name of the entity ucstring EntityName; /// The mapped name of the entity (used to store IOS generated string id) uint32 EntityNameStringId; /// the character slot sint8 EntitySlot; /// Shard id of the entity (for multi shard systems) uint32 ShardId; /// User id the character owner (aka account id) uint32 UId; /// User name of the character owner (aka account name) std::string UserName; /// A flag stating if the character is online bool Online; void serial (NLMISC::IStream &s); }; typedef std::map TEntityCont; /// clear all the registered entities from the translator. void clear(); // performs all check on a name ( name validity + uniqueness ) bool checkEntityName (const ucstring &entityName); /// return true if a name already exists bool entityNameExists(const ucstring &entityName); // register an entity in this manager void registerEntity (const CEntityId &eid, const ucstring &entityName, sint8 entitySlot, uint32 uid, const std::string &userName, uint32 shardId =0); // register or update an entity in this manager void updateEntity (const CEntityId &eid, const ucstring &entityName, sint8 entitySlot, uint32 uid, const std::string &userName, uint32 shardId =0); // unregister an entity from this manager void unregisterEntity (const CEntityId &eid); // Check if an entity is registered bool isEntityRegistered(const CEntityId &eid); // set an association entityName / entityStringId, return true if association has been set bool setEntityNameStringId(const ucstring &entityName, uint32 stringId); // set an association entityId / entityStringId, return true if association has been set bool setEntityNameStringId(const CEntityId &eid, uint32 stringId); // get string id for entityId uint32 getEntityNameStringId(const CEntityId &eid); // get the shard id of an entity uint32 getEntityShardId(const CEntityId &eid); // set an eid to online or not void setEntityOnline (const CEntityId &eid, bool online); // is an entity in online bool isEntityOnline (const CEntityId &eid); // check if parameters are coherent with the content of the class, if not, set with the parameters and warn void checkEntity (const CEntityId &eid, const ucstring &entityName, uint32 uid, const std::string &userName); // the first param is the file where are all entities information, the second is a text file (one line per pattern using * and ?) with invalid entity name void load (const std::string &fileName, const std::string &invalidEntityNamesFilename); // you must call this function to save the data into the hard drive void save (); // get eid using the entity name CEntityId getByEntity (const ucstring &entityName); // get entity name using the eid const ucstring &getByEntity (const NLMISC::CEntityId &eid); void getEntityIdInfo (const CEntityId &eid, ucstring &entityName, sint8 &entitySlot, uint32 &uid, std::string &userName, bool &online, std::string* additional = NULL); // transform a username ucstring into a string that can be compared with registered string std::string getRegisterableString( const ucstring & entityName); /// return a vector of invalid names const std::vector & getInvalidNames(){ return InvalidEntityNames; } const TEntityCont &getRegisteredEntities () { return RegisteredEntities; } static const uint Version; uint FileVersion; /** * Callback called when getEntityIdInfo called, so service may add additional info * Format MUST be [InfoName InfoValue]* (e.g. a list of 2 strings, first being name for * the retrieved info, and second being the value of the info */ typedef std::string (*TAdditionalInfoCb)(const CEntityId &eid); TAdditionalInfoCb EntityInfoCallback; static void removeShardFromName(ucstring& name); private: // get all eid for a user using the user name or the user id void getByUser (uint32 uid, std::vector &res); void getByUser (const std::string &userName, std::vector &res, bool exact=true); void getByEntity (const ucstring &entityName, std::vector &res, bool exact); // return the user id and 0 if not found uint32 getUId (const std::string &userName); std::string getUserName (uint32 uid); // Returns true if the username is valid. // It means that there only alphabetic and numerical character and the name is at least 3 characters long. bool isValidEntityName (const ucstring &entityName, NLMISC::CLog *log = NLMISC::InfoLog ); /// The container for all entity in the translator TEntityCont RegisteredEntities; typedef std::map TNameIndexCont; /// the reverse index to retreive entity by name TNameIndexCont NameIndex; // Singleton, no ctor access CEntityIdTranslator() { EntityInfoCallback = NULL; } std::string FileName; std::vector InvalidEntityNames; friend void cbInvalidEntityNamesFilename(const std::string &filename); friend struct entityNameValidClass; NLMISC_CATEGORISED_COMMAND_FRIEND(nel,findEIdByUser); NLMISC_CATEGORISED_COMMAND_FRIEND(nel,findEIdByEntity); NLMISC_CATEGORISED_COMMAND_FRIEND(nel,entityNameValid); NLMISC_CATEGORISED_COMMAND_FRIEND(nel,playerInfo); }; } #endif // NL_EID_TRANSLATOR_H /* End of eid_translator.h */ ================================================ FILE: code/nel/include/nel/misc/entity_id.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_ENTITY_ID_H #define NL_ENTITY_ID_H #include "types_nl.h" #include "debug.h" #include "common.h" #include "stream.h" namespace NLMISC { /** * Entity identifier * \author Sameh Chafik, Vianney Lecroart * \author Nevrax France * \date 2001 */ struct CEntityId { // pseudo constants enum { DYNAMIC_ID_SIZE = 8, CREATOR_ID_SIZE = 8, TYPE_SIZE = 8, ID_SIZE = 40, UNKNOWN_TYPE = (1 << TYPE_SIZE)-1 }; protected: // --------------------------------------------------------------------------------- // instantiated data union { struct { /// Id of the service where the entity is (variable routing info). uint64 DynamicId : DYNAMIC_ID_SIZE; /// Id of the service who created the entity (persistent). uint64 CreatorId : CREATOR_ID_SIZE; /// Type of the entity (persistent). uint64 Type : TYPE_SIZE; /// Local entity number (persistent). uint64 Id : ID_SIZE; } DetailedId; uint64 FullId; }; // --------------------------------------------------------------------------------- // static data /// Counter for generation of unique entity ids static NLMISC::CEntityId _NextEntityId; ///The local num service id of the local machin. static uint8 _ServerId; public: // --------------------------------------------------------------------------------- // static data ///The maximum number that we could generate without generate an overtaking exception. static const uint64 MaxEntityId; /// Unknown CEntityId is similar as a NULL pointer. static const CEntityId Unknown; // --------------------------------------------------------------------------------- // generation of new unique entity ids /// Set the service id for the generator static void setServiceId( uint8 sid ) { _NextEntityId.setDynamicId( sid ); _NextEntityId.setCreatorId( sid ); _ServerId = sid; } /// Generator of entity ids static CEntityId getNewEntityId( uint8 type ) { nlassert(_NextEntityId != Unknown ); // type may be Unknown, so isUnknownId() would return true NLMISC::CEntityId id = _NextEntityId++; id.setType( type ); return id; } // --------------------------------------------------------------------------------- // constructors ///\name Constructor //@{ CEntityId () { FullId = 0; DetailedId.Type = UNKNOWN_TYPE; /* DynamicId = 0; CreatorId = 0; Type = 127; Id = 0; */ } CEntityId (uint8 type, uint64 id, uint8 creator, uint8 dynamic) { DetailedId.DynamicId = dynamic; DetailedId.CreatorId = creator; DetailedId.Type = type; DetailedId.Id = id; } CEntityId (uint8 type, uint64 id) { DetailedId.Type = type; DetailedId.Id = id; DetailedId.CreatorId = _ServerId; DetailedId.DynamicId = _ServerId; } explicit CEntityId (uint64 p) { FullId = p; /* DynamicId = (p & 0xff); p >>= 8; CreatorId = (p & 0xff); p >>= 8; Type = (p & 0xff); p >>= 8; Id = (p); */ } CEntityId (const CEntityId &a) { FullId = a.FullId; /* DynamicId = a.DynamicId; CreatorId = a.CreatorId; Type = a.Type; Id = a.Id; */ } ///fill from read stream. CEntityId (NLMISC::IStream &is) { is.serial(FullId); /* uint64 p; is.serial(p); DynamicId = (p & 0xff); p >>= 8; CreatorId = (p & 0xff); p >>= 8; Type = (p & 0xff); p >>= 8; Id = p; */ } explicit CEntityId (const std::string &str) { fromString(str.c_str()); } explicit CEntityId (const char *str) { CEntityId (); fromString(str); } //@} // --------------------------------------------------------------------------------- // accessors /// Get the full id uint64 getRawId() const { return FullId; /* return (uint64)*this; */ } /// Get the local entity number uint64 getShortId() const { return DetailedId.Id; } /// Set the local entity number void setShortId( uint64 shortId ) { DetailedId.Id = shortId; } /// Get the variable routing info uint8 getDynamicId() const { return DetailedId.DynamicId; } /// Set the variable routing info void setDynamicId( uint8 dynId ) { DetailedId.DynamicId = dynId; } /// Get the persistent creator id uint8 getCreatorId() const { return DetailedId.CreatorId; } /// Set the persistent creator id void setCreatorId( uint8 creatorId ) { DetailedId.CreatorId = creatorId; } /// Get the entity type uint8 getType() const { return (uint8)DetailedId.Type; } /// Set the entity type void setType( uint8 type ) { DetailedId.Type = type; } /// Get the persistent part of the entity id (the dynamic part in the returned id is 0) uint64 getUniqueId() const { CEntityId id; id.FullId = FullId; id.DetailedId.DynamicId = 0; return id.FullId; } /// Test if the entity id is Unknown bool isUnknownId() const { return DetailedId.Type == UNKNOWN_TYPE; } // --------------------------------------------------------------------------------- // operators ///\name comparison of two CEntityId. //@{ bool operator == (const CEntityId &a) const // virtual bool operator == (const CEntityId &a) const { CEntityId testId ( FullId ^ a.FullId ); testId.DetailedId.DynamicId = 0; return testId.FullId == 0; /* return (Id == a.DetailedId.Id && DetailedId.CreatorId == a.DetailedId.CreatorId && DetailedId.Type == a.DetailedId.Type); */ } bool operator != (const CEntityId &a) const { return !((*this) == a); } bool operator < (const CEntityId &a) const // virtual bool operator < (const CEntityId &a) const { return getUniqueId() < a.getUniqueId(); /* if (Type < a.Type) { return true; } else if (Type == a.Type) { if (Id < a.Id) { return true; } else if (Id == a.Id) { return (CreatorId < a.CreatorId); } } return false; */ } bool operator > (const CEntityId &a) const // virtual bool operator > (const CEntityId &a) const { return getUniqueId() > a.getUniqueId(); /* if (Type > a.Type) { return true; } else if (Type == a.Type) { if (Id > a.Id) { return true; } else if (Id == a.Id) { return (CreatorId > a.CreatorId); } } // lesser return false; */ } //@} const CEntityId &operator ++(int) { if(DetailedId.Id < MaxEntityId) { DetailedId.Id ++; } else { nlerror ("CEntityId looped (max was %" NL_I64 "d", MaxEntityId); } return *this; } const CEntityId &operator = (const CEntityId &a) { FullId = a.FullId; /* DynamicId = a.DynamicId; CreatorId = a.CreatorId; Type = a.Type; Id = a.Id; */ return *this; } const CEntityId &operator = (uint64 p) { FullId = p; /* DynamicId = (uint64)(p & 0xff); p >>= 8; CreatorId = (uint64)(p & 0xff); p >>= 8; Type = (uint64)(p & 0xff); p >>= 8; Id = (uint64)(p); */ return *this; } // --------------------------------------------------------------------------------- // other methods... uint64 asUint64()const { return FullId; } /* operator uint64 () const { return FullId; uint64 p = Id; p <<= 8; p |= (uint64)Type; p <<= 8; p |= (uint64)CreatorId; p <<= 8; p |= (uint64)DynamicId; return p; } */ // --------------------------------------------------------------------------------- // loading, saving, serialising... /// Save the Id into an output stream. void save(NLMISC::IStream &os) // virtual void save(NLMISC::IStream &os) { os.serial(FullId); /* uint64 p = Id; p <<= 8; p |= (uint64)Type; p <<= 8; p |= (uint64)CreatorId; p <<= 8; p |= (uint64)DynamicId; os.serial(p); */ } /// Load the number from an input stream. void load(NLMISC::IStream &is) // virtual void load(NLMISC::IStream &is) { is.serial(FullId); /* uint64 p; is.serial(p); DynamicId = (uint64)(p & 0xff); p >>= 8; CreatorId = (uint64)(p & 0xff); p >>= 8; Type = (uint64)(p & 0xff); p >>= 8; Id = (uint64)(p); */ } void serial (NLMISC::IStream &f) throw (NLMISC::EStream) // virtual void serial (NLMISC::IStream &f) throw (NLMISC::EStream) { if (f.isReading ()) { load (f); } else { save (f); } } // --------------------------------------------------------------------------------- // string convertions /// return a string in form "(a:b:c:d)" where a,b,c,d are components of entity id. std::string toString() const { std::string ident; ident.reserve(25); ident+='('; getDebugString (ident); ident+=')'; return ident; } /// Read from a debug string, use the same format as toString() (id:type:creator:dynamic) in hexadecimal void fromString(const char *str) // virtual void fromString(const char *str) { uint64 id; uint type; uint creatorId; uint dynamicId; if (sscanf(str, "(%" NL_I64 "x:%x:%x:%x)", &id, &type, &creatorId, &dynamicId) != 4) { *this = Unknown; return; } DetailedId.Id = id; DetailedId.Type = type; DetailedId.CreatorId = creatorId; DetailedId.DynamicId = dynamicId; } /// Have a debug string. void getDebugString(std::string &str) const // virtual void getDebugString(std::string &str) const { str.reserve(str.size()+24); char b[256]; memset(b,0,255); memset(b,'0',19); sint n; uint64 x = DetailedId.Id; char baseTable[] = "0123456789abcdef"; for(n = 10; n < 20; n ++) { b[19 - n] = baseTable[(x & 15)]; x >>= 4; } b[19 - 9] = ':'; x = DetailedId.Type; for(n = 7; n < 9; n ++) { b[19 - n] = baseTable[(x & 15)]; x >>= 4; } b[19 - 6] = ':'; x = DetailedId.CreatorId; for(n = 4; n < 6; n ++) { b[19 - n] = baseTable[(x & 15)]; x >>= 4; } b[19 - 3] = ':'; x = DetailedId.DynamicId; for(n = 1; n < 3; n ++) { b[19 - n] = baseTable[(x & 15)]; x >>= 4; } str += "0x"; str += b; } /* /// \name NLMISC::IStreamable method. //@{ std::string getClassName () // virtual std::string getClassName () { return std::string (""); } //@} */ // friend std::stringstream &operator << (std::stringstream &__os, const CEntityId &__t); }; /** * a generic hasher for entities */ /*class CEidHash { public: size_t operator () ( const NLMISC::CEntityId & id ) const { uint64 hash64 = id.getUniqueId(); return size_t(hash64) ^ size_t( hash64 >> 32 ); return (uint32)id.getShortId(); } };*/ // Traits for hash_map using CEntityId struct CEntityIdHashMapTraits { enum { bucket_size = 4, min_buckets = 8, }; CEntityIdHashMapTraits() { } size_t operator() (const NLMISC::CEntityId &id ) const { uint64 hash64 = id.getUniqueId(); return size_t(hash64) ^ size_t( hash64 >> 32 ); //return size_t(id.getShortId()); } bool operator() (const NLMISC::CEntityId &id1, const NLMISC::CEntityId &id2) const { return id1.getShortId() < id2.getShortId(); } }; /*inline std::stringstream &operator << (std::stringstream &__os, const CEntityId &__t) { __os << __t.toString (); return __os; }*/ } // NLMISC #endif // NL_ENTITY_ID_H /* End of entity_id.h */ ================================================ FILE: code/nel/include/nel/misc/enum_bitset.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_ENUM_BIYSET_H #define NL_ENUM_BIYSET_H #include "types_nl.h" #include "sstring.h" namespace NLMISC { template struct TSimpleEnum { static BitsetType getValue (EnumType value) { return BitsetType(value); } }; template struct TContainedEnum { static BitsetType getValue (EnumType value) { return BitsetType(value.getValue()); } }; /** Utility to build 'ored' bit set from a 2 powered enum. * The class give to user a conprehensive interface for * dealing with 'ored' enum value. * * The class not strictly check that the enum only contains * power of 2 values because the enum can eventualy * contains pre 'ored' values. * For each access, the size in bit of the enumerated value * passed to the class is checked to not oversize the * BitsetType capacity. * By default, the BitsetType is set to 32 bits, but you * can provide your own type to narrow or expand the * capacity. * * You can add an additional checking by setting the maxValue to * the max value of the enumerated type. * * For from/to string convertion, you can also provide a delimiter * char (that is comma by default). * * * usage: * enum foo * { * value1 = 1, * value2 = 2, * value3 = 4, * value4 = 8, * maxFoo * }; * * // Create the enum bit set, using enum foo, coded on an uint32 and limited * // to the value maxFoo in order to check for invalid values. * CEnumBitSet myset; * myset.setEnumValue(value1); * myset.setEnumValue(value4); * myset.clearEnumValue(value4); * * myset.checkEnumValue(value1); // return true * myset.checkEnumValue(value2); // return false * myset.checkEnumValue(value4); // return false */ template , class SimpleEnumType = EnumType > struct CEnumBitset { // Default constructor with no flag set CEnumBitset() : Bitset(0) { } // Constructor with one flag set CEnumBitset(EnumType value) : Bitset(0) { setEnumValue(value); } // Constructor with a enumerated string CEnumBitset(const std::string &valueList) : Bitset(0) { fromString(valueList); } /// Add a bit void addEnumValue(EnumType value) { nlwarning("Deprecated, please use setEnumValue"); setEnumValue(value); // nlassert(value < maxValue); // Bitset |= value; } /// set a bit void setEnumValue(EnumType value) { nlassert(EnumAccessor::getValue(value) < maxValue); Bitset |= EnumAccessor::getValue(value); } /// clear a bit void clearEnumValue(EnumType value) { nlassert(EnumAccessor::getValue(value) < maxValue); Bitset &= ~(EnumAccessor::getValue(value)); } bool checkEnumValue(EnumType value) { return (Bitset & EnumAccessor::getValue(value)) == EnumAccessor::getValue(value); } std::string toString() const { CSString result; std::string delim; delim += Delimiter; // count up to 64 bits BitsetType value=1; uint i=0; for (; i<64; value <<= 1, ++i) { if (Bitset & value) { if (!result.empty()) result << delim; // this bit is set, add a string result << EnumType::toString(SimpleEnumType(value)); } } return result; } bool fromString(const std::string &valueList) { std::vector values; std::string delim; delim += Delimiter; NLMISC::explode(valueList, delim, values, true); for( uint i=0; i // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_EVAL_NUM_EXPR_H #define NL_EVAL_NUM_EXPR_H #include "types_nl.h" namespace NLMISC { /** * This class performs numerical expression parsing. */ class CEvalNumExpr { public: virtual ~CEvalNumExpr() {} /// Eval return error. enum TReturnState { NoError, // No error UnknownValue, // Unknown value has been parsed ValueError, // Error during user defined value evaluation UnknownFunction, // Unknown function has been parsed FunctionError, // Error during user defined function evaluation NumberSyntaxError, // Syntax error in a number expression UnknownOperator, // Unknown operator MustBeOpen, // Should be a open parenthesis MustBeClose, // Should be a close parenthesis MustBeComa, // Should be a coma character MustBeExpression, // Should be an expression NotUnaryOperator, // Should not be an unary operator MustBeEnd, // Should be the end MustBeDoubleQuote, // Should be a double quote DividByZero, // Divide by zero ReturnValueCount }; /** * Evaluate a numerical expression. * * Doesn't allocate heap memory for common complexity expression. * * \param expression is an expression string. See the expression grammar. * \param result is filled with the result if the function returns "NoError". * \param errorIndex is a pointer on an integer value filled with the index * of the parsing error in the input string if function doesn't return "NoError". * This value can be NULL. * \param userData is a user data used by user eval function * \return NoError if the expression has been parsed. Result is filled with the evaluated value. * * This expression must follow the following grammar with the following evaluation priority: * * expression: '-' expression * | '!' expression // Returns true if a equal false, else false (logical not) * | '~' expression // Returns ~ round(a) (bitwise not) * | '(' expression ')' * | expression operator expression * | function1 '(' expression ')' * | function2 '(' expression ',' expression ')' * | number * | constant * | string // User defined value, evaluated by the evalValue() callback * * operator: '*' // Calculates (a * b) * | '/' // Calculates (a / b) * | '%' // Calculates the remainder of (a / b) * | '+' // Calculates (a + b) * | '-' // Calculates (a - b) * | '<<' // Returns round(a) left 32 bits unsigned shift by round(b) * | '>>' // Returns round(a) right 32 bits unsigned shift by round(b) * | '<-' // Returns round(a) left 32 bits signed shift by round(b) * | '->' // Returns round(a) right 32 bits signed shift by round(b) * | '<' // Returns true if a is strictly smaller than b * | '<=' // Returns true if a is smaller or equal than b * | '>' // Returns true if a is strictly bigger than b * | '>=' // Returns true if a is bigger or equal than b * | '==' // Returns true if a equal b, else returns false (warning, performs a floating point comparison) * | '!=' // Returns false if a equal b, else returns true (warning, performs a floating point comparison) * | '&' // Returns round(a) & round(b) over 32 bits * | '|' // Returns round(a) | round(b) over 32 bits * | '^' // Returns round(a) ^ round(b) over 32 bits * | '&&' // Returns true if a equal true and b equal true else returns false * | '||' // Returns true if a equal true or b equal true else returns false * | '^^' // Returns true if a equal true and b equal false, or, a equal false and b equal 1.0, else returns false * * function1: abs // Calculates the absolute value * | acos // Calculates the arccosine * | asin // Calculates the arcsine * | atan // Calculates the arctangent * | ceil // Calculates the ceiling of a value ( ceil(-1.1) = -1, ceil(1.1) = 2 ) * | cos // Calculates the cosine * | cosh // Calculates the hyperbolic cosine * | exp // Calculates the exponential * | exponent // Calculates the exponent of a floating point value * | floor // Calculates the floor of a value ( floor(-1.1) = -2, floor(1.1) = 1 ) * | int // Calculates the C style integer value ( int(-1.6) = -1, int(1.6) = 1 ) * | log // Calculates logarithms * | log10 // Calculates base-10 logarithms * | mantissa // Calculates the mantissa of a floating point value * | round // Calculates the nearest integer value ( round(-1.6) = -2, round(1.1) = 1 ) * | sin // Calculate sines * | sinh // Calculate hyperbolic sines * | sq // Calculates the square * | sqrt // Calculates the square root * | tan // Calculates the tangent * | tanh // Calculates the hyperbolic tangent * | string // User defined one arg function, evaluated by the evalfunction() callback * * function2: max // Returns the larger of two values * | min // Returns the smaller of two values * | atan2 // Calculates the arctangent of arg0/arg1 * | pow // Calculates a raised at the power of b * | rand // Calculates a pseudo random value (arg0 <= randomValue < arg1) * | string // User defined two args function, evaluated by the evalfunction() callback * * number: [0-9]+ // Unsigned decimal integer * | "0x"[0-9a-fA-F]+ // Unsigned hexadecimal integer * | "0"[0-7]+ // Unsigned octal integer * | [0-9]*.[0-9]+ // Unsigned floating point value * | [0-9]*.[0-9]+[eE]-?[0-9]*.[0-9]+ // Unsigned floating point value with signed exponent * * constant: e // 2.7182818284590452353602874713527 * | pi // 3.1415926535897932384626433832795 * * string: [^ 0-9\t\n/\*-+=<>&|\^!%~\(\)\.,\"][^ \t\n/\*-+=<>&|\^!%~\(\)\.,\"]* // Labels ($foo, #foo01, _001) * | \"[]+\" // All kind of labels between double quotes "123456" "foo.foo[12]" * * Operator precedence: * * 0 - unary operator (-, ~, !) * 1 - *, /, % * 2 - +, -, * 3 - <<, >>, <-, -> * 4 - <, <=, >, >= * 5 - ==, != * 6 - & * 7 - | * 8 - ^ * 9 - && * 10 - || * 11 - ^^ * */ TReturnState evalExpression (const char *expression, double &result, int *errorIndex, uint32 userData = 0); /// Get error string const char* getErrorString (TReturnState state) const; protected: /// Overridable functions /** * Eval a user defined value. Default implementation returns UnknownValue. * The user can parse the value and fill the result double and return NoError, UnknownValue or * ValueError. * * \param value is the value to parse. * \param result is the result to fill if the value has been successfully parsed. * \param userData is a user data used by user eval function. * \return UnknownValue if the value is not known, ValueError is the value evaluation failed or NoError * if it has been parsed. */ virtual TReturnState evalValue (const char *value, double &result, uint32 userData); /** * Eval a user defined function. Default implementation returns UnknownFunction. * The user can parse the function name and fill the result double and return NoError, UnknownFunction * or FunctionError. * * To convert double argu in boolean argu, use (round (value) != 0.0) ? true : false * * \param funcName is the name of the function to evaluate. * \param arg0 is the first parameter passed to the function. * \param arg1 is the second parameter passed to the function. * \param result is the result to fill if the value has been successfully parsed. * \return UnknownFunction if the function doesn't exist, FunctionError if the function evaluation * failed, NoError if it has been parsed. */ virtual TReturnState evalFunction (const char *funcName, double arg0, double &result); virtual TReturnState evalFunction (const char *funcName, double arg0, double arg1, double &result); private: /// Implementation /// Expression tokens enum TToken { Number, // This is a number Function1, // This is a function with one argu Function2, // This is a function with two argu String, // This is a user string Operator, // This is an operator Open, // ( Close, // ) Coma, // , End, // End of string }; // Operators enum TOperator { Not = 0, // ! Tilde, // ~ Mul, // * Div, // / Remainder, // % Plus, // + Minus, // - ULeftShift, // << URightShift, // >> SLeftShift, // <- SRightShift, // -> Inferior, // < InferiorEqual, // <= Superior, // > SuperiorEqual, // >= Equal, // == NotEqual, // != And, // & Or, // | Xor, // ^ LogicalAnd, // && LogicalOr, // || LogicalXor, // ^^ OperatorCount, // NotOperator, // This is not an operator ExtOperator, // This is a 2 characters operator }; // Functions enum TReservedWord { Abs = 0, Acos, Asin, Atan, Atan2, Ceil, Cos, Cosh, Exp, Exponent, Floor, Int, Log, Log10, Mantissa, Max, Min, Pow, Rand, Round, Sin, Sinh, Sq, Sqrt, Tan, Tanh, ReservedWordCount, }; // Some constant enum { InternalStringLen = 32, InternalOperator = 4, }; /// Members TReturnState _State; // Current state const char *_ExprPtr; // Current pointer on the expression /// Read a decimal double TReturnState readDecimal (double &value); /// Read an integer void readIntegerNumberDecimal (double &value); /// Internal functions /// Get the next token TReturnState getNextToken (TToken &token); /// Evaluate an expression TReturnState evalExpression (double &result, TToken &nextToken, uint32 userData); /// Reserved word TReservedWord _ReservedWordFound; /// Current string char _InternalString[InternalStringLen]; std::string _InternalStlString; const char *_InternalStringPtr; /// Current value double _Value; /// Current operator TOperator _Op; /// Static values /// Char to operator array static const TToken _ReservedWordToken[ReservedWordCount]; static const char *_ReservedWord[ReservedWordCount]; static const TOperator _OperatorArray[128]; static const bool _StringChar[128]; static const char *_ErrorString[ReturnValueCount]; static const int _OperatorPrecedence[]; public: bool internalCheck (); }; } #endif // NL_EVAL_NUM_EXPR_H ================================================ FILE: code/nel/include/nel/misc/event_emitter.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_EVENT_EMITTER_H #define NL_EVENT_EMITTER_H #include "types_nl.h" #include "event_server.h" #include "smart_ptr.h" namespace NLMISC { /*===================================================================*/ class CEventServer; /** * CEventEmitter * Send events to the event server * */ /* *** IMPORTANT ******************** * *** IF YOU MODIFY THE STRUCTURE OF THIS CLASS, PLEASE INCREMENT IDriver::InterfaceVersion TO INVALIDATE OLD DRIVER DLL * ********************************** */ class IEventEmitter : public NLMISC::CRefCount { public: /// dtor virtual ~IEventEmitter() {} /** * sends all events to server * (should call CEventServer method postEvent() ) * \param server */ virtual void submitEvents(CEventServer & server, bool allWindows) = 0; }; } // NLMISC #endif // NL_EVENT_EMITTER_H /* End of event_emitter.h */ ================================================ FILE: code/nel/include/nel/misc/event_emitter_multi.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_EVENT_EMITTER_MULTI_H #define NL_EVENT_EMITTER_MULTI_H #include "types_nl.h" #include "event_emitter.h" #include namespace NLMISC { /** The composite pattern applied to events emmitters. * This is useful when you don't have the opportunity to register more than * one event emitter to an event server. */ class CEventEmitterMulti : public IEventEmitter { public: /// dtor virtual ~CEventEmitterMulti(); /// add an emitter void addEmitter(IEventEmitter *e, bool mustDelete); /// remove an emitter (and delete it if necessary) void removeEmitter(IEventEmitter *e); /// test whether e is in the emitter list bool isEmitter(IEventEmitter *e) const; // Get the number of registered emitters uint getNumEmitters() const { return (uint)_Emitters.size(); } // Get an emitter IEventEmitter *getEmitter(uint index); const IEventEmitter *getEmitter(uint index) const; /// From IEventEmitter. This call submitEvents on all the emitters virtual void submitEvents(CEventServer &server, bool allWindows); virtual bool copyTextToClipboard(const ucstring &text); virtual bool pasteTextFromClipboard(ucstring &text); private: typedef std::vector > TEmitterCont; TEmitterCont _Emitters; }; } // NLMISC #endif // NL_EVENT_EMITTER_MULTI_H /* End of event_emitter_multi.h */ ================================================ FILE: code/nel/include/nel/misc/event_listener.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_EVENT_LISTENER_H #define NL_EVENT_LISTENER_H #include "types_nl.h" #include "events.h" #include "bit_set.h" namespace NLMISC { class CEvent; class CEventServer; /** * Interface for event listener. A listener provides a callback. * \author Stephane Coutelas * \author Nevrax France * \date 2000 */ class IEventListener { public: /// Constructor IEventListener(); /// Destructor virtual ~IEventListener() {} /** Called by CServer::pumpEvent(). The default calls the () operator, unless a hook has been set. * In this case processEvent is called on the hook instead (the hook can forward the call to that listener afterwards). */ virtual void process(const CEvent& event) { if (_Hook) { _Hook->process(event); } else { (*this)(event); } } /** * Call back of the listener. * \param event is the event send to the listener */ virtual void operator ()(const CEvent& event)=0; // Set a hook which can intercept msgs. void setHook(IEventListener *hook) { _Hook = hook; } IEventListener *getHook() const { return _Hook; } private: IEventListener *_Hook; }; /** * CEventListenerAsync * \author Stephane Coutelas * \author Nevrax France * \date 2000 */ class CEventListenerAsync: public IEventListener { public: /// Constructor CEventListenerAsync(); virtual ~CEventListenerAsync() {} /** * Register the listener to the server. */ void addToServer (CEventServer& server); /** * Unregister the listener to the server. */ void removeFromServer (CEventServer& server); /** * Get a key down instant state. * \param key is the key to check. */ bool isKeyDown(TKey key) const; /** * Get if a the state of key has pushed since the last call of isKeyPushed with release=true. * \param key is the key to check. * \param release if true, the pushed state of the key is released (force to be false). * It will return to true next time only if key is released and then re-pushed. * \see reset() */ bool isKeyPushed (TKey key, bool release=true); /** * Clear all the Down states to false. Useful sometimes when you don't bother what has been pushed before. * e.g.: your app listen/test to the key 'A' and 'B' for a certain long period. Then, it test 'C' and 'D' later. * If the user has pressed (by mistake) the key 'C' during the first period, this API has record it, and then, at the * second period, isKeyDown(KeyC) will return true the first time the key is tested, unless if you do a * reset() at the beggining of the second period. * Clear all the pushed states to false too. * \see isKeyDown() */ void reset (); protected: /* * Call back of the listener. * \param event is the event send to the listener */ virtual void operator ()(const CEvent& event); CBitSet _KeyArray; // Must have 2 arrays because of key repetition... CBitSet _KeyDownArray, _KeyReleaseArray; }; } // NLMISC #endif // NL_EVENT_LISTENER_H /* End of event_listener.h */ ================================================ FILE: code/nel/include/nel/misc/event_server.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_EVENT_SERVER_H #define NL_EVENT_SERVER_H #include "types_nl.h" #include "class_id.h" #include #include namespace NLMISC { class IEventEmitter; class IEventListener; class CEvent; /*===================================================================*/ typedef std::multimap mapListener; /** * CEventServer * \author Stephane Coutelas * \author Nevrax France * \date 2000 */ class CEventServer { mapListener _Listeners; std::list _Emitters; std::list _Events; bool _Pumping; public: CEventServer(); virtual ~CEventServer(); /** * add event to the list * \param event */ void postEvent(CEvent * event); /** * get call every callbacks associated with event id * \param allWindows is true : pump the messages of all windows, not only the driver window. */ void pump(bool allWindows = false); /** * Add a callback (associated with an id) * \param id of the CEvent class to hook * \param listener to use with this event */ void addListener(CClassId id, IEventListener* listener ); /** * Remove a callback * \param id of event's callback * \param listener to be removed */ void removeListener(CClassId id, IEventListener* listener ); /** * Add an Emitter to the server * \param emitter */ void addEmitter(IEventEmitter * emitter); /** * Remove an Emitter from the server * \param emitter */ void removeEmitter(IEventEmitter * emitter); protected: /** * call every callbacks associated with event id * \param event * \return true if the pointer must be delete, false if it not. (post to another message queue...) */ virtual bool pumpEvent(CEvent* event); }; /*===================================================================*/ } // NLMISC #endif // NL_EVENT_SERVER_H /* End of event_server.h */ ================================================ FILE: code/nel/include/nel/misc/events.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_EVENTS_H #define NL_EVENTS_H #include "types_nl.h" #include "class_id.h" #include "ucstring.h" #include #include namespace NLMISC { /*===================================================================*/ class IEventEmitter; /** * CEvent. System event. * \date 2000 */ class CEvent : public CClassId { public: /// Emitter of the event. Can be NULL if the event is posted directly to the CEventServer. IEventEmitter* Emitter; // duplicate the object virtual CEvent *clone() const =0; virtual ~CEvent() {} protected: /** Constructor. * \param emitter is the emitter of the event. Can be NULL if the event is posted directly to the CEventServer. * \param classId is the classId of the event. Should be unique for each event. */ CEvent (IEventEmitter* emitter, const CClassId& classId) : CClassId (classId) { Emitter=emitter; } }; // Key events const CClassId EventKeyDownId (0x3c2643da, 0x43f802a1); const CClassId EventKeyUpId (0x1e62e85, 0x68a35d46); const CClassId EventCharId (0x552255fe, 0x75a2373f); const CClassId EventStringId (0x49b5af8f, 0x7f52cd26); // Window events const CClassId EventActivateId (0x7da66b0a, 0x1ef74519); const CClassId EventSetFocusId (0x17650fac, 0x19f85dde); const CClassId EventDestroyWindowId (0x69be73fe, 0x4b07603b); const CClassId EventCloseWindowId (0xb5cb1333, 0xd092e63a); // Mouse events const CClassId EventMouseMoveId (0x3dd12fdb, 0x472f548b); const CClassId EventMouseDownId (0x35b7878, 0x5d4a0f86); const CClassId EventMouseUpId (0xcce1f7e, 0x7ed344d7); const CClassId EventMouseDblClkId (0x55a94cb3, 0x3e641517); const CClassId EventMouseWheelId (0x73ac4321, 0x4c273150); // Misc events const CClassId EventDisplayChangeId(0x1751559, 0x25b52b3c); // Input Mehod Editor (IME) events const CClassId EventIME (0x261f1ede, 0x1b0a6c3a); enum TKey { KeyNOKEY =0x00, Key0 ='0', Key1 ='1', Key2 ='2', Key3 ='3', Key4 ='4', Key5 ='5', Key6 ='6', Key7 ='7', Key8 ='8', Key9 ='9', KeyA ='A', KeyB ='B', KeyC ='C', KeyD ='D', KeyE ='E', KeyF ='F', KeyG ='G', KeyH ='H', KeyI ='I', KeyJ ='J', KeyK ='K', KeyL ='L', KeyM ='M', KeyN ='N', KeyO ='O', KeyP ='P', KeyQ ='Q', KeyR ='R', KeyS ='S', KeyT ='T', KeyU ='U', KeyV ='V', KeyW ='W', KeyX ='X', KeyY ='Y', KeyZ ='Z', KeyLBUTTON =0x01, KeyRBUTTON =0x02, KeyCANCEL =0x03, KeyMBUTTON =0x04, KeyBACK =0x08, KeyTAB =0x09, KeyCLEAR =0x0C, KeyRETURN =0x0D, KeySHIFT =0x10, KeyCONTROL =0x11, KeyMENU =0x12, KeyPAUSE =0x13, KeyCAPITAL =0x14, KeyKANA =0x15, KeyHANGEUL =0x15, KeyHANGUL =0x15, KeyJUNJA =0x17, KeyFINAL =0x18, KeyHANJA =0x19, KeyKANJI =0x19, KeyESCAPE =0x1B, KeyCONVERT =0x1C, KeyNONCONVERT =0x1D, KeyACCEPT =0x1E, KeyMODECHANGE =0x1F, KeySPACE =0x20, KeyPRIOR =0x21, KeyNEXT =0x22, KeyEND =0x23, KeyHOME =0x24, KeyLEFT =0x25, KeyUP =0x26, KeyRIGHT =0x27, KeyDOWN =0x28, KeySELECT =0x29, KeyPRINT =0x2A, KeyEXECUTE =0x2B, KeySNAPSHOT =0x2C, KeyINSERT =0x2D, KeyDELETE =0x2E, KeyHELP =0x2F, KeyLWIN =0x5B, KeyRWIN =0x5C, KeyAPPS =0x5D, KeyNUMPAD0 =0x60, KeyNUMPAD1 =0x61, KeyNUMPAD2 =0x62, KeyNUMPAD3 =0x63, KeyNUMPAD4 =0x64, KeyNUMPAD5 =0x65, KeyNUMPAD6 =0x66, KeyNUMPAD7 =0x67, KeyNUMPAD8 =0x68, KeyNUMPAD9 =0x69, KeyMULTIPLY =0x6A, KeyADD =0x6B, KeySEPARATOR =0x6C, KeySUBTRACT =0x6D, KeyDECIMAL =0x6E, KeyDIVIDE =0x6F, KeyF1 =0x70, KeyF2 =0x71, KeyF3 =0x72, KeyF4 =0x73, KeyF5 =0x74, KeyF6 =0x75, KeyF7 =0x76, KeyF8 =0x77, KeyF9 =0x78, KeyF10 =0x79, KeyF11 =0x7A, KeyF12 =0x7B, KeyF13 =0x7C, KeyF14 =0x7D, KeyF15 =0x7E, KeyF16 =0x7F, KeyF17 =0x80, KeyF18 =0x81, KeyF19 =0x82, KeyF20 =0x83, KeyF21 =0x84, KeyF22 =0x85, KeyF23 =0x86, KeyF24 =0x87, KeyNUMLOCK =0x90, KeySCROLL =0x91, KeyLSHIFT =0xA0, KeyRSHIFT =0xA1, KeyLCONTROL =0xA2, KeyRCONTROL =0xA3, KeyLMENU =0xA4, KeyRMENU =0xA5, KeySEMICOLON =0xBA, KeyEQUALS =0xBB, KeyCOMMA =0xBC, KeyDASH =0xBD, KeyPERIOD =0xBE, KeySLASH =0xBF, KeyTILDE =0xC0, KeyLBRACKET =0xDB, KeyBACKSLASH =0xDC, KeyRBRACKET =0xDD, KeyAPOSTROPHE =0xDE, KeyPARAGRAPH =0xDF, KeyOEM_102 =0xE2, KeyPROCESSKEY =0xE5, KeyATTN =0xF6, KeyCRSEL =0xF7, KeyEXSEL =0xF8, KeyEREOF =0xF9, KeyPLAY =0xFA, KeyZOOM =0xFB, KeyNONAME =0xFC, KeyPA1 =0xFD, KeyOEM_CLEAR =0xFE, KeyCount =0xFF }; enum TMouseButton { noButton =0x0, leftButton =0x1, middleButton =0x2, rightButton =0x4, ctrlButton =0x8, shiftButton =0x10, altButton =0x20 }; enum TKeyButton { noKeyButton =0x0, ctrlKeyButton =0x8, shiftKeyButton =0x10, altKeyButton =0x20 }; /** * CEventKey */ class CEventKey : public CEvent { public: CEventKey (TKeyButton button, IEventEmitter* emitter, const CClassId& classId) : CEvent (emitter, classId) { Button=button; } TKeyButton Button; public: // return a TKey for its associated String (eg KeyA for "KeyA") static TKey getKeyFromString(const std::string &str); // return the string equivalent to the TKey (eg "KeyA" for KeyA) static const std::string &getStringFromKey(TKey k); }; /** * CEventKeyDown * Send when a key is push down. The key type is Key and FirstTime is true if the previous key state wasn't pushed. */ class CEventKeyDown : public CEventKey { public: CEventKeyDown (TKey key, TKeyButton button, bool bFirstTime, IEventEmitter* emitter) : CEventKey (button, emitter, EventKeyDownId) { Key=key; FirstTime=bFirstTime; } TKey Key; bool FirstTime; virtual CEvent *clone() const {return new CEventKeyDown(*this);} }; /** * CEventKeyUp */ class CEventKeyUp : public CEventKey { public: CEventKeyUp (TKey key, TKeyButton button, IEventEmitter* emitter) : CEventKey (button, emitter, EventKeyUpId) { Key=key; } TKey Key; virtual CEvent *clone() const {return new CEventKeyUp(*this);} }; /** * CEventChar */ class CEventChar : public CEventKey { public: CEventChar (ucchar c, TKeyButton button, IEventEmitter* emitter) : CEventKey (button, emitter, EventCharId), _Raw(true) { Char=c; } ucchar Char; virtual CEvent *clone() const {return new CEventChar(*this);} void setRaw( bool raw ) { _Raw = raw; } bool isRaw() const { return _Raw; } private: bool _Raw; // true if raw, false if composed by an IME }; /** * CEventString */ class CEventString : public CEventKey { public: CEventString (const ucstring &str, IEventEmitter* emitter) : CEventKey (noKeyButton, emitter, EventStringId) { String = str; } ucstring String; virtual CEvent *clone() const {return new CEventString(*this);} }; /** * CEventMouse. * Base for mouse events. */ class CEventMouse : public CEvent { public: float X,Y; TMouseButton Button; CEventMouse (float x, float y, TMouseButton button, IEventEmitter* emitter, const CClassId& classId) : CEvent (emitter, classId) { X = x; Y = y; Button = button; } }; /** * CEventMouseDown * Send when a single mouse button is pushed down. The Button value should have only ONE flag set between leftButton, rightButton and middleButton. * X and Y have the new mouse position in window coordinate system. */ class CEventMouseDown : public CEventMouse { public: CEventMouseDown (float x, float y, TMouseButton button, IEventEmitter* emitter) : CEventMouse (x, y, button, emitter, EventMouseDownId) {} virtual CEvent *clone() const {return new CEventMouseDown(*this);} }; /** * CEventMouseUp * Send when a single mouse button is pushed down. The Button value should have only ONE flag set between leftButton, rightButton and middleButton. * X and Y have the new mouse position in window coordinate system. */ class CEventMouseUp : public CEventMouse { public: CEventMouseUp (float x, float y, TMouseButton button, IEventEmitter* emitter) : CEventMouse (x, y, button, emitter, EventMouseUpId) {} virtual CEvent *clone() const {return new CEventMouseUp(*this);} }; /** * CEventMouseMove * Button have the state of the three mouse and SHIFT CTRL and ALT system keys. When the flag is set, the button is pushed. * X and Y have the new mouse position in window coordinate system. */ class CEventMouseMove : public CEventMouse { public: CEventMouseMove (float x, float y, TMouseButton button, IEventEmitter* emitter) : CEventMouse (x, y, button, emitter, EventMouseMoveId) {} virtual CEvent *clone() const {return new CEventMouseMove(*this);} }; /** * CEventMouseDblClk * Send when a single mouse button is double clicked. The Button value should have only ONE flag set between leftButton, rightButton and middleButton. * X and Y have the new mouse position in window coordinate system. */ class CEventMouseDblClk : public CEventMouse { public: CEventMouseDblClk (float x, float y, TMouseButton button, IEventEmitter* emitter) : CEventMouse (x, y, button, emitter, EventMouseDblClkId) {} virtual CEvent *clone() const {return new CEventMouseDblClk(*this);} }; /** * CEventMouseWheel * Send when the mouse wheel is actioned. * Button have the state of the three mouse and SHIFT CTRL and ALT system keys. When the flag is set, the button is pushed. * X and Y have the new mouse position in window coordinate system. * If Direction is true, the wheel was moved forward and if it is false, backward. */ class CEventMouseWheel : public CEventMouse { public: bool Direction; CEventMouseWheel (float x, float y, TMouseButton button, bool direction, IEventEmitter* emitter) : CEventMouse (x, y, button, emitter, EventMouseWheelId) { Direction=direction; } virtual CEvent *clone() const {return new CEventMouseWheel(*this);} }; /** * CEventActivate. Called when window is actived / disactived. */ class CEventActivate : public CEvent { public: /** * True if window is actived, false if it is disactived. */ bool Activate; /** * Create an activate event. Notify the activation disactivation of a window. * \param activate is True if window is actived, false if it is disactived. */ CEventActivate (bool activate, IEventEmitter* emitter) : CEvent (emitter, EventActivateId) { Activate = activate; } virtual CEvent *clone() const {return new CEventActivate(*this);} }; /** * CEventSetFocus. Called when window lost / get keyboard focus. */ class CEventSetFocus : public CEvent { public: /** * True if window get the focus, false if it lost it. */ bool Get; /** * Create focus event. Notify get and lost of the keyboard focus of a window. * \param activate is True if window get the focus, false if it lost it. */ CEventSetFocus (bool get, IEventEmitter* emitter) : CEvent (emitter, EventSetFocusId) { Get = get; } virtual CEvent *clone() const {return new CEventSetFocus(*this);} }; /** * CEventDestroyWindow */ class CEventDestroyWindow : public CEvent { public: CEventDestroyWindow (IEventEmitter* emitter) : CEvent (emitter, EventDestroyWindowId) { } virtual CEvent *clone() const {return new CEventDestroyWindow(*this);} }; /** * CEventCloseWindow */ class CEventCloseWindow : public CEvent { public: CEventCloseWindow (IEventEmitter* emitter) : CEvent (emitter, EventCloseWindowId) { } virtual CEvent *clone() const {return new CEventCloseWindow(*this);} }; /** * CEventIME */ class CEventIME : public CEvent { public: CEventIME (uint32 msg, uint32 wParam, uint32 lParam, IEventEmitter* emitter) : CEvent (emitter, EventIME), EventMessage(msg), WParam(wParam), LParam(lParam) {} uint32 EventMessage; uint32 WParam, LParam; virtual CEvent *clone() const {return new CEventIME(*this);} }; /** * CEventDisplayChange : Called user has changed the desktop resolution */ class CEventDisplayChange : public CEvent { public: uint Width; uint Height; uint BitDepth; /** * Create focus event. Notify get and lost of the keyboard focus of a window. * \param activate is True if window get the focus, false if it lost it. */ CEventDisplayChange(uint width, uint height, uint bitDepth, IEventEmitter* emitter) : CEvent (emitter, EventDisplayChangeId) { Width = width; Height = height; BitDepth = bitDepth; } virtual CEvent *clone() const {return new CEventDisplayChange(*this);} }; } // NLMISC #endif // NL_EVENTS_H /* End of events.h */ ================================================ FILE: code/nel/include/nel/misc/factory.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef FACTORY_H #define FACTORY_H #include "types_nl.h" #include "debug.h" #include namespace NLMISC { /** Interface class for object registered in the factory. * This is for factory internal use, you should not need to use this class directly. */ template class IFactoryRegister { public: virtual ~IFactoryRegister() {} /// This method is called to create an instance of the factored object. virtual BaseClass *createObject(const typename BaseClass::TCtorParam &ctorParam) = 0; }; /** Factory implementation class. * the class take 2 template argument : * * BaseClass : the common base class for all factored object of one factory. * * KeyType : the type of the key that identify the factorable object (string by default). * * The factory conforms to singleton design pattern. * * BaseClass must provide a typedef for TCTorParam corresponding to the parameter * required by the constructor of factored object. */ template class CFactory { typedef std::map*> TRegisterCont; public: /// Get the singleton instance reference. static CFactory &instance() { // Singleton instance pointer. static CFactory *instance = NULL; if (!instance) { instance = new CFactory(); } return *instance; } /** Register a factorable object in the factory. * The method receive the key for this factorable object and * a pointer on the interface of a factory register object. */ void registerClass(const KeyType &key, IFactoryRegister *factoryRegister) { nlassert(_FactoryRegisters.find(key) == _FactoryRegisters.end()); _FactoryRegisters.insert(std::make_pair(key, factoryRegister)); } /** Create a new instance of a factorable object. * \param key the identifier of the object to create. * \param ctorParam the parameter for the constructor. * \return a pointer on the newly created object. */ BaseClass *createObject(const KeyType &key, const typename BaseClass::TCtorParam &ctorParam) { typename TRegisterCont::iterator it (_FactoryRegisters.find(key)); if (it == _FactoryRegisters.end()) return NULL; else return it->second->createObject(ctorParam); } // Add some introspection void fillFactoryList(std::vector &classList) { typename TRegisterCont::iterator first(_FactoryRegisters.begin()), last(_FactoryRegisters.end()); for (; first != last; ++first) { classList.push_back(first->first); } } protected: /// Singleton instance pointer. // static CFactory *_Instance; /// Container of all registered factorable object. TRegisterCont _FactoryRegisters; }; /** This class is responsible for creating the factorable object and to register * them in the factory instance. * You must declare an instance of this class for each factorable object. **/ template class CFactoryRegister : public IFactoryRegister { public: /** Constructor. * Register the factorable object in the factory. * /param key The identifier for this factorable object. */ CFactoryRegister(const KeyType &key) { FactoryClass::instance().registerClass(key, this); } /** Create an instance of the factorable class. * Implements IFactoryRegister::createObject */ BaseClass *createObject(const typename BaseClass::TCtorParam &ctorParam) { return new FactoredClass(ctorParam); } }; /** Macro to declare a factory. * Place this macro in an appropriate cpp file to declare a factory implementation. * You just need to specify the base class type and key type. */ //#define NLMISC_IMPLEMENT_FACTORY(baseClass, keyType) NLMISC::CFactory *NLMISC::CFactory::_Instance = NULL /** Macro to declare a factorable object. * Place this macro in a cpp file after your factorable class declaration. */ #define NLMISC_REGISTER_OBJECT(baseClass, factoredClass, keyType, keyValue) NLMISC::CFactoryRegister, baseClass, factoredClass, keyType> Register##factoredClass(keyValue) #define NLMISC_GET_FACTORY(baseClass, keyType) NLMISC::CFactory::instance() /** Interface class for object registered in the indirect factory. * This is for indirect factory internal use, you should not need to use this class directly. */ template class IFactoryIndirectRegister { public: virtual ~IFactoryIndirectRegister() {} /** Return the factory implementation.*/ virtual BaseFactoryClass *getFactory() = 0; }; /** Indirect factory implementation class. * the class take 2 template argument : * * BaseFactoryClass : the common base class for all factory object of one indirect factory. * * KeyType : the type of the key that identify the factorable object (string by default). * * The indirect factory conforms to singleton design pattern. * * In indirect factory, the object returned by the factory are not instance of factored object * but instance of 'sub' factory that do the real job. * This can be useful in some case, like adapting existing code into a factory * or having a complex constructor (or more than one constructor). */ template class CFactoryIndirect { typedef std::map*> TRegisterCont; public: /// Get the singleton instance reference. static CFactoryIndirect &instance() { static CFactoryIndirect *instance = NULL; if (!instance) { instance = new CFactoryIndirect(); } return *instance; } void registerClass(const KeyType &key, IFactoryIndirectRegister *factoryRegister) { nlassert(_FactoryRegisters.find(key) == _FactoryRegisters.end()); _FactoryRegisters.insert(std::make_pair(key, factoryRegister)); } BaseFactoryClass *getFactory(const KeyType &key) { typename TRegisterCont::const_iterator it (_FactoryRegisters.find(key)); if (it == _FactoryRegisters.end()) return NULL; else return it->second->getFactory(); } // Add some introspection void fillFactoryList(std::vector &classList) { typename TRegisterCont::iterator first(_FactoryRegisters.begin()), last(_FactoryRegisters.end()); for (; first != last; ++first) { classList.push_back(first->first); } } protected: // static CFactoryIndirect *_Instance; TRegisterCont _FactoryRegisters; }; template class CFactoryIndirectRegister : public IFactoryIndirectRegister { SpecializedFactoryClass _FactoryClass; public: CFactoryIndirectRegister(const KeyType &key) { IndirectFactoryClass::instance().registerClass(key, this); } BaseFactoryClass *getFactory() { return &_FactoryClass; } }; //#define NLMISC_IMPLEMENT_FACTORY_INDIRECT(baseFactoryClass, keyType) NLMISC::CFactoryIndirect *NLMISC::CFactoryIndirect::_Instance = NULL #define NLMISC_GET_FACTORY_INDIRECT_REGISTRY(baseFactoryClass, keyType) NLMISC::CFactoryIndirect::getInstance() #define NLMISC_REGISTER_OBJECT_INDIRECT(baseFactoryClass, specializedFactoryClass, keyType, keyValue) NLMISC::CFactoryIndirectRegister, baseFactoryClass, specializedFactoryClass, keyType> RegisterIndirect##specializedFactoryClass(keyValue) #define NLMISC_DECLARE_OBJECT_INDIRECT(baseFactoryClass, specializedFactoryClass, keyType) extern NLMISC::CFactoryIndirectRegister, baseFactoryClass, specializedFactoryClass, keyType> RegisterIndirect##specializedFactoryClass #define NLMISC_GET_FACTORY_INDIRECT(specializedFactoryClass) RegisterIndirect##specializedFactoryClass.getFactory() } // namespace NLMISC #endif // FACTORY_H ================================================ FILE: code/nel/include/nel/misc/fast_floor.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_FAST_FLOOR_H #define NL_FAST_FLOOR_H #include "types_nl.h" #include #include namespace NLMISC { const uint OptFastFloorCWStackSize = 10; extern int OptFastFloorCWStack[OptFastFloorCWStackSize]; extern int *OptFastFloorCWStackPtr; extern int *OptFastFloorCWStackEnd; // fastFloor function. #if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM) && defined(NL_USE_FASTFLOOR) #include // The magic constant value. support both positive and negative numbers. extern double OptFastFloorMagicConst ; inline void OptFastFloorPushCW(int ctrl) { nlassert(OptFastFloorCWStackPtr < OptFastFloorCWStackEnd); *OptFastFloorCWStackPtr++ = _controlfp(0, 0); _controlfp( ctrl, _MCW_RC|_MCW_PC ); } inline void OptFastFloorPopCW() { nlassert(OptFastFloorCWStackPtr >= OptFastFloorCWStack); _controlfp(*(--OptFastFloorCWStackPtr), _MCW_RC|_MCW_PC); } // init float CW. inline void OptFastFloorBegin() { OptFastFloorPushCW(_RC_DOWN|_PC_53); } // reset float CW. inline void OptFastFloorEnd() { OptFastFloorPopCW(); } // Force __stdcall to not pass parameters in registers. inline sint32 __stdcall OptFastFloor(float x) { static __int64 res; __asm { fld x fadd qword ptr OptFastFloorMagicConst fstp qword ptr res } return (sint32) (res&0xFFFFFFFF); } // Force __stdcall to not pass parameters in registers. // Only used by particles system inline float __stdcall OptFastFractionnalPart(float x) { static double res; __asm { fld x fld st(0) fadd qword ptr OptFastFloorMagicConst fstp qword ptr res fisub dword ptr res fstp dword ptr res } return * (float *) &res; } // The magic constant value, for 24 bits precision support positive numbers only extern float OptFastFloorMagicConst24 ; // init float CW. Init with float 24 bits precision, for faster float operation. inline void OptFastFloorBegin24() { OptFastFloorPushCW(_RC_DOWN|_PC_24); } // reset float CW. inline void OptFastFloorEnd24() { OptFastFloorPopCW(); } // Force __stdcall to not pass parameters in registers. /// Same method as OptFastFloor, but result are always positive and should never be bigger than 2^23-1 /// Only used for float to byte color attributes conversions inline uint32 __stdcall OptFastFloor24(float x) { static uint32 res; __asm { fld x fadd dword ptr OptFastFloorMagicConst24 fstp dword ptr res } return res; } #else #ifdef __SSE__ // SSE intrinsics header #include inline void OptFastFloorPushCW(int ctrl) { nlassert(OptFastFloorCWStackPtr < OptFastFloorCWStackEnd); *OptFastFloorCWStackPtr++ = _MM_GET_ROUNDING_MODE(); _MM_SET_ROUNDING_MODE(ctrl); } inline void OptFastFloorPopCW() { nlassert(OptFastFloorCWStackPtr >= OptFastFloorCWStack); _MM_SET_ROUNDING_MODE(*(--OptFastFloorCWStackPtr)); } #endif inline void OptFastFloorBegin() { #ifdef __SSE__ OptFastFloorPushCW(_MM_ROUND_DOWN); #endif } inline void OptFastFloorEnd() { #ifdef __SSE__ OptFastFloorPopCW(); #endif } inline sint OptFastFloor(float x) { #ifdef __SSE__ return _mm_cvtss_si32(_mm_set_ss(x)); #else return (sint)floor(x); #endif } inline float OptFastFractionnalPart(float x) { #ifdef __SSE__ static __m128 a, b; a = _mm_set_ss(x); b = _mm_cvtsi32_ss(b, _mm_cvttss_si32(a)); return _mm_cvtss_f32(_mm_comilt_ss(a, b) ? _mm_sub_ss(b, a):_mm_sub_ss(a, b)); #else return x < 0.f ? (sint)x - x:x - (sint)x; #endif } inline void OptFastFloorBegin24() { #ifdef __SSE__ OptFastFloorPushCW(_MM_ROUND_DOWN); #endif } inline void OptFastFloorEnd24() { #ifdef __SSE__ OptFastFloorPopCW(); #endif } inline uint32 OptFastFloor24(float x) { #ifdef __SSE__ return (uint32)_mm_cvtss_si32(_mm_set_ss(x)); #else return (uint32)floor(x); #endif } #endif } // NLMISC #endif // NL_FAST_FLOOR_H /* End of fast_floor.h */ ================================================ FILE: code/nel/include/nel/misc/fast_id_map.h ================================================ /** * \file fast_id_map.h * \brief CFastIdMap * \date 2012-04-10 19:28GMT * \author Jan Boon (Kaetemi) * CFastIdMap */ /* * Copyright (C) 2012 by authors * * This file is part of RYZOM CORE. * RYZOM CORE is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * RYZOM CORE is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public * License along with RYZOM CORE. If not, see * . */ #ifndef NLMISC_FAST_ID_MAP_H #define NLMISC_FAST_ID_MAP_H #include // STL includes // NeL includes #include // Project includes namespace NLMISC { /** * \brief CFastIdMap * \date 2012-04-10 19:28GMT * \author Jan Boon (Kaetemi) * This template allows for assigning unique uint32 identifiers to pointers. * Useful when externally only exposing an identifier, when pointers may have been deleted. * The identifier is made from two uint16's, one being the direct index in the identifier vector, * and the other being a verification value that is increased when the identifier index is re-used. * TId must be a typedef of uint32. * TValue should be a pointer. */ template class CFastIdMap { protected: struct CIdInfo { CIdInfo() { } CIdInfo(uint16 verification, uint16 next, TValue value) : Verification(verification), Next(next), Value(value) { } uint16 Verification; uint16 Next; TValue Value; }; /// ID memory std::vector m_Ids; /// Nb of assigned IDs uint m_Size; /// Assigned IDs uint16 m_Next; public: CFastIdMap(TValue defaultValue) : m_Size(0), m_Next(0) { // Id 0 will contain the last available unused id, and be 0 if no more unused id's are available // defaultValue will be returned when the ID is not found m_Ids.push_back(CIdInfo(0, 0, defaultValue)); } virtual ~CFastIdMap() { } void clear() { m_Ids.resize(1); m_Ids[0].Next = 0; } TId insert(TValue value) { // get next unused index uint16 idx = m_Ids[0].Next; if (idx == 0) { // size of used elements must be equal to the vector size minus one, when everything is allocated nlassert((m_Ids.size() - 1) == m_Size); idx = (uint16)m_Ids.size(); uint16 verification = rand(); m_Ids.push_back(CIdInfo(verification, m_Next, value)); m_Next = idx; return (TId)(((uint32)verification) << 16) & idx; } else { m_Ids[0].Next = m_Ids[idx].Next; // restore the last unused id m_Ids[idx].Value = value; return (TId)(((uint32)m_Ids[idx].Verification) << 16) & idx; } } void erase(TId id) { uint32 idx = ((uint32)id) & 0xFFFF; uint16 verification = (uint16)(((uint32)id) >> 16); if (m_Ids[idx].Verification == verification) { m_Ids[idx].Value = m_Ids[0].Value; // clean value for safety m_Ids[idx].Verification = (uint16)(((uint32)m_Ids[idx].Verification + 1) & 0xFFFF); // change verification value, allow overflow :) m_Ids[idx].Next = m_Ids[0].Next; // store the last unused id m_Ids[0].Next = (uint16)idx; // set this as last unused id } else { nlwarning("Invalid ID"); } } TValue get(TId id) { uint32 idx = ((uint32)id) & 0xFFFF; uint16 verification = (uint16)(((uint32)id) >> 16); if (m_Ids[idx].Verification == verification) { return m_Ids[idx].Value; } else { nldebug("Invalid ID"); return m_Ids[0].Value; } } inline uint size() { return m_Size; } }; /* class CFastIdMap */ } /* namespace NLMISC */ #endif /* #ifndef NLMISC_FAST_ID_MAP_H */ /* end of file */ ================================================ FILE: code/nel/include/nel/misc/fast_mem.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_FAST_MEM_H #define NL_FAST_MEM_H #include "types_nl.h" namespace NLMISC { //typedef void *memcpyptr(void *dts, const void *src, size_t nbytes); /** * Functions for Fast Memory manipulation with Pentium-class processors. * From http://www.sgi.com/developers/technology/irix/resources/asc_cpu.html * \author Lionel Berenguier * \author Nevrax France * \date 2002 */ class CFastMem { public: /** * This is a function pointer that points on the best memcpy function available depending of the OS and proc. * In the best case, it will use memcpySSE(), and in worst case, it'll use the libc memcpy() * Simply use it this way: CFastMem::memcpy(dst, src, size); */ static void *(*memcpy)(void *dts, const void *src, size_t nbytes); /** * Fast precaching of memory in L1 cache using SSE or MMX where available * (NB: others methods don't do the test) * nbytes should not override 4K */ static void precache(const void *src, uint nbytes); ///////////////////////////////////////////// /** * Fast memcpy using SSE instructions: prefetchnta and movntq. Can be called only if SSE and MMX is supported * NB: Copy per block of 4K through L1 cache * Result is typically 420 Mo/s instead of 150 Mo/s. */ static void *memcpySSE(void *dst, const void *src, size_t nbytes); /** * Fast precaching of memory in L1 cache using MMX/SSE instructions: movq and prefetchnta * Result is typically 880 Mo/s (surely slower because of overhead). * nbytes should not override 4K */ static void precacheSSE(const void *src, uint nbytes); /** * Fast precaching of memory in L1 cache using MMX instructions only: movq * Result is typically 720 Mo/s (surely slower because of overhead). * Hence prefer precacheSSE() when available. * nbytes should not override 4K */ static void precacheMMX(const void *src, uint nbytes); }; } // NLMISC #endif // NL_FAST_MEM_H /* End of fast_mem.h */ ================================================ FILE: code/nel/include/nel/misc/file.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_FILE_H #define NL_FILE_H #include "types_nl.h" #include "stream.h" namespace NLMISC { // ====================================================================================================== /** * File Exception. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ struct EFile : public EStream { EFile () : EStream( "Unknown file error" ) {} EFile (const std::string& filename) : EStream( "Unknown file error in '"+filename+"'" ), Filename(filename) {} EFile (const std::string& filename, const std::string& text, bool ) : EStream( text ), Filename(filename) {} virtual ~EFile() throw() {} std::string Filename; }; struct EFileNotOpened : public EFile { EFileNotOpened( const std::string& filename ) : EFile( filename, "File '"+filename+"' not opened", true ) {} }; struct EReadError : public EFile { EReadError( const std::string& filename ) : EFile( filename, "Read error in file '" +filename+"' (End of file?)", true ) {} }; struct EWriteError : public EFile { EWriteError( const std::string& filename ) : EFile( filename, "Write Error in file '" +filename+"'", true ) {} }; struct EDiskFullError : public EWriteError { EDiskFullError( const std::string& filename ) : EWriteError(filename) {} }; struct ERenameError : public EFile { ERenameError( const std::string& dest, const std::string& src ) : EFile( dest, "Rename Error from the file '" +src+"' to the file '" +dest+"'", true ) {} }; // ====================================================================================================== /** * Input File. * \author Lionel Berenguier * \author Nevrax France * \date 2000 * *********************************************** * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance * It can be loaded/called through CAsyncFileManager for instance * *********************************************** */ class CIFile : public IStream { public: // Basic Usage. /// Object. NB: destructor close() the stream. CIFile(); CIFile(const std::string &path, bool text=false); ~CIFile(); /// Open a file for reading. false if failed. close() if a file was opened. bool open (const std::string &path, bool text=false); /// Set the cache file on open option (default behaviour is false (file is not cached at opening) void setCacheFileOnOpen (bool newState); /** If the file is opened with a big file, CacheFileOnOpen is replaced with big file option. Except if * allowBNPCacheFileOnOpen(false) is called. true is default. */ void allowBNPCacheFileOnOpen(bool newState); /// Set the async loading state (to go to sleep 5 ms after 100 Ko serialized) void setAsyncLoading (bool newState); public: // Advanced Usage. /// Explicit close. void close(); /// flush the file. void flush(); /// Seek the file bool seek (sint32 offset, IStream::TSeekOrigin origin) const throw(EStream); /// Get the location of the file pointer sint32 getPos () const throw(EStream); // Imp the Name of the stream as the name of the file. virtual std::string getStreamName() const; // same function that in ifstream // return a string separated by \n or eof, used to parsing text file void getline (char *buffer, uint32 bufferSize); // return the size of the file uint32 getFileSize () const { return _FileSize; } // return true if there's nothing more to read (same as ifstream) bool eof (); virtual void serialBuffer(uint8 *buf, uint len)throw(EReadError); /// \name Statistics /// Get the number of file open from the beginning of the application. Files can be in a big file. static uint32 getNumFileOpen() {return _FileOpened;} /// Get the number of read acces to a file. static uint32 getNumFileRead() {return _FileRead;} /// Get the number of byte read from the file system since the application start. static uint32 getReadFromFile() {return _ReadFromFile;} /// Get the number of byte being reading from the file system at the moment. static uint32 getReadingFromFile() {return _ReadingFromFile;} /// Get the last 40 files opened. The files can be in a big file. static void dump (std::vector &result); /// clear the dump of the last 40 files opened static void clearDump (); protected: virtual void serialBit(bool &bit) throw(EReadError); virtual uint getDbgStreamSize() const; private: FILE *_F; std::string _FileName; // Async static uint32 _NbBytesSerialized; static uint32 _NbBytesLoaded; // Stats static uint32 _FileOpened; static uint32 _FileRead; static uint32 _ReadFromFile; static uint32 _ReadingFromFile; static CSynchronized > _OpenedFiles; bool _IsAsyncLoading; // Cache bool _CacheFileOnOpen; bool _AllowBNPCacheFileOnOpen; uint8 *_Cache; mutable sint32 _ReadPos; uint32 _FileSize; // Big file & xml pack bool _AlwaysOpened; /// Flag true if file is in a big file bool _IsInBigFile; /// Flag true if file is in an xml pack bool _IsInXMLPackFile; //// Offset in bnp or xml pack uint32 _BigFileOffset; // Load async if needed in the cache. void loadIntoCache(); }; // ====================================================================================================== /** * Output File. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class COFile : public IStream { public: // Basic Usage. /// Object. NB: destructor close() the stream. COFile(); COFile(const std::string &path, bool append=false, bool text=false, bool useTempFile=false); ~COFile(); /** Open a file for writing. false if failed. close() if a file was opened. * If you open the file with the flag useTempFile, you MUST close explicitly the file * with close() if the writing as been successed. */ bool open(const std::string &path, bool append=false, bool text=false, bool useTempFile=false); bool isOpen () const { return _F!=NULL; } public: // Advanced Usage. /// Explicit close. void close(); /// flush the file. void flush(); /// Seek the file bool seek (sint32 offset, IStream::TSeekOrigin origin) const throw(EStream); /// Get the location of the file pointer sint32 getPos () const throw(EStream); // Imp the Name of the stream as the name of the file. virtual std::string getStreamName() const; // very useful to serialize string in text mode (without the size) virtual void serialBuffer(uint8 *buf, uint len) throw(EWriteError); protected: /// Internal close. void internalClose(bool success); virtual void serialBit(bool &bit) throw(EWriteError); private: FILE *_F; std::string _FileName; std::string _TempFileName; }; } #endif // NL_FILE_H /* End of file.h */ ================================================ FILE: code/nel/include/nel/misc/fixed_size_allocator.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_FIXED_SIZE_ALLOCATOR_H #define NL_FIXED_SIZE_ALLOCATOR_H #include "types_nl.h" namespace NLMISC { /** An allocator that can allocate and deallocate blocks of fixed size in O(1) * Blocks are managed by chunks. Any number of blocks can be allocated, but once * a block is allocated, a whole chunk need to be. * With 32 bits pointers, there may be a 4 - 12 bytes overhead per object * NB: Unlike CBlockManager, when a chunk contains no allocated blocks, it will be freed. * If only one chunk remains, it isn't deleted, however. * Another motivation for that class is that it can be used for a memory arena style allocator, because * size isn't a fixed parameter of template. A fixed size allocator implemented as a template for type T can be layered on this implementation. * * NB : number of blocks per chunks must be at least 3 * * \author Nicolas Vizerie * \author Nevrax France * \date 2004 */ class CFixedSizeAllocator { public: CFixedSizeAllocator(uint numBytesPerBlock, uint numBlockPerChunk); ~CFixedSizeAllocator(); /// alloc a block void *alloc(); /// destroy and dealloc a block void free(void *block); // uint getNumBytesPerBlock() const { return _NumBytesPerBlock; } uint getNumBlockPerChunk() const { return _NumBlockPerChunk; } // uint getNumAllocatedBlocks() const { return _NumAlloc; } private: class CChunk; class NL_ALIGN(NL_DEFAULT_MEMORY_ALIGNMENT) CNode { public: CChunk *Chunk; // the Chunk this node belongs to. // NB: blocks starts here in memory when node is allocated CNode *Next; // points the next free block. Valid only if node is not allocated, otherwise, block datas overlap tht field. CNode **Prev; // points the previous node 'Next' field. Valid only if node is not allocated, otherwise, block datas overlap that field. // Unlink this node from the chunk it is in // Then it is considered allocated public: void *unlink(); // Link back this node to the chunk it belongs to. // Then, it is added as a free node in the chunk and in the allocator // If all node of a chunk are unused, and it is not the last chunk of the allocator, it // is removed. void link(); }; class CChunk { public: uint NumFreeObjs; CFixedSizeAllocator *Allocator; uint8 *Mem; public: // ctor CChunk(); // dtor ~CChunk(); // init & allocate memory void init(CFixedSizeAllocator *fsa); // access to a node CNode &getNode(uint index); // get the block size in bytes (header included) uint getBlockSizeWithOverhead() const; /// a chunk has been given back inline void add(); /// a chunk has been taken inline void grab(); }; friend class CChunk; friend class CNode; // CNode *_FreeSpace; uint _NumChunks; // The number of created chunks. Once one of them is created, we manage // to keep it alive in order to avoid chunk creation / destructions // if only a few blocks are used uint _NumBytesPerBlock; uint _NumBlockPerChunk; // uint _NumAlloc; }; } // NLMISC #endif ================================================ FILE: code/nel/include/nel/misc/game_device.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_GAME_DEVICE_H #define NL_GAME_DEVICE_H #include "types_nl.h" #include "input_device.h" #include #include namespace NLMISC { /// Describe a game device struct CGameDeviceDesc { // type of the device enum TDevType { GamePad, Joystick, DontKnow, DevTypeLast } DevType; // Friendly name for the instance. For example, "Joystick 1." std::string InstanceName; // Friendly name for the product std::string ProductName; // Tells whether this device is connected bool Connected; }; // a list of game device description typedef std::vector TDeviceDescVect; /// for devices comparison. The 'Connected' field is ignored. inline bool operator == (const CGameDeviceDesc &lhs, const CGameDeviceDesc &rhs) { return lhs.InstanceName == rhs.InstanceName && lhs.ProductName == rhs.ProductName; } // inline bool operator != (const CGameDeviceDesc &lhs, const CGameDeviceDesc &rhs) { return !(lhs == rhs); } /** * This abstract a joystick or gamepad * \author Nicolas Vizerie * \author Nevrax France * \date 2002 */ struct IGameDevice : public IInputDevice { enum TAxis { XAxis = 0, YAxis, ZAxis, /* translation */ RXAxis, RYAxis, RZAxis, /* rotations */ MaxNumAxis }; /// Get a general description of this device virtual const CGameDeviceDesc &getDescription() const = 0; ///\name Controls presence //@{ // returns the number of buttons available on this game device virtual uint getNumButtons() const = 0; /** Check if the given axe is present on this game device * NB : only absolute axis are managed */ virtual bool hasAxis(TAxis axis) const = 0; // Check the number of sliders presents on this game device virtual uint getNumSliders() const = 0; // Check the number of point of views controls present on this game device virtual uint getNumPOV() const = 0; //@} ///\name Controls names. Must ensure that controls are present before calling these methods. //@{ virtual const char *getButtonName(uint index) const = 0; virtual const char *getAxisName(TAxis axis) const = 0; virtual const char *getSliderName(uint index) const = 0; virtual const char *getPOVName(uint index) const = 0; //@} ///\name Controls state. Must ensure that controls are present before calling these methods. //@{ // Return true if the given button is pushed. virtual bool getButtonState(uint index) const = 0; // Return a value in [-1, 1] for a translation axis, or an orientation. virtual float getAxisValue(TAxis axis) const = 0; // Return a value in [0, 1] virtual float getSliderPos(uint index) const = 0; // Return a CCW angle in degrees virtual float getPOVAngle(uint index) const = 0; //@} }; } // NLMISC #endif // NL_GAME_DEVICE_H /* End of GAME_device.h */ ================================================ FILE: code/nel/include/nel/misc/game_device_events.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_GAME_DEVICE_EVENT_H #define NL_GAME_DEVICE_EVENT_H #include "types_nl.h" #include "events.h" #include "game_device.h" namespace NLMISC { struct IMouseDevice; struct IGameDevice; const CClassId EventGDMouseMove(0x12142bc4, 0x43c73e74); const CClassId EventGDButtonDownId(0x57141957, 0x3efb143a); const CClassId EventGDButtonUpId(0x16105e06, 0x302536b2); const CClassId EventGDAxisMovedId(0x073306, 0x41173626); const CClassId EventGDSliderMovedId(0x68776586, 0x394a6916); const CClassId EventGDPOVChanged(0x362851b9, 0x395c4d61); //========================================================================================== /// A raw mouse move message, expressed in mickeys (relative values) class CGDMouseMove : public CEvent { public: IMouseDevice *MD; sint X, Y; public: CGDMouseMove(IEventEmitter *emitter, IMouseDevice *md, sint x, sint y) : CEvent(emitter, EventGDMouseMove), MD(md), X(x), Y(y) {} virtual CEvent *clone() const {return new CGDMouseMove(*this);} }; //========================================================================================== /** * An event from a game device (joystick, joypad ...) */ class CGameDeviceEvent : public CEvent { public: /// the game device this event come from IGameDevice *GameDevice; public: CGameDeviceEvent( IGameDevice *gameDevice, IEventEmitter *emitter, const CClassId &classId ) : CEvent(emitter, classId), GameDevice(gameDevice) {} }; //========================================================================================== /** A button state has changed */ class CGDButton : public CGameDeviceEvent { public: // index of the buttons that has been pushed uint ButtonIndex; bool Pushed; public: /// CGDButton( uint buttonIndex, bool pushed, IGameDevice *gameDevice, IEventEmitter *emitter, const CClassId &classId ) : CGameDeviceEvent(gameDevice, emitter, classId), ButtonIndex(buttonIndex), Pushed(pushed) {} }; //========================================================================================== /** A button has been pushed */ class CGDButtonDown : public CGDButton { public: /// CGDButtonDown(uint buttonIndex, IGameDevice *gameDevice, IEventEmitter *emitter) : CGDButton(buttonIndex, true, gameDevice, emitter, EventGDButtonDownId) {} virtual CEvent *clone() const {return new CGDButtonDown(*this);} }; //========================================================================================== /** A button has been released */ class CGDButtonUp : public CGDButton { public: /// CGDButtonUp(uint buttonIndex, IGameDevice *gameDevice, IEventEmitter *emitter) : CGDButton(buttonIndex, false, gameDevice, emitter, EventGDButtonUpId) {} virtual CEvent *clone() const {return new CGDButtonUp(*this);} }; //========================================================================================== /// An axis has moved class CGDAxisMoved : public CGameDeviceEvent { public: IGameDevice::TAxis Axis; // current position of the axis, ranges from -1.f to 1.f float Value; public: CGDAxisMoved( IGameDevice::TAxis axis, float value, IGameDevice *gameDevice, IEventEmitter *emitter ) : CGameDeviceEvent(gameDevice, emitter, EventGDAxisMovedId), Axis(axis), Value(value) {} virtual CEvent *clone() const {return new CGDAxisMoved(*this);} }; //========================================================================================== /// A slider position has changed class CGDSliderMoved : public CGameDeviceEvent { public: uint SliderIndex; // current position of the slider, ranges from 0.f to 1.f float SliderPos; public: CGDSliderMoved( float sliderPos, uint sliderIndex, IGameDevice *gameDevice, IEventEmitter *emitter ) : CGameDeviceEvent(gameDevice, emitter, EventGDSliderMovedId), SliderIndex(sliderIndex), SliderPos(sliderPos) {} virtual CEvent *clone() const {return new CGDSliderMoved(*this);} }; //========================================================================================== /// A point of view control changed class CGDPOVChanged : public CGameDeviceEvent { public: uint POVIndex; bool Centered; // The POV angle, in degrees (CW) float POVAngle; public: CGDPOVChanged( bool centered, float povAngle, uint povIndex, IGameDevice *gameDevice, IEventEmitter *emitter ) : CGameDeviceEvent(gameDevice, emitter, EventGDPOVChanged), POVIndex(povIndex), Centered(centered), POVAngle(povAngle) {} virtual CEvent *clone() const {return new CGDPOVChanged(*this);} }; } // NLMISC #endif // NL_GAME_DEVICE_EVENT_H /* End of game_device_event.h */ ================================================ FILE: code/nel/include/nel/misc/geom_ext.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_TRIANGLE_EXT_H #define NL_TRIANGLE_EXT_H #include "types_nl.h" #include "line.h" #include "triangle.h" #include "quad.h" #include "uv.h" #include "rgba.h" namespace NLMISC { // *************************************************************************** // *************************************************************************** // Lines. // *************************************************************************** // *************************************************************************** // *************************************************************************** /** * A line with 2 colors. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CLineColor : public CLine { public: CRGBA Color0, Color1; public: /// Constructor CLineColor() {} CLineColor &operator=(const CLine &line) { *((CLine*)this)= line; return *this; } }; // *************************************************************************** /** * A line with 2 uvs. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CLineUV : public CLine { public: CUV Uv0, Uv1; public: /// Constructor CLineUV() {} CLineUV &operator=(const CLine &line) { *((CLine*)this)= line; return *this; } }; // *************************************************************************** /** * A line with 2 colors and 2 uvs. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CLineColorUV : public CLine { public: CRGBA Color0, Color1; CUV Uv0, Uv1; public: /// Constructor CLineColorUV() {} CLineColorUV &operator=(const CLine &line) { *((CLine*)this)= line; return *this; } }; // *************************************************************************** // *************************************************************************** // Triangles. // *************************************************************************** // *************************************************************************** // *************************************************************************** /** * A triangle with 3 colors. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CTriangleColor : public CTriangle { public: CRGBA Color0, Color1, Color2; public: /// Constructor CTriangleColor() {} CTriangleColor &operator=(const CTriangle &tri) { *((CTriangle*)this)= tri; return *this; } }; // *************************************************************************** /** * A triangle with 3 uvs. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CTriangleUV : public CTriangle { public: CUV Uv0, Uv1, Uv2; public: /// Constructor CTriangleUV() {} CTriangleUV &operator=(const CTriangle &tri) { *((CTriangle*)this)= tri; return *this; } }; // *************************************************************************** /** * A triangle with 3 colors and 3 uvs. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CTriangleColorUV : public CTriangle { public: CRGBA Color0, Color1, Color2; CUV Uv0, Uv1, Uv2; public: /// Constructor CTriangleColorUV() {} CTriangleColorUV &operator=(const CTriangle &tri) { *((CTriangle*)this)= tri; return *this; } }; // *************************************************************************** // *************************************************************************** // Quads. // *************************************************************************** // *************************************************************************** // *************************************************************************** /** * A quad with 4 colors. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CQuadColor : public CQuad { public: CRGBA Color0, Color1, Color2, Color3; public: /// Constructor CQuadColor() {} CQuadColor &operator=(const CQuad &quad) { *((CQuad*)this)= quad; return *this; } }; // *************************************************************************** /** * A quad with 4 uvs. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CQuadUV : public CQuad { public: CUV Uv0, Uv1, Uv2, Uv3; public: /// Constructor CQuadUV() {} CQuadUV &operator=(const CQuad &quad) { *((CQuad*)this)= quad; return *this; } }; // *************************************************************************** /** * A quad with 4 colors and 4 uvs. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CQuadColorUV : public CQuad { public: CRGBA Color0, Color1, Color2, Color3; CUV Uv0, Uv1, Uv2, Uv3; public: /// Constructor CQuadColorUV() {} CQuadColorUV &operator=(const CQuad &quad) { *((CQuad*)this)= quad; return *this; } }; // *************************************************************************** /** * A quad with 4 colors and 8 uvs. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CQuadColorUV2 : public CQuadColorUV { public: CUV Uv02, Uv12, Uv22, Uv32; }; } // NLMISC #endif // NL_TRIANGLE_EXT_H /* End of triangle_ext.h */ ================================================ FILE: code/nel/include/nel/misc/grid_traversal.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef _GRID_TRAVERSAL_H #define _GRID_TRAVERSAL_H #include "types_nl.h" namespace NLMISC { class CVector2f; /** Utility class for incremental grid traversal * * \author Nicolas Vizerie * \author Nevrax France * \date 2005 */ class CGridTraversal { public: /** begin to traverse a grid along the given segments * \return first location in the grid */ static void startTraverse(const NLMISC::CVector2f &start, sint &nextX, sint &nextY); /** continue grid traversal from the given position * If there are remaingind cells to traverse then true is returned, x & y are updated */ static bool traverse(const NLMISC::CVector2f &start, const NLMISC::CVector2f &dir, sint &x, sint &y); }; } // NLMISC #endif ================================================ FILE: code/nel/include/nel/misc/gtk_displayer.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_GTK_DISPLAYER_H #define NL_GTK_DISPLAYER_H #ifdef NL_USE_GTK #include "types_nl.h" #include "displayer.h" #include "reader_writer.h" #include "window_displayer.h" #include namespace NLMISC { /** * this displayer displays on a gtk windows. * MT = Main Thread, DT = Display Thread * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CGtkDisplayer : public NLMISC::CWindowDisplayer { public: CGtkDisplayer (const char *displayerName = ""); virtual ~CGtkDisplayer (); private: // called by DT only void resizeLabels (); // called by DT only void updateLabels (); // called by DT only void open (std::string titleBar, bool iconified, sint x, sint y, sint w, sint h, sint hs, sint fs, const std::string &fn, bool ww, CLog *log); // called by DT only void clear (); // called by DT only void display_main (); virtual void setTitleBar (const std::string &titleBar); virtual void getWindowPos (uint32 &x, uint32 &y, uint32 &w, uint32 &h); // all these variables above are used only by the DT friend gint updateInterf (gpointer data); friend gint ButtonClicked(GtkWidget *Widget, gpointer *Data); // the MT must set the value to true to exit the thread bool Exit; }; } // NLMISC #endif // NL_USE_GTK #endif // NL_GTK_DISPLAYER_H /* End of gtk_displayer.h */ ================================================ FILE: code/nel/include/nel/misc/heap_memory.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_HEAP_MEMORY_H #define NL_HEAP_MEMORY_H #include "types_nl.h" #include namespace NLMISC { // *************************************************************************** /** * A Heap manager. Work with any kind of memory. * This heap manager is not designed for speed (because it stills use standard heap allocation), but for * use with special memory or special cases where malloc/new cannot be used. * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ class CHeapMemory { public: /// Constructor CHeapMemory(); ~CHeapMemory(); /// reset the entire container. NB: no free() is made on the heap. void reset(); /** init the heap. this reset() the heap. heap ptr is stored in this class, but no CHeapMemory methods * write or read into. They use standard heap instead (new / delete). * \param heap the heap ptr. heap should be at least N-bytes aligned, where N is the alignment you need (see * param align, 4 by default). * \param align Any size given to allocate() will be rounded to match this alignement. * Valid values are 4,8,16, or 32. 4 by default. */ void initHeap(void *heap, uint size, uint align=4); /// return the size passed in setHeap(). uint getHeapSize() const {return _HeapSize;} /// return the heap size allocated. uint getHeapSizeUsed() const {return _HeapSizeUsed;} /** allocate a block of size bytes. return NULL if not enough space or if size==0. * NB: for alignements consideration, allocation are aligned to 4 bytes. */ void *allocate(uint size); /// free a block allocated with alloate(). no-op if NULL. nlstop() if don't find this block. void free(void *ptr); // ********************* private: // The map size -> EmptySpace. typedef std::multimap TEmptySpaceSizeMap; typedef TEmptySpaceSizeMap::iterator ItEmptySpaceSizeMap; struct CEmptySpace { // The adress of this empty space, in the heap uint8 *Ptr; // The size of this empty space. uint Size; // An iterator of his place in the TEmptySpaceMap. ItEmptySpaceSizeMap SizeIt; }; // The map ptr -> EmptySpace. typedef std::map TEmptySpacePtrMap; typedef TEmptySpacePtrMap::iterator ItEmptySpacePtrMap; // The map ptr -> size: AllocatedSpace; typedef std::map TAllocatedSpaceMap; typedef TAllocatedSpaceMap::iterator ItAllocatedSpaceMap; private: uint8 *_HeapPtr; uint _HeapSize; uint _HeapSizeUsed; uint _Alignment; /// The array of empty spaces. TEmptySpacePtrMap _EmptySpaces; /// for allocate method, the size -> empty space map. TEmptySpaceSizeMap _EmptySpaceMap; // The map of allocated blocks. TAllocatedSpaceMap _AllocatedSpaceMap; void removeEmptySpace(CEmptySpace &space); void addEmptySpace(CEmptySpace &space); }; } // NLMISC #endif // NL_HEAP_MEMORY_H /* End of heap_memory.h */ ================================================ FILE: code/nel/include/nel/misc/hierarchical_timer.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_HIERARCHICAL_TIMER_H #define NL_HIERARCHICAL_TIMER_H #include #include #include #include "types_nl.h" #include "time_nl.h" #include "debug.h" #ifndef NL_NO_DEBUG # define ALLOW_TIMING_MEASURES #endif // NL_NO_DEBUG #ifdef ALLOW_TIMING_MEASURES // You should need only this macro, bench the local scope # define H_AUTO(__name) static NLMISC::CHTimer __name##_timer(#__name); NLMISC::CAutoTimer __name##_auto(&__name##_timer); // Same as H_AUTO but you don't have to give a name, it uses the function/line # define H_AUTO2 static std::string __str_##__LINE__(NLMISC::toString("%s:%d", __FUNCTION__, __LINE__)); static NLMISC::CHTimer __timer_##__LINE__(__str_##__LINE__.c_str()); NLMISC::CAutoTimer __auto_##__LINE__(&__timer_##__LINE__); // If you want to bench a specific part of the code # define H_BEFORE(__name) static NLMISC::CHTimer __name##_timer(#__name); __name##_timer.before(); # define H_AFTER(__name) __name##_timer.after(); // Display the timer info after each loop call # define H_AUTO_INST(__name) static NLMISC::CHTimer __name##_timer(#__name); NLMISC::CAutoTimerInst __name##_auto(&__name##_timer); // H_AUTO split in 2. The declaration of the static timer, and a CAutoTimer instance. // Useful to group same timer bench in different functions for example # define H_AUTO_DECL(__name) static NLMISC::CHTimer __name##_timer(#__name); # define H_AUTO_USE(__name) NLMISC::CAutoTimer __name##_auto(&__name##_timer); // # define H_TIME(__name,__inst) \ { \ static NLMISC::CHTimer nl_h_timer(#__name); \ nl_h_timer.before(); \ __inst \ nl_h_timer.after(); \ } #else // void macros # define H_TIME(__name,__inst) __inst # define H_BEFORE(__name) # define H_AFTER(__name) # define H_AUTO(__name) # define H_AUTO2 # define H_AUTO_INST(__name) # define H_AUTO_DECL(__name) # define H_AUTO_USE(__name) #endif namespace NLMISC { #ifdef NL_COMP_VC // Visual C++ warning : ebp maybe modified # pragma warning(disable:4731) #endif /** A simple clock to measure ticks. * \warning On Intel platform, processor cycles are counted, on other platforms, CTime::getPerformanceTime is used instead. * * \sa CStopWatch * \author Nicolas Vizerie * \author Nevrax France * \date 2002 */ class CSimpleClock { public: CSimpleClock() : _NumTicks(0) { #ifdef NL_DEBUG _Started = false; #endif } // start measure void start() { #ifdef NL_DEBUG nlassert(!_Started); _Started = true; #endif #ifdef NL_CPU_INTEL _StartTick = rdtsc(); #else _StartTick = CTime::getPerformanceTime(); #endif } // end measure void stop() { #ifdef NL_DEBUG nlassert(_Started); _Started = false; #endif #ifdef NL_CPU_INTEL _NumTicks = rdtsc() - _StartTick; #else _NumTicks = CTime::getPerformanceTime() - _StartTick; #endif } // get measure uint64 getNumTicks() const { #ifdef NL_DEBUG nlassert(!_Started); #endif nlassert(_NumTicks != 0); return _NumTicks; } // This compute the duration of start and stop (in cycles). static void init(); /** Get the number of ticks needed to perform start(). * Should have called init() before calling this. */ static uint64 getStartStopNumTicks() { return _StartStopNumTicks; } private: uint64 _StartTick; uint64 _NumTicks; #ifdef NL_DEBUG bool _Started; #endif static bool _InitDone; static uint64 _StartStopNumTicks; }; /** * Hierarchical timing system. Allows to accurately measure performance of routines, and displays results hierarchically. * To time a piece of code, just declare a static CHTimer object and encapsulate code between calls to before() and after() methods. * ex: *\code void myFunction() { static CHTimer myTimer("myFunction"); myTimer.before(); // some code here myTimer.after(); } *\endcode * Don't forget to call after() to avoid timing wrongness or assertion crashes ! * * \warning Supports only single-threaded applications. * \warning Supports only Intel processors. * * \author Benjamin Legros * \author Nicolas Vizerie * \author Nevrax France * \date 2001, 2002 */ class CHTimer { public: // this enum is used to sort displayed results enum TSortCriterion { NoSort, TotalTime, TotalTimeWithoutSons, MeanTime, NumVisits, MaxTime, MinTime, MaxSession, SortCriterionsLast }; public: /// ctor CHTimer() : _Name(NULL), _Parent(NULL), _IsRoot(false) {} CHTimer(const char *name, bool isRoot = false) : _Name(name), _Parent(NULL), _IsRoot(isRoot) {} /// Starts a measuring session void before() { if (_Benching) doBefore(); } // Ends a measuring session void after() { if (_Benching) doAfter(false); } void after(bool displayAfter) { if (_Benching) doAfter(displayAfter); } // Get this node name const char *getName() const { return _Name; } void setName(const char *name) { _Name = name; } /** Starts a bench session * \param wantStandardDeviation When true, benchmarks will report the standard deviation of values. This require more memory, however, because each samples must be kept. * \param quick if true, quick compute the frequency of the processor */ static void startBench(bool wantStandardDeviation = false, bool quick = false, bool reset = true); /** For backward compatibility */ static void bench() { startBench(); } /** For backward compatibility */ static void adjust() {} /// Ends a bench session static void endBench(); static bool benching () { return _Benching; } /** Display results * \param displayEx true to display more detailed infos */ static void display(CLog *log= InfoLog, TSortCriterion criterion = TotalTime, bool displayInline = true, bool displayEx = true); /** Display results by execution paths * \param displayInline true to display each result on a single line. * \param alignPaths true to display all execution paths aligned. * \param displayEx true to display more detailed infos. */ static void displayByExecutionPath(CLog *log= InfoLog, TSortCriterion criterion = TotalTime, bool displayInline = true, bool alignPaths = true, bool displayEx = true); /** Hierarchical display, no sorting is done * \param displayEx true to display more detailed infos. * \param labelNumChar */ static void displayHierarchical(CLog *log= InfoLog, bool displayEx = true, uint labelNumChar = 32, uint indentationStep = 2); /** Hierarchical display, no sorting is done * \param displayEx true to display more detailed infos. * \param labelNumChar */ static void displayHierarchicalByExecutionPath(CLog *log= InfoLog, bool displayEx = true, uint labelNumChar = 32, uint indentationStep = 2); /** Hierarchical display, sorting is done in branches * \param displayEx true to display more detailed infos. * \param labelNumChar */ static void displayHierarchicalByExecutionPathSorted(CLog *log= InfoLog, TSortCriterion criterion = TotalTime, bool displayEx = true, uint labelNumChar = 32, uint indentationStep = 2); /** Hierarchical display, sorting is done in branches * \param displayEx true to display more detailed infos. * \param labelNumChar */ static void displaySummary(CLog *log= InfoLog, TSortCriterion criterion = TotalTime, bool displayEx = true, uint labelNumChar = 32, uint indentationStep = 2, uint maxDepth = 3); /// Clears stats, and re initializes all timer structure static void clear(); /// Clears SessionMax current stats (only current value) static void clearSessionCurrent(); /// Clears all SessionMax stats (max and current values) static void clearSessionStats(); /// Update session stats static void updateSessionStats(); ////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////// private: struct CNode; typedef std::vector TNodeVect; typedef std::vector TTimerVect; // /// a node in an execution path struct CNode { typedef std::vector TTimeVect; // CNode *Parent; TNodeVect Sons; CHTimer *Owner; // the hierarchical timer this node is associated with uint64 TotalTime; // the total time spent in that node, including sons uint64 LastSonsTotalTime; uint64 SonsTotalTime; // maybe different from LastSonsTotalTime while benching the sons and if the display is called in a benched node TTimeVect Measures; // All time measures. Used only when standard deviation is wanted uint64 MinTime; // the minimum time spent in that node uint64 MaxTime; // the maximum time spent in that node uint64 NumVisits; // the number of time the execution has gone through this node // session max measure uint64 SessionCurrent; uint64 SessionMax; // uint64 SonsPreambule; // preamble time for the sons CSimpleClock Clock; // a clock to do the measures at this node // ctor CNode(CHTimer *owner = NULL, CNode *parent = NULL) : Parent(parent), Owner(owner) { reset(); } // dtor ~CNode(); // Get the number of nodes in the tree starting at this node uint getNumNodes() const; // release the sons, should not be benching when calling this void releaseSons(); // reset this node measures void reset() { SonsTotalTime = 0; TotalTime = 0; MaxTime = 0; MinTime = (uint64) -1; NumVisits = 0; SonsPreambule = 0; LastSonsTotalTime = 0; SessionCurrent = 0; SessionMax = 0; NLMISC::contReset(Measures); } // // Display this node path void displayPath(CLog *log) const; // Get this node path void getPath(std::string &dest) const; // reset session current void resetSessionCurrent() { SessionCurrent = 0; for (uint i=0; iresetSessionCurrent(); } // reset all session stats void resetSessionStats() { SessionCurrent = 0; SessionMax = 0; for (uint i=0; iresetSessionStats(); } // spread session value through the while node tree void spreadSession() { SessionMax = SessionCurrent; for (uint i=0; ispreadSession(); } }; /** Some statistics * They can be build from a set of nodes */ struct CStats { double TimeStandardDeviation; double TotalTime; double TotalTimeWithoutSons; double MeanTime; uint64 NumVisits; double MinTime; double MaxTime; double SessionMaxTime; // build stats from a single node void buildFromNode(CNode *node, double msPerTick); // build stats from a vector of nodes void buildFromNodes(CNode **firstNode, uint numNodes, double msPerTick); // display stats void display(CLog *log, bool displayEx = false, bool wantStandardDeviation = false); /** Get a string for stats (all stats on the same line) * \param statEx display extended stats */ void getStats(std::string &dest, bool statEx, double rootTotalTime, bool wantStandardDeviation = false); }; // Stats and the associated timer struct CTimerStat : public CStats { CHTimer *Timer; }; // Stats and the associated node struct CNodeStat : public CStats { CNode *Node; }; /** A statistics sorter, based on some criterion. * It works on pointers on CStats objects */ struct CStatSorter { CStatSorter(TSortCriterion criterion = TotalTime) : Criterion(criterion) {} TSortCriterion Criterion; // Less operator bool operator()(const CStats *lhs, const CStats *rhs); }; /** For Hierarchical + sorted display. displayHierarchicalByExecutionPath() * */ struct CExamStackEntry { // The node. CNode *Node; // The current child to process. uint CurrentChild; // The childes, sorted by specific criterion. std::vector Children; // The depth of the entry uint Depth; explicit CExamStackEntry(CNode *node) { Node= node; CurrentChild= 0; Depth = 0; } explicit CExamStackEntry(CNode *node, uint depth) { Node= node; CurrentChild= 0; Depth = depth; } }; // Real Job. void doBefore(); void doAfter(bool displayAfter = false); static void estimateAfterStopTime(); private: // walk the tree to current execution node, creating it if necessary void walkTreeToCurrent(); private: // node name const char *_Name; // the parent timer CHTimer *_Parent; // the sons timers TTimerVect _Sons; // Tells if this is a root node bool _IsRoot; private: // root node of the hierarchy static CNode _RootNode; // the current node of the execution static CNode *_CurrNode; // the root timer static CHTimer _RootTimer; /** This clock is used to measure the preamble of methods such as CHTimer::before() * This is static, but the Hierarchical Timer doesn't support multi threading anyway.. */ static CSimpleClock _PreambuleClock; // static double _MsPerTick; // static bool _Benching; // static bool _BenchStartedOnce; // static bool _WantStandardDeviation; // static CHTimer *_CurrTimer; // static sint64 _AfterStopEstimateTime; static bool _AfterStopEstimateTimeDone; }; /** * An automatic measuring timer. Encapsulates calls to CHTimer, and avoids missuses of before() and after(). * ex: *\code void myFunction() { static CHTimer myTimer("myFunction"); CAutoTimer myAuto(myTimer); // some code here } *\endcode * Don't forget to call after() to avoid timing wrongness or assertion crashes ! * \author Benjamin Legros * \author Nevrax France * \date 2001 */ class CAutoTimer { private: CHTimer *_HTimer; public: CAutoTimer(CHTimer *timer) : _HTimer(timer) { _HTimer->before(); } ~CAutoTimer() { _HTimer->after(); } }; /** * Same but display result at end. */ class CAutoTimerInst { private: CHTimer *_HTimer; public: CAutoTimerInst(CHTimer *timer) : _HTimer(timer) { _HTimer->before(); } ~CAutoTimerInst() { _HTimer->after(true); } }; } // NLMISC #endif // NL_HIERARCHICAL_TIMER_H /* End of hierarchical_timer.h */ ================================================ FILE: code/nel/include/nel/misc/historic.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_HISTORIC_H #define NL_HISTORIC_H #include "nel/misc/types_nl.h" #include namespace NLMISC { /** An historic with user defined size. * An historic is just a fifo with constraint on size * * \author Nicolas Vizerie * \author Nevrax France * \date 2004 */ template class CHistoric { public: CHistoric(uint maxSize = 0) : _MaxSize(maxSize) {} // Add a value at end of historic. If historic is full then the oldest entry is removed inline void push(const T &value); // Pop the value at the end of jistoric inline void pop(); // Return true is there are no values in the historics. bool empty() const { return _Historic.empty(); } // Get max number of entries in the historic. uint getMaxSize() const { return _MaxSize; } // Set number of entries in the historic. Oldest entries are removed inline void setMaxSize(uint maxSize); // Get current size of historic uint getSize() const { return (uint)_Historic.size(); } // Access to an element in history, 0 being the oldest, size - 1 being the lastest added element const T &operator[](uint index) const { return _Historic[index]; /* let STL do out of range check */ } // Clear historic void clear() { _Historic.clear(); } private: std::deque _Historic; uint _MaxSize; }; //////////////////// // IMPLEMENTATION // //////////////////// // **************************************************************************************************** template inline void CHistoric::push(const T &value) { nlassert(_Historic.size() <= _MaxSize); if (_MaxSize == 0) return; if (getSize() == _MaxSize) { _Historic.pop_front(); } _Historic.push_back(value); } // **************************************************************************************************** template inline void CHistoric::pop() { nlassert(!_Historic.empty()); _Historic.pop_back(); } // **************************************************************************************************** template inline void CHistoric::setMaxSize(uint maxSize) { if (maxSize < getSize()) { uint toRemove = std::min(getSize() - maxSize, getSize()); _Historic.erase(_Historic.begin(), _Historic.begin() + toRemove); } _MaxSize = maxSize; } } #endif ================================================ FILE: code/nel/include/nel/misc/i18n.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_I18N_H #define NL_I18N_H #include "types_nl.h" #include "debug.h" #include "file.h" #include #include #include namespace NLMISC { /** * Class for the internationalization. It's a singleton pattern. * * This class provide an easy way to localize all string. * First you load the language file with \c load(). * Now, you can get a localized string with its association with \c get(). * *\code // load the language French CI18N::load ("fr"); // display "Salut" that is the "hi" string in the selected language (French). nlinfo (CI18N::get("Hi").c_str ()); // display "rms est un master", the French version of the string nlinfo ("rms"+CI18N::get("Master").c_str ()); *\endcode * * Update 26-02-2002 Boris Boucher * * Languages are now preferably handled via official language code. * We use the ISO 639-1 code for language. * Optionally, we can append a country code (ISO 3066) to differentiate * between language flavor (eg Chinese is ISO 639-1 zh, but come in * traditional or simplified form. So we append the country code : * zh-CN (china) for simplified, zh for traditional). * * * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ class CI18N { public: /// Control over text loading enum TLineFormat { // the text file is just loaded, no conversion or checks done on line delimiters LINE_FMT_NO_CARE, // the line delimiters are forced to LF (\n, code 0x0a) LINE_FMT_LF, // the line delimiters are forced to CRLF (\r\n , code 0x0d 0x0a) LINE_FMT_CRLF }; /** Proxy interface for loading string file. * Implement this interface in client code and set it inside I18N * in order to be able to do any work on string file before they * are read by CI18N. * This is used by Ryzom to merge the working string file with * the exploitation one when they are more recent. */ struct ILoadProxy { virtual ~ILoadProxy() {} virtual void loadStringFile(const std::string &filename, ucstring &text) =0; }; /// Set the load proxy class. Proxy can be NULL to unregister. static void setLoadProxy(ILoadProxy *loadProxy); // Get the current load proxy static ILoadProxy *getLoadProxy() { return _LoadProxy; } /// Return a vector with all language available. The vector contains the name of the language. /// The index in the vector is used in \c load() function static const std::vector &getLanguageNames(); /** Return a vector with all language code available. * Code are ISO 639-2 compliant. * As in getLanguageNames(), the index in the vector can be used to call load() */ static const std::vector &getLanguageCodes(); /// Load a language file depending of the language code("en", "fr", ...). Code are ISO 639-2 compliant. static void load (const std::string &languageCode, const std::string &fallbackLanguageCode=""); /** Load a language file from its filename * \param filename name of the language file to load, with its extension * \param reload The file is being reloaded so error message won't be issued for strings that are overwritten */ static void loadFromFilename (const std::string &filename, bool reload); /// Returns the name of the language in the language name (English, Francais, ...) static ucstring getCurrentLanguageName (); /// Returns the code of the language ("fr", "en", ...) static std::string getCurrentLanguageCode (); /// Find a string in the selected language and return his association. static const ucstring &get (const std::string &label); // Test if a string has a translation in the selected language. // NB : The empty string is considered to have a translation static bool hasTranslation(const std::string &label); /** Read the content of a file as a Unicode text. * The method support 16 bits or 8bits utf-8 tagged files. * 8 bits UTF-8 encoding can be recognized by a non official header : * EF,BB, BF. * 16 bits encoding can be recognized by the official header : * FF, FE, witch can be reversed if the data are MSB first. * * Optionally, you can force the reader to consider the file as * UTF-8 encoded. * Optionally, you can ask the reader to interpret #include commands. */ static void readTextFile(const std::string &filename, ucstring &result, bool forceUtf8 = false, bool fileLookup = true, bool preprocess = false, TLineFormat lineFmt = LINE_FMT_NO_CARE, bool warnIfIncludesNotFound = true); /** Read the content of a buffer as a Unicode text. * This is to read preloaded Unicode files. * The method support 16 bits or 8bits utf-8 tagged buffer. * 8 bits UTF-8 encoding can be recognized by a non official header : * EF,BB, BF. * 16 bits encoding can be recognized by the official header : * FF, FE, witch can be reversed if the data are MSB first. * * Optionally, you can force the reader to consider the file as * UTF-8 encoded. */ static void readTextBuffer(uint8 *buffer, uint size, ucstring &result, bool forceUtf8 = false); /** Remove any C style comment from the passed string. */ static void removeCComment(ucstring &commentedString); /** Encode a Unicode string into a string using UTF-8 encoding. */ static std::string encodeUTF8(const ucstring &str); /** Write a Unicode text file using Unicode 16 or UTF-8 encoding. */ static void writeTextFile(const std::string filename, const ucstring &content, bool utf8 = true); static ucstring makeMarkedString(ucchar openMark, ucchar closeMark, const ucstring &text); //@{ //\name Parsing utility /** Skip the white space. * You can optionally pass a ucstring pointer to receive any comments string that build the * white space. * This is useful if you want to keep the comments. * NB : comments are appended to the comments string. */ static void skipWhiteSpace (ucstring::const_iterator &it, ucstring::const_iterator &last, ucstring *storeComments = NULL, bool newLineAsWhiteSpace = true); /// Parse a label static bool parseLabel (ucstring::const_iterator &it, ucstring::const_iterator &last, std::string &label); /// Parse a marked string. NB : usually, we use [ and ] as string delimiters in translation files. static bool parseMarkedString (ucchar openMark, ucchar closeMark, ucstring::const_iterator &it, ucstring::const_iterator &last, ucstring &result, uint32 *lineCounter = NULL, bool allowNewline = true); /** Try to read a given token at current position. * The function will first skip any white space then try to read the token * If found, the function return true and 'it' is advanced after the matched token, * Otherwise, the function return false and 'it' is unchanged. */ static bool matchToken(const char* token, ucstring::const_iterator &it, ucstring::const_iterator end); /// Advance iterator to the start of next line or to the end of string static void skipLine(ucstring::const_iterator &it, ucstring::const_iterator end, uint32 &lineCounter); //@} //@{ //\name Hash code tools. // Generate a hash value for a given string static uint64 makeHash(const ucstring &str); // convert a hash value to a readable string static std::string hashToString(uint64 hash); // convert a readable string into a hash value. static uint64 stringToHash(const std::string &str); // fast convert a hash value to a ucstring static void hashToUCString(uint64 hash, ucstring &dst); //@} static void setNoResolution( bool b ){ noResolution = b; } private: typedef std::map StrMapContainer; static ILoadProxy *_LoadProxy; static StrMapContainer _StrMap; static bool _StrMapLoaded; // the alternative language that will be used if the sentence is not found in the original language static StrMapContainer _StrMapFallback; static std::vector _LanguageCodes; static std::vector _LanguageNames; static bool _LanguagesNamesLoaded; static std::string _SelectedLanguageCode; static const ucstring _NotTranslatedValue; /** Structure to hold contextual info during * read of preprocessed file */ struct TReadContext { /// The defined symbols std::set Defines; /// The if stack (push true until a bad test is found, push false for /// all subsequent if imbrication) std::vector IfStack; }; private: /// Init _LanguageCodes and _LanguageNames static void initLanguages(); static bool loadFileIntoMap(const std::string &filename, StrMapContainer &dest); /// The internal read function, it does the real job of readTextFile static void _readTextFile(const std::string &filename, ucstring &result, bool forceUtf8, bool fileLookup, bool preprocess, TLineFormat lineFmt, bool warnIfIncludesNotFound, TReadContext &readContext); // Don't resolve labels static bool noResolution; }; } // NLMISC #endif // NL_I18N_H /* End of i18n.h */ ================================================ FILE: code/nel/include/nel/misc/i_xml.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_I_XML_H #define NL_I_XML_H //#define NL_DONT_USE_EXTERNAL_CODE #undef NL_DONT_USE_EXTERNAL_CODE #ifndef NL_DONT_USE_EXTERNAL_CODE #include "types_nl.h" #include "stream.h" // Include from libxml2 #include namespace NLMISC { struct EXmlParsingError : public EStream { EXmlParsingError ( const std::string& str ) : EStream( str ) {} }; /** * Input xml stream * * This class is an xml formated input stream. * * This stream use an internal stream to input source xml code. * Use setStream to initialise it. \code // Check exceptions try { // File stream CIFile file; // open the file if (file.open ("input.xml")) { // XMl stream CIXml input; // Init, read all the input file... if (input.init (file)) { // Serial the class myClass.serial (input); } // Close the file file.close (); } else { // File not found } } catch (const Exception &e) { // Something wrong appends } \endcode * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2001 */ class CIXml : public IStream { friend void xmlGenericErrorFuncRead (void *ctx, const char *msg, ...); public: /** Default ctor */ CIXml (); // If tryBinaryMode is true, try to open the stream in both, XML and Binary if XML doesn't work. // In tryBinaryMode, the stream keep a pointer on the input stream passed to init(); CIXml (bool tryBinaryMode); /** Dtor. Call release(). */ virtual ~CIXml (); /** Stream initialisation. The stream must be an input stream. * init() will load the XML tree. So init() can raise read error exceptions. * * \param stream is the stream the class will use to input xml code. * this pointer is not held by the class. This stream must support end seek functions (as files). * \return true if init success, false if stream is not an input stream. */ bool init (IStream &stream); /** Release the resources used by the stream. */ void release (); /** Get the root node pointer */ xmlNodePtr getRootNode () const; /** Get the first child node pointer named childName. NULL if no node named childName. */ static xmlNodePtr getFirstChildNode (xmlNodePtr parent, const char *childName); /** Get the next child node pointer name childName, brother of previous. NULL if no node named childName. */ static xmlNodePtr getNextChildNode (xmlNodePtr last, const char *childName); /** Get the first child node pointer of type. NULL if no node of type. */ static xmlNodePtr getFirstChildNode (xmlNodePtr parent, xmlElementType type); /** Get the next child node pointer of type. NULL if no node of type. */ static xmlNodePtr getNextChildNode (xmlNodePtr last, xmlElementType type); /** Count number of sub node named with a given name for a given node. */ static uint countChildren (xmlNodePtr node, const char *childName); /** Count number of sub node of type for a given node. */ static uint countChildren (xmlNodePtr node, xmlElementType type); /** * Read a property string * * Returns true and the result if the property has been found, else false. */ static bool getPropertyString (std::string &result, xmlNodePtr node, const char *property); /** * Read an integer property - if the property is not found the default value is returned */ static int getIntProperty(xmlNodePtr node, const char *property, int defaultValue); /** * Read a floating point property - if the property is not found the default value is returned */ static double getFloatProperty(xmlNodePtr node, const char *property, float defaultValue); /** * Read a string property - if the property is not found the default value is returned */ static std::string getStringProperty(xmlNodePtr node, const char *property, const std::string& defaultValue); /** * Read the content of the node as a string * * Returns true and the result if some text has been found, else false. */ static bool getContentString (std::string &result, xmlNodePtr node); private: /// From IStream virtual void serial(uint8 &b); virtual void serial(sint8 &b); virtual void serial(uint16 &b); virtual void serial(sint16 &b); virtual void serial(uint32 &b); virtual void serial(sint32 &b); virtual void serial(uint64 &b); virtual void serial(sint64 &b); virtual void serial(float &b); virtual void serial(double &b); virtual void serial(bool &b); #ifndef NL_OS_CYGWIN virtual void serial(char &b); #endif virtual void serial(std::string &b); virtual void serial(ucstring &b); virtual void serialBuffer(uint8 *buf, uint len); virtual void serialBit(bool &bit); virtual bool xmlPushBeginInternal (const char *nodeName); virtual bool xmlPushEndInternal (); virtual bool xmlPopInternal (); virtual bool xmlSetAttribInternal (const char *attribName); virtual bool xmlBreakLineInternal (); virtual bool xmlCommentInternal (const char *comment); // Internal functions void serialSeparatedBufferIn ( std::string &value, bool checkSeparator = true ); inline void flushContentString (); // Push has began bool _PushBegin; // Attribute present bool _AttribPresent; // Attribute name std::string _AttribName; // Current libxml node xmlNodePtr _CurrentNode; // Current libxml header node opened xmlNodePtr _CurrentElement; // Parser pointer xmlParserCtxtPtr _Parser; // Current node text std::string _ContentString; // Current index in the node string uint _ContentStringIndex; // Error message std::string _ErrorString; // Try binary mode bool _TryBinaryMode; // If not NULL, binary mode detected, use this stream in serials IStream *_BinaryStream; // System dependant structure for locale void* _Locale; }; } // NLMISC #endif // NL_DONT_USE_EXTERNAL_CODE #endif // NL_I_XML_H /* End of o_xml.h */ ================================================ FILE: code/nel/include/nel/misc/input_device.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_INPUT_DEVICE_H #define NL_INPUT_DEVICE_H #include "types_nl.h" namespace NLMISC { class CEventServer; class CInputDeviceServer; struct IInputDeviceEvent; /** * Base class that wrap to a device * \author Nicolas Vizerie * \author Nevrax France * \date 2002 */ struct IInputDevice { /** Set the buffer size for this device (the number of samples it can retains). * This return true if the size could be set */ virtual bool setBufferSize(uint size) = 0; /// Get the buffer size for this device virtual uint getBufferSize() const = 0; ///\name Device server specifics. You usually don't want to call these //@{ /** For device server usage : * Called at the beginning of each events retrieval. * If a device doesn't support buffered datas, the state changes can be directly send to the event server. * The default does nothing. */ virtual void begin(CEventServer * /* server */) {} /** For device server usage : * Poll all events from that device, and notify them to the given device server, so that they can be sorted between devices. * This retrieves messages, but do not process them. */ virtual void poll(CInputDeviceServer *dev) = 0; /** For device server usage : * Process an event (eventually update this device state), and translate the message to a IEventServerMessage */ virtual void submit(IInputDeviceEvent *deviceEvent, CEventServer *server) = 0; /** For device server usage : * Says that the next message is for another device, or that it is the last message that will be received. * This allow to pack several messages in one (for example, to sum up mouse moves until a click occurs) * The default does nothing. * The next message can be used to get a time stamp for example. It may be NULL is no next message is available */ virtual void transitionOccured(CEventServer * /* server */, const IInputDeviceEvent * /* nextMessage */) {} //@} // dtor virtual ~IInputDevice() {} }; } // NLMISC #endif // NL_INPUT_DEVICE_H /* End of input_device.h */ ================================================ FILE: code/nel/include/nel/misc/input_device_manager.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_INPUT_DEVICE_MANAGER_H #define NL_INPUT_DEVICE_MANAGER_H #include "types_nl.h" #include "game_device.h" #include "common.h" namespace NLMISC { struct IMouseDevice; struct IKeyboardDevice; struct EInputDevice : public Exception { EInputDevice(const char *reason) : Exception(reason) {} }; /** Interface for objects that give low level access to devices (mouse, keyboard, joypads and joysticks). * Generally an object implementing this interface will send the appropriate events when a device is 'created'. * (Example of implementation : a direct input event emitter) */ struct IInputDeviceManager { // Test if a mouse has been created (by a call to getMouseDeivce) virtual bool isMouseCreated() = 0; /// Create the low level mouse device if needed (one active at a time for that object, repeated calls returns the same pointer). An exception if thrown if it couldn't be obtained. virtual IMouseDevice *getMouseDevice(bool hardware) throw(EInputDevice) = 0; /// remove the low level mouse virtual void releaseMouse() = 0; /// Create the low level keyboard device if needed (one active at a time for that object, repeated calls returns the same pointer). An exception if thrown if it couldn't be obtained. virtual IKeyboardDevice *getKeyboardDevice() throw(EInputDevice) = 0; /// remove the low level keyboard virtual void releaseKeyboard() = 0; // Enumerates current game devices (gamepads, joystick etc.). The result is stored in the given vector virtual void enumerateGameDevice(TDeviceDescVect &descs) throw(EInputDevice) = 0; // Create the given game device interface from its instance name. It also means that it will begin to sends events. virtual IGameDevice *createGameDevice(const std::string &instanceName) throw(EInputDevice) = 0; // Release the given game device. virtual void releaseGameDevice(IGameDevice *gd) = 0; }; } // NLMISC #endif // NL_INPUT_DEVICE_MANAGER_H /* End of device_manager.h */ ================================================ FILE: code/nel/include/nel/misc/input_device_server.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_INPUT_DEVICE_SERVER_H #define NL_INPUT_DEVICE_SERVER_H #include "types_nl.h" #include namespace NLMISC { class CEventServer; struct IInputDevice; struct IInputDeviceEvent; /** Base class for an input device server. Unlike an event server, it manages several devices, and can sort their events (by date for example). * It keeps a list of active devices. * It can poll datas from every active device. * It can sort devices messages to submit them in correct order to a CEventServer. */ class CInputDeviceServer { public: /// register a device into this device server. void registerDevice(IInputDevice *device); /// remove a device from this server (but does not delete it). void removeDevice(IInputDevice *device); // returns the number of registered devices uint getNumDevices() const { return (uint)_Devices.size(); } // return a device IInputDevice *getDevice(uint index) { return _Devices[index]; } /// Test whether the given device is handled by this server. bool isDevice(IInputDevice *device) const; /// Retrieve datas from the devices, and submit them to the given CEventServer. void poll(CEventServer *server); /// Allow an input device to register an event. The event will then be deleted by this server void submitEvent(IInputDeviceEvent *deviceEvent); // dtor virtual ~CInputDeviceServer() {} private: typedef std::vector TDeviceCont; typedef std::vector TEventCont; private: TDeviceCont _Devices; TEventCont _Events; }; /** An event from an input device. */ struct IInputDeviceEvent { IInputDevice *Emitter; // the input device that emitted that event // Used to sort events by time stamp. virtual bool operator < (const IInputDeviceEvent &IInputDeviceEvent) const = 0; virtual ~IInputDeviceEvent() {} }; } // NLMISC #endif // NL_INPUT_DEVICE_SERVER_H /* End of input_device_server.h */ ================================================ FILE: code/nel/include/nel/misc/inter_window_msg_queue.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef RY_INTER_WINDOW_MSG_QUEUE_H #define RY_INTER_WINDOW_MSG_QUEUE_H #include "types_nl.h" #ifdef NL_OS_WINDOWS #include "nel/misc/thread.h" #include "nel/misc/mutex.h" #include "nel/misc/shared_memory.h" #include "nel/misc/mem_stream.h" #include "nel/misc/dummy_window.h" #ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif #ifndef _WIN32_WINDOWS # define _WIN32_WINDOWS 0x0410 #endif #ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0400 #endif #ifndef WINVER # define WINVER 0x0400 #endif #ifndef NOMINMAX # define NOMINMAX #endif #include namespace NLMISC { // ************************************************************************************************** /** IPC Utility class to enable easy window-window communication * * This enable 2-ways non blocking communication between 2 windows on the same machine (windows * may belong to different processes) * * Only works on microsoft windows os for now * * The implementation relies on the WM_COPYDATA message to enable communication, but create a separate thread * to enable non blocking exchange. (The WM_COPYDATA message require the use of SendMessage, which is blocking until the * target window receive the message and respond) * * Identifier should be agreed on for the 2 windows that are to communicate (windows handles are transparently * exchanged through shared memory based on this name) * * When initializing the queue for a specific window, this window message proc will be subclassed * to enable interception of the WM_COPYDATA for that window. * * 'release' should be called before the hooked window is destroyed, to avoid dangling reference to it * in this object. As one can expect 'release' is also automatically called when this object is destroyed * * Additionnaly, an internal, invisible window will be create if no one is given (second form of 'init'). This avoid having to worry * about order of init / release of subclassing. * * FIXME : In fact, creating an invisible, internal window (that is required to have a message queue), should be the default, * this would hide the internal communication mean, and we simply would have something called like 'CInterProcessMsgQueue'. * Alternatives have been considered, but this one seemed simpler at first because of the facility offered by WM_COPYDATA * Other possible implementations include shared memory (would require additionnal synchronisation & possible splitting of messages then), sockets (would make the firewall complain then ...) etc. * . */ class CInterWindowMsgQueue { public: CInterWindowMsgQueue(); ~CInterWindowMsgQueue(); /** Create a 2-way inter process message queue. * Each ownerWindow / localId / foreignId triplet should be unique, repeated call with the same value will return false * as long as the message queue created from them is alive * IMPORTANT: 'ownerWindow' will be subclassed to handle the messages. If multiple subclassing are done on that window, * they must be undone in reverse order, or an assertion will be raised. The simplest thing is use the second form of init, * which will create an internal invisible window, thusavoiding this concern. */ bool init(HINSTANCE hInstance, uint32 localId, uint32 foreignId); /** Create a 2-way message queue between 2 windows. * Each ownerWindow / localId / foreignId triplet should be unique, repeated call with the same value will return false * as long as the message queue created from them is alive * IMPORTANT: 'ownerWindow' will be subclassed to handle the messages. If multiple subclassing are done on that window, * they must be undone in reverse order, or an assertion will be raised. The simplest thing is use the second form of init, * which will create an internal invisible window, thusavoiding this concern. * * return true on success */ bool init(HWND ownerWindow, uint32 localId, uint32 foreignId); /** Release the msg queue * This will unhook the window, restoring its previous message procedure * Note than if the window was hooked by someone else, an assert will be raised * Hooks on windows msg proc should thus be 'unhooked' in reverse order */ void release(); /** Send a new message * The msg is guaranteed to be received by the other window as long as it remains alive */ void sendMessage(CMemStream &msg); // See if a message has arrived from foreign window, return true if so bool pumpMessage(CMemStream &dest); // Test if other window is present bool connected() const; // uint getSendQueueSize() const; uint getReceiveQueueSize() const; // ************************************************************************************************** private: struct CMsg { std::vector Msg; void serial(NLMISC::IStream &f) { f.serialVersion(0); f.serialCont(Msg); } }; typedef std::list TMsgList; CSynchronized _OutMessageQueue; // outgoing messages : filled by main thread, pumped by // this 'CInterWindowMsgQueue' internal thread to hide latency of SendMessage // to the main thread TMsgList _InMessageQueue; // Incoming messages : not synchronised here, because the wnd // message proc that receive foreign window messages (through WM_COPYDATA) // belong to the same thread than the reader (that calls 'pumpMessage') CDummyWindow _DummyWindow; // internal send thread class CSendTask : public IRunnable { public: CSendTask(CInterWindowMsgQueue *parent); // from IRunnable virtual void run(); // parent should call this to ask the thread to terminate void stop(); private: CInterWindowMsgQueue *_Parent; bool _StopAsked; }; friend class CSendTask; /** One protagonist in the communication. May be the 'local' of 'foreign' window * The responsbility of this class is to allow to set / retrieve the window handle * of local / foreign window. * Window handle is needed by the send thread when it need to call SendMessage */ class CProtagonist { public: CProtagonist(); ~CProtagonist(); void release(); // init this 'protagonist' bool init(uint32 id); // set handle for foreign window void setWnd(HWND wnd); // get local or foreign window handle HWND getWnd(); uint32 getId() const { return _Id; } private: uint32 _Id; HWND _Wnd; HANDLE _SharedMemMutex; // system-wide mutex for access to window handle in shared memory void *_SharedWndHandle; // no need for mutex here as the value will be written atomically (a single memory word) private: // shared memory mutex void acquireSMMutex(); void releaseSMMutex(); }; // CProtagonist _LocalWindow; CProtagonist _ForeignWindow; CSendTask *_SendTask; IThread *_SendThread; static const uint _CurrentVersion; // for messages serialisation // Unique identifier for a 2-way message queue (that is, a CInterWindowMsgQueue object after it has been // initialized) // This is required since the window message proc 'ListenerProc' is static so we must be // retrieve the associated 'CInterWindowMsgQueue' object from the (local id, foreign id) pair class CMsgQueueIdent { public: HWND Wnd; uint32 LocalId; uint32 ForeignId; public: CMsgQueueIdent(HWND wnd, uint32 localId, uint32 foreignId) : Wnd(wnd), LocalId(localId), ForeignId(foreignId) {} bool operator < (const CMsgQueueIdent &other) const { if (Wnd != other.Wnd) return Wnd < other.Wnd; if (LocalId != other.LocalId) return LocalId < other.LocalId; return LocalId < other.LocalId; } }; typedef std::map TMessageQueueMap; static CSynchronized _MessageQueueMap; // map window handle to old message queue class COldMsgProc { public: WNDPROC OldWinProc; uint RefCount; public: COldMsgProc() : OldWinProc(NULL), RefCount(0) {} }; typedef std::map TOldWinProcMap; static TOldWinProcMap _OldWinProcMap; bool initInternal(HINSTANCE hInstance, HWND ownerWindow, uint32 localId, uint32 foreignId = 0); private: static LRESULT CALLBACK listenerProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK invisibleWindowListenerProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT handleWMCopyData(HWND hwnd, COPYDATASTRUCT *cds); void updateTargetWindow(); void clearOutQueue(); }; } // NLMISC #endif #endif ================================================ FILE: code/nel/include/nel/misc/keyboard_device.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_KEYBOARD_DEVICE_H #define NL_KEYBOARD_DEVICE_H #include "types_nl.h" #include "events.h" #include "input_device.h" namespace NLMISC { /** Gives access to low level keyboard parameters * - 'Shift' messages are replaced by RShift and LShift msg. * - 'Control' messages are replaced by 'RControl' and 'LControl' msg. * - 'Menu' (alternate) messages are replaced by 'RMenu' and 'LMenu' msg. */ struct IKeyboardDevice : public IInputDevice { /// Max number of supported keys enum { NumKeys = 256 }; /// Get the delay before key repeat, in milliseconds virtual uint getKeyRepeatDelay() const = 0; /// Get the delay before key repeat, in milliseconds virtual void setKeyRepeatDelay(uint delay) = 0; /// Get the period before key repeat, in milliseconds virtual uint getKeyRepeatPeriod() const = 0; /// Get the period before key repeat, in milliseconds virtual void setKeyRepeatPeriod(uint period) = 0; /// Set a set of keys for which repetition is disabled virtual void disableRepetition(const TKey *keyTab, uint numKey) = 0; /// Get the number of disabled keys virtual uint getNumDisabledRepetition() const = 0; /** Get the disabled keys and stores in the given tab. * NB: must ensure the destination table has the right size * \see getNumDisabledKeys() */ virtual void getDisabledRepetitions(TKey *destTab) const = 0; }; } // NLMISC #endif // NL_KEYBOARD_DEVICE_H /* End of keyboard_device.h */ ================================================ FILE: code/nel/include/nel/misc/line.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_LINE_H #define NL_LINE_H #include "types_nl.h" #include "vector.h" namespace NLMISC { // *************************************************************************** /** * A simple couple of vertex. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CLine { public: CVector V0, V1; public: /// default ctor CLine() {} // ctor from 2 points CLine(const CVector &v0, const CVector &v1) : V0(v0), V1(v1) {} /// Project a vector on this line void project(const CVector &inV, CVector &outV); }; } // NLMISC #endif // NL_LINE_H /* End of line.h */ ================================================ FILE: code/nel/include/nel/misc/log.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_LOG_H #define NL_LOG_H #include "types_nl.h" #include "mutex.h" #include #include namespace NLMISC { class IDisplayer; /** * When display() is called, the logger builds a string and sends it to its attached displayers. * The positive filters, if any, are applied first, then the negative filters. * See the nldebug/nlinfo... macros in debug.h. * * \ref log_howto * \author Vianney Lecroart, Olivier Cado * \author Nevrax France * \date 2001 */ class CLog { public: typedef enum { LOG_NO=0, LOG_ERROR, LOG_WARNING, LOG_INFO, LOG_DEBUG, LOG_STAT, LOG_ASSERT, LOG_UNKNOWN } TLogType; // Debug information struct TDisplayInfo { TDisplayInfo() : Date(0), LogType(CLog::LOG_NO), ThreadId(0), FileName(NULL), Line(-1), FuncName(NULL) {} time_t Date; TLogType LogType; std::string ProcessName; size_t ThreadId; const char *FileName; sint Line; const char *FuncName; std::string CallstackAndLog; // contains the callstack and a log with not filter of N last line (only in error/assert log type) }; CLog (TLogType logType = LOG_NO); /// Add a new displayer in the log. You have to create the displayer, remove it and delete it when you have finish with it. /// For example, in a 3dDisplayer, you can add the displayer when you want, and the displayer displays the string if the 3d /// screen is available and do nothing otherwise. In this case, if you want, you could leave the displayer all the time. void addDisplayer (IDisplayer *displayer, bool bypassFilter = false); /// Return the first displayer selected by his name IDisplayer *getDisplayer (const char *displayerName); /// Remove a displayer. If the displayer doesn't work in a specific time, you could remove it. void removeDisplayer (IDisplayer *displayer); /// Remove a displayer using his name void removeDisplayer (const char *displayerName); /// Returns true if the specified displayer is attached to the log object bool attached (IDisplayer *displayer) const; /// Returns true if no displayer is attached bool noDisplayer () const { return _Displayers.empty() && _BypassFilterDisplayers.empty(); } /// Set the name of the process static void setProcessName (const std::string &processName); /// Find the process name if nobody call setProcessName before static void setDefaultProcessName (); /// If !noDisplayer(), sets line and file parameters, and enters the mutex. If !noDisplayer(), don't forget to call display...() after, to release the mutex. void setPosition (sint line, const char *fileName, const char *funcName = NULL); #ifdef NL_OS_WINDOWS #define CHECK_TYPES2(__a,__b) \ inline __a(const char *fmt) { __b(fmt); } \ template __a(const char *fmt, A a) { _check(a); __b(fmt, a); } \ template __a(const char *fmt, A a, B b) { _check(a); _check(b); __b(fmt, a, b); } \ template __a(const char *fmt, A a, B b, C c) { _check(a); _check(b); _check(c); __b(fmt, a, b, c); } \ template __a(const char *fmt, A a, B b, C c, D d) { _check(a); _check(b); _check(c); _check(d); __b(fmt, a, b, c, d); } \ template __a(const char *fmt, A a, B b, C c, D d, E e) { _check(a); _check(b); _check(c); _check(d); _check(e); __b(fmt, a, b, c, d, e); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); __b(fmt, a, b, c, d, e, f); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); __b(fmt, a, b, c, d, e, f, g); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); __b(fmt, a, b, c, d, e, f, g, h); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); __b(fmt, a, b, c, d, e, f, g, h, i); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); __b(fmt, a, b, c, d, e, f, g, h, i, j); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); __b(fmt, a, b, c, d, e, f, g, h, i, j, k); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); _check(x); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x, Y y) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); _check(x); _check(y); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x, Y y, Z z) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); _check(x); _check(y); _check(z); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z); } /// Display a string in decorated and final new line form to all attached displayers. Call setPosition() before. Releases the mutex. void _displayNL (const char *format, ...); CHECK_TYPES2(void displayNL, _displayNL) /// Display a string in decorated form to all attached displayers. Call setPosition() before. Releases the mutex. void _display (const char *format, ...); CHECK_TYPES2(void display, _display) /// Display a string with a final new line to all attached displayers. Call setPosition() before. Releases the mutex. void _displayRawNL (const char *format, ...); CHECK_TYPES2(void displayRawNL, _displayRawNL) /// Display a string (and nothing more) to all attached displayers. Call setPosition() before. Releases the mutex. void _displayRaw (const char *format, ...); CHECK_TYPES2(void displayRaw, _displayRaw) /// Display a raw text to the normal displayer but without filtering /// It's used by the Memdisplayer (little hack to work) void _forceDisplayRaw (const char *format, ...); CHECK_TYPES2(void forceDisplayRaw, _forceDisplayRaw) #else /// Display a string in decorated and final new line form to all attached displayers. Call setPosition() before. Releases the mutex. void displayNL (const char *format, ...); /// Display a string in decorated form to all attached displayers. Call setPosition() before. Releases the mutex. void display (const char *format, ...); /// Display a string with a final new line to all attached displayers. Call setPosition() before. Releases the mutex. void displayRawNL (const char *format, ...); /// Display a string (and nothing more) to all attached displayers. Call setPosition() before. Releases the mutex. void displayRaw (const char *format, ...); /// Display a raw text to the normal displayer but without filtering /// It's used by the Memdisplayer (little hack to work) void forceDisplayRaw (const char *format, ...); #endif /// Adds a positive filter. Tells the logger to log only the lines that contain filterstr void addPositiveFilter( const char *filterstr ); /// Adds a negative filter. Tells the logger to discard the lines that contain filterstr void addNegativeFilter( const char *filterstr ); /// Reset both filters void resetFilters(); /// Removes a filter by name (in both filters). void removeFilter( const char *filterstr = NULL); /// Displays the list of filter into a log void displayFilter( CLog &log ); /// Do not call this unless you know why you're doing it, it kills the debug/log system! static void releaseProcessName(); protected: /// Symetric to setPosition(). Automatically called by display...(). Do not call if noDisplayer(). void unsetPosition(); /// Returns true if the string must be logged, according to the current filter bool passFilter( const char *filter ); TLogType _LogType; static std::string *_ProcessName; const char *_FileName; sint _Line; const char *_FuncName; typedef std::list CDisplayers; CDisplayers _Displayers; CDisplayers _BypassFilterDisplayers; // these displayers always log info (by pass filter system) CMutex _Mutex; uint32 _PosSet; /// "Discard" filter std::list _NegativeFilter; /// "Crop" filter std::list _PositiveFilter; /// Display a string in decorated form to all attached displayers. void displayString (const char *str); /// Display a Raw string to all attached displayers. void displayRawString (const char *str); std::string TempString; TDisplayInfo TempArgs; }; } // NLMISC #endif // NL_LOG_H /* End of log.h */ ================================================ FILE: code/nel/include/nel/misc/matrix.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_MATRIX_H #define NL_MATRIX_H #include "vector.h" #include "vector_h.h" #include "quat.h" namespace NLMISC { class CPlane; // ====================================================================================================== /** * A 4*4 Homogeneous Matrix. * This is a column matrix, so operations like: \c v1=A*B*C*v0; applies C first , then B, then A to vector v0. \n * Since it is a column matrix, the first column is the I vector of the base, 2nd is J, 3th is K. \n * 4th column vector is T, the translation vector. * * Angle orientation are: Xaxis: YtoZ. Yaxis: ZtoX. Zaxis: XtoY. * * This matrix keep a matrix state to improve Matrix, vector and plane computing (matrix inversion, vector multiplication...). * The internal matrix know if: * - matrix is identity * - matrix has a translation component * - matrix has a rotation component * - matrix has a uniform scale component (scale which is the same along the 3 axis) * - matrix has a non-uniform scale component * - matrix has a projection component (4th line of the matrix is not 0 0 0 1). * * An example of improvement is that CMatrix::operator*(const CVector &v) return v if the matrix is identity. * * By default, a matrix is identity. But for a performance view, this is just a StateBit=0... * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class NL_ALIGN_SSE2 CMatrix { public: /// Rotation Order. enum TRotOrder { XYZ, XZY, YXZ, YZX, ZXY, ZYX }; /// The identity matrix. Same as CMatrix(). static const CMatrix Identity; public: /// \name Object //@{ /// Constructor which init to identity(). CMatrix() { StateBit= 0; // Init just Pos because must always be valid for faster getPos() M[12]= M[13]= M[14]= 0; } /// Copy Constructor. CMatrix(const CMatrix &); /// operator=. CMatrix &operator=(const CMatrix &); //@} /// \name Sets //@{ /// Reset the matrix to identity. void identity(); /** Explicit setup the Rotation/Scale matrix (base). * Avoid it. It implies low compute since no check is done on base to see what type of matrix it is * (identity, rotation, scale, uniform scale...) * \param i The I vector of the Cartesian base. * \param j The J vector of the Cartesian base. * \param k The K vector of the Cartesian base. * \param hintNoScale set it to true if you are sure that your rot matrix is a pure rot matrix with no scale. * If set to true and your rotation is not an orthonormal basis, unpredictable result are excepted. */ void setRot(const CVector &i, const CVector &j, const CVector &k, bool hintNoScale=false); /** Explicit setup the Rotation/Scale matrix (base). * Avoid it. It implies low compute since no check is done on m33 to see what type of matrix it is * (identity, rotation, scale, uniform scale) * \param m33 the 3*3 column rotation matrix. (3x3 matrix stored in column-major order as 9 consecutive values) * \param hintNoScale set it to true if you are sure that your rot matrix is a pure rot matrix with no scale. * If set to true and your rotation is not an orthonormal basis, unpredictable result are excepted. */ void setRot(const float m33[9], bool hintNoScale=false); /** Explicit setup the Rotation matrix (base) as a Euler rotation matrix. * \param v a vector of 3 angle (in radian), giving rotation around each axis (x,y,z) * \param ro the order of transformation applied. if ro==XYZ, then the transform is M=M*Rx*Ry*Rz */ void setRot(const CVector &v, TRotOrder ro); /** Explicit setup the Rotation matrix (base) as a Quaternion rotation matrix. * \param quat a UNIT quaternion */ void setRot(const CQuat &quat); /** Explicit setup the Rotation/Scale matrix (base) with the rotation part of another matrix. * \param matrix the matrix to copy rot part. */ void setRot(const CMatrix &matrix); /** Explicit setup the Rotation/Scale matrix (base) with a scale (=> matrix has no Rotation). * 1 is tested to update bits accordingly * \param scale the scale to set */ void setScale(float scale); /** Explicit setup the Rotation/Scale matrix (base) with a scale (=> matrix has no Rotation). * case where v.x==v.y==v.z is tested to set a uniform scale * \param scale the scale to set */ void setScale(const CVector &v); /** Explicit setup the Translation component. * v==Null is tested to see if the matrix now have a translation component. * \param v the translation vector. */ void setPos(const CVector &v); /** Explicit move the Translation component. * \param v a vector to move the translation vector. */ void movePos(const CVector &v); /** Explicit setup the Projection component. * Proj is tested to see if the matrix now have a projection component. * \param proj the 4th line of the matrix. Set it to 0 0 0 1 to reset it to default. */ void setProj(const float proj[4]); /** Reset the Projection component to 0 0 0 1. */ void resetProj(); /** Explicit setup the 4*4 matrix. * Avoid it. It implies low compute since no check is done on rotation matrix to see what type of matrix it is * (identity, rotation, scale, uniform scale). * BUT check are made to see if it has translation or projection components. * \param m44 the 4*4 column matrix (4x4 matrix stored in column-major order as 16 consecutive values) */ void set(const float m44[16]); /** Setup the (i, j) matrix coefficient * \param coeff: coefficient value. * \param i : column index. * \param j : line index. */ void setCoefficient(float coeff, sint i, sint j) { M[ (j<<2) + i] = coeff; } //@} /** Choose an arbitrary rotation matrix for the given direction. The matrix will have I==idir * \param idir: vector direction. MUST be normalized. */ void setArbitraryRotI(const CVector &idir); /** Choose an arbitrary rotation matrix for the given direction. The matrix will have J==jdir * \param jdir: vector direction. MUST be normalized. */ void setArbitraryRotJ(const CVector &jdir); /** Choose an arbitrary rotation matrix for the given direction. The matrix will have K==kdir * \param kdir: vector direction. MUST be normalized. */ void setArbitraryRotK(const CVector &kdir); //@} /// \name Gets. //@{ /** Get the Rotation/Scale matrix (base). * \param i The matrix's I vector of the Cartesian base. * \param j The matrix's J vector of the Cartesian base. * \param k The matrix's K vector of the Cartesian base. */ void getRot(CVector &i, CVector &j, CVector &k) const; /** Get the Rotation/Scale matrix (base). * \param m33 the matrix's 3*3 column rotation matrix. (3x3 matrix stored in column-major order as 9 consecutive values) */ void getRot(float m33[9]) const; /** Get the Rotation matrix (base). * \param quat the return quaternion. */ void getRot(CQuat &quat) const; /** Get the Rotation matrix (base). * \param quat the return quaternion. */ CQuat getRot() const {CQuat ret; getRot(ret); return ret;} /** Get the Translation component. * \param v the matrix's translation vector. */ void getPos(CVector &v) const {v.x= M[12]; v.y= M[13]; v.z= M[14];} /** Get the Translation component. * NB: a const & works because it is a column vector * \return the matrix's translation vector. */ const CVector &getPos() const {return *(CVector*)(M+12);} /** Get the Projection component. * \param proj the matrix's projection vector. */ void getProj(float proj[4]) const; /// Get the I vector of the Rotation/Scale matrix (base). CVector getI() const; /// Get the J vector of the Rotation/Scale matrix (base). CVector getJ() const; /// Get the K vector of the Rotation/Scale matrix (base). CVector getK() const; /** Get 4*4 matrix. * \param m44 the matrix's 4*4 column matrix (4x4 matrix stored in column-major order as 16 consecutive values) */ void get(float m44[16]) const; /** Get 4*4 matrix. * \return the matrix's 4*4 column matrix (4x4 matrix stored in column-major order as 16 consecutive values) */ const float *get() const; //@} /// \name 3D Operations. //@{ /// Apply a translation to the matrix. same as M=M*T void translate(const CVector &v); /** Apply a rotation on axis X to the matrix. same as M=M*Rx * \param a angle (in radian). */ void rotateX(float a); /** Apply a rotation on axis Y to the matrix. same as M=M*Ry * \param a angle (in radian). */ void rotateY(float a); /** Apply a rotation on axis Z to the matrix. same as M=M*Rz * \param a angle (in radian). */ void rotateZ(float a); /** Apply a Euler rotation. * \param v a vector of 3 angle (in radian), giving rotation around each axis (x,y,z) * \param ro the order of transformation applied. if ro==XYZ, then the transform is M=M*Rx*Ry*Rz */ void rotate(const CVector &v, TRotOrder ro); /** Apply a quaternion rotation. */ void rotate(const CQuat &quat); /// Apply a uniform scale to the matrix. void scale(float f); /// Apply a non-uniform scale to the matrix. void scale(const CVector &scale); //@} /// \name Matrix Operations. //@{ /** Matrix multiplication. Because of copy avoidance, this is the fastest method * Equivalent to *this= m1 * m2 * \warning *this MUST NOT be the same as m1 or m2, else it doesn't work (not checked/nlasserted) */ void setMulMatrix(const CMatrix &m1, const CMatrix &m2); /// Matrix multiplication CMatrix operator*(const CMatrix &in) const { CMatrix ret; ret.setMulMatrix(*this, in); return ret; } /// equivalent to M=M*in CMatrix &operator*=(const CMatrix &in) { CMatrix ret; ret.setMulMatrix(*this, in); *this= ret; return *this; } /** Matrix multiplication assuming no projection at all in m1/m2 and Hence this. Even Faster than setMulMatrix() * Equivalent to *this= m1 * m2 * NB: Also always suppose m1 has a translation, for optimization consideration * \warning *this MUST NOT be the same as m1 or m2, else it doesn't work (not checked/nlasserted) */ void setMulMatrixNoProj(const CMatrix &m1, const CMatrix &m2); /** transpose the rotation part only of the matrix (swap columns/lines). */ void transpose3x3(); /** transpose the matrix (swap columns/lines). * NB: this transpose the 4*4 matrix entirely (even proj/translate part). */ void transpose(); /** Invert the matrix. * if the matrix can't be inverted, it is set to identity. */ void invert(); /** Return the matrix inverted. * if the matrix can't be inverted, identity is returned. */ CMatrix inverted() const; /** Normalize the matrix so that the rotation part is now an orthonormal basis, ie a rotation with no scale. * NB: projection part and translation part are not modified. * \param pref the preference axis order to normalize. ZYX means that K direction will be kept, and the plane JK * will be used to lead the I vector. * \return false if One of the vector basis is null. true otherwise. */ bool normalize(TRotOrder pref); //@} /// \ Vector Operations. //@{ /// Multiply a normal. ie v.w=0 so the Translation component doesn't affect result. Projection doesn't affect result. CVector mulVector(const CVector &v) const; /// Multiply a point. ie v.w=1 so the Translation component do affect result. Projection doesn't affect result. CVector mulPoint(const CVector &v) const; /** Multiply a point. \sa mulPoint */ CVector operator*(const CVector &v) const { return mulPoint(v); } /// Multiply with an homogeneous vector CVectorH operator*(const CVectorH& v) const; //@} /// \name Misc //@{ void serial(IStream &f); /// return true if the matrix has a scale part (by scale(), by multiplication etc...) bool hasScalePart() const; /// return true if hasScalePart() and if if this scale is uniform. bool hasScaleUniform() const; /// return true the uniform scale. valid only if hasScaleUniform() is true, else 1 is returned. float getScaleUniform() const; /// return true if the matrix has a projection part (by setProj(), by multiplication etc...) bool hasProjectionPart() const; //@} // Friend. /// Plane (line vector) multiplication. friend CPlane operator*(const CPlane &p, const CMatrix &m); private: float M[16]; float Scale33; uint32 StateBit; // BitVector. 0<=>identity. // Methods For inversion. bool fastInvert33(CMatrix &ret) const; bool slowInvert33(CMatrix &ret) const; bool slowInvert44(CMatrix &ret) const; // access to M, in math conventions (mat(1,1) ... mat(4,4)). Indices from 0 to 3. float &mat(sint i, sint j) { return M[ (j<<2) + i]; } // access to M, in math conventions (mat(1,1) ... mat(4,4)). Indices from 0 to 3. const float &mat(sint i, sint j) const { return M[ (j<<2) + i]; } // return the good 3x3 Id to compute the minor of (i,j); void getCofactIndex(sint i, sint &l1, sint &l2, sint &l3) const { switch(i) { case 0: l1=1; l2=2; l3=3; break; case 1: l1=0; l2=2; l3=3; break; case 2: l1=0; l2=1; l3=3; break; case 3: l1=0; l2=1; l3=2; break; default: l1=0; l2=0; l3=0; break; } } // true if MAT_TRANS. // trans part is true means the right 3x1 translation part matrix is relevant. // Else it IS initialized to (0,0,0) (exception!!!) bool hasTrans() const; // true if MAT_ROT | MAT_SCALEUNI | MAT_SCALEANY. // rot part is true means the 3x3 rot matrix AND Scale33 are relevant. // Else they are not initialized but are supposed to represent identity and Scale33==1. bool hasRot() const; // true if MAT_PROJ. // proj part is true means the bottom 1x4 projection part matrix is relevant. // Else it is not initialized but is supposed to represent the line vector (0,0,0,1). bool hasProj() const; bool hasAll() const; void testExpandRot() const; void testExpandProj() const; // inline void setScaleUni(float scale); }; } #endif // NL_MATRIX_H /* End of matrix.h */ ================================================ FILE: code/nel/include/nel/misc/md5.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_MD5_H #define NL_MD5_H #include "types_nl.h" #include namespace NLMISC { class IStream; // **************************************************************************** /** * MD5 Low level routines * Largely inspired from the RSA Data Security works * \author Matthieu Besson * \author Nevrax France * \date July 2004 */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ // **************************************************************************** struct CHashKeyMD5 { uint8 Data[16]; void clear(); std::string toString() const; bool fromString(const std::string &in); bool operator==(const CHashKeyMD5 &in) const; bool operator!=(const CHashKeyMD5 &in) const; bool operator<(const CHashKeyMD5 &in) const; void serial (NLMISC::IStream &s); }; // **************************************************************************** class CMD5Context { public: void init(); void update (const uint8 *pBufIn, uint32 nBufLength); void final (CHashKeyMD5 &out); private: uint32 State[4]; // state (ABCD) uint32 Count[2]; // number of bits, modulo 2^64 (lsb first) uint8 Buffer[64]; // input buffer static uint8 Padding[64]; private: void transform (uint32 state[4], const uint8 block[64]); void encode (uint8 *output, const uint32 *input, uint len); void decode (uint32 *output, const uint8 *input, uint len); }; // **************************************************************************** /** * MD5 High level routines * Largely inspired from the RSA Data Security works * \author Matthieu Besson * \author Nevrax France * \date July 2004 */ /* inline bool operator <(const struct CHashKeyMD5 &a,const struct CHashKeyMD5 &b) { return a < b; } */ // This function get a filename (it works with big files) and returns his MD5 hash key CHashKeyMD5 getMD5(const std::string &filename); // This function get a buffer with size and returns his MD5 hash key CHashKeyMD5 getMD5(const uint8 *buffer, uint32 size); }; // namespace NLMISC #endif // NL_MD5_H /* End of md5.h */ ================================================ FILE: code/nel/include/nel/misc/mem_displayer.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_MEM_DISPLAYER_H #define NL_MEM_DISPLAYER_H #include "types_nl.h" #include "displayer.h" #include #include namespace NLMISC { /** * Display into a string vector * \author Benjamin Legros * \author Nevrax France * \date 2001 */ class CMemDisplayer : public IDisplayer { public: /// Constructor CMemDisplayer (const char *displayerName = ""); /// Set Parameter of the displayer if not set at the ctor time void setParam (uint32 maxStrings = 50); /// Write N last line into a displayer (InfoLog by default) void write (CLog *log = NULL, bool quiet=true); void write (std::string &str, bool crLf=false); const std::deque &lockStrings () { _CanUseStrings = false; return _Strings; } void unlockStrings() { _CanUseStrings = true; } void clear () { if (_CanUseStrings) _Strings.clear (); } protected: /// Put the string into the file. virtual void doDisplay ( const CLog::TDisplayInfo& args, const char *message ); bool _NeedHeader; uint32 _MaxStrings; // number of string in the _Strings queue (default is 50) bool _CanUseStrings; std::deque _Strings; }; /** * Same as CMemDisplayer but only display the text (no line, no date, no process...) * \author Vianney Lecroart * \author Nevrax France * \date 2002 */ class CLightMemDisplayer : public CMemDisplayer { public: /// Constructor CLightMemDisplayer (const char *displayerName = "") : CMemDisplayer(displayerName) { } protected: /// Put the string into the file. virtual void doDisplay ( const CLog::TDisplayInfo& args, const char *message ); }; } // NLMISC #endif // NL_MEM_DISPLAYER_H /* End of mem_displayer.h */ ================================================ FILE: code/nel/include/nel/misc/mem_stream.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_MEM_STREAM_H #define NL_MEM_STREAM_H #include "types_nl.h" #include "stream.h" #include "object_vector.h" #include "fast_mem.h" #include "smart_ptr.h" #include #include namespace NLMISC { /// Exception class for CMemStream struct EMemStream : public NLMISC::EStream { EMemStream( const std::string& str ) : EStream( str ) {} }; /** This class implement a copy on write behavior for memory stream buffer. * The goal is to allow buffer sharing between CMemStream object, so that * a CMemStream can be copied or passed by value as input/output parameter * without copying the data buffer (thus making a CMemStrem copy almost free). * This class reference a TMemStreamBuffer object with a smart pointer, * when some code call the getBufferWrite() method to obtain write access * to the memory buffer, if the ref count is more than 1, then we make a copy * of the internal buffer for the current object. * * \Author Boris Boucher */ class CMemStreamBuffer { public: typedef CObjectVector TBuffer; private: struct TMemStreamBuffer : public CRefCount { // the buffer himself TBuffer _Buffer; }; typedef CSmartPtr TMemStreamBufferPtr; TMemStreamBufferPtr _SharedBuffer; public: mutable uint32 Pos; /// constructor, allocate a shared buffer CMemStreamBuffer() { _SharedBuffer = new TMemStreamBuffer; Pos = 0; } /// Return a read accessor to the buffer const TBuffer &getBuffer() const { return _SharedBuffer->_Buffer; } /** Return a write accessor to the buffer, create acopy it if more than * one CMemStreamBuffer reference then buffer. */ TBuffer &getBufferWrite() { if (_SharedBuffer->getRefCount() > 1) { // we need to duplicate the buffer _SharedBuffer = new TMemStreamBuffer(*_SharedBuffer); } return _SharedBuffer->_Buffer; } /// Exchange the buffer of two CMemStreamBuffer (just swap memory pointer) void swap(CMemStreamBuffer &other) { std::swap(_SharedBuffer, other._SharedBuffer); std::swap(Pos, other.Pos); } }; /** * Memory stream. * * How output mode works: * The buffer size is increased by factor 2. It means the stream can be smaller than the buffer size. * The size of the stream is the current position in the stream (given by lengthS() which is equal * to getPos()), because data is always written at the end (except when using poke()). * About seek() particularities: see comment of the seek() method. * * buffer() ----------------------------------- getPos() ---------------- size() * data already serialized out | * length() = lengthS() * * How input mode works: * The stream is exactly the buffer (the size is given by lengthR()). Data is read inside the stream, * at the current position (given by getPos()). If you try to read data while getPos() is equal to * lengthR(), you'll get an EStreamOverflow exception. * * buffer() ----------------------------------- getPos() ------------------------- size() * data already serialized in data not read yet | * length() = lengthR() * * \seealso CBitMemStream * \seealso NLNET::CMessage * \author Olivier Cado, Vianney Lecroart * \author Nevrax France * \date 2000, 2002 */ class CMemStream : public NLMISC::IStream { public: /// Initialization constructor CMemStream( bool inputStream=false, bool stringmode=false, uint32 defaultcapacity=0 ) : NLMISC::IStream( inputStream ), _StringMode( stringmode ) { _DefaultCapacity = (std::max)( (uint32)defaultcapacity, (uint32)16 ); // prevent from no allocation _Buffer.getBufferWrite().resize (_DefaultCapacity); _Buffer.Pos = 0; } /// Copy constructor CMemStream( const CMemStream& other ) : IStream (other) { operator=( other ); } /// Assignment operator CMemStream& operator=( const CMemStream& other ) { IStream::operator= (other); _Buffer = other._Buffer; _StringMode = other._StringMode; _DefaultCapacity = other._DefaultCapacity; return *this; } /// allocated memory exchange void swap(CMemStream &other); /// Set string mode void setStringMode( bool stringmode ) { _StringMode = stringmode; } /// Return string mode bool stringMode() const { return _StringMode; } /** Returns a readable string to display it to the screen. It's only for debugging purpose! * Don't use it for anything else than to debugging, the string format could change in the future. * \param hexFormat If true, display all bytes in hexadecimal, else display as chars (above 31, otherwise '.') */ std::string toString( bool hexFormat=false ) const; /// Method inherited from IStream virtual void serialBuffer(uint8 *buf, uint len); /// Method inherited from IStream virtual void serialBit(bool &bit); /** * Moves the stream pointer to a specified location. * * Warning: in output mode, seek(end) does not point to the end of the serialized data, * but on the end of the whole allocated buffer (see size()). * If you seek back and want to return to the end of the serialized data, you have to * store the position (a better way is to use reserve()/poke()). * * NB: If the stream doesn't support the seek fonctionnality, it throws ESeekNotSupported. * Default implementation: * { throw ESeekNotSupported; } * \param offset is the wanted offset from the origin. * \param origin is the origin of the seek * \return true if seek sucessfull. * \see ESeekNotSupported SeekOrigin getPos */ virtual bool seek (sint32 offset, TSeekOrigin origin) const throw(EStream); /** * Get the location of the stream pointer. * * NB: If the stream doesn't support the seek fonctionnality, it throws ESeekNotSupported. * Default implementation: * { throw ESeekNotSupported; } * \param offset is the wanted offset from the origin. * \param origin is the origin of the seek * \return the new offset regarding from the origin. * \see ESeekNotSupported SeekOrigin seek */ virtual sint32 getPos () const throw(EStream) { return sint32(_Buffer.Pos); } /** * When writing, skip 'len' bytes and return the position of the blank space for a future poke(). * Warning: this has nothing to do with the semantics of reserve() in std::vector! */ sint32 reserve( uint len ) { sint32 pos = sint32(_Buffer.Pos); if ( ! isReading() ) { increaseBufferIfNecessary( len ); _Buffer.Pos += len; } return pos; } /** * When writing, fill a value previously reserved by reserve() * (warning: you MUST have called reserve() with sizeof(T) before poking). * Usually it's an alternative to use serialCont with a vector. * Example: * uint8 counter=0; * sint32 counterPos = msgout.reserve( sizeof(counter) ); * counter = serialSelectedItems( msgout ); * msgout.poke( counter, counterPos ); */ template void poke( T value, sint32 pos ) { if ( ! isReading() ) { uint8 *pokeBufPos = _Buffer.getBufferWrite().getPtr() + pos; nlassert( pokeBufPos + sizeof(T) <= pokeBufPos+_Buffer.Pos ); *(T*)pokeBufPos = value; } } /// Clears the message virtual void clear() { resetPtrTable(); _Buffer.getBufferWrite().clear(); if (!isReading()) { _Buffer.getBufferWrite().resize (_DefaultCapacity); } _Buffer.Pos = 0; } /** * Returns the length (size) of the message, in bytes. * If isReading(), it is the number of bytes that can be read, * otherwise it is the number of bytes that have been written. */ virtual uint32 length() const { if ( isReading() ) { return lengthR(); } else { return lengthS(); } } /// Returns the size of the buffer (can be greater than the length, especially in output mode) uint32 size() const { return _Buffer.getBuffer().size(); } /** Returns a pointer to the message buffer (read only) * Returns NULL if the buffer is empty */ virtual const uint8 *buffer() const { return _Buffer.getBuffer().getPtr(); } /** * When you fill the buffer externaly (using bufferAsVector) you have to reset the BufPos calling this method * * If you are using the stream only in output mode, you can use this method as a faster version * of clear() *if you don't serialize pointers*. */ virtual void resetBufPos() { _Buffer.Pos = 0; } /** * Resize the message buffer and fill data at position 0. * Input stream: the current position is set at the beginning; * Output stream: the current position is set after the filled data. */ void fill( const uint8 *srcbuf, uint32 len ) { if (len == 0) return; _Buffer.getBufferWrite().resize( len ); CFastMem::memcpy( _Buffer.getBufferWrite().getPtr(), srcbuf, len ); if (isReading()) { _Buffer.Pos = 0; } else { _Buffer.Pos = _Buffer.getBuffer().size(); } } /** * Resize the buffer. * Warning: the position is unchanged, only the size is changed. */ void resize (uint32 size); /** * Resize the stream with the specified size, set the current position at the beginning * of the stream and return a pointer to the stream buffer. * * Precondition: the stream is an input stream. * * Suggested usage: construct an input stream, resize and get the buffer using bufferToFillAndRead(), * fill it with raw data using any filling function (warning: don't fill more than 'msgsize' * bytes!), then you are ready to read, using serial(), the data you've just filled. */ virtual uint8 *bufferToFill( uint32 msgsize ) { #ifdef NL_DEBUG nlassert( isReading() ); #endif if ( msgsize == 0 ) return NULL; _Buffer.getBufferWrite().resize( msgsize ); _Buffer.Pos = 0; return _Buffer.getBufferWrite().getPtr(); } /** * Transforms the message from input to output or from output to input * * Precondition: * - If the stream is in input mode, it must not be empty (nothing filled), otherwise the position * will be set to the end of the preallocated buffer (see DefaultCapacity). * Postcondition: * - Read->write, the position is set at the end of the stream, it is possible to add more data - - Write->Read, the position is set at the beginning of the stream */ virtual void invert() { if ( isReading() ) { // In->Out: We want to write (serialize out) what we have read (serialized in) uint32 sizeOfReadStream = lengthR(); resetPtrTable(); setInOut( false ); _Buffer.Pos = sizeOfReadStream; } else { // Out->In: We want to read (serialize in) what we have written (serialized out) resetPtrTable(); setInOut( true ); // TODO : is it necessary ? _Buffer.getBufferWrite().resize (_Buffer.Pos); _Buffer.Pos = 0; } } /// Force to reset the ptr table void resetPtrTable() { IStream::resetPtrTable() ; } /// Increase the buffer size if 'len' can't enter, otherwise, do nothing #ifdef NL_OS_WINDOWS __forceinline #endif void increaseBufferIfNecessary(uint32 len) { uint32 oldBufferSize = _Buffer.getBuffer().size(); if (_Buffer.Pos + len > oldBufferSize) { // need to increase the buffer size _Buffer.getBufferWrite().resize(oldBufferSize*2 + len); } } template void fastSerial (T &val) { #ifdef NL_LITTLE_ENDIAN if(isReading()) { // Check that we don't read more than there is to read if ( lengthS()+sizeof(T) > length() ) // calls virtual length (cf. sub messages) throw EStreamOverflow(); // Serialize in val = *(T*)(_Buffer.getBuffer().getPtr() + _Buffer.Pos); } else { increaseBufferIfNecessary (sizeof(T)); *(T*)(_Buffer.getBufferWrite().getPtr() + _Buffer.Pos) = val; } _Buffer.Pos += sizeof (T); #else // NL_LITTLE_ENDIAN IStream::serial( val ); #endif // NL_LITTLE_ENDIAN } template void fastWrite( const T& value ) { //nldebug( "MEMSTREAM: Writing %u-byte value in %p at pos %u", sizeof(value), this, _BufPos - _Buffer.getPtr() ); increaseBufferIfNecessary (sizeof(T)); *(T*)(_Buffer.getBufferWrite().getPtr() + _Buffer.Pos) = value; _Buffer.Pos += sizeof (T); } template void fastRead( T& value ) { //nldebug( "MEMSTREAM: Reading %u-byte value in %p at pos %u", sizeof(value), this, _BufPos - _Buffer.getPtr() ); // Check that we don't read more than there is to read if ( lengthS()+sizeof(value) > length() ) // calls virtual length (cf. sub messages) { throw EStreamOverflow(); } // Serialize in value = *(T*)(_Buffer.getBuffer().getPtr() + _Buffer.Pos); _Buffer.Pos += sizeof(value); } /// Template serialization (should take the one from IStream) template void serial(T &obj) { obj.serial(*this); } template void serialCont(std::vector &cont) {IStream::serialCont(cont);} template void serialCont(std::list &cont) {IStream::serialCont(cont);} template void serialCont(std::deque &cont) {IStream::serialCont(cont);} template void serialCont(std::set &cont) {IStream::serialCont(cont);} template void serialCont(std::multiset &cont) {IStream::serialCont(cont);} template void serialCont(std::map &cont) {IStream::serialCont(cont);} template void serialCont(std::multimap &cont) {IStream::serialCont(cont);} /// Specialisation of serialCont() for vector virtual void serialCont(std::vector &cont) {IStream::serialCont(cont);} /// Specialisation of serialCont() for vector virtual void serialCont(std::vector &cont) {IStream::serialCont(cont);} /// Specialisation of serialCont() for vector virtual void serialCont(std::vector &cont) {IStream::serialCont(cont);} template void serial(T0 &a, T1 &b) { serial(a); serial(b);} template void serial(T0 &a, T1 &b, T2 &c) { serial(a); serial(b); serial(c);} template void serial(T0 &a, T1 &b, T2 &c, T3 &d) { serial(a); serial(b); serial(c); serial(d);} template void serial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e) { serial(a); serial(b); serial(c); serial(d); serial(e);} template void serial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e, T5 &f) { serial(a); serial(b); serial(c); serial(d); serial(e); serial(f);} /** \name Base types serialisation, redefined for string mode * Those method are a specialisation of template method "void serial(T&)". */ //@{ virtual void serial(uint8 &b) ; virtual void serial(sint8 &b) ; virtual void serial(uint16 &b) ; virtual void serial(sint16 &b) ; virtual void serial(uint32 &b) ; virtual void serial(sint32 &b) ; virtual void serial(uint64 &b) ; virtual void serial(sint64 &b) ; virtual void serial(float &b) ; virtual void serial(double &b) ; virtual void serial(bool &b) ; #ifndef NL_OS_CYGWIN virtual void serial(char &b) ; #endif virtual void serial(std::string &b) ; virtual void serial(ucstring &b) ; virtual void serial(google::protobuf::Message* message); //@} ///\name String-specific methods //@{ /// Input: read len bytes at most from the stream until the next separator, and return the number of bytes read. The separator is then skipped. uint serialSeparatedBufferIn( uint8 *buf, uint len ); /// Output: writes len bytes from buf into the stream void serialSeparatedBufferOut( uint8 *buf, uint len ); /// Serialisation in hexadecimal virtual void serialHex(uint32 &b); //@} protected: /// Returns the serialized length (number of bytes written or read) virtual uint32 lengthS() const { return _Buffer.Pos; // not calling getPos() because virtual and not const! } /** * Returns the "read" message size (number of bytes to read) * Do not use directly, use length() instead in reading mode (which is virtual) */ uint32 lengthR() const { return size(); } /** Get the size for this stream. return 0 by default. Only implemented for input stream that know their size. * Used internally to detect OverFlow with vector<> for instance */ virtual uint getDbgStreamSize() const; CMemStreamBuffer _Buffer; mutable bool _StringMode; uint32 _DefaultCapacity; }; // Input #define readnumber(dest,thetype,digits,convfunc) \ char number_as_cstring [digits+1]; \ uint realdigits = serialSeparatedBufferIn( (uint8*)number_as_cstring, digits ); \ number_as_cstring[realdigits] = '\0'; \ dest = (thetype)convfunc( number_as_cstring ); // Output #define writenumber(src,format,digits) \ char number_as_cstring [digits+1]; \ sprintf( number_as_cstring, format, src ); \ serialSeparatedBufferOut( (uint8*)number_as_cstring, (uint)strlen(number_as_cstring) ); /* * atoihex */ inline uint32 atoihex( const char* ident ) { uint32 number; sscanf( ident, "%x", &number ); return number; } inline uint32 atoui( const char *ident) { return (uint32) strtoul (ident, NULL, 10); } static const char SEPARATOR = ' '; static const int SEP_SIZE = 1; // the code is easier to read with that // // inline serial functions // // ====================================================================================================== inline void CMemStream::serial(uint8 &b) { if ( _StringMode ) { if ( isReading() ) { readnumber( b, uint8, 3, atoi ); // 255 } else { writenumber( (uint16)b,"%hu", 3 ); } } else { fastSerial (b); } } // ====================================================================================================== inline void CMemStream::serial(sint8 &b) { if ( _StringMode ) { if ( isReading() ) { readnumber( b, sint8, 4, atoi ); // -128 } else { writenumber( (sint16)b, "%hd", 4 ); } } else { fastSerial (b); } } // ====================================================================================================== inline void CMemStream::serial(uint16 &b) { if ( _StringMode ) { // No byte swapping in text mode if ( isReading() ) { readnumber( b, uint16, 5, atoi ); // 65535 } else { writenumber( b, "%hu", 5 ); } } else { fastSerial (b); } } // ====================================================================================================== inline void CMemStream::serial(sint16 &b) { if ( _StringMode ) { if ( isReading() ) { readnumber( b, sint16, 6, atoi ); // -32768 } else { writenumber( b, "%hd", 6 ); } } else { fastSerial (b); } } // ====================================================================================================== inline void CMemStream::serial(uint32 &b) { if ( _StringMode ) { if ( isReading() ) { readnumber( b, uint32, 10, atoui ); // 4294967295 } else { writenumber( b, "%u", 10 ); } } else { fastSerial (b); } } // ====================================================================================================== inline void CMemStream::serial(sint32 &b) { if ( _StringMode ) { if ( isReading() ) { readnumber( b, sint32, 11, atoi ); // -2147483648 } else { writenumber( b, "%d", 11 ); } } else { fastSerial (b); } } // ====================================================================================================== inline void CMemStream::serial(uint64 &b) { if ( _StringMode ) { if ( isReading() ) { readnumber( b, uint64, 20, atoiInt64 ); // 18446744073709551615 } else { writenumber( b, "%" NL_I64 "u", 20 ); } } else { fastSerial (b); } } // ====================================================================================================== inline void CMemStream::serial(sint64 &b) { if ( _StringMode ) { if ( isReading() ) { readnumber( b, sint64, 20, atoiInt64 ); // -9223372036854775808 } else { writenumber( b, "%" NL_I64 "d", 20 ); } } else { fastSerial (b); } } // ====================================================================================================== inline void CMemStream::serial(float &b) { if ( _StringMode ) { if ( isReading() ) { readnumber( b, float, 128, atof ); // ? } else { writenumber( (double)b, "%f", 128 ); } } else { fastSerial (b); } } // ====================================================================================================== inline void CMemStream::serial(double &b) { if ( _StringMode ) { if ( isReading() ) { readnumber( b, double, 128, atof ); // } else { writenumber( b, "%f", 128 ); } } else { fastSerial (b); } } // ====================================================================================================== inline void CMemStream::serial(bool &b) { if ( _StringMode ) { serialBit(b); } else { fastSerial (b); } } #ifndef NL_OS_CYGWIN // ====================================================================================================== inline void CMemStream::serial(char &b) { if ( _StringMode ) { char buff [2]; if ( isReading() ) { serialBuffer( (uint8*)buff, 2 ); b = buff[0]; } else { buff[0] = b; buff[1] = SEPARATOR; serialBuffer( (uint8*)buff, 2 ); } } else { fastSerial (b); } } #endif // ====================================================================================================== inline void CMemStream::serial(std::string &b) { if ( _StringMode ) { uint32 len=0; // Read/Write the length. if(isReading()) { serial(len); checkStreamSize((uint)len); /*if (len>1000000) throw NLMISC::EInvalidDataStream( "CMemStream/str: Trying to read a string of %u bytes", len ); */ b.resize(len); } else { len= (uint32)b.size(); if (len>1000000) throw NLMISC::EInvalidDataStream( "CMemStream/str: Trying to write a string of %u bytes", len ); serial(len); } // Read/Write the string. for(uint i=0;i!=len;++i) serialBuffer( (uint8*)&(b[i]), sizeof(b[i]) ); char sep = SEPARATOR; serialBuffer( (uint8*)&sep, 1 ); } else { if (isReading()) { if (!isXML()) { uint32 len=0; fastSerial(len); checkStreamSize((uint)len); /* if (len>1000000) throw NLMISC::EInvalidDataStream( "CMemStream: Trying to read a string of %u bytes", len ); */ b.resize(len); if (len > 0) { // can serial all in a single call to serialBuffer, since sizeof(char) == 1 serialBuffer((uint8 *) &b[0], len); } } else { IStream::serial( b ); } } else { IStream::serial( b ); } } } // ====================================================================================================== inline void CMemStream::serial(ucstring &b) { if ( _StringMode ) { uint32 len=0; // Read/Write the length. if(isReading()) { serial(len); checkStreamSize((uint)len); /* if (len>1000000) throw NLMISC::EInvalidDataStream( "CMemStream/str: Trying to read an ucstring of %u bytes", len ); */ b.resize(len); } else { len= (uint32)b.size(); if (len>1000000) throw NLMISC::EInvalidDataStream( "CMemStream/str: Trying to write an ucstring of %u bytes", len ); serial(len); } // Read/Write the string. for(uint i=0;i!=len;++i) serialBuffer( (uint8*)&b[i], sizeof(b[i]) ); char sep = SEPARATOR; serialBuffer( (uint8*)&sep, 1 ); } else { IStream::serial( b ); } } /* * Serialisation in hexadecimal */ inline void CMemStream::serialHex(uint32 &b) { if ( _StringMode ) { if ( isReading() ) { readnumber( b, uint32, 10, atoihex ); // 4294967295 } else { writenumber( b, "%x", 10 ); } } else { IStream::serial( b ); } } inline void CMemStream::serial( google::protobuf::Message* message ) { if ( message==NULL ) { throw EInvalidDataStream(); } if ( stringMode() ) { //nlassert(0); throw EInvalidDataStream(); } else { std::string str_buff; if (isReading()) { serial(str_buff); if( !message->ParseFromString(str_buff) ) { throw EInvalidDataStream(); } } else { if ( !message->SerializeToString(&str_buff) ) { throw EInvalidDataStream(); } serial(str_buff); } } } } #endif // NL_MEM_STREAM_H /* End of mem_stream.h */ ================================================ FILE: code/nel/include/nel/misc/mouse_device.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_MOUSE_DEVICE_H #define NL_MOUSE_DEVICE_H #include "types_nl.h" #include "input_device.h" namespace NLMISC { class CRect; /// An interface to a low level mouse device struct IMouseDevice : public IInputDevice { enum TAxisMode { Raw, Clamped, AxisModeLast }; enum TAxis { XAxis = 0, YAxis = 1, AxisLast }; enum TMessageMode { NormalMode, RawMode, MessageModeLast }; ///\name Messages //@{ /** Tells what messages should be sent : * DEFAULT is 'raw' messages * Raw messages : - no clamping nor frames applied * - no speed applied * - no factor applied * - CGDMouseMove messages are sent * - Move expressed in mickeys * Normal messages : - CEventMouseMove messages are sent * - A frame may clamp one or both axis * - The mouse speed can be changed */ virtual void setMessagesMode(TMessageMode mode) = 0; /// retrieve what kinds of messages are sent virtual TMessageMode getMessagesMode() const = 0; //@} ///\name Mouse MOVE, valid only //@{ /** Set the mode of axis of the mouse. This can be raw, or clamped. In clamped mode, a frame is used to limit the move. * NB : invalid in raw message mode * \see setMouseFrame(const CRect &rect) */ virtual void setMouseMode(TAxis axis, TAxisMode axisMode) = 0; /** returns the mode of the mouse for the given axis. * NB : invalid in raw message mode */ virtual TAxisMode getMouseMode(TAxis axis) const = 0; /** Set the mouse speed. It must be in the ]0, +inf] range, 1 gives the natural mouse speed. * NB : invalid in raw message mode */ virtual void setMouseSpeed(float speed) = 0; /** Get the mouse speed. * NB : invalid in raw message mode */ virtual float getMouseSpeed() const = 0; /** Set the mouse acceleration. It is the threshold in mickey, when start the acceleration. 0 means not acceleration. */ virtual void setMouseAcceleration(uint speed) = 0; /** Get the mouse acceleration. */ virtual uint getMouseAcceleration() const = 0; /** Set the current frame in which the mouse can move, expressed in pixels. * NB do not forget to call setMouseFactors if you want the results to be reported in the 0-1 range. * NB : invalid in raw message mode. * \see setMouseFactors */ virtual void setMouseFrame(const CRect &rect) = 0; /** Gives factor by which the mouse coordinates must be multiplied before an event is sent. * The default factor is 1. * NB : invalid in raw message mode. * * Example : this set a frame of 800x600 and reports event in the [0, 1] range. * \code * mouse->setMouseFrame(800, 600); * mouse->setMouseMode(XAxis, IMouseDevice::Clamped); * mouse->setMouseMode(YAxis, IMouseDevice::Clamped); * mouse->setFactors(1.f / 800, 1.f / 600); * \endcode */ virtual void setFactors(float xFactor, float yFactor) = 0; /** Get the x factor, use to multiply the mouse position before an event is sent. * NB : invalid in raw message mode. * \see setFactors() */ virtual float getXFactor() const = 0; /** Get the y factor, use to multiply the mouse position before an event is sent. * NB : invalid in raw message mode. * \see setFactors() */ virtual float getYFactor() const = 0; //@} // Get the current frame used for limiting mouse movements virtual const CRect &getMouseFrame() const = 0; // Set the maximum delay for a double click to be taken in account (in ms). virtual void setDoubleClickDelay(uint ms) = 0; // Get the maximum delay for double click (in ms) virtual uint getDoubleClickDelay() const = 0; // Force the position of the mouse, expressed in pixels virtual void setMousePos(float x, float y) = 0; /// From a delta of a mouse position input (eg from CEventMouseMove), deduce delta in mickeys (eg: like received from a CGDMouseMove) virtual void convertStdMouseMoveInMickeys(float &dx, float &dy) const = 0; }; } // NLMISC #endif // NL_MOUSE_DEVICE_H /* End of u_mouse_device.h */ ================================================ FILE: code/nel/include/nel/misc/mouse_smoother.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_MOUSE_SMOOTHER_H #define NL_MOUSE_SMOOTHER_H #include "types_nl.h" #include "vector_2f.h" namespace NLMISC { /** * This smooth position of mouse using cubic splines. * The mouse is sampled at the given period. The higher the period, the smoother the movement. * However there is a delay of 2 * samplingPeriod between the user moving the mouse and the pointer reaching * the wanted position. * * \author Nicolas Vizerie * \author Nevrax France * \date 1/2004 */ class CMouseSmoother { public: // create a mouse smoother with the given sampling period. CMouseSmoother(double samplingPeriod = 0.2); /** Change the sampling period. The longer it lasts, the more smooth the movement. * NB : this reset the smoother */ void setSamplingPeriod(double period); // Get the sampling period double getSamplingPeriod() const { return _SamplingPeriod; } // Reset smoother. The next returned position will be the exact position of mouse (no smoothing with previous position is done) void reset(); // \return trueif no sampling has occured since last resetor construction bool isReseted() const { return !_Init; } // Sample pos, and return smoothed position CVector2f samplePos(const CVector2f &wantedPos, double date); private: // sample of mouse position class CSample { public: double Date; CVector2f Pos; public: // default ctor CSample() {} // ctor with pos & date CSample(double date, const NLMISC::CVector2f &pos) : Date(date), Pos(pos) { } }; double _SamplingPeriod; bool _Init; /** 4 samples are needed to compute smoothed position : * Sample 0 & 2 are used to compute tangent at sample 1 * Sample 1 & 3 are used to compute tangent at sample 2 */ CSample _Sample[4]; }; } // NLMISC #endif ================================================ FILE: code/nel/include/nel/misc/mutable_container.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_MUTABLE_CONTAINER_H #define NL_MUTABLE_CONTAINER_H namespace NLMISC { /** Container wrapper that allow read/write access to element stored in * a const container. * In fact, the template only allow calling begin() and end() over * a const container. * This prevent the user to change the structure of the container. * Usage : * * class foo * { * typedef TMutableContainer > TMyCont; * TMyCont _MyCont; * * public: * // return the container with mutable item content but const item list * const TMyCont getContainer() const { return _MyCont; }; * } * */ template struct TMutableContainer : public BaseContainer { typename BaseContainer::iterator begin() const { return const_cast(static_cast(this))->begin(); } typename BaseContainer::iterator end() const { return const_cast(static_cast(this))->end(); } }; } // namespace NLMISC #endif // NL_MUTABLE_CONTAINER_H ================================================ FILE: code/nel/include/nel/misc/mutex.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_MUTEX_H #define NL_MUTEX_H #include "types_nl.h" #include "time_nl.h" #include "common.h" #include #ifdef NL_OS_WINDOWS # ifdef NL_NO_ASM # include # endif #elif defined(NL_OS_UNIX) # include // PThread # ifdef NL_OS_MAC # include # else # include // PThread POSIX semaphores # endif # include # define __forceinline # ifdef NL_OS_MAC # include # endif #endif // NL_OS_WINDOWS #undef MUTEX_DEBUG namespace NLMISC { /* * This define must be disabled when sharing a mutex between several processes that can * have a different debug mode (because when __STL_DEBUG is on, sizeof(string) is twice * the common string size). */ #define STORE_MUTEX_NAME #ifdef NL_OS_WINDOWS // By default on Windows, all mutex/synchronization use the CFair* class to avoid freeze problem. # define CMutex CFairMutex # define CSynchronized CFairSynchronized #else // On GNU/Linux and Mac, we use CUnfair* everwise it creates some strange deadlock during loading and after # define CMutex CUnfairMutex # define CSynchronized CUnfairSynchronized #endif /** * Classic mutex implementation (not necessarly fair) * Don't assume the mutex are recursive (ie don't call enter() several times * on the same mutex from the same thread without having called leave()) ; * and don't assume either the threads are woken-up in the same order as they * were put to sleep ! * * Windows: uses Mutex, cannot be shared among processes. * Linux: uses PThread POSIX Mutex, cannot be shared among processes. * *\code CUnfairMutex m; m.enter (); // do critical stuffs m.leave (); *\endcode * \author Vianney Lecroart, Olivier Cado * \author Nevrax France * \date 2000 */ class CUnfairMutex { public: /// Constructor CUnfairMutex(); CUnfairMutex( const std::string &name ); /// Destructor ~CUnfairMutex(); /// Enter the critical section void enter (); /// Leave the critical section void leave (); private: #ifdef NL_OS_WINDOWS void *_Mutex; #elif defined NL_OS_UNIX pthread_mutex_t mutex; #else # error "No unfair mutex implementation for this OS" #endif }; // Inline assembler for gcc tutorial: // AT&T syntax: // - operands reversed, // - l after opcode replaces dword ptr, // - () instead of [], // - immediate values prefixed by $ /* // Tested: works on multi-processor #ifdef HAVE_X86_64 # define ASM_ASWAP_FOR_GCC_XCHG __asm__ volatile( \ "mov %1, %%rcx;" \ "mov $1, %%eax;" \ "xchg %%eax, (%%rcx);" \ "mov %%eax, %0" \ : "=m" (result) \ : "m" (lockPtr) \ : "eax", "rcx", "memory" ); // force to use registers and memory #else # define ASM_ASWAP_FOR_GCC_XCHG __asm__ volatile( \ "mov %1, %%ecx;" \ "mov $1, %%eax;" \ "xchg %%eax, (%%ecx);" \ "mov %%eax, %0" \ : "=m" (result) \ : "m" (lockPtr) \ : "eax", "ecx", "memory" ); // force to use registers and memory #endif */ /* // Tested: does not work (at least on multi-processor)! (with or without 'lock' prefix) #define ASM_ASWAP_FOR_GCC_CMPXCHG __asm__ volatile( \ "mov $1, %%edx;" \ "mov %1, %%ecx;" \ "mov (%%ecx), %%eax;" \ "1:nop;" \ "lock cmpxchgl %%edx, (%%ecx);" \ "jne 1b;" \ "mov %%eax, %0" \ : "=m" (result) \ : "m" (lockPtr) \ : "eax", "ecx", "edx", "memory" ); // force to use registers and memory */ // Tested: does not work on hyper-threading processors! /*ASM_ASWAP_FOR_MSVC_CMPXCHG { __asm { mov edx,1 mov ecx,l mov eax,[ecx] test_again: nop cmpxchg dword ptr [ecx],edx jne test_again mov [result],eax } }*/ /** * Fast mutex implementation (not fairly) * The mutex ARE NOT recursive (ie don't call enter() several times * on the same mutex from the same thread without having called leave()) ; * The threads ARE NOT woken-up in the same order as they were put to sleep. * The threads ARE NOT woken-up using signals but using Sleep(). * This mutex works but is not optimal for multiprocessors because if the mutex is locked, * next enter will be sleeped without waiting a little. * * Implementation notes: * - Implementated under WIN32 * - Other OS use CMutex * * Tested: OK on Windows and Linux single & multi-processor * *\code CFastMutex m; m.enter (); // do critical stuffs m.leave (); *\endcode * \author Cyril 'Hulud' Corvazier * \author Olivier Cado * \author Nevrax France * \date 2002, 2003 */ #if defined(__ppc__) && !defined(NL_OS_MAC) && (GCC_VERSION <= 40100) # error "no CFastMutex implementation available, try to use GCC >4.0.1" #endif #ifdef NL_OS_WINDOWS #pragma managed(push, off) #endif class CFastMutex { public: /// Constructor CFastMutex() : _Lock(0) {} /// Same as constructor, useful for init in a shared memory block void init() volatile { _Lock = 0; } /// Atomic swap __forceinline static bool atomic_swap (volatile uint32 *lockPtr) { uint32 result; #ifdef NL_OS_WINDOWS # ifdef NL_NO_ASM result = _InterlockedExchange(reinterpret_cast(lockPtr), 1); # else # ifdef NL_DEBUG // Workaround for dumb inlining bug (returning of function goes into the choux): push/pop registers __asm { push eax push ecx mov ecx,lockPtr mov eax,1 xchg [ecx],eax mov [result],eax pop ecx pop eax } # else __asm { mov ecx,lockPtr mov eax,1 xchg [ecx],eax mov [result],eax } # endif // NL_DEBUG # endif // NL_NO_ASM #elif defined(NL_OS_MAC) return OSAtomicCompareAndSwap32(0, 1, reinterpret_cast(lockPtr)); #elif defined(NL_OS_UNIX) // GCC implements the same functionality using a builtin function // http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html // the macro below crashed on Mac OS X 10.6 in a 64bit build # if (GCC_VERSION > 40100) // return __sync_bool_compare_and_swap(lockPtr, 0, 1); result = __sync_val_compare_and_swap(lockPtr, 0, 1); # elif defined(NL_COMP_CLANG) result = __sync_val_compare_and_swap(lockPtr, 0, 1); # else ASM_ASWAP_FOR_GCC_XCHG # endif #endif // NL_OS_WINDOWS return result != 0; } // Enter critical section __forceinline void enter () volatile { //std::cout << "Entering, Lock=" << _Lock << std::endl; if (atomic_swap (&_Lock)) { // First test uint i; for (i = 0 ;; ++i) { uint wait_time = i + 6; // Increment wait time with a log function if (wait_time > 27) wait_time = 27; // Sleep if (wait_time <= 20) wait_time = 0; else wait_time = 1 << (wait_time - 20); if (!atomic_swap (&_Lock)) break; #ifdef NL_OS_WINDOWS nlSleep (wait_time); #else //std::cout << "Sleeping i=" << i << std::endl; usleep( wait_time*1000 ); #endif } } } // Leave critical section __forceinline void leave () volatile { _Lock = 0; //std::cout << "Leave" << std::endl; } private: volatile uint32 _Lock; }; /** * Fast mutex for multiprocessor implementation (not fairly). * Used for multiprocessor critical section synchronisation. * The mutex ARE NOT recursive (ie don't call enter() several times * on the same mutex from the same thread without having called leave()) ; * The threads use a spin system to wait a little time before be put to sleep. * It waits using CPU time. * * Implementation notes: * - Implementated under WIN32 * - Other OS use CMutex * *\code CFastMutexMP m; m.enter (); // do critical stuffs m.leave (); *\endcode * \author Cyril 'Hulud' Corvazier * \author Olivier Cado * \author Nevrax France * \date 2002, 2003 */ #ifndef __ppc__ class CFastMutexMP { public: /// Constructor CFastMutexMP() : _Lock(0) {} /// Same as constructor, useful for init in a shared memory block void init() volatile { _Lock = 0; } // Enter critical section __forceinline void enter () volatile { //std::cout << "Entering, Lock=" << _Lock << std::endl; while (CFastMutex::atomic_swap (&_Lock)) { static uint last = 0; static uint _max = 30; uint spinMax = _max; uint lastSpins = last; volatile uint temp = 17; uint i; for (i = 0; i < spinMax; ++i) { if (i < lastSpins/2 || _Lock) { temp *= temp; temp *= temp; temp *= temp; temp *= temp; } else { if (!CFastMutex::atomic_swap(&_Lock)) { last = i; _max = 1000; return; } } } _max = 30; // First test for (i = 0 ;; ++i) { uint wait_time = i + 6; // Increment wait time with a log function if (wait_time > 27) wait_time = 27; // Sleep if (wait_time <= 20) wait_time = 0; else wait_time = 1 << (wait_time - 20); if (!CFastMutex::atomic_swap (&_Lock)) break; #ifdef NL_OS_WINDOWS nlSleep (wait_time); #else //std::cout << "Sleeping i=" << i << std::endl; usleep( wait_time*1000 ); #endif } } } // Leave critical section __forceinline void leave () volatile { _Lock = 0; //std::cout << "Leave" << std::endl; } private: volatile uint32 _Lock; }; #endif /** * Windows: uses Mutex, the handle can't be shared among processes, but * the mutex still can be be shared by passing a common object name to * createByName() / createByKey(). Note: the mutex must be explicitely * destroyed by calling destroy(). * * \author Olivier Cado * \author Nevrax France * \date 2002 */ class CSharedMutex { public: /// Constructor (does not create the mutex, see createByName()/createByKey()) CSharedMutex(); #ifdef NL_OS_WINDOWS /// Create or access an existing mutex (created by another process) with a specific object name. Returns false if it failed. bool createByName( const char *objectName ); #else /// Create (with createNew to true) or access an existing mutex (created by another process) with a specific key. Returns false if it failed. bool createByKey( int key, bool createNew ); #endif /// Destroy the mutex void destroy(); /// Enter the critical section void enter (); /// Leave the critical section void leave (); private: #ifdef NL_OS_WINDOWS /// The mutex handle void *_Mutex; #else /// The semaphore id int _SemId; #endif }; #ifdef NL_OS_WINDOWS /** * Trick to avoid including ! * winbase.h: typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; * The original RTL_CRITICAL_SECTION is in winnt.h. */ struct TNelRtlCriticalSection { void *DebugInfo; long LockCount; long RecursionCount; void *OwningThread; // from the thread's ClientId->UniqueThread void *LockSemaphore; uint32 SpinCount; }; #endif // NL_OS_WINDOWS /** * Kind of "fair" mutex * * Windows: uses Critical Section, cannot be shared among processes * Linux: uses PThread (POSIX) semaphore, cannot be shared among processes * *\code CUnfairMutex m; m.enter (); // do critical stuffs m.leave (); *\endcode * \author Olivier Cado * \author Nevrax France * \date 2000 * *\code CFairMutex m; m.enter (); // do critical stuffs m.leave (); *\endcode * \author Olivier Cado * \author Nevrax France * \date 2001 */ class CFairMutex { public: /// Constructor CFairMutex(); CFairMutex(const std::string &name); /// Destructor ~CFairMutex(); void enter (); void leave (); #ifdef STORE_MUTEX_NAME std::string Name; #endif private: #ifdef NL_OS_WINDOWS TNelRtlCriticalSection _Cs; #elif defined(NL_OS_MAC) dispatch_semaphore_t _Sem; #elif defined(NL_OS_UNIX) sem_t _Sem; #else # error "No fair mutex implementation for this OS" #endif #ifdef MUTEX_DEBUG // debug stuffs void debugCreateMutex(); void debugBeginEnter(); void debugEndEnter(); void debugLeave(); void debugDeleteMutex(); #endif // MUTEX_DEBUG }; /* * Debug info */ #ifdef MUTEX_DEBUG struct TMutexLocks { TMutexLocks(uint32 m=0) : TimeToEnter(0), TimeInMutex(0), Nb(0), WaitingMutex(0), MutexNum(m), ThreadHavingTheMutex(0xFFFFFFFF), Dead(false) {} uint32 TimeToEnter; // cumulated time blocking on enter uint32 TimeInMutex; // cumulated time between enter and leave uint32 Nb; // number of calls of enter uint32 WaitingMutex; // number of thread that waiting this mutex sint32 MutexNum; // identifying a mutex uint ThreadHavingTheMutex; // thread id of the thread that is in this mutex (0xFFFFFFFF if no thread) bool Dead; // True if the mutex is dead (deleted) std::string MutexName; // Name of the mutex NLMISC::TTicks BeginEnter; NLMISC::TTicks EndEnter; }; /// Inits the "mutex debugging info system" void initAcquireTimeMap(); /// Gets the debugging info for all mutexes (call it evenly) std::map getNewAcquireTimes(); /// The number of created mutexes (does not take in account the destroyed mutexes) extern uint32 NbMutexes; #endif // MUTEX_DEBUG /** * This class ensure that the Value is accessed by only one thread. First you have to create a CSynchronized class with your type. * Then, if a thread want to modify or do anything on it, you create a CAccessor in a \b sub \b scope. You can modify the value * of the CUnfairSynchronized using the value() function \b until the end of the scope. So you have to put the smaller scope as you can. * * Internally, this class uses a CUnfairMutex object (see CUnfairMutex for programming considerations). * *\code // the value that you want to be thread safe. CUnfairSynchronized val; { // create a new scope for the access // get an access to the value CUnfairSynchronized::CAccessor acces(&val); // now, you have a thread safe access until the end of the scope, so you can do whatever you want. for example, change the value acces.value () = 10; } // end of the access *\endcode * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ template class CUnfairSynchronized { public: CUnfairSynchronized (const std::string &name) : _Mutex(name) { } /** * This class give you a thread safe access to the CSynchronized Value. Look at the example in the CSynchronized. */ class CAccessor { CUnfairSynchronized *Synchronized; public: /// get the mutex or wait CAccessor(CUnfairSynchronized *cs) { Synchronized = cs; const_cast(Synchronized->_Mutex).enter(); } /// release the mutex ~CAccessor() { const_cast(Synchronized->_Mutex).leave(); } /// access to the Value T &value() { return const_cast(Synchronized->_Value); } }; private: friend class CUnfairSynchronized::CAccessor; /// The mutex of the synchronized value. volatile CUnfairMutex _Mutex; /// The synchronized value. volatile T _Value; }; /** * This class is similar to CUnfairSynchronized, but it ensures that the threads * are woken-up in the same order as they were put to sleep. * Internally, it uses a CFairMutex object instead of a CUnfairMutex object. * \author Olivier Cado * \author Nevrax France * \date 2001 */ template class CFairSynchronized { public: CFairSynchronized (const std::string &name) : _Cs(name) { } /** * This class give you a thread safe access to the CFairSynchronized Value. Look at the example in CSynchronized. */ class CAccessor { CFairSynchronized *Synchronized; public: /// get the mutex or wait CAccessor(CFairSynchronized *cs) { Synchronized = cs; const_cast(Synchronized->_Cs).enter(); } /// release the mutex ~CAccessor() { const_cast(Synchronized->_Cs).leave(); } /// access to the Value T &value() { return const_cast(Synchronized->_Value); } }; private: friend class CFairSynchronized::CAccessor; /// The mutex of the synchronized value. volatile CFairMutex _Cs; /// The synchronized value. volatile T _Value; }; /** Helper class that allow easy usage of mutex to protect * a local block of code with an existing mutex. */ template class CAutoMutex { TMutex &_Mutex; // forbeden copy or assignent CAutoMutex(const CAutoMutex &/* other */) { } CAutoMutex &operator = (const CAutoMutex &/* other */) { return *this; } public: CAutoMutex(TMutex &mutex) : _Mutex(mutex) { _Mutex.enter(); } ~CAutoMutex() { _Mutex.leave(); } }; } // NLMISC #endif // NL_MUTEX_H /* End of mutex.h */ ================================================ FILE: code/nel/include/nel/misc/noise_value.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_NOISE_VALUE_H #define NL_NOISE_VALUE_H #include "types_nl.h" #include "vector.h" #include "stream.h" #include "rgba.h" namespace NLMISC { // *************************************************************************** /** * A class which generate noisy value, according to a position * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ class CNoiseValue { public: float Abs; float Rand; float Frequency; public: /// Default to 0, 1, 1. CNoiseValue(); CNoiseValue(float abs, float rand, float freq); /** return Abs + Rand* noise(Pos*Frequency). with noise() E [0..1]. * Warning! Use OptFastFloor()! So call must be enclosed with a OptFastFloorBegin()/OptFastFloorEnd(). */ float eval(const CVector &posInWorld) const; /** same as eval, but eval just one random level for noise() => act much more like a random. * Warning! Use OptFastFloor()! So call must be enclosed with a OptFastFloorBegin()/OptFastFloorEnd(). */ float evalOneLevelRandom(const CVector &posInWorld) const; void serial(IStream &f); // ******************* private: /// pos scale is in [0..1] float noise(const CVector &pos) const; float evalRandom(const CVector &pos) const; }; // *************************************************************************** /** * A noisy color generator * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ class CNoiseColorGradient { public: /// Abs and Rand should be 0 and 1 here. If not, some colors may not be generated... CNoiseValue NoiseValue; std::vector Gradients; public: /** Use NoiseValue to compute a PerlinNoise E [0..1], and peek in Gradients, with linear interpolation. * result unmodified if no colors. If only one color, copied into result. * Warning! Use OptFastFloor()! So call must be enclosed with a OptFastFloorBegin()/OptFastFloorEnd(). */ void eval(const CVector &posInWorld, CRGBAF &result) const; void serial(IStream &f); }; } // NL3D #endif // NL_NOISE_VALUE_H /* End of noise_value.h */ ================================================ FILE: code/nel/include/nel/misc/o_xml.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_O_XML_H #define NL_O_XML_H //#define NL_DONT_USE_EXTERNAL_CODE #undef NL_DONT_USE_EXTERNAL_CODE #ifndef NL_DONT_USE_EXTERNAL_CODE #include "types_nl.h" #include "stream.h" // Include from libxml2 #include namespace NLMISC { /** * Output xml stream * * This class is an xml formated output stream. * * This stream use an internal stream to output final xml code. \code // Check exceptions try { // File stream COFile file; // Open the file file.open ("output.xml"); // Create the XML stream COXml output; // Init if (output.init (&file, "1.0")) { // Serial the class myClass.serial (output); // Flush the stream, write all the output file output.flush (); } // Close the file file.close (); } catch (const Exception &e) { } \endcode * * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2001 */ class COXml : public IStream { friend int xmlOutputWriteCallbackForNeL ( void *context, const char *buffer, int len ); friend int xmlOutputCloseCallbackForNeL ( void *context ); friend void xmlGenericErrorFuncWrite (void *ctx, const char *msg, ...); public: /** Stream ctor * */ COXml (); /** Stream initialisation * * \param stream is the stream the class will use to output xml code. * this pointer is held by the class but won't be deleted. * \param version is the version to write in the XML header. Default is 1.0. * \return true if initialisation is successful, false if the stream passed is not an output stream. */ bool init (IStream *stream, const char *version="1.0"); /** Return the error string. * if not empty, something wrong appends */ const char *getErrorString () const; /** Default dstor * * Flush the stream. */ virtual ~COXml (); /** Flush the stream. * * You can only flush the stream when all xmlPushBegin - xmlPop have been closed. */ void flush (); /** Get root XML document pointer */ xmlDocPtr getDocument (); /** Return true if the string is valid to be stored in a XML property without modification. */ static bool isStringValidForProperties (const char *str); private: /// From IStream virtual void serial(uint8 &b); virtual void serial(sint8 &b); virtual void serial(uint16 &b); virtual void serial(sint16 &b); virtual void serial(uint32 &b); virtual void serial(sint32 &b); virtual void serial(uint64 &b); virtual void serial(sint64 &b); virtual void serial(float &b); virtual void serial(double &b); virtual void serial(bool &b); #ifndef NL_OS_CYGWIN virtual void serial(char &b); #endif virtual void serial(std::string &b); virtual void serial(ucstring &b); virtual void serialBuffer(uint8 *buf, uint len); virtual void serialBit(bool &bit); virtual bool xmlPushBeginInternal (const char *nodeName); virtual bool xmlPushEndInternal (); virtual bool xmlPopInternal (); virtual bool xmlSetAttribInternal (const char *attribName); virtual bool xmlBreakLineInternal (); virtual bool xmlCommentInternal (const char *comment); // Internal functions void serialSeparatedBufferOut( const char *value ); inline void flushContentString (); // Push mode bool _PushBegin; // Attribute defined bool _AttribPresent; // Attribute name std::string _AttribName; // The internal stream IStream *_InternalStream; // Document pointer xmlDocPtr _Document; // Document version std::string _Version; // Current nodes xmlNodePtr _CurrentNode; // Current content string std::string _ContentString; // Error message std::string _ErrorString; // System dependant structure for locale void* _Locale; }; } // NLMISC #endif // NL_DONT_USE_EXTERNAL_CODE #endif // NL_O_XML_H /* End of o_xml.h */ ================================================ FILE: code/nel/include/nel/misc/object_arena_allocator.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_OBJECT_ARENA_ALLOCATOR_H #define NL_OBJECT_ARENA_ALLOCATOR_H #include "types_nl.h" #include "singleton.h" namespace NLMISC { class CFixedSizeAllocator; /** An allocator that can allocate/release in O(1) for a finite number of possible blocks size (usually small).. * For a given block size, a fixed size allocator is used. * One possible use is with a family of class for which new and delete have been redefined at the top of the hierarchy * (which the NL_USES_DEFAULT_ARENA_OBJECT_ALLOCATOR macro does) * * \author Nicolas Vizerie * \author Nevrax France * \date 2004 */ class CObjectArenaAllocator { public: /** ctor * \param maxAllocSize maximum intended size of allocation. */ CObjectArenaAllocator(uint maxAllocSize, uint granularity = 4); // dtor ~CObjectArenaAllocator(); /** Allocate a block with the given size. 0 is an invalid size an will cause an assert. * If the size is > to the max size given at init, the allocation will succeed, but will use the standard allocator. */ void *alloc(uint size); // free an object that has previously been allocated with alloc. size should be remembered by the caller. void free(void *); // get the number of allocated objects uint getNumAllocatedBlocks() const; # ifdef NL_DEBUG // for debug, useful to catch memory leaks void dumpUnreleasedBlocks(); // set a break for the given allocation void setBreakForAllocID(bool enabled, uint id); # endif // for convenience, a default allocator is available static CObjectArenaAllocator &getDefaultAllocator(); private: std::vector _ObjectSizeToAllocator; uint _MaxAllocSize; uint _Granularity; # ifdef NL_DEBUG uint _AllocID; std::map _MemBlockToAllocID; bool _WantBreakOnAlloc; uint _BreakAllocID; # endif static CObjectArenaAllocator *_DefaultAllocator; }; // Macro that redefines the new & delete operator of a class so that the default arena object allocator is used. // This should be used inside the definition of the class. // All derived class will use the same allocator, so this definition can be used only at the top of the hierarchy of class for // which it is of interest. // // NL_USES_DEFAULT_ARENA_OBJECT_ALLOCATOR // for fast alloc # define NL_USES_DEFAULT_ARENA_OBJECT_ALLOCATOR \ void *operator new(size_t size) { return NLMISC::CObjectArenaAllocator::getDefaultAllocator().alloc((uint) size); }\ void operator delete(void *block) { NLMISC::CObjectArenaAllocator::getDefaultAllocator().free(block); } } #endif ================================================ FILE: code/nel/include/nel/misc/object_vector.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_OBJECT_VECTOR_H #define NL_OBJECT_VECTOR_H #include "types_nl.h" #include "common.h" #include "stream.h" #include "debug.h" // With NeL Memory Debug, use new #ifndef NL_USE_DEFAULT_MEMORY_MANAGER # ifndef NLMISC_HEAP_ALLOCATION_NDEBUG # define NL_OV_USE_NEW_ALLOCATOR # endif // NLMISC_HEAP_ALLOCATION_NDEBUG #endif // NL_USE_DEFAULT_MEMORY_MANAGER #ifndef NL_OV_USE_NEW_ALLOCATOR # ifdef NL_HAS_SSE2 # define NL_OV_USE_NEW_ALLOCATOR # endif // NL_HAS_SSE2 #endif // NL_OV_USE_NEW_ALLOCATOR namespace NLMISC { // *************************************************************************** /** Exception raised when a reallocation fails. * */ struct EReallocationFailed : public Exception { EReallocationFailed() : Exception( "Can't reallocate memory" ) {} }; // *************************************************************************** /** * The purpose of this class is to copy most (but not all) of stl vector<> features, without * some of the speed/memory problems involved: * - size of a vector is 16 bytes typically. size of a CObjectVector is 8 bytes (only a ptr and a size). * - CObjectVector::size() is faster than vector::size() * - CObjectVector::resize() is faster because it do not copy from a default value, it just call the * default constructor of the objects. * - clear() actually free memory (no reserve scheme) * * Object contructors, destructors, operator= are correctly called, unless * EnableObjectBehavior template argument is set to false (default is true) * In this case: ctor, dtor are not called, and operator=() use memcpy. * * Of course some features are not implemented (for benefit of speed/memory): * - no reserve() scheme * * Also, for now, not all vector<> features are implemented (iterator, erase etc...). * * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ template class CObjectVector { public: /// \name Object // @{ CObjectVector() { _Ptr= NULL; _Size= 0; } ~CObjectVector() { clear(); } /** copy cons. * \throw EReallocationFailed() if realloc fails. */ CObjectVector(const CObjectVector &vec) { _Ptr= NULL; _Size= 0; operator=(vec); } /** copy the array. * \throw EReallocationFailed() if realloc fails. */ CObjectVector &operator=(const CObjectVector &vec) { // *this=*this mgt. if(this==&vec) return *this; // resize to the same size as vec. resize(vec._Size); // copy All the array. copy(0, _Size, vec._Ptr); return *this; } // swap this vector content with another vector void swap(CObjectVector &other) { std::swap(_Ptr, other._Ptr); std::swap(_Size, other._Size); } // @} /// \name Allocation // @{ /** clear the array. */ void clear() { destruct(0, _Size); #ifndef NL_OV_USE_NEW_ALLOCATOR free(_Ptr); #else // NL_OV_USE_NEW_ALLOCATOR if (_Ptr) delete [] (char*)_Ptr; #endif // NL_OV_USE_NEW_ALLOCATOR _Ptr= NULL; _Size= 0; } /** resize the array. * If reallocation occurs, ptr returned by getPtr() may not be the same. * When reallocation occurs, memory is coped, but operator= are not called. * \throw EReallocationFailed() if realloc fails. */ void resize(uint32 s) { // if same size, no-op. if(s==_Size) return; // if empty, just clear. if(s==0) clear(); // crop the array? else if(s<_Size) { // destruct the objects to be freed destruct(s, _Size); // realloc myRealloc(s); _Size = s; } // else, enlarge the array else { // realloc first myRealloc(s); // For all new elements, construct them. construct(_Size, s); // change size. _Size= s; } } // @} /// \name Accessor // @{ /** return true if the container is empty */ bool empty() const {return _Size==0;} /** return size of the array (in number of elements) */ uint32 size() const {return _Size;} /** Element accessor. no check is made on index. (No exception, no nlassert()) */ const T &operator[](uint index) const { return _Ptr[index]; } /** Element accessor. no check is made on index. (No exception, no nlassert()) */ T &operator[](uint index) { return _Ptr[index]; } /** return a ptr on the first element of the array. NULL if empty. */ const T *getPtr() const {return _Ptr;} /** return a ptr on the first element of the array. NULL if empty. */ T *getPtr() {return _Ptr;} // @} /// \name Tools // @{ /** copy elements from an array ptr to this vector, beetween dstFirst element (included) and dstLast element (not included). * nlassert if last is too big. copy(y, x, ...) where y>=x is valid, and nothing is copied. */ void copy(uint32 dstFirst, uint32 dstLast, const T *srcPtr) { // test if something to copy. if(dstFirst>=dstLast) return; nlassert(dstLast<=_Size); // if not object elements if(!EnableObjectBehavior) { // just memcpy memcpy(_Ptr+dstFirst, srcPtr, (dstLast-dstFirst)*sizeof(T)); } else { // call ope= for all elements. for(uint i=dstFirst; i=dstLast) return; nlassert(dstLast<=_Size); // call ope= for all elements. for(uint i=dstFirst; i and the serial of a CObjectVector is the same in the stream. */ void serial(NLMISC::IStream &f) { // Open a node header f.xmlPushBegin ("VECTOR"); // Attrib size f.xmlSetAttrib ("size"); sint32 len=0; if(f.isReading()) { f.serial(len); // Open a node header f.xmlPushEnd (); // special version for vector: adjut good size. contReset(*this); resize (len); // Read the vector for(sint i=0;i _Size*sizeof(T))) { // Reallocate char *newblock = new char[allocSize]; // if success and need to copy if (newblock && _Ptr) { memcpy (newblock, _Ptr, _Size*sizeof(T)); delete [] (char*)_Ptr; } newPtr = (T*)newblock; } else if(allocSize < _Size*sizeof(T)) { // Reallocate char *newblock = new char[allocSize]; // if success and need to copy if (newblock && _Ptr) { memcpy (newblock, _Ptr, s*sizeof(T)); delete [] (char*)_Ptr; } newPtr = (T*)newblock; } #endif // NL_OV_USE_NEW_ALLOCATOR // if realloc failure if(newPtr==NULL) { // leave the array unchanged. // exception. throw EReallocationFailed(); } else { _Ptr= newPtr; } } // For all elements in the range, destruct. void destruct(uint32 i0, uint32 i1) { // don't do it if elements don't need it. if(!EnableObjectBehavior) return; // for all elements for(uint i=i0;i class CObjectVector : public CObjectVector { }; template<> class CObjectVector : public CObjectVector { }; template<> class CObjectVector : public CObjectVector { }; template<> class CObjectVector : public CObjectVector { }; template<> class CObjectVector : public CObjectVector { }; template<> class CObjectVector : public CObjectVector { }; template<> class CObjectVector : public CObjectVector { }; template<> class CObjectVector : public CObjectVector { }; #ifdef NL_COMP_VC6 template<> class CObjectVector : public CObjectVector { }; template<> class CObjectVector : public CObjectVector { }; #endif // !NL_COMP_VC6 template<> class CObjectVector : public CObjectVector { }; template<> class CObjectVector : public CObjectVector { }; } // NLMISC #endif // NL_OBJECT_VECTOR_H /* End of object_vector.h */ ================================================ FILE: code/nel/include/nel/misc/p_thread.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_P_THREAD_H #define NL_P_THREAD_H #include "types_nl.h" #ifdef NL_OS_UNIX #include "thread.h" #include namespace NLMISC { /** * Posix Thread * \author Olivier Cado * \author Nevrax France * \date 2001 */ class CPThread : public IThread { public: enum TThreadState { ThreadStateNone, ThreadStateRunning, ThreadStateFinished, }; /// Constructor CPThread( IRunnable *runnable, uint32 stackSize); virtual ~CPThread(); virtual void start(); virtual bool isRunning(); virtual void terminate(); virtual void wait(); virtual bool setCPUMask(uint64 cpuMask); virtual uint64 getCPUMask(); virtual void setPriority(TThreadPriority priority); virtual std::string getUserName(); virtual IRunnable *getRunnable() { return Runnable; } /// Internal use IRunnable *Runnable; TThreadState _State; pthread_t _ThreadHandle; private: uint32 _StackSize; }; /** * Posix Process * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2001 */ class CPProcess : public IProcess { public: virtual ~CPProcess() {} virtual uint64 getCPUMask(); virtual bool setCPUMask(uint64 mask); }; } // NLMISC #endif // NL_OS_UNIX #endif // NL_P_THREAD_H /* End of p_thread.h */ ================================================ FILE: code/nel/include/nel/misc/path.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_PATH_H #define NL_PATH_H #include "types_nl.h" #include "time_nl.h" #include "common.h" #include "string_mapper.h" #include #include #include namespace NLMISC { /// Exception throw when a find is not found in a lookup() call struct EPathNotFound : public Exception { EPathNotFound (const std::string& filename) : Exception ("Path not found for " + filename) { } }; /** Utility to store a pre-built list of file, bnp and xml_pack * Used by CPath to store the default application patch. * Can be used by user to build a custom set of file. * \warning addSearchPath(), clearMap() and remapExtension() are not reentrant. * \warning all path and files are *case sensitive* on linux. */ class CFileContainer { // no copy allowed CFileContainer(const CFileContainer &/* other */) {} CFileContainer &operator =(const CFileContainer &/* other */) { return *this; } public: CFileContainer() { _MemoryCompressed = false; _AllFileNames = NULL; } ~CFileContainer(); void addSearchPath (const std::string &path, bool recurse, bool alternative, class IProgressCallback *progressCallBack = NULL); /** Used only for compatibility with the old CPath. In this case, we don't use the map to have the same behavior as the old CPath */ void addSearchPath (const std::string &path) { addSearchPath (path, false, true, NULL); } /** Same as AddSearchPath but with a file "c:/autoexec.bat" this file only will included. wildwards *doesn't* work */ void addSearchFile (const std::string &file, bool remap = false, const std::string &virtual_ext = "", class NLMISC::IProgressCallback *progressCallBack = NULL); /** Same as AddSearchPath but with a path file "c:/test.pth" all files name contain in this file will be included (the extention is used to know that it's a path file) */ void addSearchListFile (const std::string &filename, bool recurse, bool alternative); /** Same as AddSearchPath but with a big file "c:/test.nbf" all files name contained in the big file will be included (the extention (Nel Big File) is used to know that it's a big file) */ void addSearchBigFile (const std::string &filename, bool recurse, bool alternative, class NLMISC::IProgressCallback *progressCallBack = NULL); /** Same as AddSearchPath but with a xml pack file "c:/test.xml_pack" all files name contained in the xml pack will be included */ void addSearchXmlpackFile (const std::string &sXmlpackFilename, bool recurse, bool alternative, class NLMISC::IProgressCallback *progressCallBack = NULL); /** Remove all search path contains in the alternative directories */ void removeAllAlternativeSearchPath (); // Remove a set of big file from the search paths (and also from CBigFile) void removeBigFiles(const std::vector &bnpFilenames); /** Returns the long name (path + filename) for the specified file. * The directory separator is always '/'. * First, the lookup() lookups in standard directories (Alternative=false). * If not found, it lookups in the Alternative directories. * If not found the lookup() returns empty string "" (and generate an exception if throwException is true) * * The filename is not case sensitive so if the real filename is "FooBAR.Jpg" and you call lookup("fOOBar.jPg"), it'll * return the real filename "FooBAR.Jpg" * * \param filename the file name you are seeking. (ex: "test.txt") * \param throwException used for backward compatibility, set to true to generate an EPathNotFound. * \param displayWarning set to false if you don't want the function displays a warning if the file is not found * \param lookupInLocalDirectory if true, the lookup() will first try to open the file without path. * \return empty string if file is not found or the full path + file name (ex: "c:/temp/test.txt"); * * *********************************************** * WARNING: This Method is NOT thread safe * user must ensure that no mutator is called on CPath while async loading * *********************************************** * */ std::string lookup (const std::string &filename, bool throwException = true, bool displayWarning = true, bool lookupInLocalDirectory = true); /** Return if a file is present in the lookup map. * The function changes filename into lower case and removes ended spaces before searching. * * \warning This function checks *only* in the map, not in local dir or alternative dir * * \param filename the file name you are seeking. (ex: "test.txt") * \param lookupInLocalDirectory if true, the lookup() will first try to open the file without path. * \return true if the filename exists in the map used by lookup to know where the file is, false otherwise */ bool exists (const std::string &filename); /** Clears the map that contains all cached files (Use this function to take into account new files). */ void clearMap (); /** Add a remapping function to allow file extension substitution. * - eg remapExtension("dds", "tga", true) Where the boolean indicates whether * the "dds" should replace a "tga" if one exists - again - a warning should * be generated if the two are present. * * ie: If you have a file called pic.dds and you call remapExtension("dds", "tga", true), * if you call lookup("pic.tga"), it'll return "pic.dds" * */ void remapExtension (const std::string &ext1, const std::string &ext2, bool substitute); /** Add file remapping * ie: If you have a file called pic.dds, and call remapFile("picture.dds", "pic.dds") * calling lookup("picture.dds") will in fact call lookup("pic.dds") */ void remapFile (const std::string &file1, const std::string &file2); /** Load a file containing the remapped file (you must have done addsearchpath, this method use lookup) * Format is remapped_name_file, real_file * separators are , and \n */ void loadRemappedFiles (const std::string &file); void display (); /** Take a path and put it in the portable format and add a terminated / if needed * ie: "C:\\Game/dir1" will become "C:/Game/dir1/" or "C:/Game/dir1" if addFinalSlash is false */ std::string standardizePath (const std::string &path, bool addFinalSlash = true); /** Replace / with \ for dos process. Use only this function if can't do another way. * For example, if you do a system("copy data/toto data/tata"); it'll not work because dos doesn't * understand /. * But in the majority of case, / working (it works for fopen for example) */ std::string standardizeDosPath (const std::string &path); /** List all files in a directory. * \param path path where files are scanned. No-op if empty * \param recurse true if want to recurs directories * \param wantDir true if want to add directories in result * \param wantFile true if want to add files in result * \param result list of string where directories/files names are added. * \param progressCallBack is a progression callback interface pointer. * \param showEverything false skips *.log files and CVS directories */ void getPathContent (const std::string &path, bool recurse, bool wantDir, bool wantFile, std::vector &result, class IProgressCallback *progressCallBack = NULL, bool showEverything=false); /** Get the full path based on a file/path and the current directory. Example, imagine that the current path is c:\temp and toto is a directory * getFullPath ("toto") returns "c:/temp/toto/" * getFullPath ("../toto") returns "c:/temp/../toto/" * getFullPath ("d:\dir\toto") returns "d:/dir/toto/" * getFullPath ("\toto") returns "c:/toto/" * getFullPath ("") returns "c:/temp/" * * \param path the path * \return the full path */ std::string getFullPath (const std::string &path, bool addFinalSlash = true); /** Returns the current path of the application. */ std::string getCurrentPath (); /** Set the current path of the application. */ bool setCurrentPath (const std::string &path); /** Create a list of file having the requested extension. */ void getFileList(const std::string &extension, std::vector &filenames); /** Create a list of file having the requested string in the filename and the requested extension. */ void getFileListByName(const std::string &extension, const std::string &name, std::vector &filenames); /** Create a list of file having the requested string in the path and the requested extension. */ void getFileListByPath(const std::string &extension, const std::string &path, std::vector &filenames); /** Make a path relative to another if possible, else doesn't change it. * \param basePath is the base path to be relative to. * \param relativePath is the path to make relative to basePath. * return true if relativePath as been done relative to basePath, false is relativePath has not been changed. */ bool makePathRelative (const char *basePath, std::string &relativePath); /** If File in this list is added more than one in an addSearchPath, it doesn't launch a warning. */ void addIgnoredDoubleFile(const std::string &ignoredFile); /** For the moment after memoryCompress you cant addsearchpath anymore */ void memoryCompress(); void memoryUncompress(); bool isMemoryCompressed() { return _MemoryCompressed; } /** Get the ms windows directory (in standardized way with end slash), or returns an empty string on other os */ std::string getWindowsDirectory(); /** Get application directory. * \return directory where applications should write files. */ std::string getApplicationDirectory(const std::string &appName = ""); /** Get a temporary directory. * \return temporary directory where applications should write files. */ std::string getTemporaryDirectory(); private: // All path in this vector must have a terminated '/' std::vector _AlternativePaths; std::vector IgnoredFiles; std::map _RemappedFiles; // ---------------------------------------------- // MEMORY WISE // ---------------------------------------------- bool _MemoryCompressed; CStaticStringMapper SSMext; CStaticStringMapper SSMpath; // If NOT memory compressed use this // --------------------------------- struct CFileEntry { std::string Name; // Normal case uint32 idPath : 16; uint32 idExt : 15; uint32 Remapped : 1; }; typedef std::map TFiles; TFiles _Files; // first is the filename in lowercase (can be with a remapped extension) // If memory compressed use this // ----------------------------- struct CMCFileEntry { char *Name; // Normal case (the search is done by using nlstricmp) uint32 idPath : 16; // Path (not with file at the end) - look in the SSMpath (65536 different path allowed) uint32 idExt : 15; // real extension of the file if remapped - look in the SSMext (32768 different extension allowed) uint32 Remapped : 1; // true if the file is remapped }; char *_AllFileNames; // first is the filename that can be with a remapped extension std::vector _MCFiles; // Compare a MCFileEntry with a lowered string (useful for MCfind) class CMCFileComp { public: sint specialCompare(const CMCFileEntry &fe, const char *rhs) { char *lhs = fe.Name; uint8 lchar, rchar; while (*lhs != '\0' && *rhs != '\0') { // lower case compare because name is in normal case lchar = uint8(::tolower(*lhs)); rchar = uint8(::tolower(*rhs)); if (lchar != rchar) return ((sint)lchar) - ((sint)rchar); ++lhs; ++rhs; } if (*lhs != 0) return 1; if (*rhs != 0) return -1; return 0; } bool operator()( const CMCFileEntry &fe, const CMCFileEntry &rhs ) { return specialCompare( fe, rhs.Name ) < 0; } }; /// first ext1, second ext2 (ext1 could replace ext2) std::vector > _Extensions; CMCFileEntry *MCfind (const std::string &filename); sint findExtension (const std::string &ext1, const std::string &ext2); void insertFileInMap (const std::string &filename, const std::string &filepath, bool remap, const std::string &extension); }; /** * Utility class for searching files in different paths. * * Change in jun 2007 : now the implementation code is in CFileContainer, the * CPath class is just a wrapper class that contains one instance of CFileContainer. * * \warning addSearchPath(), clearMap() and remapExtension() are not reentrant. * \warning all path and files are *case sensitive* on linux. * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CPath { NLMISC_SAFE_SINGLETON_DECL_PTR(CPath); public: /** Adds a search path. * The path is a directory "c:/temp" all files in the directory will be included (and recursively if asked) * * Alternative directories are not pre-cached (instead of non Alternative files) and will be used when a file is not found in the standard directories. * For example, local data will be in the cached directories and server repository files will be in the Alternative files. If a new file is not * found in the local data, we'll try to find it on the repository. * * When Alternative is false, all added file names must be unique or a warning will be display. In the Alternative directories, it could have * more than one file with the same name. * * \warning the path you provide is case sensitive, you must be sure that the path name is exactly the same * * \param path the path name.k The separator for directories could be '/' or '\' (bit '\' will be translate into '/' in the function). * \param recurse true if you want the function recurse in sub-directories. * \param Alternative true if you want to add the path in the Alternative directories. * \param progressCallBack is a progression callback interface pointer. */ static void addSearchPath (const std::string &path, bool recurse, bool alternative, class IProgressCallback *progressCallBack = NULL); /** Used only for compatibility with the old CPath. In this case, we don't use the map to have the same behavior as the old CPath */ static void addSearchPath (const std::string &path) { addSearchPath (path, false, true, NULL); } /** Same as AddSearchPath but with a file "c:/autoexec.bat" this file only will included. wildwards *doesn't* work */ static void addSearchFile (const std::string &file, bool remap = false, const std::string &virtual_ext = "", class NLMISC::IProgressCallback *progressCallBack = NULL); /** Same as AddSearchPath but with a path file "c:/test.pth" all files name contain in this file will be included (the extention is used to know that it's a path file) */ static void addSearchListFile (const std::string &filename, bool recurse, bool alternative); /** Same as AddSearchPath but with a big file "c:/test.nbf" all files name contained in the big file will be included (the extention (Nel Big File) is used to know that it's a big file) */ static void addSearchBigFile (const std::string &filename, bool recurse, bool alternative, class NLMISC::IProgressCallback *progressCallBack = NULL); /** Same as AddSearchPath but with a xml pack file "c:/test.xml_pack" all files name contained in the xml pack will be included */ static void addSearchXmlpackFile (const std::string &sXmlpackFilename, bool recurse, bool alternative, class NLMISC::IProgressCallback *progressCallBack = NULL); /** Remove all search path contains in the alternative directories */ static void removeAllAlternativeSearchPath (); // Remove a set of big file from the search paths (and also from CBigFile) static void removeBigFiles(const std::vector &bnpFilenames); /** Returns the long name (path + filename) for the specified file. * The directory separator is always '/'. * First, the lookup() lookups in standard directories (Alternative=false). * If not found, it lookups in the Alternative directories. * If not found the lookup() returns empty string "" (and generate an exception if throwException is true) * * The filename is not case sensitive so if the real filename is "FooBAR.Jpg" and you call lookup("fOOBar.jPg"), it'll * return the real filename "FooBAR.Jpg" * * \param filename the file name you are seeking. (ex: "test.txt") * \param throwException used for backward compatibility, set to true to generate an EPathNotFound. * \param displayWarning set to false if you don't want the function displays a warning if the file is not found * \param lookupInLocalDirectory if true, the lookup() will first try to open the file without path. * \return empty string if file is not found or the full path + file name (ex: "c:/temp/test.txt"); * * *********************************************** * WARNING: This Method is NOT thread safe * user must ensure that no mutator is called on CPath while async loading * *********************************************** * */ static std::string lookup (const std::string &filename, bool throwException = true, bool displayWarning = true, bool lookupInLocalDirectory = true); /** Return if a file is present in the lookup map. * The function changes filename into lower case and removes ended spaces before searching. * * \warning This function checks *only* in the map, not in local dir or alternative dir * * \param filename the file name you are seeking. (ex: "test.txt") * \param lookupInLocalDirectory if true, the lookup() will first try to open the file without path. * \return true if the filename exists in the map used by lookup to know where the file is, false otherwise */ static bool exists (const std::string &filename); /** Clears the map that contains all cached files (Use this function to take into account new files). */ static void clearMap (); /** Add a remapping function to allow file extension substitution. * - eg remapExtension("dds", "tga", true) Where the boolean indicates whether * the "dds" should replace a "tga" if one exists - again - a warning should * be generated if the two are present. * * ie: If you have a file called pic.dds and you call remapExtension("dds", "tga", true), * if you call lookup("pic.tga"), it'll return "pic.dds" * */ static void remapExtension (const std::string &ext1, const std::string &ext2, bool substitute); /** Add file remapping * ie: If you have a file called pic.dds, and call remapFile("picture.dds", "pic.dds") * calling lookup("picture.dds") will in fact call lookup("pic.dds") */ static void remapFile (const std::string &file1, const std::string &file2); /** Load a file containing the remapped file (you must have done addsearchpath, this method use lookup) * Format is remapped_name_file, real_file * separators are , and \n */ static void loadRemappedFiles (const std::string &file); static void display (); /** Take a path and put it in the portable format and add a terminated / if needed * ie: "C:\\Game/dir1" will become "C:/Game/dir1/" or "C:/Game/dir1" if addFinalSlash is false */ static std::string standardizePath (const std::string &path, bool addFinalSlash = true); /** Replace / with \ for dos process. Use only this function if can't do another way. * For example, if you do a system("copy data/toto data/tata"); it'll not work because dos doesn't * understand /. * But in the majority of case, / working (it works for fopen for example) */ static std::string standardizeDosPath (const std::string &path); /** List all files in a directory. * \param path path where files are scanned. No-op if empty * \param recurse true if want to recurs directories * \param wantDir true if want to add directories in result * \param wantFile true if want to add files in result * \param result list of string where directories/files names are added. * \param progressCallBack is a progression callback interface pointer. * \param showEverything false skips *.log files and CVS directories */ static void getPathContent (const std::string &path, bool recurse, bool wantDir, bool wantFile, std::vector &result, class IProgressCallback *progressCallBack = NULL, bool showEverything=false); /** Get the full path based on a file/path and the current directory. Example, imagine that the current path is c:\temp and toto is a directory * getFullPath ("toto") returns "c:/temp/toto/" * getFullPath ("../toto") returns "c:/temp/../toto/" * getFullPath ("d:\dir\toto") returns "d:/dir/toto/" * getFullPath ("\toto") returns "c:/toto/" * getFullPath ("") returns "c:/temp/" * * \param path the path * \return the full path */ static std::string getFullPath (const std::string &path, bool addFinalSlash = true); /** Returns the current path of the application. */ static std::string getCurrentPath (); /** Set the current path of the application. */ static bool setCurrentPath (const std::string &path); /** Create a list of file having the requested extension. */ static void getFileList(const std::string &extension, std::vector &filenames); /** Create a list of file having the requested string in the filename and the requested extension. */ static void getFileListByName(const std::string &extension, const std::string &name, std::vector &filenames); /** Create a list of file having the requested string in the path and the requested extension */ static void getFileListByPath(const std::string &extension, const std::string &path, std::vector &filenames); /** Make a path relative to another if possible, else doesn't change it. * \param basePath is the base path to be relative to. * \param relativePath is the path to make relative to basePath. * return true if relativePath as been done relative to basePath, false is relativePath has not been changed. */ static bool makePathRelative (const char *basePath, std::string &relativePath); /** Make path absolute * \param relativePath - The relative path * \param directory - the directory to which the path is relative to * returns the absolute path, or empty if something went wrong. */ static std::string makePathAbsolute (const std::string &relativePath, const std::string &directory ); /** If File in this list is added more than one in an addSearchPath, it doesn't launch a warning. */ static void addIgnoredDoubleFile(const std::string &ignoredFile); /** For the moment after memoryCompress you cant addsearchpath anymore */ static void memoryCompress(); static void memoryUncompress(); static bool isMemoryCompressed() { return getInstance()->_FileContainer.isMemoryCompressed(); } /** Get the ms windows directory (in standardized way with end slash), or returns an empty string on other os */ static std::string getWindowsDirectory(); /** Get application directory. * \return directory where applications should write files. */ static std::string getApplicationDirectory(const std::string &appName = ""); /** Get a temporary directory. * \return temporary directory where applications should write files. */ static std::string getTemporaryDirectory(); // release singleton static void releaseInstance(); private: CPath() { } /// The container used by the standard CPath CFileContainer _FileContainer; }; /** * Utility class for file manipulation * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ struct CFile { /** * Retrieve the associated file name. * An empty string is returned if the path is invalid */ static std::string getFilename (const std::string &filename); /** * Retrieve the associated file path with the trailing slash. * Returns an empty string if the path is invalid */ static std::string getPath (const std::string &filename); /** * Just to know if it is a directory. * _FileName empty and path not !!! */ static bool isDirectory (const std::string &filename); /** * Return true if the file exists. * Warning: this test will also tell that the file does not * exist if you don't have the rights to read it (Unix). */ static bool fileExists (const std::string &filename); /** * Return true if the file OR directory exists. * Warning: this test will also tell that the file does not * exist if you don't have the rights to read it (Unix). */ static bool isExists (const std::string& filename); /** * Create an empty file. * Return true if the file has been correctly created. */ static bool createEmptyFile (const std::string& filename); /** * Return a new filename that doesn't exist. It's used for screenshot filename for example. * example: findNewFile("foobar.tga"); * will try foobar001.tga, if the file exists, try foobar002.tga and so on until it finds an unexistant file. */ static std::string findNewFile (const std::string &filename); /** * Return the position between [begin,end[ of the last separator between path and filename ('/' or '\'). * If there's no separator, it returns string::npos. */ static int getLastSeparator (const std::string &filename); static std::string getFilenameWithoutExtension (const std::string &filename); static std::string getExtension (const std::string &filename); /** * Return the size of the file (in bytes). * * You have to provide the full path of the file (the function doesn't lookup) */ static uint32 getFileSize (const std::string &filename); /** * Return the size of the file (in bytes). */ static uint32 getFileSize (FILE *f); /** * Return Time of last modification of file. 0 if not found. * * You have to provide the full path of the file (the function doesn't lookup) * The time is measured in second since 01-01-1970 0:0:0 UTC */ static uint32 getFileModificationDate(const std::string &filename); /** * Set the time of last modification of file. * * You have to provide the full path of the file (the function doesn't lookup) * The time is measured in second since 01-01-1970 0:0:0 UTC * Return 'true' if the file date has been changed or false in case of error. */ static bool setFileModificationDate(const std::string &filename, uint32 modTime); /** * Return creation Time of the file. 0 if not found. * * You have to provide the full path of the file (the function doesn't lookup) */ static uint32 getFileCreationDate(const std::string &filename); /** * Add a callback that will be call when the content file, named filename, changed. * The system use the file modification date. To work, you need to call evenly the * function checkFileChange(), this function only checks every 1s by default (you can * change the default time) * * ie: * void cb (const std::string &filename) { nlinfo ("the file %s changed", filename.c_str()); } * CFile::addFileChangeCallback ("myfile.txt", cb); * */ static void addFileChangeCallback (const std::string &filename, void (*)(const std::string &filename)); /** * Remove a file that was previously added by addFileChangeCallback */ static void removeFileChangeCallback (const std::string &filename); /** * You have to call this function evenly (each frame for example) to enable the file change callback system. * If the file not exists and is created in the run time, the callback will be called. * If the file exists and is removed in the run time, the callback will be called. * * \param frequency the time in millisecond that we wait before check another time (1s by default). */ static void checkFileChange (TTime frequency = 1000); /** Copy a file * NB this keeps file attributes * \param failIfExists If the destination file exists, nothing is done, and it returns false. * \return true if the copy succeeded */ static bool copyFile(const std::string &dest, const std::string &src, bool failIfExists = false, class IProgressCallback *progress = NULL); /** Compare 2 files * \return true if both files exist and the files have same timestamp and size */ static bool quickFileCompare(const std::string &fileName0, const std::string &fileName1); /** Compare 2 files * \param maxBufSize fixes max memory space to use for the pair buffers used for data comparison (eg 16 would allow 8 bytes per buffer for the 2 buffers) * \return true if both files exist and the files have same contents (timestamp is ignored) */ static bool thoroughFileCompare(const std::string &fileName0, const std::string &fileName1,uint32 maxBufSize=1024*1024*2); /** Move a file * NB this keeps file attributes */ static bool moveFile(const char *dest, const char *src); /** Create a directory * \return true if success */ static bool createDirectory(const std::string &dirname); /** Create a directory and any missing parent directories * \return true if success */ static bool createDirectoryTree(const std::string &dirname); /** Try to set the file access to read/write if not already set. * return true if the file doesn't exist or if the file already have RW access. * Work actually only on Windows and returns always true on other platforms. * \return true if RW access is granted */ static bool setRWAccess(const std::string &filename); /** Delete a file if possible (change the write access if possible) * \return true if the delete occurs. */ static bool deleteFile(const std::string &filename); /** Delete a directory if possible (change the write access if possible) * \return true if the delete occurs. */ static bool deleteDirectory(const std::string &filename); /** Get temporary output filename. * Call this method to get a temporary output filename. If you have successfully saved your data, delete the old filename and move the new one. */ static void getTemporaryOutputFilename (const std::string &originalFilename, std::string &tempFilename); }; } // NLMISC #endif // NL_PATH_H /* End of path.h */ ================================================ FILE: code/nel/include/nel/misc/plane.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_PLANE_H #define NL_PLANE_H #include "stream.h" #include "vector.h" namespace NLMISC { class CUV; // ====================================================================================================== /** * Class CPlane. a 3D Plane. * * A vector v is said "front" of a plane p if p*v>0. * * A "front segment" or a "front polygon" have all their vertices in front of the plane. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CPlane { public: float a,b,c,d; public: /// \name Object. //@{ /// Constructor that does nothing. CPlane() {} /// Constructor . CPlane(float _a, float _b, float _c, float _d) : a(_a), b(_b), c(_c), d(_d) {} /// Copy Constructor. CPlane(const CPlane &v) : a(v.a), b(v.b), c(v.c), d(v.d) {} //@} /// \name Construction/Get. //@{ /** * Make a plane with a normal and a vertex. * NB: the plane normal is normalized by make(). */ void make(const CVector &normal, const CVector &pos); /** * Make a plane with 3 vertices. * NB: the plane normal is normalized by make(). */ void make(const CVector &p0, const CVector &p1, const CVector &p2); /** * Return the normal vector of the plane. * Since the normal of the plane may not be normalized (if setuped without make()), the returned normal * may NOT be normalized. */ CVector getNormal() const; /** * Normalize the plane, such that getNormal() return a normalized vector. */ void normalize(); /** * return the normalized version of a plane. \see normalize() */ inline CPlane normed() const; //@} /// \name Projection / clipping. //@{ /** * Return the distance of p from the plane. Hence, the result is >=0. * Since the plane normal may not be normalized, distance() compute the distance with the normalized normal * of plane. If you are sure that your plane has a normalized normal, it is much faster to do a \c fabs(p*v). */ float distance(const CVector &p) const; /// Return plane*vector. inline float operator*(const CVector &p) const; /// Intersect a line onto a plane. p1 is returned if line // to plane. CVector intersect(const CVector &p0,const CVector &p1) const; /// Project a point onto a plane. CVector project(const CVector &p0) const; /** * Clip a segment onto a plane. * The "back segment" is written in (p1,p2). If segment is entirely "front", (p1,p2) is not modified. * \return false if segment entirely front, or true. * \sa clipSegmentFront() */ bool clipSegmentBack(CVector &p0, CVector &p1) const; /** * Clip a segment onto a plane. * The "front segment" is written in (p1,p2). If segment is entirely "back", (p1,p2) is not modified. * \return false if segment entirely back, or true. * \sa clipSegmentBack() */ bool clipSegmentFront(CVector &p0, CVector &p1) const; /** Clip a polygon by a plane. The "back polygon" is returned. * Nb: Out must be allocated to nIn+1 (at less). * \param in the input polygon * \param out the clipped back polygon * \param nIn number of vertices of input polygon * \return number of vertices of out. 0 is returned if In polygon entirely front, or if nIn<=2. */ sint clipPolygonBack(CVector in[], CVector out[], sint nIn) const; // Clip a polygon with uvs by a plane sint clipPolygonBack(const CVector in[], const CUV inUV[], CVector out[], CUV outUV[], sint nIn) const; /** Clip a polygon by a plane. The "front polygon" is returned. * Nb: Out must be allocated to nIn+1 (at less). * \param in the input polygon * \param out the clipped front polygon * \param nIn number of vertices of input polygon * \return number of vertices of out. 0 is returned if In polygon entirely back, or if nIn<=2. */ sint clipPolygonFront(CVector in[], CVector out[], sint nIn) const; //@} /// \name normal inversion //@{ /// get the inverted version of this plane (same position, but inverted normal) CPlane inverted() const; /// invert this plane (same position, but inverted normal) void invert(); //@} /// \name Misc //@{ void serial(IStream &f) { f.serial(a,b,c,d); } // Strict equality comparator bool operator==(const CPlane &o) const { return a==o.a && b==o.b && c==o.c && d==o.d; } //@} }; } #include "plane_inline.h" #endif // NL_PLANE_H /* End of plane.h */ ================================================ FILE: code/nel/include/nel/misc/plane_inline.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_PLANE_INLINE_H #define NL_PLANE_INLINE_H namespace NLMISC { //============================================================ inline CVector CPlane::getNormal() const { return CVector(a,b,c); } //============================================================ inline float CPlane::distance(const CVector &v) const { CPlane p= normed(); return (float)fabs(p*v); } //============================================================ inline float CPlane::operator*(const CVector &p) const { return a*p.x + b*p.y + c*p.z + d; } //============================================================ inline CVector CPlane::intersect(const CVector &p0,const CVector &p1) const { float decal; float da= (*this)*p0; float db= (*this)*p1; if(db-da == 0) return p0; decal= ( 0-da ) / ( db - da ); return p0 + (p1-p0)*decal; } //============================================================ inline CVector CPlane::project(const CVector &p0) const { return intersect(p0, p0+getNormal()); } //============================================================ inline void CPlane::normalize() { float n= getNormal().norm(); if(n) { float oon= 1.0f/n; a*= oon; b*= oon; c*= oon; d*= oon; } } //============================================================ inline CPlane CPlane::normed() const { CPlane ret= *this; ret.normalize(); return ret; } } #endif // NL_PLANE_H /* End of plane.h */ ================================================ FILE: code/nel/include/nel/misc/polygon.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_POLYGON_H #define NL_POLYGON_H #include "types_nl.h" #include "matrix.h" #include "stream.h" #include "vector_2f.h" #include namespace NLMISC { class CTriangle; // Used by the method toConvexPolygons class CBSPNode2v; // *************************************************************************** /** * A polygon, with an unlimited size of vertices. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CPolygon { public: std::vector Vertices; public: /// Constructor CPolygon() {} /// Constructor. Init with a triangle. CPolygon(const CVector &a, const CVector &b, const CVector &c); sint getNumVertices() const {return (sint)Vertices.size();} // build a triangle fan from this polygon, appending resulting tris to 'dest' void toTriFan(std::vector &dest) const; /// Clip a polygon with a set of planes. Cohen-sutherland... clipPolygonBack() is used on planes. void clip(const CPlane *planes, uint nPlanes); /// Clip a polygon with a set of planes. Cohen-sutherland clipping... clipPolygonBack() is used on planes. void clip(const std::vector &planes); float computeArea() const; /// Serial this polygon void serial(NLMISC::IStream &f) throw(NLMISC::EStream); /** * Convert a concave polygon into a list of convex polygons using a 2d projection. * The polygon mustn't overlap itself in the XY plane of the basis passed in parameter. * The polygon must be direct in the XY plane of the basis passed in parameter. (Counter clock wise) * * The subdivison is in non-constant n*log(n) with n is the number of vertices. * * \param outputPolygons is the list filled with clipped convex polygons. The list is not cleared at the beginning. * New polygons are just appended at the end. * \param basis is the basis of the polygon projection. * \return true if the polygon has been subdivided. false if the polygon overlap itself in the XY plane of the basis * or if the polygon is not direct (clock wise). */ bool toConvexPolygons (std::list& outputPolygons, const CMatrix& basis) const; /** * Chain the arg polygons with this polygon testing 2d intersections. * The 2d intersection test has been done in the XY plane of the basis passed at the function. * * The polygon a-b-c-d-e chained with f-g-h-i-j will give the polygon a-b-f-g-h-i-j-f-b-c-d-e * if the edge b-f is not 2d clipped by any edge plane in the XY plane of basis. * * \param basis is the basis of the polygon projection. * \return false if chain failed. else true. */ bool chain (const std::vector &other, const CMatrix& basis); /// get the best triplet from this poly (the one that has the highest area) void getBestTriplet(uint &index0, uint &index1, uint &index2); /** Takes the best triplet from this poly to build a normal. * From this normal and a points, build a basis (the normal is the K vector of the basis) * This can be used to transform the poly in 2D after it has been inverted */ void buildBasis(CMatrix &dest); // Used by the method toConvexPolygons and chain void toConvexPolygonsLocalAndBSP (std::vector &localVertices, CBSPNode2v &root, const CMatrix &basis) const; static bool toConvexPolygonsEdgeIntersect (const CVector2f& a0, const CVector2f& a1, const CVector2f& b0, const CVector2f& b1); static bool toConvexPolygonsLeft (const std::vector &vertex, uint a, uint b, uint c); static bool toConvexPolygonsLeftOn (const std::vector &vertex, uint a, uint b, uint c); static bool toConvexPolygonsInCone (const std::vector &vertex, uint a, uint b); static bool toConvexPolygonsDiagonal (const std::vector &vertex, const CBSPNode2v &bsp, uint a, uint b); }; /** * A 2d convex polygon */ class CPolygon2D { public: typedef std::vector TVec2fVect; TVec2fVect Vertices; public: /// default ctor CPolygon2D() {} // swap this poly content with another poly content void swap(CPolygon2D &other) { Vertices.swap(other.Vertices); } /** Build a 2D polygon from this 3D polygon, by using the given projection matrix * The x and y components of projected vertices are used to create the 2D polygon */ CPolygon2D(const CPolygon &src, const CMatrix &projMat = CMatrix::Identity); /** Reinit a 2D polygon from this 3D polygon, by using the given projection matrix * The x and y components of projected vertices are used to create the 2D polygon */ void fromPolygon(const CPolygon &src, const CMatrix &projMat = CMatrix::Identity); /** Build a 2D polygon from the given triangle, by using the given projection matrix * The x and y components of projected vertices are used to create the 2D polygon */ CPolygon2D(const CTriangle &tri, const CMatrix &projMat = CMatrix::Identity); /// Check whether this polygon is convex; bool isConvex(); /** Build a convex hull from this polygon. The result poly is ordered, so it can also be used to order a convex * poly given its set of vertices. * NB: require this != &dest */ void buildConvexHull(CPolygon2D &dest) const; /// get the best triplet of vector. e.g the triplet that has the best surface void getBestTriplet(uint &index0, uint &index1, uint &index2); /// Serial this polygon void serial(NLMISC::IStream &f) throw(NLMISC::EStream); typedef std::pair TRaster; typedef std::vector TRasterVect; /** Compute the borders of this poly with sub-pixel accuracy. No clipping is performed. * Only points exactly inside or exactly on the left border of the polygon are kept. * This means that pixels are seen as points, not as surfaces. * The output is in a vector of sint pairs. minimumY is filled with the minimum y value of the poly. * Each pairs gives [xmin, xmax] for the current segment. if xmin > xmax, then no point is valid for this segment. * Otherwise, all points from x = xmin (included) to x = xmax (included) are valid. * IMPORTANT: coordinates must be in the -32000, 32000 range. This is checked in debug */ void computeBorders(TRasterVect &borders, sint &minimumY) const; /** The same as compute borders, but pixel are seen as surfaces and not as points. * Any pixel that is touched by the poly will be selected * IMPORTANT: coordinates must be in the -32000, 32000 range. This is checked in debug */ void computeOuterBorders(TRasterVect &borders, sint &minimumY) const; /** The same as compute borders, but pixel are seen as surfaces and not as points * In this version, only pixels that are entirely INSIDE the poly are kept * IMPORTANT: coordinates must be in the -32000, 32000 range. This is checked in debug */ void computeInnerBorders(TRasterVect &borders, sint &minimumY) const; /// Test whether this polygon intersect another convex polygon. Currently not optimized. bool intersect(const CPolygon2D &other) const; /// Check whether a point is contained by this poly bool contains(const CVector2f &p, bool hintIsConvex = true) const; /** Get the index of a segment of this poly that is a non null segment. * \return true if such a segment was found */ bool getNonNullSeg(uint &seg) const; /// Get a line equation of the seg starting at the given index void getLineEquation(uint index, float &a, float &b, float &c) const; // Test if current poly is CCW oriented (in a right handed coord. system) bool isCCWOriented() const; // get bounding rect (poly must not be empty) void getBoundingRect(CVector2f &minCorner, CVector2f &maxCorner) const; // test self intersection bool selfIntersect() const; private: /// Sum the dot product of this poly vertices against a line equation a*x + b*y + c float sumDPAgainstLine(float a, float b, float c) const; /// Get ref to the first vertex that start at index const CVector2f &getSegRef0(uint index) const { nlassert(index < Vertices.size()); return Vertices[index]; } const CVector2f &getSegRef1(uint index) const { nlassert(index < Vertices.size()); return index + 1 == Vertices.size() ? Vertices[0] : Vertices[index + 1]; } void checkValidBorders() const; }; // comparison of 2D polygon bool operator == (const CPolygon2D &lhs, const CPolygon2D &rhs); bool operator < (const CPolygon2D &lhs, const CPolygon2D &rhs); } // NLMISC #endif // NL_POLYGON_H /* End of polygon.h */ ================================================ FILE: code/nel/include/nel/misc/pool_memory.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_POOL_MEMORY_H #define NL_POOL_MEMORY_H #include "types_nl.h" #include #include namespace NLMISC { /** * Pool memory allocation * * This memory manager allocates bloc of elements and free all the * elements at the same time. Useful for temporary allocation. * * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2001 */ template class CPoolMemory { public: /* * Constructor * * \param blockSize is the default bloc size */ CPoolMemory (uint blockSize=10) { _BlockSize=blockSize; _BlockPointer=_BlockList.end(); } /* * Allocate an element. * * Return a pointer on the element. */ T* allocate () { // End of block ? if ( (_BlockPointer!=_BlockList.end()) && (_BlockPointer->size()>=_BlockSize) ) { // Get next block _BlockPointer++; } // Out of memory ? if (_BlockPointer==_BlockList.end()) { // Add a block _BlockList.resize (_BlockList.size()+1); // Pointer on the new block _BlockPointer=_BlockList.end (); _BlockPointer--; // Reserve it _BlockPointer->reserve (_BlockSize); } // Allocate _BlockPointer->resize (_BlockPointer->size()+1); // Return the pointer return &*((_BlockPointer->end ()-1)); } /* * Free all the elements allocated since last free(). Memory is kept for next allocations. */ void free () { typename std::list< std::vector >::iterator ite=_BlockList.begin(); while (ite!=_BlockList.end()) { // Clear the block ite->clear (); // Check size in not zero nlassert (ite->capacity ()>0); ite++; } // Pointer at the beginning _BlockPointer=_BlockList.begin(); } /* * Purge memory. All the memory used by the allocator is freid for real. */ void purge () { _BlockList.clear(); _BlockPointer=_BlockList.end(); } private: uint _BlockSize; std::list< std::vector > _BlockList; typename std::list< std::vector >::iterator _BlockPointer; }; } // NLMISC #endif // NL_POOL_MEMORY_H /* End of pool_memory.h */ ================================================ FILE: code/nel/include/nel/misc/progress_callback.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_PROGRESS_CALLBACK_H #define NL_PROGRESS_CALLBACK_H #include "types_nl.h" namespace NLMISC { /** * Progress callback interface * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2002 */ class IProgressCallback { public: IProgressCallback (); virtual ~IProgressCallback () {} /** * Call back * * progressValue should be 0 ~ 1 */ virtual void progress (float progressValue); /** * Push crop values */ void pushCropedValues (float min, float max); /** * Push crop values */ void popCropedValues (); /** * Get croped value */ float getCropedValue (float value) const; public: /// Display string std::string DisplayString; private: class CCropedValues { public: CCropedValues (float min, float max) { Min = min; Max = max; } float Min; float Max; }; std::vector _CropedValues; }; } // NLMISC #endif // NL_PROGRESS_CALLBACK_H /* End of progress_callback.h */ ================================================ FILE: code/nel/include/nel/misc/quad.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_QUAD_H #define NL_QUAD_H #include "types_nl.h" #include "vector.h" namespace NLMISC { // *************************************************************************** /** * A simple quad of vertex. * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ class CQuad { public: CVector V0, V1, V2, V3; public: /// Constructor CQuad() {} /// Constructor CQuad(const NLMISC::CVector &v0, const NLMISC::CVector &v1, const NLMISC::CVector &v2, const NLMISC::CVector &v3) : V0(v0), V1(v1), V2(v2), V3(v3) {} void set(const NLMISC::CVector &v0, const NLMISC::CVector &v1, const NLMISC::CVector &v2, const NLMISC::CVector &v3) { V0 = v0; V1 = v1; V2 = v2; V3 = v3; } const CQuad &operator = ( const CQuad& q) { V0 = q.V0; V1 = q.V1; V2 = q.V2; V3 = q.V3; return *this; } }; } // NLMISC #endif // NL_QUAD_H /* End of quad.h */ ================================================ FILE: code/nel/include/nel/misc/quat.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_QUAT_H #define NL_QUAT_H #include "types_nl.h" #include "vector.h" #include "stream.h" #include namespace NLMISC { // *************************************************************************** const double QuatEpsilon= 0.000001; // *************************************************************************** /** * An AngleAxis. * \author Antoine Viau. * \author Nevrax France * \date 2000 */ struct CAngleAxis { CVector Axis; /// an axis. float Angle; /// angle in radians. CAngleAxis() {} CAngleAxis(const CVector &axis, float ang) : Axis(axis), Angle(ang) {} /// serial. void serial(IStream &f) { f.serial(Axis); f.serial(Angle); } }; // *************************************************************************** /** * A Template quaternion. Use CQuat and CQuatD. * \author Antoine Viau. * \author Nevrax France * \date 2000 */ template class CQuatT { public: T x,y,z,w; public: /// \name Object // @{ CQuatT() : x((T)0.0),y((T)0.0),z((T)0.0),w((T)1.0) {} CQuatT(T X, T Y, T Z, T W) : x(X), y(Y), z(Z), w(W) {} /// ctor of a UNIT quaternion, from an angle axis. CQuatT(const CVector &axis, float angle) {setAngleAxis(axis, angle);} /// ctor of a UNIT quaternion, from an angle axis. CQuatT(const CAngleAxis &aa) {setAngleAxis(aa);} // @} /// \name Sets. // @{ void set(T X, T Y, T Z, T W) {x= X; y= Y; z= Z; w= W;} // @} /// \name Comparison // @{ bool operator==(const CQuatT& a) const {return (x==a.x && y==a.y && z==a.z && w==a.w);} bool equal(const CQuatT& a, float epsilon = 1E-6f) const; void identity() {x = y = z = 0.0f ; w = 1.0f; } bool isIdentity() const {return (x==0.0f && y==0.0f && z==0.0f && w==1.0f);} // @} /// \name 4D vector operations. // @{ CQuatT& operator+=(const CQuatT&o) {x+=o.x; y+=o.y; z+=o.z; w+=o.w; return *this;} CQuatT& operator-=(const CQuatT&o) {x-=o.x; y-=o.y; z-=o.z; w-=o.w; return *this;} CQuatT& operator*=(T f) {x*=f;y*=f;z*=f;w*=f; return *this;} CQuatT& operator/=(T f) {double oof= 1.0/f; x=(T)(x*oof); y=(T)(y*oof); z= (T)(z*oof); w=(T)(w*oof); return *this;} CQuatT operator+(const CQuatT&o) const {return CQuatT(x+o.x,y+o.y,z+o.z,w+o.w);} CQuatT operator-(const CQuatT&o) const {return CQuatT(x-o.x,y-o.y,z-o.z,w-o.w);} CQuatT operator*(T f) const {return CQuatT(x*f,y*f,z*f,w*f);} CQuatT operator/(T f) const {double oof= 1.0/f; return CQuatT(x*oof,y*oof,z*oof,w*oof);} CQuatT operator-() const {return(CQuatT(-x,-y,-z,-w)); } CQuatT operator+() const {return *this; } /// return the square of the norm of the 4D vector. T sqrnorm() const {return (x*x + y*y + z*z + w*w);} /// return the norm of the 4D vector. T norm() const {return (T)sqrt(sqrnorm());} /// Normalize the quaternion. void normalize(); /// Return the quaternion normalized. CQuatT normed() const {CQuatT ret= *this; ret.normalize(); return ret;} // @} /// \name Basic Quaternions operations. // @{ /// Quaternion multiplication/composition. CQuatT operator*(const CQuatT&) const; CQuatT& operator*=(const CQuatT&); /// Invert this quaternion. If normalized, conjugate is faster and does same thing. void invert(); /// return the quaternion inverted. CQuatT inverted() const {CQuatT ret= *this; ret.invert(); return ret;} /// return the conjugate of this quaternion. CQuatT conjugate() const {return CQuatT(-x, -y, -z, w);} // @} /// \name To/From other orientation. // @{ /// Return the equivalent Unit axis of this quaternion. CVector getAxis() const {CVector ret((float)x,(float)y,(float)z); return ret.normed();} /// Return the equivalent angle of this quaternion. (in radian). float getAngle() const {return (float)(2*acos(w/norm()));} /// Return the equivalent Unit AngleAxis of this quaternion. CAngleAxis getAngleAxis() const {return CAngleAxis(getAxis(), getAngle());} /// Build a UNIT quaternion from an AngleAxis. void setAngleAxis(const CVector &axis, float angle); /// Build a UNIT quaternion from an AngleAxis. void setAngleAxis(const CAngleAxis &angAxis) {setAngleAxis(angAxis.Axis, angAxis.Angle);} // @} /// \name Misc. // @{ /// compute logn quaternion. CQuatT log(); /// compute quaternion exponent. CQuatT exp(); /// ensure that *this and q are on same side of hypersphere, ie dotProduct(*this,q) is >0, modifying this if necessary. void makeClosest(const CQuatT &o); /// serial. void serial(IStream &f) { f.serial(x,y,z,w); } // @} public: /// \name Quaternions static functions. // @{ /// Return the dotProduct of 2 quaternions. static T dotProduct(const CQuatT &q0, const CQuatT &q1); /** Quaternion spherical linear interpolation. when t==0, ret==q0, when t==1, ret==q1. * No hemisphere correction is made. */ static CQuatT slerp(const CQuatT& q0, const CQuatT& q1, float t); /** Quaternion Quadratic spherical linear interpolation. when t==0, ret==q0, when t==1, ret==q1. * No hemisphere correction is made. */ static CQuatT squad(const CQuatT& q0, const CQuatT& tgtQ0, const CQuatT& tgtQ1, const CQuatT& q1, float t); /** Quaternion Quadratic spherical linear interpolation, with multi revision support. */ static CQuatT squadrev(const CAngleAxis &rot, const CQuatT& q0, const CQuatT& tgtQ0, const CQuatT& tgtQ1, const CQuatT& q1, float t); /// compute lnDiff of q0.inverted()*q1. static CQuatT lnDif(const CQuatT &q0, const CQuatT &q1); // @} }; // *************************************************************************** /// \name Quaternions functions. // @{ /// f*quat operator template inline CQuatT operator*(T f, const CQuatT &o) {return o*f;} // @} // *************************************************************************** // *************************************************************************** // Template implementation. // *************************************************************************** // *************************************************************************** // *************************************************************************** template inline bool CQuatT::equal(const CQuatT& a, float epsilon) const { if (fabs(x-a.x) inline CQuatT CQuatT::operator*(const CQuatT& o) const { // wres= ww' - v.v' // vres= wv' + w'v + v^v' ] return CQuatT( (w*o.x) +(x*o.w) + (y*o.z)-(z*o.y), (w*o.y) +(y*o.w) + (z*o.x)-(x*o.z), (w*o.z) +(z*o.w) + (x*o.y)-(y*o.x), (w*o.w)-(x*o.x)-(y*o.y)-(z*o.z) ); } // *************************************************************************** template inline CQuatT& CQuatT::operator*=(const CQuatT& o) { *this= *this * o; return *this; } // *************************************************************************** template inline void CQuatT::invert() { // Must invert the norm. T f= sqrnorm(); if(f!=0) { *this/=f; } *this= conjugate(); } // *************************************************************************** template inline void CQuatT::normalize() { T f= norm(); if(f==0) identity(); else { *this/=f; } } // *************************************************************************** template inline void CQuatT::setAngleAxis(const CVector &axis, float angle) { CVector v= axis; v.normalize(); double ca= cos(angle/2); double sa= sin(angle/2); x= (T)(v.x*sa); y= (T)(v.y*sa); z= (T)(v.z*sa); w= (T)(ca); } // *************************************************************************** template T CQuatT::dotProduct(const CQuatT &q0, const CQuatT &q1) { return q0.x*q1.x + q0.y*q1.y + q0.z*q1.z + q0.w*q1.w; } // *************************************************************************** template CQuatT CQuatT::slerp(const CQuatT& q0, const CQuatT& q1, float t) { // omega is the 4D angle between q0 and q1. double omega, cosom,sinom; T factq0= 1; T s0,s1; cosom = CQuatT::dotProduct(q0, q1); // Make q0 and q1 on the same hemisphere. /*if(cosom<0) { cosom= -cosom; factq0= -1; }*/ // ???? if ( cosom < 1.0 - NLMISC::QuatEpsilon) { omega = acos(cosom); sinom = sin(omega); s0 = (T) (sin((1.0f - t)*omega) / sinom); s1 = (T) (sin(t*omega) / sinom); } else { // q0 and q1 are nearly the same => sinom nearly 0. We can't slerp. // just linear interpolate. s0 = (T)(1.0 - t); s1 = t; } return q0*(factq0*s0) + q1*s1; } // *************************************************************************** template CQuatT CQuatT::squad(const CQuatT& q0, const CQuatT& tgtQ0, const CQuatT& tgtQ1, const CQuatT& q1, float t) { return CQuatT::slerp( CQuatT::slerp(q0, q1, t), CQuatT::slerp(tgtQ0, tgtQ1, t), 2.f*(1.f-t)*t); } // *************************************************************************** template CQuatT CQuatT::squadrev(const CAngleAxis &rot, const CQuatT& q0, const CQuatT& tgtQ0, const CQuatT& tgtQ1, const CQuatT& q1, float t) { float s,v; float omega = rot.Angle* 0.5f; float nrevs = 0.0f; CQuatT ret,qaxis,pp,qq; // just one rev? //============== if (omega::squad(q0,tgtQ0,tgtQ1,q1,t); return ret; } // multirev. //============== // rotation of 180deg around rot.Axis. (=> sin(a/2)==sin(Pi/2)==1, and c(a/2)=0). qaxis.set(rot.Axis.x, rot.Axis.y, rot.Axis.z, 0); // the number of revisions (float!) nrevs= (float)(omega/Pi); // Angle>2Pi. squad from 0 to Pi, slerp from Pi to Angle-Pi, squad from Angle-Pi to Angle. s = t*2*nrevs; // So for s, squad from 0 to 1, slerp from 1 to 2*nrevs-1, squad from 2*nrevs-1 to 2*nrevs. if (s < 1.0f) { // first part. pp = q0*qaxis; ret = CQuatT::squad(q0,tgtQ0,pp,pp,s); } else { v = s - (2.0f*nrevs - 1.0f); if( v <= 0.0f) { // middle part while (s >= 2.0f) s -= 2.0f; pp = q0*qaxis; // s vary from 1 to 2. This is still correct for slerp(). ret = CQuatT::slerp(q0,pp,s); } else { // Last part. qq = - q1*qaxis; ret= CQuatT::squad(qq,qq,tgtQ1,q1,v); } } return ret; } // *************************************************************************** template CQuatT CQuatT::log() { double len; len = sqrt (x*x + y*y + z*z); if (len < QuatEpsilon) return CQuatT(0.f, 0.f, 0.f, 0.f); else { double div = (float) acos (w) / len; return CQuatT( (T)(x*div), (T)(y*div), (T)(z*div), 0.f); } } // *************************************************************************** template CQuatT CQuatT::exp() { double len; len = sqrt (x*x + y*y + z*z); if (len < QuatEpsilon) return CQuatT(0.f, 0.f, 0.f, 1.f); else { double len1 = sin(len) / len; return CQuatT( (T)(x*len1), (T)(y*len1), (T)(z*len1), (T)cos(len)); } } // *************************************************************************** template CQuatT CQuatT::lnDif(const CQuatT &q0, const CQuatT &q1) { CQuatT dif = q0.inverted()*q1; dif.normalize(); return dif.log(); } // *************************************************************************** template void CQuatT::makeClosest(const CQuatT &o) { if( dotProduct(*this, o) < 0 ) *this= -(*this); } // *************************************************************************** // *************************************************************************** // CQuat/CQuatD // *************************************************************************** // *************************************************************************** // *************************************************************************** /** * A float quaternion. * \author Antoine Viau. * \author Nevrax France * \date 2000 */ class CQuat : public CQuatT { public: static const CQuat Identity; /// \name Object // @{ CQuat &operator=(const CQuatT &o) {x=o.x; y=o.y; z=o.z; w=o.w; return *this;} CQuat(const CQuatT &o) : CQuatT(o) {} CQuat() {} CQuat(float X, float Y, float Z, float W) : CQuatT(X,Y,Z,W) {} /// ctor of a UNIT quaternion, from an angle axis. CQuat(const CVector &axis, float angle) : CQuatT(axis, angle) {} /// ctor of a UNIT quaternion, from an angle axis. CQuat(const CAngleAxis &aa) : CQuatT(aa) {} // @} }; // *************************************************************************** /** * A double quaternion. * \author Antoine Viau. * \author Nevrax France * \date 2000 */ class CQuatD : public CQuatT { public: static const CQuatD Identity; /// \name Object // @{ CQuatD &operator=(const CQuatT &o) {x=o.x; y=o.y; z=o.z; w=o.w; return *this;} CQuatD(const CQuatT &o) : CQuatT(o) {} CQuatD() {} CQuatD(double X, double Y, double Z, double W) : CQuatT(X,Y,Z,W) {} /// ctor of a UNIT quaternion, from an angle axis. CQuatD(const CVector &axis, float angle) : CQuatT(axis, angle) {} /// ctor of a UNIT quaternion, from an angle axis. CQuatD(const CAngleAxis &aa) : CQuatT(aa) {} // @} /// \name CQuat conversion. // @{ CQuatD(const CQuat &o) {x=o.x; y=o.y; z=o.z; w=o.w;} CQuatD &operator=(const CQuatT &o) {x=o.x; y=o.y; z=o.z; w=o.w; return *this;} operator CQuat() const {return CQuat((float)x, (float)y, (float)z, (float)w);} // @} }; } // NLMISC #endif // NL_QUAT_H ================================================ FILE: code/nel/include/nel/misc/random.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_RANDOM_H #define NL_RANDOM_H #include "types_nl.h" namespace NLMISC { /** A simple, os-independant random generator. * \author Nicolas Vizerie * \author Nevrax France * \date 2002 */ class CRandom { public: // The max value that can be returned by the random generator enum { RandMax = 0x7fff }; public: // ctor inline CRandom(); // generate a random value in [0, RandMax] inline sint32 rand(); // generate a random value in [0, mod] inline sint32 rand(uint16 mod); // generate a floating point random value in [0, mod] inline float frand(double mod=1.0f); // generate a random value in [-mod, mod] inline sint32 randPlusMinus(uint16 mod); // generate a random value in [-mod, mod] inline float frandPlusMinus(double mod=1.0); // set a new seed for the random generator inline void srand(sint32 seed); private: sint32 _Seed; }; //=========================================================================== inline CRandom::CRandom() : _Seed(1) { } //=========================================================================== // NB : In fact this random generator has the same behaviour than the VC6 one inline sint32 CRandom::rand() { return ((_Seed = _Seed * 214013L + 2531011L) >> 16) & RandMax; } //=========================================================================== inline sint32 CRandom::rand(uint16 mod) { sint32 m=mod; return rand()*(m+1)/(sint32(RandMax)+1); } //=========================================================================== inline sint32 CRandom::randPlusMinus(uint16 mod) { sint32 m=mod; return m - rand()*(2*m+1)/(sint32(RandMax)+1); } //=========================================================================== inline float CRandom::frand(double mod) { double r = (double) rand(); r /= (double) RandMax; return (float)(r * mod); } //=========================================================================== inline float CRandom::frandPlusMinus(double mod) { return frand(2*mod)-(float)mod; } //=========================================================================== inline void CRandom::srand(sint32 seed) { _Seed = seed; } } #endif ================================================ FILE: code/nel/include/nel/misc/reader_writer.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_READER_WRITER_H #define NL_READER_WRITER_H #include "types_nl.h" #include "mutex.h" namespace NLMISC { /** * This class allows a reader/writer ressource usage policy. * \author Benjamin Legros * \author Nevrax France * \date 2001 */ class CReaderWriter { private: volatile CMutex _Fairness; volatile CMutex _ReadersMutex; volatile CMutex _RWMutex; volatile sint _ReadersLevel; public: CReaderWriter(); ~CReaderWriter(); void enterReader() { const_cast(_Fairness).enter(); const_cast(_ReadersMutex).enter(); ++_ReadersLevel; if (_ReadersLevel == 1) const_cast(_RWMutex).enter(); const_cast(_ReadersMutex).leave(); const_cast(_Fairness).leave(); } void leaveReader() { const_cast(_ReadersMutex).enter(); --_ReadersLevel; if (_ReadersLevel == 0) const_cast(_RWMutex).leave(); const_cast(_ReadersMutex).leave(); } void enterWriter() { const_cast(_Fairness).enter(); const_cast(_RWMutex).enter(); const_cast(_Fairness).leave(); } void leaveWriter() { const_cast(_RWMutex).leave(); } }; /** * This class uses a CReaderWriter object to implement a synchronized object (see mutex.h for standard CSynchronized.) * \author Benjamin Legros * \author Nevrax France * \date 2001 */ template class CRWSynchronized { public: class CReadAccessor { CRWSynchronized *_RWSynchronized; public: CReadAccessor(CRWSynchronized *cs) { _RWSynchronized = cs; const_cast(_RWSynchronized->_RWSync).enterReader(); } ~CReadAccessor() { const_cast(_RWSynchronized->_RWSync).leaveReader(); } const T &value() { return const_cast(_RWSynchronized->_Value); } }; class CWriteAccessor { CRWSynchronized *_RWSynchronized; public: CWriteAccessor(CRWSynchronized *cs) { _RWSynchronized = cs; const_cast(_RWSynchronized->_RWSync).enterWriter(); } ~CWriteAccessor() { const_cast(_RWSynchronized->_RWSync).leaveWriter(); } T &value() { return const_cast(_RWSynchronized->_Value); } }; private: friend class CRWSynchronized::CReadAccessor; friend class CRWSynchronized::CWriteAccessor; volatile CReaderWriter _RWSync; volatile T _Value; }; } // NLMISC #endif // NL_READER_WRITER_H /* End of reader_writer.h */ ================================================ FILE: code/nel/include/nel/misc/rect.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_RECT_H #define NL_RECT_H #include "types_nl.h" namespace NLMISC { class CVector2f; /** * This class describe an integer 2d rectangle. * \author Cyril Corvazier * \author Nevrax France * \date 2000 */ class CRect { public: /// default ctor CRect() {} /// Constructor with a 2d point, a width and a height CRect (sint32 x, sint32 y, uint32 width, uint32 height); /// Constructor with a single 2d point. Build a rectangle with width and height = 0. CRect (sint32 x, sint32 y) { X=x; Y=y; Width=0; Height=0; } /// Set from a 2d point, a width and a height void setWH(sint32 x, sint32 y, uint32 width, uint32 height); /// Set from 2 2d points void set(sint32 x0, sint32 y0, sint32 x1, sint32 y1); /// Extend the box for including the point which coordinates are passed in parameter. void extend (sint32 x, sint32 y); /// Return the lower X coordinate of the box sint32 left() const { return X; } /// Return the higher X coordinate of the box + 1 sint32 right() const { return X+(sint32)Width; } /// Return the lower Y coordinate of the box sint32 top() const { return Y; } /// Return the higher Y coordinate of the box + 1 sint32 bottom() const { return Y+(sint32)Height; } /// Compute the x center of the rectangle sint32 getXCenter() const { return X+(sint32)(Width>>1); } /// Compute the y center of the rectangle sint32 getYCenter() const { return Y+(sint32)(Height>>1); } /// Lower X coordinate of the rect sint32 X; /// Lower Y coordinate of the rect sint32 Y; /// Width of the rect uint32 Width; /// Height of the rect uint32 Height; }; } // NLMISC #endif // NL_RECT_H /* End of rect.h */ ================================================ FILE: code/nel/include/nel/misc/report.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_REPORT_H #define NL_REPORT_H #include "types_nl.h" namespace NLMISC { /** Display a custom message box. * * \param title set the title of the report. If empty, it'll display "NeL report". * \param header message displayed before the edit text box. If empty, it displays the default message. * \param body message displayed in the edit text box. This string will be sent by email. * \param debugButton 0 for disabling it, 1 for enable with default behaviors (generate a breakpoint), 2 for enable with no behavior * * * * \return the button clicked or error */ enum TReportResult { ReportDebug, ReportIgnore, ReportQuit, ReportError }; TReportResult report (const std::string &title, const std::string &header, const std::string &subject, const std::string &body, bool enableCheckIgnore, uint debugButton, bool ignoreButton, sint quitButton, bool sendReportButton, bool &ignoreNextTime, const std::string &attachedFile = ""); /** call this in the main of your appli to enable email: setReportEmailFunction (sendEmail); */ void setReportEmailFunction (void *emailFunction); } // NLMISC #endif // NL_REPORT_H /* End of report.h */ ================================================ FILE: code/nel/include/nel/misc/resource_ptr.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_RESOURCE_PTR_H #define NL_RESOURCE_PTR_H #include "nel/misc/types_nl.h" #include "nel/misc/debug.h" #include "nel/misc/stream.h" #include "nel/misc/smart_ptr.h" #include namespace NLMISC { // For debug only. #define REF_TRACE(_s) ((void)0) //#define REF_TRACE(_s) nlinfo("%s: %d \n", _s, pinfo!=&CRefCount::NullPtrInfo?pinfo->RefCount:0) // *************************************************************************** /** * CResourcePtr: an handle on a ptr. T Must derive from CRefCount. * A CResourcePtr is a CRefPtr able to find its pointer using a key. * * This way, the resource can be loaded, unloaded, changed and the pointer stays valid. * Sample: *\code // Our resource type class CResource : NLMISC::CRefCount { public: int data; void thisIsGood(); }; // Provide a class to retrieve a resource using a key (here, it is a string) class CResourceFinder { public: static void *getResource (const std::string &key) { static CResource a; static CResource b; if (key == "a") return &a; if (key == "b") return &b; return NULL; } }; // Pointer typedef typedef CResourcePtr TAPtr; // Exemple of utilsation void foo() { // Get the "a" resource TAPtr rscA("a"); // The test call the cast operator and update the cached pointer. // If the pointer has been deleted, the function is called to retrieve a new pointer. // If the resource doesn't exist, it returns NULL. if (rscA) { // Use the pointer in cache, this is fast rscA->thisIsGood(); } // Get the "b" resource rsc = "b"; if (rsc) { // Use the pointer in cache, this is fast rsc->thisIsGood(); } } \endcode * * \b PERFORMANCE \b WARNING! operator=() and the cast operator are about 10 times slower than normal pointers. So use them wisely. * A good way to do it : using CResourcePtr in a debug mode in which the resources can be unloaded/reloaded, and using CStaticResourcePtr, else. * Also, an object used with a CResourcePtr will allocate a small PtrInfo (one only per object, not per ptr). * TPtr is the type of the pointed object. * TKey is the key used to retrieve the object pointer. * TResourceFinder is a class with a static method "static void *getResource (const TKey &key)" that returns a pointer on an object using a key. * If the function return a non NULL pointer (resource found), the ResourcePtr is initialised with it. * \sa CSmartPtr, CRefCount, CRefPtr * \author Cyril 'Hulud' Corvazier */ template class CResourcePtr { private: CRefCount::CPtrInfo *pinfo; // A ptr to the handle of the object. TKey Key; // The key used to find the pointer mutable TPtr *Ptr; // A cache for pinfo->Ptr. Useful to speed up ope->() and ope*() void unRef() const; // Just release the handle pinfo, but do not update pinfo/Ptr, if deleted. public: /// Init a NULL Ptr. CResourcePtr(); /// Retrieve a ptr using the key. If the pointer doesn't exist, the CResourcePtr is NULL. CResourcePtr(const TKey &key); /// Copy constructor. CResourcePtr(const CResourcePtr ©); /// Release the RefPtr. ~CResourcePtr(void); /// Cast operator. Check if the object has been deleted somewhere, and return NULL if this is the case. operator TPtr*() const; /// Cast operator. Check if the object has been deleted somewhere, and return NULL if this is the case. TPtr* getPtr() const; /** Indirection operator. Doesn't update the ptr and doesn't test if the pointer has been deleted, and doesn't check NULL. * You must test the pointer first using the cast operator. */ TPtr& operator*(void) const; /** Selection operator. Doesn't update the ptr and doesn't test if the pointer has been deleted, and doesn't check NULL. * You must test the pointer first using the cast operator. */ TPtr* operator->(void) const; /// Retrieve a ptr using the key. If the pointer doesn't exist, the CResourcePtr is NULL. CResourcePtr& operator=(const TKey &key); /// operator=. Giving a NULL pointer is a valid operation. CResourcePtr& operator=(const CResourcePtr ©); }; // *************************************************************************** /** * CStaticResourcePtr: a CResourcePtr remplacement that doesn't support the resource unload/reload. * The object size is the same than a standard pointer. * The pointer resource is retrieved at once and is keeped all along the life of the object. * No memory / cpu overhead. * Typically, you will use the CResourcePtr in a "reloadable resource version" of your software and * the CStaticResourcePtr in the release version of your software. * * \author Cyril 'Hulud' Corvazier */ template class CStaticResourcePtr { private: mutable TPtr *Ptr; // The pointer public: /// Init a NULL Ptr. CStaticResourcePtr(); /// Retrieve a ptr using the key. If the pointer doesn't exist, the CStaticResourcePtr is NULL. CStaticResourcePtr(const TKey &key); /// Copy constructor. CStaticResourcePtr(const CStaticResourcePtr ©); /// Release the RefPtr. ~CStaticResourcePtr(void); /// Cast operator. No check are done. operator TPtr*() const; /// Cast operator. No check are done. TPtr* getPtr() const; /// Indirection operator. No check are done. TPtr& operator*(void) const; /// Selection operator. No check are done. TPtr* operator->(void) const; /// Retrieve a ptr using the key. If the pointer doesn't exist, the CStaticResourcePtr is NULL. CStaticResourcePtr& operator=(const TKey &key); /// operator=. Giving a NULL pointer is a valid operation. CStaticResourcePtr& operator=(const CStaticResourcePtr ©); }; } // *************************************************************************** // *************************************************************************** // Implementation. // *************************************************************************** // *************************************************************************** #include "resource_ptr_inline.h" #undef SMART_TRACE #undef REF_TRACE #endif // NL_RESOURCE_PTR_H /* End of resource_ptr.h */ ================================================ FILE: code/nel/include/nel/misc/resource_ptr_inline.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_RESOURCE_PTR_INLINE_H #define NL_RESOURCE_PTR_INLINE_H #include "types_nl.h" namespace NLMISC { // *************************************************************************** #ifdef NL_OS_WINDOWS #define SMART_INLINE __forceinline #else #define SMART_INLINE inline #endif // *************************************************************************** // *************************************************************************** // CResourcePtr. // *************************************************************************** // *************************************************************************** // *************************************************************************** template SMART_INLINE void CResourcePtr::unRef() const { pinfo->RefCount--; if(pinfo->RefCount==0) { // In CResourcePtr, Never delete the object. // We may be in the case that this==NullPtrInfo, and our NullPtrInfo has done a total round. Test it. if(pinfo->IsNullPtrInfo) { // This should not happens, but I'm not sure :) ... // Reset the NullPtrInfo to a middle round. pinfo->RefCount= 0x7FFFFFFF; } else { // If the CResourcePtr still point to a valid object. if(pinfo->Ptr) { // Inform the Object that no more CResourcePtr points on it. ((TPtr*)(pinfo->Ptr))->pinfo= static_cast(&CRefCount::NullPtrInfo); } // Then delete the pinfo. delete pinfo; } } } // *************************************************************************** // Cons - dest. template inline CResourcePtr::CResourcePtr() { pinfo= static_cast(&CRefCount::NullPtrInfo); Ptr= NULL; REF_TRACE("Smart()"); } // *************************************************************************** template inline CResourcePtr::CResourcePtr(const TKey &key) { Key = key; Ptr = (TPtr*)TResourceFinder::getResource(Key); if(Ptr) { // If no CResourcePtr handles v, create a pinfo ref... if(Ptr->pinfo->IsNullPtrInfo) Ptr->pinfo=new CRefCount::CPtrInfo(Ptr); pinfo=Ptr->pinfo; // v is now used by this. pinfo->RefCount++; } else pinfo= static_cast(&CRefCount::NullPtrInfo); REF_TRACE("Smart(TPtr*)"); } // *************************************************************************** template inline CResourcePtr::CResourcePtr(const CResourcePtr ©) { pinfo=copy.pinfo; pinfo->RefCount++; Ptr= (TPtr*)pinfo->Ptr; Key= copy.Key; REF_TRACE("SmartCopy()"); } // *************************************************************************** template inline CResourcePtr::~CResourcePtr(void) { REF_TRACE("~Smart()"); unRef(); pinfo= static_cast(&CRefCount::NullPtrInfo); Ptr= NULL; } // *************************************************************************** // Operators=. template CResourcePtr &CResourcePtr::operator=(const TKey &key) { REF_TRACE("ope=(TPtr*)Start"); Key = key; Ptr = (TPtr*)TResourceFinder::getResource(Key); if(Ptr) { // If no CResourcePtr handles v, create a pinfo ref... if(Ptr->pinfo->IsNullPtrInfo) Ptr->pinfo=new CRefCount::CPtrInfo(Ptr); // The auto equality test is implicitly done by upcounting first "Ptr", then downcounting "this". Ptr->pinfo->RefCount++; unRef(); pinfo= Ptr->pinfo; } else { unRef(); pinfo= static_cast(&CRefCount::NullPtrInfo); } REF_TRACE("ope=(TPtr*)End"); return *this; } // *************************************************************************** template CResourcePtr &CResourcePtr::operator=(const CResourcePtr ©) { REF_TRACE("ope=(Smart)Start"); // The auto equality test is implicitly done by upcounting first "copy", then downcounting "this". copy.pinfo->RefCount++; unRef(); pinfo=copy.pinfo; // Must Refresh the ptr and the key. Ptr= (TPtr*)pinfo->Ptr; Key= copy.Key; REF_TRACE("ope=(Smart)End"); return *this; } // *************************************************************************** // Operations. /* Not needed for the moment in CResourcePtr template void CResourcePtr::kill() { REF_TRACE("SmartKill"); T *ptr= (T*)pinfo->Ptr; // First, release the refptr. unRef(); pinfo= static_cast(&CRefCount::NullPtrInfo); Ptr= NULL; // Then delete the pointer. if(ptr) delete ptr; }*/ // *************************************************************************** // Cast. template inline CResourcePtr::operator TPtr*() const { REF_TRACE("SmartCast TPtr*()"); // Refresh the Ptr. Ptr= (TPtr*)pinfo->Ptr; if (pinfo != static_cast(&CRefCount::NullPtrInfo)) { // Does the pointer has been deleted ? if (Ptr == NULL) { REF_TRACE("SmartCast TPtr*() has been deleted, get a new one"); // Try to get it Ptr = (TPtr*)TResourceFinder::getResource(Key); } else REF_TRACE("SmartCast TPtr*() has not been deleted"); } else REF_TRACE("SmartCast TPtr*() is NULL"); return Ptr; } // *************************************************************************** template inline TPtr* CResourcePtr::getPtr() const { return static_cast(*this); } // *************************************************************************** // Operators. template inline TPtr& CResourcePtr::operator*(void) const { REF_TRACE("Smart *()"); return *Ptr; } template inline TPtr* CResourcePtr::operator->(void) const { REF_TRACE("Smart ->()"); return Ptr; } // *************************************************************************** // *************************************************************************** // CStaticResourcePtr. // *************************************************************************** // *************************************************************************** // *************************************************************************** // Cons - dest. template inline CStaticResourcePtr::CStaticResourcePtr() { Ptr= NULL; REF_TRACE("Smart()"); } // *************************************************************************** template inline CStaticResourcePtr::CStaticResourcePtr(const TKey &key) { Ptr = (TPtr*)TResourceFinder::getResource(key); REF_TRACE("Smart(TPtr*)"); } // *************************************************************************** template inline CStaticResourcePtr::CStaticResourcePtr(const CStaticResourcePtr ©) { Ptr= copy.Ptr; REF_TRACE("SmartCopy()"); } // *************************************************************************** template inline CStaticResourcePtr::~CStaticResourcePtr(void) { REF_TRACE("~Smart()"); Ptr= NULL; } // *************************************************************************** // Operators=. template CStaticResourcePtr &CStaticResourcePtr::operator=(const TKey &key) { REF_TRACE("ope=(TPtr*)Start"); Ptr = (TPtr*)TResourceFinder::getResource(key); REF_TRACE("ope=(TPtr*)End"); return *this; } // *************************************************************************** template CStaticResourcePtr &CStaticResourcePtr::operator=(const CStaticResourcePtr ©) { REF_TRACE("ope=(Smart)Start"); Ptr= copy.Ptr; REF_TRACE("ope=(Smart)End"); return *this; } // *************************************************************************** // Operations. /* Not needed for the moment in CStaticResourcePtr template void CStaticResourcePtr::kill() { REF_TRACE("SmartKill"); T *ptr= (T*)pinfo->Ptr; // First, release the refptr. unRef(); pinfo= static_cast(&CRefCount::NullPtrInfo); Ptr= NULL; // Then delete the pointer. if(ptr) delete ptr; }*/ // *************************************************************************** // Cast. template inline CStaticResourcePtr::operator TPtr*() const { REF_TRACE("SmartCast TPtr*()"); return Ptr; } // *************************************************************************** template inline TPtr* CStaticResourcePtr::getPtr() const { return static_cast(*this); } // *************************************************************************** // Operators. template inline TPtr& CStaticResourcePtr::operator*(void) const { REF_TRACE("Smart *()"); return *Ptr; } template inline TPtr* CStaticResourcePtr::operator->(void) const { REF_TRACE("Smart ->()"); return Ptr; } // *************************************************************************** #undef SMART_INLINE } // NLMISC #endif // NL_RESOURCE_PTR_INLINE_H ================================================ FILE: code/nel/include/nel/misc/rgba.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_RGBA_H #define NL_RGBA_H #include "types_nl.h" #include "common.h" #include namespace NLMISC { class IStream; /** * Class pixel RGBA * \author Cyril Corvazier * \author Nevrax France * \date 2000 */ class CRGBA { public: /// Default constructor. do nothing CRGBA() {} /** * Constructor. * \param r Red componant. * \param g Green componant. * \param b Blue componant. * \param a Alpha componant. */ CRGBA(uint8 r, uint8 g, uint8 b, uint8 a=255) : R(r), G(g), B(b), A(a) {} /** * setup as a packed pixel */ void setPacked(uint packed) { R= (packed>>24)&255; G= (packed>>16)&255; B= (packed>>8)&255; A= packed & 255; } /** * Return a packed pixel */ uint getPacked() const {return ((uint)R<<24) + ((uint)G<<16) + ((uint)B<<8) + A;} /** * Comparison operator. */ bool operator<(CRGBA c) const {return getPacked()>8); G = uint8((c0.G*a2 + c1.G*a1) >>8); B = uint8((c0.B*a2 + c1.B*a1) >>8); A = uint8((c0.A*a2 + c1.A*a1) >>8); } /** * Modulate colors with a constant. * \param c0 Color 0. * \param a E [0,256]. c0*a returned into this. */ void modulateFromui (CRGBA c0, uint a) { R = uint8((c0.R*a) >>8); G = uint8((c0.G*a) >>8); B = uint8((c0.B*a) >>8); A = uint8((c0.A*a) >>8); } /** * Modulate colors with another color. * \param c0 Color 0. * \param c1 Color 1. c0*c1 returned into this. */ void modulateFromColor (CRGBA c0, CRGBA c1) { R = (c0.R*c1.R) >>8; G = (c0.G*c1.G) >>8; B = (c0.B*c1.B) >>8; A = (c0.A*c1.A) >>8; } /** * Set colors. * \param r Red componant. * \param g Green componant. * \param b Blue componant. * \param a Alpha componant. */ void set (uint8 r, uint8 g, uint8 b, uint8 a=255); /** * Convert to gray value */ uint8 toGray() const; /** * Get a 16 bits 565 pixel. */ uint16 get565 () const { return ((uint16)(R&0xf8)<<8) | ((uint16)(G&0xfc)<<3) | (uint16)(B>>3); } /** * Set the RGB fields with a 16 bits 565 pixel. */ void set565(uint16 col) { // unpack. R= col>>11; G= (col>>5)&0x3F; B= (col)&0x1F; // to 8 bits. R= (R<<3) + (R>>2); G= (G<<2) + (G>>4); B= (B<<3) + (B>>2); } /** * Compute in this the average of 2 RGBA. */ void avg2(CRGBA a, CRGBA b) { R= ((uint)a.R+(uint)b.R)>>1; G= ((uint)a.G+(uint)b.G)>>1; B= ((uint)a.B+(uint)b.B)>>1; A= ((uint)a.A+(uint)b.A)>>1; } /** * Compute in this the average of 4 RGBA. * The average is "correct": +1 is added to the four color, to make a "round" like average. */ void avg4(CRGBA a, CRGBA b, CRGBA c, CRGBA d) { R= ((uint)a.R+(uint)b.R+(uint)c.R+(uint)d.R+ 1)>>2; G= ((uint)a.G+(uint)b.G+(uint)c.G+(uint)d.G+ 1)>>2; B= ((uint)a.B+(uint)b.B+(uint)c.B+(uint)d.B+ 1)>>2; A= ((uint)a.A+(uint)b.A+(uint)c.A+(uint)d.A+ 1)>>2; } /** * Do the sum of 2 rgba, clamp, and store in this */ void add(CRGBA c0, CRGBA c1) { uint r,g,b,a; r= c0.R + c1.R; r= std::min(r, 255U); R= (uint8)r; g= c0.G + c1.G; g= std::min(g, 255U); G= (uint8)g; b= c0.B + c1.B; b= std::min(b, 255U); B= (uint8)b; a= c0.A + c1.A; a= std::min(a, 255U); A= (uint8)a; } /** * Compute c0 - c1, and store in this */ void sub(CRGBA c0, CRGBA c1) { sint r,g,b,a; r= c0.R - c1.R; r= std::max(r, 0); R= (uint8)r; g= c0.G - c1.G; g= std::max(g, 0); G= (uint8)g; b= c0.B - c1.B; b= std::max(b, 0); B= (uint8)b; a= c0.A - c1.A; a= std::max(a, 0); A= (uint8)a; } /// \name RGBOnly methods. Same f() as their homonym, but don't modify A component. // @{ /// see blendFromui() void blendFromuiRGBOnly(CRGBA c0, CRGBA c1, uint coef) // coef must be in [0,256] { uint a1 = coef; uint a2 = 256-a1; R = uint8((c0.R*a2 + c1.R*a1) >>8); G = uint8((c0.G*a2 + c1.G*a1) >>8); B = uint8((c0.B*a2 + c1.B*a1) >>8); } /// see modulateFromui() void modulateFromuiRGBOnly(CRGBA c0, uint a) { R = uint8((c0.R*a) >>8); G = uint8((c0.G*a) >>8); B = uint8((c0.B*a) >>8); } /// see modulateFromColor() void modulateFromColorRGBOnly(CRGBA c0, CRGBA c1) { R = (c0.R*c1.R) >>8; G = (c0.G*c1.G) >>8; B = (c0.B*c1.B) >>8; } /// see avg2() void avg2RGBOnly(CRGBA a, CRGBA b) { R= ((uint)a.R+(uint)b.R)>>1; G= ((uint)a.G+(uint)b.G)>>1; B= ((uint)a.B+(uint)b.B)>>1; } /// see avg4() void avg4RGBOnly(CRGBA a, CRGBA b, CRGBA c, CRGBA d) { R= ((uint)a.R+(uint)b.R+(uint)c.R+(uint)d.R+ 1)>>2; G= ((uint)a.G+(uint)b.G+(uint)c.G+(uint)d.G+ 1)>>2; B= ((uint)a.B+(uint)b.B+(uint)c.B+(uint)d.B+ 1)>>2; } /// see add() void addRGBOnly(CRGBA c0, CRGBA c1) { uint r,g,b; r= c0.R + c1.R; r= std::min(r, 255U); R= (uint8)r; g= c0.G + c1.G; g= std::min(g, 255U); G= (uint8)g; b= c0.B + c1.B; b= std::min(b, 255U); B= (uint8)b; } /// see sub() void subRGBOnly(CRGBA c0, CRGBA c1) { sint r,g,b; r= c0.R - c1.R; r= std::max(r, 0); R= (uint8)r; g= c0.G - c1.G; g= std::max(g, 0); G= (uint8)g; b= c0.B - c1.B; b= std::max(b, 0); B= (uint8)b; } // @} ///\name Color group manipulation //@{ /** Add a group of colors with saturation, using mmx instructions when present. * \param dest The destination color buffer, encoded as CRGBA's. * \param src1 The first source color buffer, encoded as CRGBA's. * \param src2 The second source color buffer, encoded as CRGBA's. * \param numColors The number of colors to compute * \param Stride between each source color. * \param Stride between each destination color. * \param Dup the number of time the result must be duplicated in the destination. */ static void addColors(CRGBA *dest, const CRGBA *src1, const CRGBA *src2, uint numColors, uint srcStride = sizeof(CRGBA), uint destStride = sizeof(CRGBA), uint dup = 1); /** Modulate a group of colors with saturation, using mmx instructions when present. * \param dest The destination color buffer, encoded as CRGBA's. * \param src1 The first source color buffer, encoded as CRGBA's. * \param src2 The second source color buffer, encoded as CRGBA's. * \param numColors The number of colors to compute * \param Stride between each color. It is the same for sources and destination. */ static void modulateColors(CRGBA *dest, const CRGBA *src1, const CRGBA *src2, uint numColors, uint srcStride = sizeof(CRGBA), uint destStride = sizeof(CRGBA), uint dup = 1); /** Subtract a group of colors with saturation (src1 - src2), using mmx instructions when present. * \param dest The destination color buffer, encoded as CRGBA's. * \param src1 The first source color buffer, encoded as CRGBA's. * \param src2 The second source color buffer, encoded as CRGBA's. * \param numColors The number of colors to compute * \param Stride between each color. It is the same for sources and destination. */ static void subtractColors(CRGBA *dest, const CRGBA *src1, const CRGBA *src2, uint numColors, uint srcStride = sizeof(CRGBA), uint destStride = sizeof(CRGBA), uint dup = 1); //@} /// \name Color space conversions RGB only //@{ /** Convert to HLS color space. * Lightness and satuation ranges from 0 to 1 * There's no range for hue, (all hues colors range from 0 to 360, from 360 to 720 and so on) * \return true if the color is achromatic */ bool convertToHLS(float &h, float &l, float &S) const; /** Build from HLS valued * Each component ranges from 0 to 1.f */ void buildFromHLS(float h, float l, float s); //@} static CRGBA stringToRGBA( const char *ptr ); std::string toString() const; bool fromString( const std::string &s ); /// Swap the B and R components, to simulate a CBRGA void swapBR() { std::swap(R,B); } /// Red componant. uint8 R; /// Green componant. uint8 G; /// Blue componant. uint8 B; /// Alpha componant. uint8 A; /// some colors static const CRGBA Black ; static const CRGBA Red ; static const CRGBA Green ; static const CRGBA Yellow ; static const CRGBA Blue ; static const CRGBA Magenta ; static const CRGBA Cyan ; static const CRGBA White ; }; /** * Class pixel BGRA, Windows style pixel. * \author Cyril Corvazier * \author Nevrax France * \date 2000 */ class CBGRA { public: /// Default constructor. do nothing CBGRA() {} /** * Constructor from a CRGBA * \param c CRGBA color. */ CBGRA(CRGBA c) { R=c.R; G=c.G; B=c.B; A=c.A; }; /** * Constructor. * \param r Red componant. * \param g Green componant. * \param b Blue componant. * \param a Alpha componant. */ CBGRA(uint8 r, uint8 g, uint8 b, uint8 a=255) : B(b), G(g), R(r), A(a) {} /** * Cast operator to CRGBA. */ operator CRGBA() { return CRGBA (R, G, B, A); } /** * Return a packed pixel */ uint getPacked() const { return ((uint)B<<24) + ((uint)G<<16) + ((uint)R<<8) + A; } /** * Comparison operator. */ bool operator<(const CBGRA &c) const { return getPacked() inline CRGBA blend(CRGBA c0, CRGBA c1, U blendFactor) { CRGBA result; result.blendFromui(c0, c1, (uint) ((float) blendFactor * 256.f)); return result; } /** * Class pixel float RGBA * \author Cyril Corvazier * \author Nevrax France * \date 2000 */ class CRGBAF { public: /// Default constructor. do nothing CRGBAF () {} /** * Constructor. * \param _r Red componant. * \param _g Green componant. * \param _b Blue componant. * \param _a Alpha componant. */ CRGBAF (float _r, float _g, float _b, float _a=1.f) { R=_r; G=_g; B=_b; A=_a; } /** * Constructor with a CRGBA. * \param c CRGBA color. */ CRGBAF (CRGBA c) { R=(float)c.R/255.f; G=(float)c.G/255.f; B=(float)c.B/255.f; A=(float)c.A/255.f; } /** * Cast operator to CRGBA. */ operator CRGBA() const { uint8 _r=(uint8)(R*255.f); uint8 _g=(uint8)(G*255.f); uint8 _b=(uint8)(B*255.f); uint8 _a=(uint8)(A*255.f); return CRGBA (_r, _g, _b, _a); } /** * Normalize component between [0.f,1.f] */ void normalize () { R= (R>1.f) ? 1.f : (R<0.f) ? 0.f : R; G= (G>1.f) ? 1.f : (G<0.f) ? 0.f : G; B= (B>1.f) ? 1.f : (B<0.f) ? 0.f : B; A= (A>1.f) ? 1.f : (A<0.f) ? 0.f : A; } /** * Add operator. Sum components. * \param c CRGBA color. * \return Return the result of the opertor */ CRGBAF operator+ (const CRGBAF& c) const { return CRGBAF (R+c.R, G+c.G, B+c.B, A+c.A); } /** * Sub operator. Substract components. * \param c CRGBA color. * \return Return the result of the opertor */ CRGBAF operator- (const CRGBAF& c) const { return CRGBAF (R-c.R, G-c.G, B-c.B, A-c.A); } /** * Mul operator. Mul components. * \param c CRGBA color. * \return Return the result of the opertor */ CRGBAF operator* (const CRGBAF& c) const { return CRGBAF (R*c.R, G*c.G, B*c.B, A*c.A); } /** * Mul float operator. Mul each component by f. * \param f Float factor. * \return Return the result of the opertor */ CRGBAF operator* (float f) const { return CRGBAF (R*f, G*f, B*f, A*f); } /** * Div float operator. Div each component by f. * \param f Float factor. * \return Return the result of the opertor */ CRGBAF operator/ (float f) const { return CRGBAF (R/f, G/f, B/f, A/f); } /** * Add operator. Add each component. * \param c CRGBA color. * \return Return a reference on the caller object */ CRGBAF& operator+= (const CRGBAF& c) { R+=c.R; G+=c.G; B+=c.B; A+=c.A; return *this; } /** * Sub operator. Substract each component. * \param c CRGBA color. * \return Return a reference on the caller object */ CRGBAF& operator-= (const CRGBAF& c) { R-=c.R; G-=c.G; B-=c.B; A-=c.A; return *this; } /** * Mul operator. Multiplate each component. * \param c CRGBA color. * \return Return a reference on the caller object */ CRGBAF& operator*= (const CRGBAF& c) { R*=c.R; G*=c.G; B*=c.B; A*=c.A; return *this; } /** * Mul float operator. Multiplate each component by f. * \param f Float factor. * \return Return a reference on the caller object */ CRGBAF& operator*= (float f) { R*=f; G*=f; B*=f; A*=f; return *this; } /** * Div float operator. Divide each component by f. * \param f Float factor. * \return Return a reference on the caller object */ CRGBAF& operator/= (float f) { R/=f; G/=f; B/=f; A/=f; return *this; } /** * Serialisation. * \param f Stream used for serialisation. */ void serial(class NLMISC::IStream &f); /** * Set colors. * \param r Red componant. * \param g Green componant. * \param b Blue componant. * \param a Alpha componant. */ void set(float r, float g, float b, float a); /// Red componant. float R; /// Green componant. float G; /// Blue componant. float B; /// Alpha componant. float A; }; /** * Mul float operator. Multiplate each component by f. * \param f Float factor. * \return Return the result */ inline CRGBAF operator* (float f, const CRGBAF& c) { return CRGBAF (c.R*f, c.G*f, c.B*f, c.A*f); } #ifdef NL_LITTLE_ENDIAN #define NL_RGBA_R_DWORD_MASK (0x000000ff) #define NL_RGBA_G_DWORD_MASK (0x0000ff00) #define NL_RGBA_B_DWORD_MASK (0x00ff0000) #define NL_RGBA_A_DWORD_MASK (0xff000000) #else // NL_LITTLE_ENDIAN #define NL_RGBA_R_DWORD_MASK (0xff0000) #define NL_RGBA_G_DWORD_MASK (0x00ff0000) #define NL_RGBA_B_DWORD_MASK (0x0000ff00) #define NL_RGBA_A_DWORD_MASK (0x000000ff) #endif // NL_LITTLE_ENDIAN } // NLMISC #endif // NL_RGBA_H /* End of rgba.h */ ================================================ FILE: code/nel/include/nel/misc/sha1.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_SHA1_H #define NL_SHA1_H #include "types_nl.h" #include "common.h" #include "stream.h" #include struct CHashKey { CHashKey () { HashKeyString.resize(20); } CHashKey (const unsigned char Message_Digest[20]) { HashKeyString = ""; for(sint i = 0; i < 20 ; ++i) { HashKeyString += Message_Digest[i]; } } // Init the hash key with a binary key format or a text key format CHashKey (const std::string &str) { if (str.size() == 20) { HashKeyString = str; } else if (str.size() == 40) { HashKeyString = ""; for(uint i = 0; i < str.size(); i+=2) { uint8 val; if (isdigit((unsigned char)str[i+0])) val = str[i+0]-'0'; else val = 10+tolower(str[i+0])-'a'; val *= 16; if (isdigit((unsigned char)str[i+1])) val += str[i+1]-'0'; else val += 10+tolower(str[i+1])-'a'; HashKeyString += val; } } else { nlwarning ("SHA: Bad hash key format"); } } // return the hash key in text format std::string toString() const { std::string str; for (uint i = 0; i < HashKeyString.size(); i++) { str += NLMISC::toString("%02X", (uint8)(HashKeyString[i])); } return str; } // serial the hash key in binary format void serial (NLMISC::IStream &stream) { stream.serial (HashKeyString); } bool operator==(const CHashKey &v) const { return HashKeyString == v.HashKeyString; } // this string is always 20 bytes long and is the code in binary format (can't print it directly) std::string HashKeyString; }; inline bool operator <(const struct CHashKey &a,const struct CHashKey &b) { return a.HashKeyString // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_SHARED_MEMORY_H #define NL_SHARED_MEMORY_H #include "types_nl.h" #ifdef NL_OS_WINDOWS #include #endif namespace NLMISC { #ifdef NL_OS_WINDOWS typedef const char *TSharedMemId; #else typedef key_t TSharedMemId; #endif /* Helpers: * toSharedMemId: converts an integer to TSharedMemId * NL_SMID: format type used for printf syntax. Ex: nldebug( "Segment %"NL_SMID" was created", sharedMemId ); */ #ifdef NL_OS_WINDOWS #define toSharedMemId( id ) toString( "NeLSM_%d", id ).c_str() #define NL_SMID "s" #else #define toSharedMemId( id ) (id) #define NL_SMID "d" #endif /** * Encapsulation of shared memory APIs. * Using file mapping under Windows, System V shared memory (shm) under Linux. * * Note: under Linux, an option could be added to prevent a segment to be swapped out. * * \author Olivier Cado * \author Nevrax France * \date 2002 */ class CSharedMemory { public: // Constructor //CSharedMemory(); /** * Create a shared memory segment and get access to it. The id must not be used. * The id 0x3a732235 is reserved by the NeL memory manager. * \return Access address of the segment of the choosen size */ static void * createSharedMemory( TSharedMemId sharedMemId, uint32 size ); /** * Get access to an existing shared memory segment. The id must be used. * \return Access address of the segment. Its size was determined at the creation. */ static void * accessSharedMemory( TSharedMemId sharedMemId ); /** * Close (detach) a shared memory segment, given the address returned by createSharedMemory() * or accessSharedMemory(). Must be called by each process that called createSharedMemory() * or accessSharedMemory(). */ static bool closeSharedMemory( void * accessAddress ); /** * Destroy a shared memory segment (must be called by the process that created the segment, * not by the accessors). * * "Rescue feature": set "force" to true if a segment was created and left out of * control (meaning a new createSharedMemory() with the same sharedMemId fails), but * before, make sure the segment really belongs to you! * * Note: this method does nothing under Windows, destroying is automatic. * Under Unix, the segment will actually be destroyed after the last detach * (quoting shmctl man page). It means after calling destroySharedMemory(), the * segment is still accessible by another process until it calls closeSharedMemory(). */ static void destroySharedMemory( TSharedMemId sharedMemId, bool force=false ); }; } // NLMISC #endif // NL_SHARED_MEMORY_H /* End of shared_memory.h */ ================================================ FILE: code/nel/include/nel/misc/sheet_id.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_SHEET_ID_H #define NL_SHEET_ID_H // misc #include "types_nl.h" #include "stream.h" #include "static_map.h" // std #include #include namespace NLMISC { #ifdef NL_DEBUG # define NL_DEBUG_SHEET_ID #endif // Use 24 bits id and 8 bits file types #define NL_SHEET_ID_ID_BITS 24 #define NL_SHEET_ID_TYPE_BITS 32 - NL_SHEET_ID_ID_BITS /** * CSheetId * * \author Stephane Coutelas * \author Nevrax France * \date 2002 */ class CSheetId { public : /// Unknow CSheetId is similar as an NULL pointer. static const CSheetId Unknown; /** * Constructor */ explicit CSheetId( uint32 sheetRef = 0 ); /** * Constructor */ explicit CSheetId( const std::string& sheetName ); /** * Constructor, uses defaultType as extension when sheetName * contains no file extension. */ explicit CSheetId( const std::string& sheetName, const std::string &defaultType ); // build from a string and returns true if the build succeed bool buildSheetId(const std::string& sheetName); // build from a SubSheetId and a type void buildSheetId(uint32 shortId, uint32 type); /** * Load the association sheet ref / sheet name */ static void init(bool removeUnknownSheet = true); /** * Init the sheet id to work without knowlege of sheet name */ static void initWithoutSheet(); /** * Remove all allocated memory */ static void uninit(); /** * Return the **whole** sheet id (id+type) */ uint32 asInt() const { return _Id.Id; } /** * Return the sheet type (sub part of the sheetid) */ uint32 getSheetType() const { return _Id.IdInfos.Type; } /** * Return the sheet sub id (sub part of the sheetid) */ uint32 getShortId() const { return _Id.IdInfos.Id; } /** * Operator= */ CSheetId& operator=( const CSheetId& sheetId ); /** * Operator= */ CSheetId& operator=( const std::string& sheetName ); /** * Operator= */ CSheetId& operator=( uint32 sheetRef ); /** * Operator< */ bool operator < (const CSheetId& sheetRef ) const; /** * Operator== */ inline bool operator == (const CSheetId& sheetRef ) const { return ( _Id.Id == sheetRef._Id.Id) ; } /** * Operator != */ inline bool operator != (const CSheetId& sheetRef ) const { return (_Id.Id != sheetRef._Id.Id) ; } /** * Return the sheet id as a string * If the sheet id is not found, then: * - if 'ifNotFoundUseNumericId==false' the returned string is "" with the id in %d * - if 'ifNotFoundUseNumericId==tue' the returned string is "#%u" with the id in %u */ std::string toString(bool ifNotFoundUseNumericId=false) const; /** * Serial */ void serial(NLMISC::IStream &f) throw(NLMISC::EStream); void serialString(NLMISC::IStream &f, const std::string &defaultType = "") throw(NLMISC::EStream); /** * Display the list of valid sheet ids with their associated file names * if (type != -1) then restrict list to given type */ static void display(); static void display(uint32 type); /** * Generate a vector of all the sheet ids of a given type * This operation is non-destructive, the new entries are appended to the result vector * note: fileExtension *not* include the '.' eg "bla" and *not* ".bla" **/ static void buildIdVector(std::vector &result); static void buildIdVector(std::vector &result, uint32 type); static void buildIdVector(std::vector &result, std::vector &resultFilenames, uint32 type); static void buildIdVector(std::vector &result, const std::string &fileExtension); static void buildIdVector(std::vector &result, std::vector &resultFilenames, const std::string &fileExtension); /** * Convert between file extensions and numeric sheet types * note: fileExtension *not* include the '.' eg "bla" and *not* ".bla" **/ static const std::string &fileExtensionFromType(uint32 type); static uint32 typeFromFileExtension(const std::string &fileExtension); private : /// sheet id union TSheetId { uint32 Id; struct { uint32 Type : NL_SHEET_ID_TYPE_BITS; uint32 Id : NL_SHEET_ID_ID_BITS; } IdInfos; }; TSheetId _Id; #ifdef NL_DEBUG_SHEET_ID // Add some valuable debug information to sheetId const char *_DebugSheetName; #endif /// associate sheet id and sheet name //static std::map _SheetIdToName; //static std::map _SheetNameToId; class CChar { public: char *Ptr; CChar() { Ptr = NULL; } CChar(const CChar& c) { Ptr = c.Ptr; } // WARNING : Share Pointer }; class CCharComp { public: bool operator()(CChar x, CChar y) const { return strcmp(x.Ptr, y.Ptr) < 0; } }; static CChar _AllStrings; static CStaticMap _SheetIdToName; static CStaticMap _SheetNameToId; static std::vector _FileExtensions; static bool _Initialised; static bool _RemoveUnknownSheet; static void loadSheetId (); static void loadSheetAlias (); static void cbFileChange (const std::string &filename); /** * When initialized without sheet_id.bin, the sheet id are assigned * dynamically. Separate maps are used, because in sheet_id.bin * mode it uses static maps optimized during load. */ static bool _DontHaveSheetKnowledge; static std::map _DevTypeNameToId; /// outer vector is type, inner vector is sheet id static std::vector > _DevSheetIdToName; static std::map _DevSheetNameToId; }; /** * Class to be used as a hash traits for a hash_map accessed by CSheetId * Ex: hash_map< CSheetId, CMyData, CSheetIdHashMapTraits> _MyHashMap; */ class CSheetIdHashMapTraits { public: enum { bucket_size = 4, min_buckets = 8, }; inline size_t operator() ( const CSheetId& sheetId ) const { return sheetId.asInt() >> 5; } bool operator() (const CSheetId &strId1, const CSheetId &strId2) const { return strId1.asInt() < strId2.asInt(); } }; } // NLMISC #endif // NL_SHEET_ID_H /* End of sheet_id.h */ ================================================ FILE: code/nel/include/nel/misc/singleton.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_SINGLETON_H #define NL_SINGLETON_H #include "nel/misc/common.h" #include "nel/misc/debug.h" #include "nel/misc/thread.h" #include "nel/misc/app_context.h" namespace NLMISC { /** * Example: * \code struct CFooSingleton : public CSingleton { void foo() { nlinfo("foo!"); } }; // call the foo function: CFooSingleton::getInstance().foo(); * \endcode * \author Vianney Lecroart * \author Nevrax France * \date 2004 */ template class CSingleton { public: virtual ~CSingleton() {} /// returns a reference and not a pointer to be sure that the user /// doesn't have to test the return value and can directly access the class static T &getInstance() { if(!Instance) { Instance = new T; nlassert(Instance); } return *Instance; } /// shorter version of getInstance() static T &instance() { return getInstance(); } static void releaseInstance() { if(Instance) { delete Instance; Instance = NULL; } } protected: /// no public ctor to be sure that the user can't create an instance CSingleton() { } static T *Instance; }; template T* CSingleton::Instance = 0; /** A variant of the singleton, not fully compliant with the standard design pattern * It is more appropriate for object built from a factory but that must * be instanciate only once. * The singleton paradigm allow easy access to the unique instance but * I removed the automatic instanciation of getInstance(). * * Consequently, the getInstance return a pointer that can be NULL * if the singleton has not been build yet. * * Example: * \code struct CFooSingleton : public CManualSingleton { void foo() { nlinfo("foo!"); } }; // create an instance by any mean CFooSingleton mySingleton // call the foo function: CFooSingleton::getInstance()->foo(); // create another instance is forbiden CFooSingleton otherInstance; // ASSERT ! * \endcode * \author Boris 'sonix' Boucher * \author Nevrax France * \date 2005 */ template class CManualSingleton { static T *&_instance() { static T *instance = NULL; return instance; } protected: CManualSingleton() { nlassert(_instance() == NULL); _instance() = static_cast(this); } ~CManualSingleton() { nlassert(_instance() == this); _instance() = NULL; } public: static bool isInitialized() { return _instance() != NULL; } static T* getInstance() { nlassert(_instance() != NULL); return _instance(); } }; /** A macro for safe global variable value. * Concept : global initialized variable value are inherently unsafe because the order of * initialisation if undefined. If some init code use static value, you * may encounter hazardous error, depending on you compiler will, when you * read the value of a global, you may read it before it is initialized. * This little class is a workaround that allow a safe global value. * A drawback is that the value is enclosed inside a function and thus not * accessible in the debugger. * use getGlobal_() to retrieve a reference to the value. */ #define NL_MISC_SAFE_GLOBAL(type, name, value) \ type &getGlobal_##name() \ { \ static type theVar = (value); \ return theVar; \ } \ #define NL_MISC_SAFE_CLASS_GLOBAL(type, name, value) \ static type &getGlobal_##name() \ { \ static type theVar = (value); \ return theVar; \ } \ } // NLMISC #endif // NL_SINGLETON_H /* End of singleton.h */ ================================================ FILE: code/nel/include/nel/misc/smart_ptr.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_SMART_PTR_H #define NL_SMART_PTR_H #include "types_nl.h" #include "debug.h" #include "stream.h" #include namespace NLMISC { // *************************************************************************** /** * To use CSmartPtr or CRefPtr, derive from this class. * Your class doens't have to be virtual, or doesn't have to provide a virtual dtor. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CRefCount { public: /// Destructor which release pinfo if necessary. ~CRefCount(); /// Default constructor init crefs to 0. CRefCount() { crefs = 0; pinfo=static_cast(&NullPtrInfo); } /* The instance handle. Can't put those to private since must be used by CRefPtr (and friend doesn't work with template). Use struct CPtrInfoBase / CPtrInfo idiom for NullPtrInfo, because of problems of static constructor: NullPtrInfo must be init BEFORE ANY constructor calls. */ struct CPtrInfoBase { const CRefCount* Ptr; // to know if the instance is valid. sint RefCount; // RefCount of ptrinfo (!= instance) bool IsNullPtrInfo; // For dll problems, must use a flag to mark NullPtrInfo. }; struct CPtrInfo : public CPtrInfoBase { CPtrInfo(CRefCount const* p) {Ptr=p; RefCount=0; IsNullPtrInfo=false;} }; // OWN null for ref ptr. (Optimisations!!!) static CPtrInfoBase NullPtrInfo; friend struct CPtrInfo; // for special case use only. inline const sint &getRefCount() const { return crefs; } public: // Can't put this to private since must be used by CSmartPtr (and friend doesn't work with template). // Provide incref()/decref() function doen't work since decref() can't do a delete this on a non virtual dtor. // So Ptr gestion can only be used via CSmartPtr. mutable sint crefs; // The ref counter for SmartPtr use. mutable CPtrInfo *pinfo; // The ref ptr for RefPtr use. /// operator= must NOT copy crefs/pinfo!! CRefCount &operator=(const CRefCount &) {return *this;} /// copy cons must NOT copy crefs/pinfo!! CRefCount(const CRefCount &) {crefs = 0; pinfo=static_cast(&NullPtrInfo);} }; // To use CVirtualRefPtr (or if you just want to have a RefCount with virtual destructor), derive from this class. class CVirtualRefCount : public CRefCount { public: /// Virtual destructor virtual ~CVirtualRefCount() {} }; // *************************************************************************** // For debug only. #define SMART_TRACE(_s) ((void)0) #define REF_TRACE(_s) ((void)0) //#define SMART_TRACE(_s) printf("%s: %d \n", _s, Ptr?Ptr->crefs:0) //#define REF_TRACE(_s) printf("%s: %d \n", _s, pinfo!=&CRefCount::NullPtrInfo?pinfo->RefCount:0) /** * Standard SmartPtr class. T Must derive from CRefCount. * Once a normal ptr is assigned to a SmartPtr, the smartptr will own this pointer, and delete it when no other smartptr * reference the object (with a reference couting scheme). The following code works, since the object himself must herit * from CRefCount, and so hold the refcount. * \code CSmartPtr a0, a1; A *p0; a0= new A; // Ok. RefCount==1. p0= a0; // Ok, cast operator. object still owned by a0. a1= p0; // Ok!! RefCount==2. Object owned by a0 and a1; // At destruction, a1 unref(), then a0 unref() and delete the object. \endcode * * The ref counter cannot be put directly in the smartptr since the preceding behavior must be supported and inheritance must be supported too. * Here, if A is a base class of B, Pa and Pb are smartptr of a and b respectively, then \c Pa=Pb; is a valid operation. * But, doing this, you may ensure that you have a virtual dtor(), since dtor() Pa may call ~A() (or you may ensure that Pa * won't destruct A, which it sound much more as a normal pointer :) ). * * Sample: *\code class A : public CRefCount { public: A() {puts("A()");} virtual ~A() {puts("~A()");} }; class B : public A { public: B() {puts("B()");} ~B() {puts("~B()");} }; void testPtr() { CSmartPtr a0,a1,a2; CSmartPtr b0; a0= new A; a1= a0; a1= new A; a2= a1; a1=NULL; b0= new B; a0=b0; printf("%d\n", (A*)NULL==a0); printf("%d\n", b0!=a0); printf("%d\n", (A*)NULL==a1); printf("%d\n", a2!=a0); } *\endcode * * SmartPtr are compatible with RefPtr. A ptr may be link to a CRefPtr and a CSmartPtr. As example, when the CSmartPtr * will destroy him, CRefPtr will be informed... * Sample: *\code void foo() { A *p; CSmartPtr sp; CRefPtr rp; p= new A; sp= p; // OK. p is now owned by sp and will be deleted by sp. rp= p; // OK. rp handle p. sp= NULL; // Destruction. p deleted. rp automatically informed. p= rp; // result: p==NULL. } \endcode * * \b PERFORMANCE \b WARNING! operator=() are about 10 times slower than normal pointers. * For local use, prefer cast the smartptr to a normal Ptr. * \sa CRefPtr * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ template class CSmartPtr { T* Ptr; public: typedef T element_type; /// Init a NULL Ptr. CSmartPtr() { Ptr=NULL; SMART_TRACE("ctor()"); } /// Attach a ptr to a SmartPtr. CSmartPtr(T* p) { Ptr=p; if(Ptr) Ptr->crefs++; SMART_TRACE("ctor(T*)"); } /// Copy constructor. CSmartPtr(const CSmartPtr ©) { Ptr=copy.Ptr; if(Ptr) Ptr->crefs++; SMART_TRACE("ctor(Copy)"); } /// Release the SmartPtr. ~CSmartPtr(); /// Cast operator. operator T*(void) const { SMART_TRACE("castT*()"); return Ptr; } /// Indirection operator. Doesn't check NULL. T& operator*(void) const { SMART_TRACE("ope*()"); return *Ptr; } /// Selection operator. Doesn't check NULL. T* operator->(void) const { SMART_TRACE("ope->()"); return Ptr; } /// returns if there's no object pointed by this SmartPtr. bool isNull () const { return Ptr==NULL; } /// Return the pointer T *getPtr() const { return Ptr;} /// operator=. Giving a NULL pointer is a valid operation. CSmartPtr& operator=(T* p); /// operator=. Giving a NULL pointer is a valid operation. CSmartPtr& operator=(const CSmartPtr &p); /// operator<. Compare the pointers. bool operator<(const CSmartPtr &p) const; sint getNbRef() { if(Ptr) return Ptr->crefs; else return 0; } // No need to do any operator==. Leave the work to cast operator T*(void). std::string toString() { if(Ptr) return toString(*Ptr); else return ""; } // serial using serialPtr void serialPtr(NLMISC::IStream &f) throw(NLMISC::EStream ) { T* obj= NULL; if(f.isReading()) { f.serialPtr(obj); // assign correctly (NB: obj may be NULL) *this= obj; } else { obj= Ptr; f.serialPtr(obj); } } // serial using serialPloyPtr void serialPolyPtr(NLMISC::IStream &f) throw(NLMISC::EStream ) { T* obj= NULL; if(f.isReading()) { f.serialPolyPtr(obj); // assign correctly (NB: obj may be NULL) *this= obj; } else { obj= Ptr; f.serialPolyPtr(obj); } } }; // *************************************************************************** /** * CRefPtr: an handle on a ptr. T Must derive from CRefCount. * If you use CRefPtr, you can kill the object simply by calling delete (T*)RefPtr, or the kill() method. All other CRefPtr which * point to it can know if it has been deleted. (but you must be sure that this ptr is not handle by a SmartPtr, of course...) * * SmartPtr are compatible with RefPtr. A ptr may be link to a CRefPtr and a CSmartPtr. As example, when the CSmartPtr * will destroy him, CRefPtr will be informed... * Sample: *\code void foo() { A *p; CSmartPtr sp; CRefPtr rp; p= new A; sp= p; // OK. p is now owned by sp and will be deleted by sp. rp= p; // OK. rp handle p. sp= NULL; // Destruction. p deleted. rp automatically informed. if(rp==NULL) thisIsGood(); // rp==NULL. } \endcode * * \b PERFORMANCE \b WARNING! operator=() are about 10 times slower than normal pointers. So use them wisely. * For local use, prefer cast the refptr to a normal Ptr. * Also, an object used with a CRefPtr will allocate a small PtrInfo (one only per object, not per ptr). * \sa CSmartPtr */ template class CRefPtr { private: CRefCount::CPtrInfo *pinfo; // A ptr to the handle of the object. mutable T *Ptr; // A cache for pinfo->Ptr. Useful to speed up ope->() and ope*() void unRef() const; // Just release the handle pinfo, but do not update pinfo/Ptr, if deleted. public: /// Init a NULL Ptr. CRefPtr(); /// Attach a ptr to a RefPtr. CRefPtr(T *v); /// Copy constructor. CRefPtr(const CRefPtr ©); /// Release the RefPtr. ~CRefPtr(void); /// Cast operator. Check if the object has been deleted somewhere, and return NULL if this is the case. operator T*() const; /// Indirection operator. Doesn't test if ptr has been deleted somewhere, and doesn't check NULL. T& operator*(void) const; /// Selection operator. Doesn't test if ptr has been deleted somewhere, and doesn't check NULL. T* operator->(void) const; /// operator=. Giving a NULL pointer is a valid operation. CRefPtr& operator=(T *v); /// operator=. Giving a NULL pointer is a valid operation. CRefPtr& operator=(const CRefPtr ©); /** * kill/delete the object pointed by the pointer, and inform the other RefPtr of this. * "rp.kill()" and "delete (T*)rp" do the same thing, except that rp NULLity is updated with kill(). * RefPtr which point to the same object could know if the object is valid, by just testing it ( * by an implicit call to the cast operator to T*). But any calls to operator->() or operator*() will have * unpredictible effects (may crash... :) ). */ void kill(); // serial using serialPloyPtr void serialPolyPtr(NLMISC::IStream &f) throw(NLMISC::EStream ) { T* obj= NULL; if(f.isReading()) { f.serialPolyPtr(obj); // assign correctly (NB: obj may be NULL) *this= obj; } else { obj= Ptr; f.serialPolyPtr(obj); } } }; #if defined(NL_COMP_VC) && NL_COMP_VC_VERSION >= 80 // This operator only purpose is to compare with NULL value template bool operator == (const CRefPtr &refPtr, int null) { nlassert(null == 0); return (T*)refPtr == (T*)null; } #endif template bool operator == (const CRefPtr &refPtr, T *ptr) { return (T*)refPtr == ptr; } template bool operator == (const CRefPtr &leftRef, const CRefPtr &rightRef) { return (T*)leftRef == (T*) rightRef; } template class CVirtualRefPtr { private: CRefCount::CPtrInfo *pinfo; // A ptr to the handle of the object. mutable T *Ptr; // A cache for pinfo->Ptr. Useful to speed up ope->() and ope*() void unRef() const; // Just release the handle pinfo, but do not update pinfo/Ptr, if deleted. public: /// Init a NULL Ptr. CVirtualRefPtr(); /// Attach a ptr to a VirtualRefPtr. CVirtualRefPtr(T *v); /// Copy constructor. CVirtualRefPtr(const CVirtualRefPtr ©); /// Release the VirtualRefPtr. ~CVirtualRefPtr(void); /// Cast operator. Check if the object has been deleted somewhere, and return NULL if this is the case. operator T*() const; /// Indirection operator. Doesn't test if ptr has been deleted somewhere, and doesn't check NULL. T& operator*(void) const; /// Selection operator. Doesn't test if ptr has been deleted somewhere, and doesn't check NULL. T* operator->(void) const; /// operator=. Giving a NULL pointer is a valid operation. CVirtualRefPtr& operator=(T *v); /// operator=. Giving a NULL pointer is a valid operation. CVirtualRefPtr& operator=(const CVirtualRefPtr ©); /** * kill/delete the object pointed by the pointer, and inform the other VirtualRefPtr of this. * "rp.kill()" and "delete (T*)rp" do the same thing, except that rp NULLity is updated with kill(). * VirtualRefPtr which point to the same object could know if the object is valid, by just testing it ( * by an implicit call to the cast operator to T*). But any calls to operator->() or operator*() will have * unpredictible effects (may crash... :) ). */ void kill(); // No need to do any operator==. Leave the work to cast operator T*(void). }; /** * A little quick coded class made to find invalid object pointer existence while a destructor call on an objet. * Futur job is to do not have CstCDbgPtr .. (error due to a lack of time). * * Feature: * If you try to delete an object and if there still some pointer referencing it, it causes an assertion. * This Debug feature depends on NL_DEBUG_PTR definition (change it as your convenience). * These are only debug classes and are not design to use information for your code comportment * as they are made to desappear in final version (NL_DEBUG_PTR undefined), * so don't use method calls outside NL_DEBUG_PTR scope. * * How to: * Derivate your objet from CDbgRefCount where T is the type of pointer you allow to use on this object (you can use many). * then use CDbgPtr to point an object of type T (which must derivates from CDbgRefCount), its the pointer. * * Warning: * Be carefull to derivates first from CDbgRefCount as derivation order implicates constructor/destructor order calls. * Sometimes u may have to write some explicit casts, don't worry, it would be only common courtesy ;) * * Futur work (only if you need it): * enhanced features (like __FILE__ __LINE__ information). * * Extension by Jerome Vuarand * I've added additional information to trace back invalid pointers. A linked list in the ref counter can be used to access to * invalid pointers on referenced object deletion, and an additionnal data field in each pointer let pointer owner to specify * additionnal information. The linked list insertion occurs on head. The linked is doubly-linked to avoid parsing it on deletion. * When a reference is still present on referenced object deletion, an assert is issued and access to pointers is given. Each * CDbgPtr owner can attach a data pointer to the CDbgPtr. A good way to use the feature is to derive the owner from IDbgPtrData, * pass this as the data to the CDbgPtr, and to let RTTI find the owner during assert manual handling. * * \author Stephane Le Dorze * \author Jerome Vuarand * \author Nevrax France * \date 2003-2005 */ #ifdef NL_DEBUG #define NL_DEBUG_PTR #endif template class CDbgPtr; template class CstCDbgPtr; class IDbgPtrData { public: virtual ~IDbgPtrData() { } }; template class CDbgRefCount { #ifdef NL_DEBUG_PTR public: CDbgRefCount(const CDbgRefCount& other) : _DbgCRefs(0) , _DbgCCstRefs(0) , _MaxRef(other._MaxRef) , _CheckOn(other._CheckOn) , _FirstReference(NULL) , _FirstCstReference(NULL) { } CDbgRefCount(sint32 maxRef = (1<<30)) : _DbgCRefs(0) , _DbgCCstRefs(0) , _MaxRef(maxRef) , _FirstReference(NULL) , _FirstCstReference(NULL) { } virtual ~CDbgRefCount() { if (_DbgCRefs!=0 || _DbgCCstRefs!=0) { const CDbgPtr* ref0, *ref1, *ref2, *ref3, *ref4; ref0=ref1=ref2=ref3=ref4=(CDbgPtr*)NULL; IDbgPtrData* dat0, *dat1, *dat2, *dat3, *dat4; dat0=dat1=dat2=dat3=dat4=(IDbgPtrData*)NULL; if (_DbgCRefs>0) { ref0 = _FirstReference; dat0 = ref0->getData(); } if (_DbgCRefs>1) { ref1 = ref0->getNextReference(); dat1 = ref1->getData(); } if (_DbgCRefs>2) { ref2 = ref1->getNextReference(); dat2 = ref2->getData(); } if (_DbgCRefs>3) { ref3 = ref2->getNextReference(); dat3 = ref3->getData(); } if (_DbgCRefs>4) { ref4 = ref3->getNextReference(); dat4 = ref4->getData(); } const CstCDbgPtr* cref0, *cref1, *cref2, *cref3, *cref4; cref0=cref1=cref2=cref3=cref4=(CstCDbgPtr*)NULL; IDbgPtrData* cdat0, *cdat1, *cdat2, *cdat3, *cdat4; cdat0=dat1=cdat2=cdat3=cdat4=(IDbgPtrData*)NULL; if (_DbgCCstRefs>0) { cref0 = _FirstCstReference; cdat0 = cref0->getData(); } if (_DbgCCstRefs>1) { cref1 = cref0->getNextReference(); cdat1 = cref1->getData(); } if (_DbgCCstRefs>2) { cref2 = cref1->getNextReference(); cdat2 = cref2->getData(); } if (_DbgCCstRefs>3) { cref3 = cref2->getNextReference(); cdat3 = cref3->getData(); } if (_DbgCCstRefs>4) { cref4 = cref3->getNextReference(); cdat4 = cref4->getData(); } nlassert(_DbgCRefs==0); nlassert(_DbgCCstRefs==0); } } sint getDbgRef(const CDbgPtr& ptr) const { return _DbgCRefs + _DbgCCstRefs; } sint getDbgRef(const CstCDbgPtr& ptr) const { return _DbgCRefs + _DbgCCstRefs; } void incRef(const CDbgPtr& ptr) const { if (_CheckOn) nlassert(_DbgCRefs<_MaxRef); ++_DbgCRefs; // Linked list management nlassert(_FirstReference!=&ptr); ptr.setNextReference(_FirstReference); ptr.setPrevReference((CDbgPtr*)NULL); if (_FirstReference) _FirstReference->setPrevReference(&ptr); _FirstReference = &ptr; } void decRef(const CDbgPtr& ptr) const { nlassert(_DbgCRefs>0); --_DbgCRefs; // Linked list management if (ptr.getNextReference()) ptr.getNextReference()->setPrevReference(ptr.getPrevReference()); if (ptr.getPrevReference()) ptr.getPrevReference()->setNextReference(ptr.getNextReference()); if (_FirstReference==&ptr) _FirstReference = ptr.getNextReference(); } void incRef(const CstCDbgPtr& ptr) const { if (_CheckOn) nlassert(_DbgCCstRefs<_MaxRef); ++_DbgCCstRefs; } void decRef(const CstCDbgPtr& ptr) const { nlassert(_DbgCCstRefs>0); --_DbgCCstRefs; } void setCheckMax(const bool checkOnOff) const { _CheckOn = checkOnOff; } private: mutable sint _DbgCRefs; mutable sint _DbgCCstRefs; sint32 _MaxRef; mutable bool _CheckOn; mutable const CDbgPtr* _FirstReference; mutable const CstCDbgPtr* _FirstCstReference; #endif }; template class CDbgPtr { T* Ptr; #ifdef NL_DEBUG_PTR /// \name Linked list management //@{ private: // Data IDbgPtrData* Data; mutable const CDbgPtr* NextReference; mutable const CDbgPtr* PrevReference; public: // Methods void setData(IDbgPtrData* data) { Data = data; } IDbgPtrData* getData() const { return Data; } void setNextReference(const CDbgPtr* reference) const { NextReference = reference; } const CDbgPtr* getNextReference() const { return NextReference; } void setPrevReference(const CDbgPtr* reference) const { PrevReference = reference; } const CDbgPtr* getPrevReference() const { return PrevReference; } //@} #endif public: CDbgPtr() : Ptr(NULL) #ifdef NL_DEBUG_PTR , Data(NULL) , NextReference(NULL) , PrevReference(NULL) #endif { } template CDbgPtr(const W* p) #ifdef NL_DEBUG_PTR : Data(NULL) , NextReference(NULL) , PrevReference(NULL) #endif { Ptr = const_cast(NLMISC::type_cast(p)); #ifdef NL_DEBUG_PTR if (Ptr) { CDbgRefCount* ref = static_cast*>(Ptr); ref->incRef(*this); } #endif } CDbgPtr(const CDbgPtr& copy) #ifdef NL_DEBUG_PTR : Data(NULL) , NextReference(NULL) , PrevReference(NULL) #endif { Ptr = copy.Ptr; #ifdef NL_DEBUG_PTR if (Ptr) { CDbgRefCount* ref = static_cast*>(Ptr); ref->incRef(*this); } #endif } ~CDbgPtr(); bool isNULL() const { return Ptr==NULL; } T* ptr() const { return Ptr; } operator T*(void) const { return Ptr; } template operator W*(void) const { return NLMISC::type_cast(Ptr); } T& operator*(void) const { return *Ptr; } T* operator->(void) const { return Ptr; } template CDbgPtr& operator=(const W* p) { #ifdef NL_DEBUG_PTR CDbgRefCount* oldRef = (CDbgRefCount*)NULL, *newRef = (CDbgRefCount*)NULL; if (Ptr) oldRef = static_cast*>(Ptr); if (p) newRef = static_cast*>(const_cast(NLMISC::type_cast(p))); if (oldRef!=newRef) { if (oldRef) oldRef->decRef(*this); Ptr = const_cast(NLMISC::type_cast(p)); if (newRef) newRef->incRef(*this); } #else Ptr = const_cast(NLMISC::type_cast(p)); #endif return *this; } /* CDbgPtr& operator=(const int value) { #ifdef NL_DEBUG nlassert(value==NULL); #endif #ifdef NL_DEBUG_PTR if (Ptr) { CDbgRefCount* ref=static_cast*>(Ptr); ref->decRef(*this); } #endif Ptr = NULL; return *this; } */ CDbgPtr& operator =(const CDbgPtr& p); bool operator <(const CDbgPtr& p) const; template bool operator ==(const W* p) const { return Ptr==NLMISC::type_cast(p); } template bool operator !=(const W* p) const { return Ptr!=NLMISC::type_cast(p); } bool operator ==(const CDbgPtr &p) const { return Ptr==p.Ptr; } bool operator !=(const CDbgPtr &p) const { return Ptr!=p.Ptr; } bool operator ==(int p) const { nlassert(p == 0); return Ptr==0; } bool operator !=(int p) const { nlassert(p == 0); return Ptr!=0; } }; template inline CDbgPtr::~CDbgPtr(void) { #ifdef NL_DEBUG_PTR if (Ptr) { CDbgRefCount* ref = static_cast*>(Ptr); ref->decRef(*this); Ptr = NULL; } #else Ptr=NULL; #endif } template CDbgPtr& CDbgPtr::operator =(const CDbgPtr& p) { return CDbgPtr::operator =(p.Ptr); } template bool CDbgPtr::operator <(const CDbgPtr& p) const { return Ptr class CstCDbgPtr { const T* Ptr; #ifdef NL_DEBUG_PTR /// \name Linked list management //@{ private: // Data IDbgPtrData* Data; mutable const CstCDbgPtr* NextReference; mutable const CstCDbgPtr* PrevReference; public: // Methods void setData(IDbgPtrData* data) { Data = data; } IDbgPtrData* getData() const { return Data; } void setNextReference(const CstCDbgPtr* reference) const { NextReference = reference; } const CstCDbgPtr* getNextReference() const { return NextReference; } void setPrevReference(const CstCDbgPtr* reference) const { PrevReference = reference; } const CstCDbgPtr* getPrevReference() const { return PrevReference; } //@} #endif public: CstCDbgPtr() : Ptr(NULL) #ifdef NL_DEBUG_PTR , Data(NULL) , NextReference(NULL) , PrevReference(NULL) #endif { } CstCDbgPtr(const T* p) #ifdef NL_DEBUG_PTR : Data(NULL) , NextReference(NULL) , PrevReference(NULL) #endif { Ptr = p; #ifdef NL_DEBUG_PTR if (Ptr) { CDbgRefCount* ref = static_cast*>(const_cast(Ptr)); ref->incRef(*this); } #endif } CstCDbgPtr(const CstCDbgPtr& copy) #ifdef NL_DEBUG_PTR : Data(NULL) , NextReference(NULL) , PrevReference(NULL) #endif { Ptr = copy.Ptr; #ifdef NL_DEBUG_PTR if (Ptr) { CDbgRefCount* ref = static_cast*>(const_cast(Ptr)); ref->incRef(*this); } #endif } ~CstCDbgPtr(); const T* ptr() const { return Ptr; } bool isNULL() const { return Ptr==NULL; } operator const T*(void) const { return Ptr; } const T& operator*(void) const { return *Ptr; } const T* operator->(void) const { return Ptr; } CstCDbgPtr& operator =(const T* p); CstCDbgPtr& operator =(const CstCDbgPtr& p); bool operator <(const CstCDbgPtr& p) const; }; template CstCDbgPtr::~CstCDbgPtr(void) { #ifdef NL_DEBUG_PTR if (Ptr) { CDbgRefCount* ref = static_cast*>(const_cast(Ptr)); ref->decRef(*this); } #endif Ptr = NULL; } template CstCDbgPtr& CstCDbgPtr::operator =(const T* p) { #ifdef NL_DEBUG_PTR if (p) { CDbgRefCount* ref = static_cast*>(const_cast(p)); ref->incRef(*this); } if (Ptr) { CDbgRefCount* ref = static_cast*>(const_cast(Ptr)); ref->decRef(*this); } #endif Ptr = p; return *this; } template CstCDbgPtr& CstCDbgPtr::operator =(const CstCDbgPtr& p) { return CstCDbgPtr::operator =(p.Ptr); } template bool CstCDbgPtr::operator <(const CstCDbgPtr& p) const { return Ptr // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_SMARTPTR_INLINE_H #define NL_SMARTPTR_INLINE_H #include "types_nl.h" namespace NLMISC { // *************************************************************************** #ifdef NL_OS_WINDOWS #define SMART_INLINE __forceinline #else #define SMART_INLINE inline #endif // *************************************************************************** inline CRefCount::~CRefCount() { // This is the destruction of the objet. #ifdef NL_DEBUG nlassert(crefs==0); #endif // If a CRefPtr still points on me... if(!pinfo->IsNullPtrInfo) { // inform them of my destruction. pinfo->Ptr= NULL; } } // *************************************************************************** // *************************************************************************** // CSmartPtr. // *************************************************************************** // *************************************************************************** // *************************************************************************** template inline CSmartPtr::~CSmartPtr(void) { SMART_TRACE("dtor()"); if(Ptr) { #ifdef NL_DEBUG nlassert(Ptr->crefs>=0); #endif if (--(Ptr->crefs) == 0) delete Ptr; Ptr=NULL; } } template SMART_INLINE CSmartPtr& CSmartPtr::operator=(T* p) { SMART_TRACE("ope=(T*)Start"); // Implicit manage auto-assignation. if(p) p->crefs++; if(Ptr) { if (--(Ptr->crefs) == 0) delete Ptr; } Ptr = p; SMART_TRACE("ope=(T*)End"); return *this; } template SMART_INLINE CSmartPtr& CSmartPtr::operator=(const CSmartPtr &p) { return operator=(p.Ptr); } template SMART_INLINE bool CSmartPtr::operator<(const CSmartPtr &p) const { return Ptr SMART_INLINE void CRefPtr::unRef() const { pinfo->RefCount--; if(pinfo->RefCount==0) { // In CRefPtr, Never delete the object. // We may be in the case that this==NullPtrInfo, and our NullPtrInfo has done a total round. Test it. if(pinfo->IsNullPtrInfo) { // This should not happens, but I'm not sure :) ... // Reset the NullPtrInfo to a middle round. pinfo->RefCount= 0x7FFFFFFF; } else { // If the CRefPtr still point to a valid object. if(pinfo->Ptr) { // Inform the Object that no more CRefPtr points on it. pinfo->Ptr->pinfo= static_cast(&CRefCount::NullPtrInfo); } // Then delete the pinfo. delete pinfo; } } } // *************************************************************************** // Cons - dest. template inline CRefPtr::CRefPtr() { pinfo= static_cast(&CRefCount::NullPtrInfo); Ptr= NULL; REF_TRACE("Smart()"); } template inline CRefPtr::CRefPtr(T *v) { Ptr= v; if(v) { // If no CRefPtr handles v, create a pinfo ref... if(v->pinfo->IsNullPtrInfo) v->pinfo=new CRefCount::CPtrInfo(v); pinfo=v->pinfo; // v is now used by this. pinfo->RefCount++; #ifdef NL_DEBUG nlassert(v == const_cast(static_cast(pinfo->Ptr))); #endif } else pinfo= static_cast(&CRefCount::NullPtrInfo); REF_TRACE("Smart(T*)"); } template inline CRefPtr::CRefPtr(const CRefPtr ©) { pinfo=copy.pinfo; pinfo->RefCount++; Ptr= const_cast(static_cast(pinfo->Ptr)); REF_TRACE("SmartCopy()"); } template inline CRefPtr::~CRefPtr(void) { REF_TRACE("~Smart()"); unRef(); pinfo= static_cast(&CRefCount::NullPtrInfo); Ptr= NULL; } // *************************************************************************** // Operators=. template CRefPtr &CRefPtr::operator=(T *v) { REF_TRACE("ope=(T*)Start"); Ptr= v; if(v) { // If no CRefPtr handles v, create a pinfo ref... if(v->pinfo->IsNullPtrInfo) v->pinfo=new CRefCount::CPtrInfo(v); // The auto equality test is implicitly done by upcounting first "v", then downcounting "this". v->pinfo->RefCount++; unRef(); pinfo= v->pinfo; #ifdef NL_DEBUG nlassert(v == const_cast(static_cast(pinfo->Ptr))); #endif } else { unRef(); pinfo= static_cast(&CRefCount::NullPtrInfo); } REF_TRACE("ope=(T*)End"); return *this; } template CRefPtr &CRefPtr::operator=(const CRefPtr ©) { REF_TRACE("ope=(Smart)Start"); // The auto equality test is implicitly done by upcounting first "copy", then downcounting "this". copy.pinfo->RefCount++; unRef(); pinfo=copy.pinfo; // Must Refresh the ptr. Ptr= const_cast(static_cast(pinfo->Ptr)); REF_TRACE("ope=(Smart)End"); return *this; } // *************************************************************************** // Operations. template void CRefPtr::kill() { REF_TRACE("SmartKill"); T *ptr= const_cast(static_cast(pinfo->Ptr)); // First, release the refptr. unRef(); pinfo= static_cast(&CRefCount::NullPtrInfo); Ptr= NULL; // Then delete the pointer. if(ptr) delete ptr; } // *************************************************************************** // Cast. template inline CRefPtr::operator T*() const { REF_TRACE("SmartCast T*()"); // Refresh Ptr. // NB: It is preferable (faster) here to just copy than testing if NULL and set NULL if necessary. // (static_cast is like a simple copy but for multiple inheritance) Ptr= const_cast(static_cast(pinfo->Ptr)); return Ptr; } // *************************************************************************** // Operators. template inline T& CRefPtr::operator*(void) const { REF_TRACE("Smart *()"); return *Ptr; } template inline T* CRefPtr::operator->(void) const { REF_TRACE("Smart ->()"); return Ptr; } // *************************************************************************** // *************************************************************************** // CVirtualRefPtr. // *************************************************************************** // *************************************************************************** // *************************************************************************** template SMART_INLINE void CVirtualRefPtr::unRef() const { pinfo->RefCount--; if(pinfo->RefCount==0) { // In CVirtualRefPtr, Never delete the object. // We may be in the case that this==NullPtrInfo, and our NullPtrInfo has done a total round. Test it. if(pinfo->IsNullPtrInfo) { // This should not happens, but I'm not sure :) ... // Reset the NullPtrInfo to a middle round. pinfo->RefCount= 0x7FFFFFFF; } else { // If the CVirtualRefPtr still point to a valid object. if(pinfo->Ptr) { // Inform the Object that no more CVirtualRefPtr points on it. pinfo->Ptr->pinfo= static_cast(&CRefCount::NullPtrInfo); } // Then delete the pinfo. delete pinfo; } } } // *************************************************************************** // Cons - dest. template inline CVirtualRefPtr::CVirtualRefPtr() { pinfo= static_cast(&CRefCount::NullPtrInfo); Ptr= NULL; REF_TRACE("Smart()"); } template inline CVirtualRefPtr::CVirtualRefPtr(T *v) { Ptr= v; if(v) { // If no CVirtualRefPtr handles v, create a pinfo ref... if(v->pinfo->IsNullPtrInfo) v->pinfo=new CRefCount::CPtrInfo(static_cast(v)); // v MUST derive from CVirtualRefCount pinfo=v->pinfo; // v is now used by this. pinfo->RefCount++; #ifdef NL_DEBUG nlassert(v == const_cast(dynamic_cast(static_cast(pinfo->Ptr)))); #endif } else pinfo= static_cast(&CRefCount::NullPtrInfo); REF_TRACE("Smart(T*)"); } template inline CVirtualRefPtr::CVirtualRefPtr(const CVirtualRefPtr ©) { pinfo=copy.pinfo; pinfo->RefCount++; Ptr= const_cast(dynamic_cast(static_cast(pinfo->Ptr))); nlassert(Ptr != NULL || pinfo->Ptr == NULL); REF_TRACE("SmartCopy()"); } template inline CVirtualRefPtr::~CVirtualRefPtr(void) { REF_TRACE("~Smart()"); unRef(); pinfo= static_cast(&CRefCount::NullPtrInfo); Ptr= NULL; } // *************************************************************************** // Operators=. template CVirtualRefPtr &CVirtualRefPtr::operator=(T *v) { REF_TRACE("ope=(T*)Start"); Ptr= v; if(v) { // If no CVirtualRefPtr handles v, create a pinfo ref... if(v->pinfo->IsNullPtrInfo) v->pinfo=new CRefCount::CPtrInfo(static_cast(v)); // v MUST derive from CVirtualRefCount // The auto equality test is implicitly done by upcounting first "v", then downcounting "this". v->pinfo->RefCount++; unRef(); pinfo= v->pinfo; #ifdef NL_DEBUG nlassert(v == const_cast(dynamic_cast(static_cast(pinfo->Ptr)))); #endif } else { unRef(); pinfo= static_cast(&CRefCount::NullPtrInfo); } REF_TRACE("ope=(T*)End"); return *this; } template CVirtualRefPtr &CVirtualRefPtr::operator=(const CVirtualRefPtr ©) { REF_TRACE("ope=(Smart)Start"); // The auto equality test is implicitly done by upcounting first "copy", then downcounting "this". copy.pinfo->RefCount++; unRef(); pinfo=copy.pinfo; // Must Refresh the ptr. Ptr= const_cast(dynamic_cast(static_cast(pinfo->Ptr))); nlassert(Ptr != NULL || pinfo->Ptr == NULL); REF_TRACE("ope=(Smart)End"); return *this; } // *************************************************************************** // Operations. template void CVirtualRefPtr::kill() { REF_TRACE("SmartKill"); T *ptr= const_cast(dynamic_cast(static_cast(pinfo->Ptr))); nlassert(ptr != NULL || pinfo->Ptr == NULL); // First, release the refptr. unRef(); pinfo= static_cast(&CRefCount::NullPtrInfo); Ptr= NULL; // Then delete the pointer. if(ptr) delete ptr; } // *************************************************************************** // Cast. template inline CVirtualRefPtr::operator T*() const { REF_TRACE("SmartCast T*()"); // Refresh Ptr if necessary. // NB: It is preferable (faster) here to test if NULL and set NULL if necessary, than dynamic_casting the ptr. if (pinfo->Ptr == NULL) Ptr = NULL; return Ptr; } // *************************************************************************** // Operators. template inline T& CVirtualRefPtr::operator*(void) const { REF_TRACE("Smart *()"); return *Ptr; } template inline T* CVirtualRefPtr::operator->(void) const { REF_TRACE("Smart ->()"); return Ptr; } // *************************************************************************** #undef SMART_INLINE } // NLMISC #endif // NL_SMARTPTR_INLINE_H ================================================ FILE: code/nel/include/nel/misc/speaker_listener.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef SPEAKER_LISTENER_H #define SPEAKER_LISTENER_H #include "types_nl.h" namespace NLMISC { class ISpeaker; class IListener { public: virtual void speakerIsDead (ISpeaker *speaker) =0; }; class ISpeaker { public: virtual void registerListener (IListener *listener) =0; virtual void unregisterListener (IListener *listener) =0; }; template class CSpeaker : public ISpeaker { public: typedef std::set TListeners; private: TListeners _Listeners; public: ~CSpeaker() { while (!_Listeners.empty()) { IListener *listener = *_Listeners.begin(); listener->speakerIsDead(this); _Listeners.erase(_Listeners.begin()); } } void registerListener (IListener *listener) { _Listeners.insert(listener); } void unregisterListener (IListener *listener) { _Listeners.erase(listener); } const TListeners &getListeners() { return _Listeners; } }; /** A macro to facilitate method invocation on listeners */ #define NLMISC_BROADCAST_TO_LISTENER(listenerClass, methodAndParam) \ CSpeaker::TListeners::const_iterator first(CSpeaker::getListeners().begin()), last(CSpeaker::getListeners().end()); \ for (; first != last; ++first) \ { \ listenerClass *listener = static_cast(*first); \ \ listener->methodAndParam; \ } \ template class CListener : public IListener { ISpeaker *_Speaker; void speakerIsDead(ISpeaker *speaker) { nlassert(speaker == _Speaker); _Speaker = NULL; } public: CListener() : _Speaker(NULL) { } ~CListener() { if (_Speaker != NULL) _Speaker->unregisterListener(this); } void registerListener(ISpeaker *speaker) { nlassert(_Speaker == NULL); _Speaker = speaker; _Speaker->registerListener(this); } void unregisterListener(ISpeaker * /* speaker */) { nlassert(_Speaker != NULL); _Speaker->unregisterListener(this); _Speaker = NULL; } ISpeaker *getSpeaker() { return _Speaker; } }; } // NLMISC #endif // SPEAKER_LISTENER_H ================================================ FILE: code/nel/include/nel/misc/sstring.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_SSTRING_H #define NL_SSTRING_H //#include "types_nl.h" #include #include #include #include "stream.h" #include "path.h" #include "string_common.h" namespace NLMISC { // advanced class declaration... //class CVectorSString; class CSString; typedef std::vector CVectorSString; /** * CSString : std::string with more functionalities and case insensitive compare * * \author Daniel Miller * \author Nevrax * \date 2003 */ class CSString: public std::string { public: /// ctor CSString(); /// ctor CSString(const char *s); /// ctor CSString(const std::string &s); /// ctor CSString(char c); /// ctor CSString(int i,const char *fmt="%d"); /// ctor CSString(uint32 u,const char *fmt="%u"); /// ctor CSString(double d,const char *fmt="%f"); /// ctor CSString(const char *s,const char *fmt); /// ctor CSString(const std::string &s,const char *fmt); /// ctor CSString(const std::vector& v,const std::string& separator="\n"); /// Const [] operator std::string::const_reference operator[](std::string::size_type idx) const; /// Non-Const [] operator std::string::reference operator[](std::string::size_type idx); /// Return the first character, or '\\0' is the string is empty char operator*(); /// Return the n right hand most characters of a string char back() const; /// Return the n left hand most characters of a string CSString left(uint32 count) const; /// Return the n right hand most characters of a string CSString right(uint32 count) const; /// Return the string minus the n left hand most characters of a string CSString leftCrop(uint32 count) const; /// Return the string minus the n right hand most characters of a string CSString rightCrop(uint32 count) const; /// Return sub string up to but not including first instance of given character, starting at 'iterator' /// on exit 'iterator' indexes first character after extracted string segment CSString splitToWithIterator(char c,uint32& iterator) const; /// Return sub string up to but not including first instance of given character CSString splitTo(char c) const; /// Return sub string up to but not including first instance of given character CSString splitTo(char c,bool truncateThis=false,bool absorbSeparator=true); /// Return sub string up to but not including first instance of given character CSString splitTo(const char *s,bool truncateThis=false); /// Return sub string up to but not including first non-quote encapsulated '//' CSString splitToLineComment(bool truncateThis=false, bool useSlashStringEscape=true); /// Return sub string from character following first instance of given character on CSString splitFrom(char c) const; /// Return sub string from character following first instance of given character on CSString splitFrom(const char *s) const; /// Behave like a s strtok() routine, returning the sun string extracted from (and removed from) *this CSString strtok(const char *separators, bool useSmartExtensions=false, // if true then match brackets etc (and refine with following args) bool useAngleBrace=false, // - treat '<' and '>' as brackets bool useSlashStringEscape=true, // - treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true); // - treat """" as '"') /// Return first word (blank separated) - can remove extracted word from source string CSString firstWord(bool truncateThis=false); /// Return first word (blank separated) CSString firstWordConst() const; /// Return sub string remaining after the first word CSString tailFromFirstWord() const; /// Count the number of words in a string uint32 countWords() const; /// Extract the given word CSString word(uint32 idx) const; /// Return first word or quote-encompassed sub-string - can remove extracted sub-string from source string CSString firstWordOrWords(bool truncateThis=false,bool useSlashStringEscape=true,bool useRepeatQuoteStringEscape=true); /// Return first word or quote-encompassed sub-string CSString firstWordOrWordsConst(bool useSlashStringEscape=true,bool useRepeatQuoteStringEscape=true) const; /// Return sub string following first word (or quote-encompassed sub-string) CSString tailFromFirstWordOrWords(bool useSlashStringEscape=true,bool useRepeatQuoteStringEscape=true) const; /// Count the number of words (or quote delimited sub-strings) in a string uint32 countWordOrWords(bool useSlashStringEscape=true,bool useRepeatQuoteStringEscape=true) const; /// Extract the given words (or quote delimited sub-strings) CSString wordOrWords(uint32 idx,bool useSlashStringEscape=true,bool useRepeatQuoteStringEscape=true) const; /// Return first line - can remove extracted line from source string CSString firstLine(bool truncateThis=false); /// Return first line CSString firstLineConst() const; /// Return sub string remaining after the first line CSString tailFromFirstLine() const; /// Count the number of lines in a string uint32 countLines() const; /// Extract the given line CSString line(uint32 idx) const; /// A handy utility routine for knowing if a character is a white space character or not (' ','\t','\n','\r',26) static bool isWhiteSpace(char c); /// Test whether character matches '{', '(','[' or '<' (the '<' test depends on the useAngleBrace parameter static bool isOpeningDelimiter(char c,bool useAngleBrace=false); /// Test whether character matches '}', ')',']' or '>' (the '>' test depends on the useAngleBrace parameter static bool isClosingDelimiter(char c,bool useAngleBrace=false); /// Test whether character matches '\'' or '\"' static bool isStringDelimiter(char c); /// Tests whether the character 'b' is the closing delimiter or string delimiter corresponding to character 'a' static bool isMatchingDelimiter(char a,char b); /// A handy utility routine for knowing if a character is a valid component of a file name static bool isValidFileNameChar(char c); /// A handy utility routine for knowing if a character is a valid first char for a keyword (a..z, '_') static bool isValidKeywordFirstChar(char c); /// A handy utility routine for knowing if a character is a valid subsequent char for a keyword (a..z, '_', '0'..'9') static bool isValidKeywordChar(char c); /// A handy utility routine for knowing if a character is printable (isValidFileNameChar + more basic punctuation) static bool isPrintable(char c); /// A handy utility routine for knowing if a character is a hex digit 0..9, a..f static bool isHexDigit(char c); /// A handy utility routine for converting a hex digit to a numeric value 0..15 static char convertHexDigit(char c); // a handy routine that tests whether a given string contains binary characters or not. Only characters>32 + isWhiteSpace() are valid bool isValidText(); // a handy routine that tests whether a given string is a valid file name or not // "\"hello there\\bla\"" is valid // "hello there\\bla" is not valid - missing quotes // "\"hello there\"\\bla" is not valid - text after quotes bool isValidFileName() const; // a second handy routine that tests whether a given string is a valid file name or not // equivalent to ('\"'+*this+'\"').isValidFileName() // "\"hello there\\bla\"" is not valid - too many quotes // "hello there\\bla" is valid bool isValidUnquotedFileName() const; // a handy routine that tests whether or not a given string is a valid keyword bool isValidKeyword() const; // a handy routine that tests whether or not a given string is quote encapsulated bool isQuoted( bool useAngleBrace=false, // treat '<' and '>' as brackets bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true) const; // treat """" as '"' /// Search for the closing delimiter matching the opening delimiter at position 'startPos' in the 'this' string /// on error returns startPos uint32 findMatchingDelimiterPos(bool useAngleBrace,bool useSlashStringEscape,bool useRepeatQuoteStringEscape,uint32 startPos=0) const; /// Extract a chunk from the 'this' string /// if first non-blank character is a string delimiter or an opening delimiter then extracts up to the matching closing delimiter /// in all other cases an empty string is returned /// the return string includes the opening blank characters (it isn't stripped) CSString matchDelimiters(bool truncateThis=false, bool useAngleBrace=false, // treat '<' and '>' as brackets bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true); // treat """" as '"' /// copy out section of string up to separator character, respecting quotes (but not brackets etc) /// on error tail after returned string doesn't begin with valid separator character CSString splitToStringSeparator( char separator, bool truncateThis=false, bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true, // treat """" as '"' bool truncateSeparatorCharacter=false); // if true tail begins after separator char /// copy out section of string up to separator character, respecting quotes, brackets, etc /// on error tail after returned string doesn't begin with valid separator character /// eg: splitToSeparator(','); - this might be used to split some sort of ',' separated input CSString splitToSeparator( char separator, bool truncateThis=false, bool useAngleBrace=false, // treat '<' and '>' as brackets bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true, // treat """" as '"' bool truncateSeparatorCharacter=false); // if true tail begins after separator char CSString splitToSeparator( char separator, bool useAngleBrace=false, // treat '<' and '>' as brackets bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true) const; // treat """" as '"' /// copy out section of string up to any of a given set of separator characters, respecting quotes, brackets, etc /// on error tail after returned string doesn't begin with valid separator character /// eg: splitToOneOfSeparators(",;",true,false,false,true); - this might be used to split a string read from a CSV file CSString splitToOneOfSeparators( const CSString& separators, bool truncateThis=false, bool useAngleBrace=false, // treat '<' and '>' as brackets bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true, // treat """" as '"' bool truncateSeparatorCharacter=false, // if true tail begins after separator char bool splitStringAtBrackets=true); // if true consider brackets as breaks in the string CSString splitToOneOfSeparators( const CSString& separators, bool useAngleBrace=false, // treat '<' and '>' as brackets bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true) const; // treat """" as '"' /// Return true if the string is a single block encompassed by a pair of delimiters /// eg: "((a)(b)(c))" or "(abc)" return true wheras "(a)(b)(c)" or "abc" return false bool isDelimitedMonoBlock( bool useAngleBrace=false, // treat '<' and '>' as brackets bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true // treat """" as '"' ) const; /// Return the sub string with leading and trailing delimiters ( such as '(' and ')' or '[' and ']' ) removed /// if the string isn't a delimited monoblock then the complete string is returned /// eg "((a)b(c))" returns "(a)b(c)" whereas "(a)b(c)" returns the identical "(a)b(c)" CSString stripBlockDelimiters( bool useAngleBrace=false, // treat '<' and '>' as brackets bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true // treat """" as '"' ) const; /// Append the individual words in the string to the result vector /// retuns true on success bool splitWords(CVectorSString& result) const; /// Append the individual "wordOrWords" elements in the string to the result vector /// retuns true on success bool splitWordOrWords(CVectorSString& result,bool useSlashStringEscape=true,bool useRepeatQuoteStringEscape=true) const; /// Append the individual lines in the string to the result vector /// retuns true on success bool splitLines(CVectorSString& result) const; /// Append the separator-separated elements in the string to the result vector /// retuns true on success bool splitBySeparator( char separator, CVectorSString& result, bool useAngleBrace=false, // treat '<' and '>' as brackets bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true, // treat """" as '"' bool skipBlankEntries=false // dont add blank entries to the result vector ) const; /// Append the separator-separated elements in the string to the result vector /// retuns true on success bool splitByOneOfSeparators( const CSString& separators, CVectorSString& result, bool useAngleBrace=false, // treat '<' and '>' as brackets bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true, // treat """" as '"' bool retainSeparators=false, // have the separators turn up in the result vector bool skipBlankEntries=false // dont add blank entries to the result vector ) const; /// join an array of strings to form a single string (appends to the existing content of this string) /// if this string is not empty then a separator is added between this string and the following const CSString& join(const std::vector& strings, const CSString& separator=""); const CSString& join(const std::vector& strings, char separator); /// Return a copy of the string with leading and trainling spaces removed CSString strip() const; /// Return a copy of the string with leading spaces removed CSString leftStrip() const; /// Return a copy of the string with trainling spaces removed CSString rightStrip() const; /// Making an upper case copy of a string CSString toUpper() const; /// Making a lower case copy of a string CSString toLower() const; /// encapsulate string in quotes, adding escape characters as necessary CSString quote( bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true // treat """" as '"' ) const; /// if a string is not already encapsulated in quotes then return quote() else return *this CSString quoteIfNotQuoted( bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true // treat """" as '"' ) const; /// if a string is not a single word and is not already encapsulated in quotes then return quote() else return *this CSString quoteIfNotAtomic( bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true // treat """" as '"' ) const; /// strip delimiting quotes and clear through escape characters as necessary CSString unquote(bool useSlashStringEscape=true, // treat '\' as escape char so "\"" == '"' bool useRepeatQuoteStringEscape=true // treat """" as '"' ) const; /// equivalent to if (isQuoted()) unquote() CSString unquoteIfQuoted(bool useSlashStringEscape=true, bool useRepeatQuoteStringEscape=true ) const; /// encode special characters such as quotes, gt, lt, etc to xml encoding /// the isParameter paramter is true if the string is to be used in an XML parameter block CSString encodeXML(bool isParameter=false) const; /// decode special characters such as quotes, gt, lt, etc from xml encoding CSString decodeXML() const; /// verifies whether a string contains sub-strings that correspond to xml special character codes bool isEncodedXML() const; /// verifies whether a string contains any XML incompatible characters /// in this case the string can be converted to xml compatible format via encodeXML() /// the isParameter paramter is true if the string is to be used in an XML parameter block bool isXMLCompatible(bool isParameter=false) const; /// Replacing all occurences of one string with another CSString replace(const char *toFind,const char *replacement) const; /// Find index at which a sub-string starts (case not sensitive) - if sub-string not found then returns string::npos std::string::size_type find(const char *toFind, std::string::size_type startLocation=0) const; /// Find index at which a sub-string starts (case NOT sensitive) - if sub-string not found then returns string::npos std::string::size_type findNS(const char *toFind, std::string::size_type startLocation=0) const; /// Return true if this contains given sub string bool contains(const char *toFind) const; /// Return true if this contains given sub string bool contains(int character) const; /// Handy atoi routines... int atoi() const; sint32 atosi() const; uint32 atoui() const; sint64 atoi64() const; sint64 atosi64() const; uint64 atoui64() const; /// A handy atof routine... double atof() const; /// assignment operator CSString& operator=(const char *s); /// assignment operator CSString& operator=(const std::string &s); /// assignment operator CSString& operator=(char c); /// assignment operator CSString& operator=(int i); /// assignment operator CSString& operator=(uint32 u); /// assignment operator CSString& operator=(double d); /// Case insensitive string compare bool operator==(const CSString &other) const; /// Case insensitive string compare bool operator==(const std::string &other) const; /// Case insensitive string compare bool operator==(const char* other) const; /// Case insensitive string compare bool operator!=(const CSString &other) const; /// Case insensitive string compare bool operator!=(const std::string &other) const; /// Case insensitive string compare bool operator!=(const char* other) const; /// Case insensitive string compare bool operator<=(const CSString &other) const; /// Case insensitive string compare bool operator<=(const std::string &other) const; /// Case insensitive string compare bool operator<=(const char* other) const; /// Case insensitive string compare bool operator>=(const CSString &other) const; /// Case insensitive string compare bool operator>=(const std::string &other) const; /// Case insensitive string compare bool operator>=(const char* other) const; /// Case insensitive string compare bool operator>(const CSString &other) const; /// Case insensitive string compare bool operator>(const std::string &other) const; /// Case insensitive string compare bool operator>(const char* other) const; /// Case insensitive string compare bool operator<(const CSString &other) const; /// Case insensitive string compare bool operator<(const std::string &other) const; /// Case insensitive string compare bool operator<(const char* other) const; //@{ //@name Easy concatenation operator to build strings template CSString &operator <<(const T &value) { operator +=(NLMISC::toString(value)); return *this; } // specialisation for C string CSString &operator <<(const char *value) { static_cast(this)->operator +=(value); return *this; } // specialisation for character CSString &operator <<(char value) { static_cast(this)->operator +=(value); return *this; } // specialisation for std::string CSString &operator <<(const std::string &value) { static_cast(this)->operator +=(value); return *this; } // specialisation for CSString CSString &operator <<(const CSString &value) { static_cast(this)->operator +=(value); return *this; } //@} /// Case insensitive string compare (useful for use as map keys, see less below) bool icompare(const std::string &other) const; /// Serial void serial( NLMISC::IStream& s ); /// Read a text file into a string bool readFromFile(const CSString& fileName); /// Write a string to a text file // returns true on success, false on failure bool writeToFile(const CSString& fileName) const; /// Write a string to a text file // if the file already exists and its content is identicall to our own then it is not overwritten // returns true on success (including the case where the file exists and is not overwritten), false on failure bool writeToFileIfDifferent(const CSString& fileName) const; }; /* * Vector of CSString compatible with vector */ //typedef std::vector CVectorSString; /*CVectorSString &operator = (CVectorSString &left, const std::vector &right) { left = reinterpret_cast(right); } CVectorSString &operator = (CVectorSString &left, const std::vector &right) { left = reinterpret_cast(right); } */ //class CVectorSString : public std::vector //{ //public: // // cast to and convert from std::vector // operator std::vector& () // { // return reinterpret_cast&>(*this); // } // operator const std::vector& () const // { // return reinterpret_cast&>(*this); // } // CVectorSString& operator= ( const std::vector& v ) // { // *this = reinterpret_cast(v); // return *this; // } // // // simple ctors // CVectorSString() {} // CVectorSString( const CVectorSString& v ) { operator=(v); } // // // ctors for building from different vetor types // CVectorSString( const std::vector& v ): std::vector(v) {} // CVectorSString( const std::vector& v ): std::vector(*(std::vector*)&v) {} // // // ctor for extracting sub_section of another vector // CVectorSString( const const_iterator& first, const const_iterator& last ): std::vector(first,last) {} //}; /* * Inlines */ inline CSString::CSString() { } inline CSString::CSString(const char *s) { *(std::string *)this=s; } inline CSString::CSString(const std::string &s) { assign( s.c_str(), s.size() ); } inline CSString::CSString(char c) { *(std::string *)this=c; } inline CSString::CSString(int i,const char *fmt) { char buf[1024]; sprintf(buf,fmt,i); *this=buf; } inline CSString::CSString(uint32 u,const char *fmt) { char buf[1024]; sprintf(buf,fmt,u); *this=buf; } inline CSString::CSString(double d,const char *fmt) { char buf[1024]; sprintf(buf,fmt,d); *this=buf; } inline CSString::CSString(const char *s,const char *fmt) { char buf[1024]; sprintf(buf,fmt,s); *this=buf; } inline CSString::CSString(const std::string &s,const char *fmt) { char buf[1024]; sprintf(buf,fmt,s.c_str()); *this=buf; } inline CSString::CSString(const std::vector& v,const std::string& separator) { for (uint32 i=0;i0) *this+=separator; *this+=v[i]; } } inline char CSString::operator*() { if (empty()) return 0; return (*this)[0]; } inline char CSString::back() const { return (*this)[size()-1]; } inline CSString CSString::right(uint32 count) const { if (count>=size()) return *this; return substr(size()-count); } inline CSString CSString::rightCrop(uint32 count) const { if (count>=size()) return CSString(); return substr(0,size()-count); } inline CSString CSString::left(uint32 count) const { return substr(0,count); } inline CSString CSString::leftCrop(uint32 count) const { if (count>=size()) return CSString(); return substr(count); } inline CSString CSString::splitToWithIterator(char c,uint32& iterator) const { uint32 i; CSString result; for (i=iterator;i'); } inline bool CSString::isStringDelimiter(char c) { return c=='\"' || c=='\''; } inline bool CSString::isMatchingDelimiter(char a,char b) { return (a=='(' && b==')') || (a=='[' && b==']') || (a=='{' && b=='}') || (a=='<' && b=='>') || (a=='\"' && b=='\"') || (a=='\'' && b=='\''); } inline bool CSString::isValidFileNameChar(char c) { if (c>='a' && c<='z') return true; if (c>='A' && c<='Z') return true; if (c>='0' && c<='9') return true; if (c=='_') return true; if (c==':') return true; if (c=='/') return true; if (c=='\\') return true; if (c=='.') return true; if (c=='#') return true; if (c=='-') return true; return false; } inline bool CSString::isPrintable(char c) { if (isValidFileNameChar(c)) return true; if (c==' ') return true; if (c=='*') return true; if (c=='?') return true; if (c=='!') return true; if (c=='@') return true; if (c=='&') return true; if (c=='|') return true; if (c=='+') return true; if (c=='=') return true; if (c=='%') return true; if (c=='<') return true; if (c=='>') return true; if (c=='(') return true; if (c==')') return true; if (c=='[') return true; if (c==']') return true; if (c=='{') return true; if (c=='}') return true; if (c==',') return true; if (c==';') return true; if (c=='$') return true; if ((uint8)c==156) return true; // Sterling Pound char causing error in gcc 4.1.2 if (c=='^') return true; if (c=='~') return true; if (c=='\'') return true; if (c=='\"') return true; return false; } inline bool CSString::isQuoted(bool useAngleBrace,bool useSlashStringEscape,bool useRepeatQuoteStringEscape) const { return (left(1)=="\"") && (right(1)=="\"") && isDelimitedMonoBlock(useAngleBrace,useSlashStringEscape,useRepeatQuoteStringEscape); } inline bool CSString::isValidKeywordFirstChar(char c) { if (c>='a' && c<='z') return true; if (c>='A' && c<='Z') return true; if (c=='_') return true; return false; } inline bool CSString::isValidKeywordChar(char c) { if (c>='a' && c<='z') return true; if (c>='A' && c<='Z') return true; if (c>='0' && c<='9') return true; if (c=='_') return true; return false; } inline bool CSString::isHexDigit(char c) { if (c>='0' && c<='9') return true; if (c>='A' && c<='F') return true; if (c>='a' && c<='f') return true; return false; } inline char CSString::convertHexDigit(char c) { if (c>='0' && c<='9') return c-'0'; if (c>='A' && c<='F') return c-'A'+10; if (c>='a' && c<='f') return c-'a'+10; return 0; } inline CSString& CSString::operator=(const char *s) { *(std::string *)this=s; return *this; } inline CSString& CSString::operator=(const std::string &s) { assign( s.c_str(), s.size() ); return *this; } inline CSString& CSString::operator=(char c) { *(std::string *)this=c; return *this; } inline CSString& CSString::operator=(int i) { CSString other(i); *this = other; return *this; } inline CSString& CSString::operator=(uint32 u) { CSString other(u); *this = other; return *this; } inline CSString& CSString::operator=(double d) { CSString other(d); *this = other; return *this; } inline bool CSString::operator==(const CSString &other) const { return stricmp(c_str(),other.c_str())==0; } inline bool CSString::operator==(const std::string &other) const { return stricmp(c_str(),other.c_str())==0; } inline bool CSString::operator==(const char* other) const { return stricmp(c_str(),other)==0; } inline bool CSString::operator!=(const CSString &other) const { return stricmp(c_str(),other.c_str())!=0; } inline bool CSString::operator!=(const std::string &other) const { return stricmp(c_str(),other.c_str())!=0; } inline bool CSString::operator!=(const char* other) const { return stricmp(c_str(),other)!=0; } inline bool CSString::operator<=(const CSString &other) const { return stricmp(c_str(),other.c_str())<=0; } inline bool CSString::operator<=(const std::string &other) const { return stricmp(c_str(),other.c_str())<=0; } inline bool CSString::operator<=(const char* other) const { return stricmp(c_str(),other)<=0; } inline bool CSString::operator>=(const CSString &other) const { return stricmp(c_str(),other.c_str())>=0; } inline bool CSString::operator>=(const std::string &other) const { return stricmp(c_str(),other.c_str())>=0; } inline bool CSString::operator>=(const char* other) const { return stricmp(c_str(),other)>=0; } inline bool CSString::operator>(const CSString &other) const { return stricmp(c_str(),other.c_str())>0; } inline bool CSString::operator>(const std::string &other) const { return stricmp(c_str(),other.c_str())>0; } inline bool CSString::operator>(const char* other) const { return stricmp(c_str(),other)>0; } inline bool CSString::operator<(const CSString &other) const { return stricmp(c_str(),other.c_str())<0; } inline bool CSString::operator<(const std::string &other) const { return stricmp(c_str(),other.c_str())<0; } inline bool CSString::operator<(const char* other) const { return stricmp(c_str(),other)<0; } inline std::string::const_reference CSString::operator[](std::string::size_type idx) const { static char zero=0; if (idx >= size()) return zero; return data()[idx]; } inline std::string::reference CSString::operator[](std::string::size_type idx) { static char zero=0; if (idx >= size()) return zero; return const_cast(data()[idx]); } inline bool CSString::icompare(const std::string &other) const { return stricmp(c_str(),other.c_str())<0; } inline void CSString::serial( NLMISC::IStream& s ) { s.serial( reinterpret_cast( *this ) ); } /* inline CSString operator+(const CSString& s0,char s1) { return CSString(s0)+s1; } inline CSString operator+(const CSString& s0,const char* s1) { return CSString(s0)+s1; } inline CSString operator+(const CSString& s0,const std::string& s1) { return CSString(s0)+s1; } inline CSString operator+(const CSString& s0,const CSString& s1) { return CSString(s0)+s1; } */ inline CSString operator+(char s0,const CSString& s1) { return CSString(s0) + s1.c_str(); } inline CSString operator+(const char* s0,const CSString& s1) { return CSString(s0) + s1.c_str(); } #if !defined(NL_COMP_VC) || (NL_COMP_VC_VERSION <= 100) // TODO: check if it can be disabled for other compilers too inline CSString operator+(const std::string& s0,const CSString& s1) { return s0+static_cast(s1); } #endif } // NLMISC // *** The following was commented out by Sadge because there were strange compilation/ link issues *** // *** The '<' operator was implemented instead *** //_STLP_BEGIN_NAMESPACE //namespace std //{ // /* // * less is case insensitive // */ // template <> // struct less : public std::binary_function // { // bool operator()(const NLMISC::CSString& x, const NLMISC::CSString& y) const { return x.icompare(y); } // }; //} // std //_STLP_END_NAMESPACE //namespace std //{ // /* // * less is case insensitive // */ // template <> // struct less : public std::binary_function // { // bool operator()(const NLMISC::CSString& x, const NLMISC::CSString& y) const { return x.icompare(y); } // }; //} // std //_STLP_END_NAMESPACE /** * Instead of overriding std::less, please use the following predicate. * For example, declare your map as: * std::map MyMap; * Caution: a map declared without CUnsensitiveSStringLessPred will behave as a * standard string map. * * \see also CUnsensitiveStrLessPred in misc/string_conversion.h * for a similar predicate with std::string. */ struct CUnsensitiveSStringLessPred : public std::less { bool operator()(const NLMISC::CSString& x, const NLMISC::CSString& y) const { return x < y; /*.icompare(y);*/ } }; #endif // NL_SSTRING_H /* End of sstring.h */ ================================================ FILE: code/nel/include/nel/misc/static_map.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_STATIC_MAP_H #define NL_STATIC_MAP_H #include "types_nl.h" #include "common.h" #include "stream.h" #include "debug.h" #include // With NeL Memory Debug, use new #ifndef NL_USE_DEFAULT_MEMORY_MANAGER # ifndef NLMISC_HEAP_ALLOCATION_NDEBUG # define NL_OV_USE_NEW_ALLOCATOR # endif // NLMISC_HEAP_ALLOCATION_NDEBUG #endif // NL_USE_DEFAULT_MEMORY_MANAGER namespace NLMISC { // *************************************************************************** /** * Implemented with a std::vector * Use it not like a map : begin by adding all your values with add()/del()/fromMap() * and then call endAdd() that performs a slow sort on the vector and then call find() * to find the element you want. If you have not called endAdd() its done in find(), * but take care that endAdd() is slow. * \author Matthieu 'Trap' Besson * \author Nevrax France * \date October 2003 */ template > class CStaticMap { public: typedef Key key_type; typedef Typ data_type; typedef Typ mapped_type; typedef std::pair value_type; typedef Comp key_compare; class value_compare : public std::binary_function { friend class CStaticMap; public: bool operator()(const value_type& __x, const value_type& __y) const { return _CompareFunc(__x.first, __y.first); } protected : Comp _CompareFunc; protected : // Constructor value_compare(Comp __c) : _CompareFunc(__c) {} }; private: std::vector _Data; bool _DataSorted; Comp _CompFunc; public: typedef typename std::vector::reference reference; typedef typename std::vector::const_reference const_reference; typedef typename std::vector::iterator iterator; typedef typename std::vector::const_iterator const_iterator; typedef typename std::vector::reverse_iterator reverse_iterator; typedef typename std::vector::const_reverse_iterator const_reverse_iterator; typedef typename std::vector::size_type size_type; typedef typename std::vector::difference_type difference_type; // allocation/deallocation CStaticMap() : _DataSorted(true) { } explicit CStaticMap (const Comp& /* __comp */) : _DataSorted(true) { } CStaticMap (const_iterator __first, const_iterator __last) { _DataSorted = false; _Data.insert(__first, __last); endAdd(); } CStaticMap (const_iterator __first, const_iterator __last, const Comp& __comp) : _CompFunc(__comp) { _DataSorted = false; _Data.insert(__first, __last); endAdd(); } CStaticMap(const CStaticMap& __x) : _Data(__x._Data) , _DataSorted(__x._DataSorted), _CompFunc(__x._CompFunc) { } CStaticMap& operator= (const CStaticMap& __x) { _Data = __x._Data; endAdd(); return *this; } // accessors: key_compare key_comp() const { return _Data.key_comp(); } value_compare value_comp() const { return value_compare(_CompFunc); } iterator begin() { endAdd(); return _Data.begin(); } const_iterator begin() const { endAdd(); return _Data.begin(); } iterator end() { endAdd(); return _Data.end(); } const_iterator end() const { endAdd(); return _Data.end(); } reverse_iterator rbegin() { endAdd(); return _Data.rbegin(); } const_reverse_iterator rbegin() const { endAdd(); return _Data.rbegin(); } reverse_iterator rend() { endAdd(); return _Data.rend(); } const_reverse_iterator rend() const { endAdd(); return _Data.rend(); } bool empty() const { return _Data.empty(); } size_type size() const { return _Data.size(); } size_type max_size() const { return _Data.max_size(); } Typ& operator[](const key_type& __k) { iterator __i = find(__k); // The key MUST exist no automatic insertion done in this class nlassert(__i != end()); return (*__i).second; } void swap (CStaticMap& __x) { _Data.swap (__x._Data); _DataSorted = false; } // Add an element in the static map void reserve(size_type n) { _Data.reserve(n); } void add(const value_type& __v) { _DataSorted = false; _Data.push_back (__v); } void fromMap (const std::map &m) { _DataSorted = false; _Data.reserve(m.size()); typename std::map::const_iterator itEnd = m.end(); typename std::map::const_iterator it = m.begin(); for (; it != itEnd; it++) _Data.push_back (std::pair(it->first, it->second)); } void endAdd() { if (_DataSorted) return; _DataSorted = true; sort (_Data.begin(), _Data.end(), value_comp()); // Sort the vector } // Delete an element from the static map void del(iterator __position) { nlassert(_DataSorted); _Data.erase (__position); } size_type del(const key_type& __x) { endAdd(); return _Data.erase (__x); } void del(iterator __first, iterator __last) { nlassert(_DataSorted); _Data.erase (__first, __last); } void clear() { _Data.clear(); } // map operations: iterator find(const key_type& __x) { endAdd(); value_type __v(__x, Typ()); iterator it = lower_bound((iterator)_Data.begin(), (iterator)_Data.end(), __v, value_comp()); if ((it != end()) && (!value_comp()(*it,__v) && !value_comp()(__v,*it))) return it; else return end(); } const_iterator find(const key_type& __x) const { endAdd(); value_type __v(__x, Typ()); iterator it = lower_bound((const_iterator)_Data.begin(), (const_iterator)_Data.end(), __v, value_comp()); if ((it != end()) && (!value_comp()(*it,__v) && !value_comp()(__v,*it))) return it; else return end(); } size_type count(const key_type& __x) const { endAdd(); return find(__x) == _Data.end() ? 0 : 1; } }; } // NLMISC #endif // NL_STATIC_MAP_H /* End of static_map.h */ ================================================ FILE: code/nel/include/nel/misc/stl_block_allocator.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_STL_BLOCK_ALLOCATOR_H #define NL_STL_BLOCK_ALLOCATOR_H #include "types_nl.h" #include "block_memory.h" namespace NLMISC { // *************************************************************************** /** * This class is a STL block allocator which use CBlockMemory. see CBlockMemory for description * of block memory management/advantages. * * This class works with STLPort. It implements __stl_alloc_rebind() (not C++ standard??) to work properly * with list<>/set<> etc... node allocations. * * NB: if used with a vector<> or a deque<> (ie if allocate(..,n) is called with n>1), it's still work, * but it's use malloc()/free() instead, so it is fully useless in this case :) * * CSTLBlockAllocator use a pointer on a CBlockMemory, so multiple containers can share the same * blockMemory, for maximum space/speed efficiency. * * Because of CBlockMemory allocation scheme, only same containers of same types can share the * same CBlockMemory instance (eg: "list; vector;" is invalid and * will assert when allocations will occur). * * To construct a container which use this allocator, do like this: * list > myList( ptrOnBlockMemory ); * * But see CSTLBlockList for easier list instanciation, because using it, you'll do like this: * CSTLBlockList myList(ptrOnBlockMemory); * * Note: CSTLBlockAllocator take only 4 bytes in memory (a ptr on a CBlockMemory) * * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ template class CSTLBlockAllocator : public std::allocator< T > { public: /// Constructor. Must gives a blockMemory to ctor. NB: must gives a CBlockMemory !!! CSTLBlockAllocator(CBlockMemory * /* bm */) { } /// copy ctor CSTLBlockAllocator(const CSTLBlockAllocator &other) : std::allocator(other) { } /// dtor ~CSTLBlockAllocator() { } }; #if 0 #if defined(NL_OS_WINDOWS) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES) template class CSTLBlockAllocator { public: /// \name standard allocator interface. // @{ typedef T value_type; typedef value_type *pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef size_t size_type; typedef ptrdiff_t difference_type; pointer adress(reference x) const { return &x; } const_pointer adress(const_reference x) const { return &x; } void construct(pointer p, const T &val) { new (p) T(val); } void destroy(pointer p) { p->T::~T(); } // @} public: /// Constructor. Must gives a blockMemory to ctor. NB: must gives a CBlockMemory !!! CSTLBlockAllocator(CBlockMemory *bm) : _BlockMemory(bm) { } /// copy ctor CSTLBlockAllocator(const CSTLBlockAllocator &other) : _BlockMemory(other._BlockMemory) { // just copy the block memory from the other allocator. } /// dtor ~CSTLBlockAllocator() { _BlockMemory= NULL; } pointer allocate(size_type n, const_pointer hint= NULL) { if(n==0) return NULL; // If sizeof 1, use CBlockMemory allocation if(n==1) { #ifdef NL_DEBUG // verify that we allocate with good size!! (verify __stl_alloc_rebind scheme). // ie an allocator can be used only to allocate a kind of element uint eltSize= std::max(sizeof(T), sizeof(void*)); nlassert( eltSize == _BlockMemory->__stl_alloc_getEltSize() ); #endif // and allocate. return _BlockMemory->allocate(); } // else use std malloc else return (T*)new uint8[n*sizeof(T)]; } void deallocate(void *p, size_type n) { if(n==0) return; // If sizeof 1, use CBlockMemory allocation if(n==1) _BlockMemory->free((T*)p); // else use std free else delete [] ((uint8*)p); } template CSTLBlockAllocator& __stl_alloc_rebind(CSTLBlockAllocator<_Tp>& __a, const U*) { // must change the internal eltSize of __a. __a._BlockMemory->__stl_alloc_changeEltSize(sizeof(U)); // and just typecast/return him return (CSTLBlockAllocator&)(__a); } template CSTLBlockAllocator __stl_alloc_create(const CSTLBlockAllocator<_Tp>&, const U*) { return CSTLBlockAllocator(); } // ******************* private: // The blockMemory used to allocate elements CBlockMemory *_BlockMemory; }; #else // NL_OS_WINDOWS # if !defined (__STL_USE_SGI_ALLOCATORS) template class CSTLBlockAllocator : public std::allocator< T > { public: /// Constructor. Must gives a blockMemory to ctor. NB: must gives a CBlockMemory !!! CSTLBlockAllocator(CBlockMemory *bm) { } /// copy ctor CSTLBlockAllocator(const CSTLBlockAllocator &other) : std::allocator(other) { } /// dtor ~CSTLBlockAllocator() { } }; # else // !defined (__STL_USE_SGI_ALLOCATORS) class CSTLBlockAllocator : public __sgi_alloc { public: /// Constructor. Must gives a blockMemory to ctor. NB: must gives a CBlockMemory !!! CSTLBlockAllocator(CBlockMemory *bm) { } /// copy ctor CSTLBlockAllocator(const CSTLBlockAllocator &other) : __sgi_alloc(other) { } /// dtor ~CSTLBlockAllocator() { } }; # endif // !defined (__STL_USE_SGI_ALLOCATORS) #endif // NL_OS_WINDOWS #endif // 0 } // NLMISC #endif // NL_STL_BLOCK_ALLOCATOR_H /* End of stl_block_allocator.h */ ================================================ FILE: code/nel/include/nel/misc/stl_block_list.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_STL_BLOCK_LIST_H #define NL_STL_BLOCK_LIST_H #include "types_nl.h" #include "stl_block_allocator.h" #include namespace NLMISC { // *************************************************************************** /** * This class is a list<> which use CSTLBlockAllocator * * You construct such a list like this: * CSTLBlockList myList(ptrOnBlockMemory); * * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ template class CSTLBlockList : public std::list > { public: typedef typename NLMISC::CSTLBlockList::size_type TSizeType; typedef typename NLMISC::CSTLBlockList::const_iterator TBlockListConstIt; explicit CSTLBlockList(CBlockMemory *bm ) : std::list >(CSTLBlockAllocator(bm)) { } explicit CSTLBlockList(TSizeType n, CBlockMemory *bm ) : std::list >(n,T(),CSTLBlockAllocator(bm)) { } explicit CSTLBlockList(TSizeType n, const T& v, CBlockMemory *bm ) : std::list >(n,v,CSTLBlockAllocator(bm)) { } CSTLBlockList(TBlockListConstIt first,TBlockListConstIt last, CBlockMemory *bm ): std::list >(first,last,CSTLBlockAllocator(bm)) { } }; } // NLMISC #endif // NL_STL_BLOCK_LIST_H /* End of stl_block_list.h */ ================================================ FILE: code/nel/include/nel/misc/stop_watch.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_STOP_WATCH_H #define NL_STOP_WATCH_H #include "types_nl.h" #include "time_nl.h" #include namespace NLMISC { typedef uint32 TTickDuration; typedef uint32 TMsDuration; /** * Stopwatch class used for performance measurements and statistics. * To measure the duration of a cycle, call stop(), get the results, then call start(). * \author Olivier Cado * \author Nevrax France * \date 2001 */ class CStopWatch { public: /// Constructor. Set a non-zero queueLength for partial average calculation CStopWatch( uint queueLength=0 ); /// Begin measurement void start(); /// Pause void pause(); /// Resume void resume(); /// Add time (in ticks unit) to the current measurement void addTime( TTickDuration t ); /// End measurement void stop(); /// Add an external duration (in ticks unit) to the average queue void addMeasurement( TTickDuration t ); /// Elapsed time in millisecond (call it after stop()) TMsDuration getDuration() const; /// Average duration of the queueLength last durations (using the queueLength argument specified in the constructor) TMsDuration getPartialAverage() const; /// Average of the duration TMsDuration getAverageDuration() const; /// Sum of the measured durations (in ticks) TTickDuration sumTicks() const { return _SumTicks; } /// Number of measurements uint32 measurementNumber() const { return _MeasurementNumber; } private: TTicks _BeginTime; TTickDuration _ElapsedTicks; TTickDuration _SumTicks; uint32 _MeasurementNumber; std::deque _Queue; uint _QLength; }; } // NLMISC #endif // NL_STOP_WATCH_H /* End of stop_watch.h */ ================================================ FILE: code/nel/include/nel/misc/stream.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_STREAM_H #define NL_STREAM_H #include "types_nl.h" #include "ucstring.h" #include "class_registry.h" #include "common.h" #include #include #include #include #include #include #include namespace NLMISC { class IStream; class CMemStream; // ====================================================================================================== // ====================================================================================================== // Stream System. // ====================================================================================================== // ====================================================================================================== // For Big/little Endian. # define NLMISC_BSWAP16(src) (src) = (((src)>>8)&0xFF) | (((src)&0xFF)<<8) # if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM) # define NLMISC_BSWAP32(src) _asm mov eax,(src) _asm bswap eax _asm mov (src),eax # else # define NLMISC_BSWAP32(src) (src) = (((src)>>24)&0xFF) | ((((src)>>16)&0xFF)<<8) | ((((src)>>8)&0xFF)<<16) | (((src)&0xFF)<<24) # endif # define NLMISC_BSWAP64(src) (src) = (((src)>>56)&0xFF) | ((((src)>>48)&0xFF)<<8) | ((((src)>>40)&0xFF)<<16) | ((((src)>>32)&0xFF)<<24) | ((((src)>>24)&0xFF)<<32) | ((((src)>>16)&0xFF)<<40) | ((((src)>>8)&0xFF)<<48) | (((src)&0xFF)<<56) // convert a 4 characters string to uint32 #ifdef NL_LITTLE_ENDIAN # define NELID(x) (uint32((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3]))) #else # define NELID(x) (uint32((x[3] << 24) | (x[2] << 16) | (x[1] << 8) | (x[0]))) #endif // ====================================================================================================== /** * Stream Exception. * \author Lionel Berenguier * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ struct EStream : public Exception { EStream() : Exception( "Stream Error" ) {} EStream( const std::string& str ) : Exception( str ) {} EStream( const IStream &f ); EStream( const IStream &f, const std::string& str ); virtual ~EStream() throw() {} // May Not be Filled... std::string StreamName; }; struct EOlderStream : public EStream { EOlderStream() : EStream("The version in stream is older than the class" ) {} EOlderStream(const IStream &f) : EStream(f, "The version in stream is older than the class" ) {} }; struct ENewerStream : public EStream { ENewerStream() : EStream("The version in stream is newer than the class" ) {} ENewerStream(const IStream &f) : EStream(f, "The version in stream is newer than the class" ) {} }; struct EInvalidDataStream : public EStream { EInvalidDataStream() : EStream("Invalid data format" ) {} EInvalidDataStream(const IStream &f) : EStream(f, "Invalid data format" ) {} // msg must contain "%u" for the position of 'size' EInvalidDataStream(const char *msg, uint size); }; struct ESeekNotSupported : public EStream { ESeekNotSupported() : EStream("Seek fonctionnality is not supported" ) {} ESeekNotSupported(const IStream &f) : EStream(f, "Seek fonctionnality is not supported" ) {} }; struct ENotOutputStream : public EStream { ENotOutputStream() : EStream("The stream is NOT an output stream, can't write in" ) {} ENotOutputStream(const IStream &f) : EStream(f, "The stream is NOT an output stream, can't write in" ) {} }; struct ENotInputStream : public EStream { ENotInputStream () : EStream("The stream is NOT an input stream, cannot read in" ) {} ENotInputStream (const IStream &f) : EStream(f, "The stream is NOT an input stream, cannot read in" ) {} }; /// This exception is raised when someone tries to serialize in more than there is. struct EStreamOverflow : public EStream { EStreamOverflow() : EStream( "Stream Overflow Error" ) {} // msg must contain "%u" for the position of 'size' EStreamOverflow(const char *msg, uint size); }; class IStreamable; // ====================================================================================================== /** * A IO stream interface. * This is the base interface for stream objects. Differents kind of streams may be implemented, * by specifying serialBuffer() methods. * * \b Deriver \b Use: * * The deriver must: * - construct object specifying his type, see IStream(). A stream may be setup Input or Output at construction, but cannot * change during his life. * - specify serialBuffer(), to save or load pack of bytes. * - specify serialBit(), to save or load a bit. * - call resetPtrTable() when the stream reset itself (e.g.: CIFile::close() ) * * Sample of streams: COutMemoryStream, CInFileStream ... * * \b Client \b Use: * * An object which can be serialized, must provide a "void serial(IStream &)" method. In this method, he can use * any of the IStream method to help himself like: * - serial() with a base type (uint32, string, char...), or even with an object which provide "void serial(IStream &)" * - template serial(T0&, T1&, ...) to serialize multiple object/variables in one call (up to 6). * - serialCont() to serialize containers. * - serialVersion() to check/store a version number of his class. * - serialPtr() to use the ptr support of IStream (see serialPtr() for more information) * - isReading() to know if he write in the stream, or if he read. * * The using is very simple as shown in this example: * * \code class A { public: float x; uint32 y; Class1 a; // this class must provide a serial() method too... Base *c,*d; // Base must derive from IStreamable vector tab; public: void serial(IStream &f) { sint streamver= f.serialVersion(3); f.serial(x,y,a); f.serialPtr(c); f.serialCont(tab); if(streamver>=2) f.serialPtr(d); } }; \endcode * * NB: \b YOU \b CANNOT use serial with a int / uint / sint type, since those type have unspecified length. * \author Lionel Berenguier * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ class IStream { public: /** * Set the behavior of IStream regarding input stream that are older/newer than the class. * If throwOnOlder==true, IStream throws a EOlderStream when needed. * If throwOnNewer==true, IStream throws a ENewerStream when needed. * * By default, the behavior is throwOnOlder=false, throwOnNewer=true. * \see serialVersion() getVersionException() */ static void setVersionException(bool throwOnOlder, bool throwOnNewer); /** * Get the behavior of IStream regarding input stream that are older/newer than the class. * \see serialVersion() setVersionException() */ static void getVersionException(bool &throwOnOlder, bool &throwOnNewer); public: /** * Constructor. * Notice that those behavior can be set at construction only. * \param inputStream is the stream an Input (read) stream? */ explicit IStream(bool inputStream); /// Destructor. virtual ~IStream() {} /// Copy constructor IStream( const IStream& other ); /// Assignment operator IStream& operator=( const IStream& other ); /// exchange void swap(IStream &other); /// Is this stream a Read/Input stream? bool isReading() const; // is it a xml stream ? bool isXML() const { return _XML; } /** * Template Object serialisation. * \param obj any object providing a "void serial(IStream&)" method. The object doesn't have to derive from IStreamable. * * the VC++ error "error C2228: left of '.serial' must have class/struct/union type" means you don't provide * a serial() method to your object. Or you may have use serial with a int / uint / sint type. REMEMBER YOU CANNOT * do this, since those type have unspecified length. */ template void serial(T &obj) { obj.serial(*this); } // an utility template to unconst a type template static T& unconst(const T &t) { return const_cast(t);} #define nlWriteSerial(_stream, _obj) \ if ((_stream).isReading()) \ throw NLMISC::ENotOutputStream(); \ (_stream).serial(NLMISC::IStream::unconst(_obj)); #define nlWrite(_stream, _serialType, _obj) \ if ((_stream).isReading()) \ throw NLMISC::ENotOutputStream(); \ (_stream)._serialType(NLMISC::IStream::unconst(_obj)); #define nlReadSerial(_stream, _obj) \ if (!(_stream).isReading()) \ throw NLMISC::ENotInputStream(); \ NLMISC::IStream::unconst(_stream).serial(_obj); #define nlRead(_stream, _serialType, _obj) \ if (!(_stream).isReading()) \ throw NLMISC::ENotInputStream(); \ NLMISC::IStream::unconst(_stream)._serialType(_obj); // helper macro to serialize boolean encoded as 'bool foo : 1' (they can't be referenced) #define nlSerialBitBool(_stream, _boolean) \ { \ bool tmpBool = _boolean; \ _stream.serial(tmpBool); \ _boolean = tmpBool; \ } /** \name Base type serialization. * Those method are a specialization of template method "void serial(T&)". */ //@{ virtual void serial(uint8 &b) ; virtual void serial(sint8 &b) ; virtual void serial(uint16 &b) ; virtual void serial(sint16 &b) ; virtual void serial(uint32 &b) ; virtual void serial(sint32 &b) ; virtual void serial(uint64 &b) ; virtual void serial(sint64 &b) ; virtual void serial(float &b) ; virtual void serial(double &b) ; virtual void serial(bool &b) ; #ifndef NL_OS_CYGWIN virtual void serial(char &b) ; #endif virtual void serial(std::string &b) ; virtual void serial(ucstring &b) ; //@} /// Template enum serialisation. Serialized as a sint32. template void serialEnum(T &em) { sint32 i; if(isReading()) { serial(i); em = (T)i; } else { i = em; serial(i); } } /// Template short enum serialisation. Serialized as a uint8 (with checking). template void serialShortEnum(T &em) { uint8 i; if(isReading()) { serial(i); em = (T)i; } else { nlassert(em < 0xff); i = uint8(em); serial(i); } } /// Serial memstream, bitmemstream... virtual void serialMemStream( CMemStream &b ); /** \name BitField serialisation. * Unlike other serial method, The reading bitfield is returned!! If !this->isReading(), bf is returned. * * MUST use it simply like this: a= serialBitFieldX(a); // where X== 8, 16 or 32. * * NB: Performance warning: the data is stored as an uint8, uint16 or uint32, according to the method you use. */ //@{ /// Serialisation of bitfield <=8 bits. uint8 serialBitField8(uint8 bf); /// Serialisation of bitfield <=16 bits. uint16 serialBitField16(uint16 bf); /// Serialisation of bitfield <=32 bits. uint32 serialBitField32(uint32 bf); //@} /** \name Multiple serialisation. * Template for easy multiple serialisation. */ //@{ template void serial(T0 &a, T1 &b) { serial(a); serial(b);} template void serial(T0 &a, T1 &b, T2 &c) { serial(a); serial(b); serial(c);} template void serial(T0 &a, T1 &b, T2 &c, T3 &d) { serial(a); serial(b); serial(c); serial(d);} template void serial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e) { serial(a); serial(b); serial(c); serial(d); serial(e);} template void serial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e, T5 &f) { serial(a); serial(b); serial(c); serial(d); serial(e); serial(f);} //@} /** \name standard STL containers serialisation. * Known Supported containers: vector<>, list<>, deque<>, set<>, multiset<>, map<>, multimap<> * Support up to sint32 length containers. * \see serialContPtr() serialContPolyPtr() */ template void serialCont(std::vector &cont) {serialVector(cont);} template void serialCont(std::list &cont) {serialSTLCont(cont);} template void serialCont(std::deque &cont) {serialSTLCont(cont);} template void serialCont(std::set &cont) {serialSTLCont(cont);} template void serialCont(std::multiset &cont) {serialSTLCont(cont);} template void serialCont(std::map &cont) {serialMap(cont);} template void serialCont(CHashMap &cont) {serialMap(cont);} template void serialCont(std::multimap &cont) {serialMultimap(cont);} /** \name standard STL containers serialisation. * Thse variants suppose contained type is a NeL smart pointer. * Known Supported containers: map<> * Support up to sint32 length containers. * \see serialCont() serialContPtr() serialContPolyPtr() */ template void serialPtrCont(std::map &cont) {serialPtrMap(cont);} /// Specialisation of serialCont() for vector virtual void serialCont(std::vector &cont) ; /// Specialisation of serialCont() for vector virtual void serialCont(std::vector &cont) ; /// Specialisation of serialCont() for vector virtual void serialCont(std::vector &cont) ; /** \name standard STL containers serialisation. Elements must be pointers on a base type (uint...) or on a * object providing "void serial(IStream&)" method. * Known Supported containers: vector<>, list<>, deque<>, set<>, multiset<> * Support up to sint32 length containers. * \see serialCont() serialContPolyPtr() */ template void serialContPtr(std::vector &cont) {serialVectorPtr(cont);} template void serialContPtr(std::list &cont) {serialSTLContPtr(cont);} template void serialContPtr(std::deque &cont) {serialSTLContPtr(cont);} template void serialContPtr(std::set &cont) {serialSTLContPtr(cont);} template void serialContPtr(std::multiset &cont) {serialSTLContPtr(cont);} /** \name standard STL containers serialisation. Elements must be pointers on a IStreamable object. * Known Supported containers: vector<>, list<>, deque<>, set<>, multiset<> * Support up to sint32 length containers. * \see serialCont() serialContPtr() */ template void serialContPolyPtr(std::vector &cont) {serialVectorPolyPtr(cont);} template void serialContPolyPtr(std::list &cont) {serialSTLContPolyPtr(cont);} template void serialContPolyPtr(std::deque &cont) {serialSTLContPolyPtr(cont);} template void serialContPolyPtr(std::set &cont) {serialSTLContPolyPtr(cont);} template void serialContPolyPtr(std::multiset &cont) {serialSTLContPolyPtr(cont);} template void serialContPolyPtr(std::map &cont) {serialMapPolyPtr(cont);} /** * Serialize Non Polymorphic Objet Ptr. * Works with NULL pointers. If the same object is found mutliple time in the stream, ONLY ONE instance is written! * NB: The ptr is serialised as a uint64 (64 bit compliant). * \param ptr a pointer on a base type or an object. * \see resetPtrTable() */ template void serialPtr(T* &ptr) { uint64 node; // Open the node header xmlPushBegin ("PTR"); xmlSetAttrib ("id"); if(isReading()) { serial(node); // Close the header xmlPushEnd (); if(node==0) ptr=NULL; else { ItIdMap it; it= _IdMap.find(node); // Test if object already created/read. if( it==_IdMap.end() ) { // Construct object. ptr= new T; if(ptr==NULL) throw EStream(); // Insert the node. _IdMap.insert( ValueIdMap(node, ptr) ); // Read the object! serial(*ptr); } else ptr= static_cast(it->second); } } else { if(ptr==NULL) { node= 0; serial(node); // Close the header xmlPushEnd (); } else { ItIdMap it; it = _IdMap.find((uint64)ptr); // Test if object has been already written if( it==_IdMap.end() ) { // Not yet written // Get the next available ID node = _NextSerialPtrId++; // Serial the id serial(node); // Insert the pointer in the map with the id _IdMap.insert( ValueIdMap((uint64)ptr, (void*)node) ); // Close the header xmlPushEnd (); // Write the object serial(*ptr); } else { // Write only the object id node = (uint64)(it->second); serial(node); // Close the header xmlPushEnd (); } } } // Close the node xmlPop (); } /** * Serialize Polymorphic Objet Ptr. * Works with NULL pointers. If the same object is found mutliple time in the stream, ONLY ONE instance is written! * NB: The ptr is serialised as a uint64 (64 bit compliant). * \param ptr a pointer on a IStreamable object. * \see resetPtrTable() */ template void serialPolyPtr(T* &ptr) { IStreamable *p=ptr; serialIStreamable(p); ptr= static_cast(p);} /** * Serialize a version number. * Each object should store/read first a version number, using this method. * Then he can use the streamVersion returned to see how he should serialise himself. * * NB: Version Number is read/store as a uint8, or uint32 if too bigger.. * \param currentVersion the current version of the class, provided by user. * \return the version of the stream. If the stream is an Output stream, currentVersion is returned. * \see setVersionException() getVersionException() */ uint serialVersion(uint currentVersion) ; /** * Serialize a check value. * An object can stream a check value to check integrity or format of filed or streamed data. * Just call serial check with a const value. Write will serial the value. Read will * check the value is the same. If it is not, it will throw EInvalidDataStream exception. * * NB: The type of the value must implement an operator == and must be serializable. * \param value the value used to the check. * \see EInvalidDataStream */ template void serialCheck(const T& value) { // Open a node xmlPush ("CHECK"); if (isReading()) { T read; serial (read); if (read!=value) throw EInvalidDataStream(*this); } else { serial (const_cast(value)); } // Close the node xmlPop (); } /// \name Seek fonctionnality /** * Parameters for seek(). * begin seek from the beginning of the stream. * current seek from the current location of the stream pointer. * end seek from the end of the stream. */ enum TSeekOrigin { begin, current, end }; /** * Moves the stream pointer to a specified location. * * NB: If the stream doesn't support the seek fonctionnality, it throw ESeekNotSupported. * Default implementation: * { throw ESeekNotSupported; } * \param offset is the wanted offset from the origin. * \param origin is the origin of the seek * \return true if seek sucessfull. * \see ESeekNotSupported SeekOrigin getPos */ virtual bool seek (sint32 offset, TSeekOrigin origin) const; /** * Get the location of the stream pointer. * * NB: If the stream doesn't support the seek fonctionnality, it throw ESeekNotSupported. * Default implementation: * { throw ESeekNotSupported; } * \param offset is the wanted offset from the origin. * \param origin is the origin of the seek * \return the new offset regarding from the origin. * \see ESeekNotSupported SeekOrigin seek */ virtual sint32 getPos () const; /** Get a name for this stream. maybe a fileName if FileStream. * Default is to return "". */ virtual std::string getStreamName() const; /** \name XML user interface * * Those functions are used to add information in your stream to structure it like * a XML document. Exemple of a serial sequence : \code // Start the opening of a new node named Identity stream.xmlPush ("Identity") // Serial some infos stream.serial (name); stream.serial (pseudo); // Open a new node header named Address stream.xmlPushBegin ("Address"); // Set a property name stream.xmlSetAttrib ("Street") // Serial the property stream.serial ("Street"); // Close the new node header stream.xmlPushEnd (); // Serial in this node stream.serial (cityName); // Close the address node stream.xmlPop (); // Add a comment stream.xmlComment ("Hello"); // Close the identity node stream.xmlPop (); \endcode * * The result will be an xml document structured like this: * \code Corvazier Hulud
Paris <\Address> <\Identity> \endcode * * Node header serials are the serialisations done between xmlPushBegin() and xmlPushEnd() call. There is some restrictions on them: * Node header serials are only available for basic types (numbers and strings). * xmlSetAttrib() must be called before node header serial. * * Note that XML documents only have ONE root node, so all serialisation must be done between a xmlPush() and a xmlPop() call. * * When a xml input stream will try to open a node, it will scan all currrent child nodes to find the good one. * So input xml stream can skip unknown node. */ /** * xmlSerial() serial a values into a node. */ template void xmlSerial (T& value0, const char *nodeName) { // Open the node xmlPush (nodeName); // Serial the value serial (value0); // Close the node xmlPop (); } template void xmlSerial (T& value0, T& value1, const char *nodeName) { // Open the node xmlPush (nodeName); // Serial the values serial (value0, value1); // Close the node xmlPop (); } template void xmlSerial (T& value0, T& value1, T& value2, const char *nodeName) { // Open the node xmlPush (nodeName); // Serial the values serial (value0, value1, value2); // Close the node xmlPop (); } template void xmlSerial (T& value0, T& value1, T& value2, T& value3, const char *nodeName) { // Open the node xmlPush (nodeName); // Serial the values serial (value0, value1, value2, value3); // Close the node xmlPop (); } /** * xmlPush() open recurcively a new node. You must call xmlPop to close this node. * * \name is the name of the node to open * \return true if you can open the node, false if the stream is between a xmlPushBegin() and a xmlPushEnd() call. */ bool xmlPush (const char *name) { // XML Mode ? if (_XML) { // Open the header bool res=xmlPushBeginInternal (name); if (res) // close the header xmlPushEndInternal (); // Return the result return res; } // Return ok return true; } /** * xmlPushBegin() open recurcively a new node and open its header. You must call xmlPushEnd() to close the header and xmlPop() to close this node. * * \name is the name of the node to open * \return true if you can open the node header, false if the stream is between a xmlPushBegin() and a xmlPushEnd() call. */ bool xmlPushBegin (const char *name) { // XML Mode ? if (_XML) { return xmlPushBeginInternal (name); } // Return ok return true; } /** * xmlPushEnd() close the node header. * * \return true if you can close the node header, false if no node header have been opened with xmlPushBegin(). */ bool xmlPushEnd () { // XML Mode ? if (_XML) { return xmlPushEndInternal (); } // Return ok return true; } /** * xmlPop() close the node. * * \return true if you can close the node, false if the node can't be closed (its header is still opened) or if there is no node to close. */ bool xmlPop () { // XML Mode ? if (_XML) { return xmlPopInternal (); } // Return ok return true; } /** * xmlSetAttrib() set the name of the next node header attribute serialised. * * \param name is the name of the node header attribute serialised. * \return true if the attribute name have been set, false if the node header is not open (the call is not between xmlPushBegin and xmlPushEnd) */ bool xmlSetAttrib (const char *name) { // XML Mode ? if (_XML) { return xmlSetAttribInternal (name); } // Return ok return true; } /** * xmlBreakLine() insert a break line in the XML stream. * * \return true if the break line is added, return false if no node is opened. */ bool xmlBreakLine () { // XML Mode ? if (_XML) { return xmlBreakLineInternal (); } // Return ok return true; } /** * xmlComment() insert a comment line in the XML stream. * * \return true if the comment is added, return false if no node is opened. */ bool xmlComment (const char *comment) { // XML Mode ? if (_XML) { return xmlCommentInternal (comment); } // Return ok return true; } protected: /// \name XML implementation interface /** Set the XML mode * \param on is true to enable XML mode else false */ void setXMLMode (bool on); /// xmlPushBegin implementation virtual bool xmlPushBeginInternal (const char * /* name */) { return true; }; /// xmlPushEnd implementation virtual bool xmlPushEndInternal () { return true; }; /// xmlPop implementation virtual bool xmlPopInternal () { return true; }; /// xmlBreakLine implementation virtual bool xmlSetAttribInternal (const char * /* name */) { return true; }; /// xmlBreakLine implementation virtual bool xmlBreakLineInternal () { return true; }; /// xmlComment implementation virtual bool xmlCommentInternal (const char * /* comment */) { return true; }; /** * for Deriver: reset the PtrTable in the stream. * If Derived stream provide reset()-like methods, they must call this method in their reset() methods. * For example, CFile::close() must call it, so it will work correctly with next serialPtr() */ void resetPtrTable(); /** * Change, in live, the state of the inputStream. This could be useful in certain case. * The deriver which would want to do such a thing must call this method, and implement his own behavior. * In certain case, it should call resetPtrTable() if he want to reset the stream ptr info (maybe always)... */ void setInOut(bool inputStream); /** Get the size for this stream. return 0 by default. Only implemented for input stream that know their size. * Used internally to detect OverFlow with vector<> for instance */ virtual uint getDbgStreamSize() const {return 0;} /** * Elementarily check at least n bytes can be serialized from this stream (or throw EStreamOverflow) */ void checkStreamSize(uint numBytes) const { uint ssize = getDbgStreamSize(); if (ssize > 0 && ssize < numBytes) throw EStreamOverflow("stream does not contain at least %u bytes for check", numBytes); } public: //@{ /** Method to be specified by the Deriver. * \warning Do not call these methods from outside, unless you really know what you are doing. * Using them instead of serial() can lead to communication problems between different platforms ! */ virtual void serialBuffer(uint8 *buf, uint len) =0; virtual void serialBit(bool &bit) =0; //@} /// This method first serializes the size of the buffer and after the buffer itself, it enables /// the possibility to serial with a serialCont() on the other side. virtual void serialBufferWithSize(uint8 *buf, uint32 len) { serial (len); serialBuffer (buf, len); } private: bool _InputStream; static bool _ThrowOnOlder; static bool _ThrowOnNewer; // Ptr registry. We store 64 bit Id, to be compatible with future 64+ bits pointers. uint32 _NextSerialPtrId; CHashMap _IdMap; typedef CHashMap::iterator ItIdMap; typedef CHashMap::value_type ValueIdMap; // Ptr serialization. void serialIStreamable(IStreamable* &ptr) ; private: /** * standard STL containers serialization. Don't work with map<> and multimap<>. * Support up to sint32 length containers. serialize just len element of the container. */ template void serialSTLContLen(T &cont, sint32 len) { typedef typename T::value_type __value_type; typedef typename T::iterator __iterator; if(isReading()) { // check stream holds enough bytes (avoid STL to crash on resize) checkStreamSize(len); for(sint i=0;i(*it)); xmlPop (); } } } /** * standard STL containers serialisation. Don't work with map<> and multimap<>. * Support up to sint32 length containers. * * the object T must provide: * \li typedef iterator; (providing operator++() and operator*()) * \li typedef value_type; (a base type (uint...), or an object providing "void serial(IStream&)" method.) * \li void clear(); * \li size_type size() const; * \li iterator begin(); * \li iterator end(); * \li iterator insert(iterator it, const value_type& x); * * Known Supported containers: vector<>, list<>, deque<>, set<>, multiset<>. * \param cont a STL container (vector<>, set<> ...). */ template void serialSTLCont(T &cont) { // Open a node header xmlPushBegin ("CONTAINER"); // Attrib size xmlSetAttrib ("size"); sint32 len=0; if(isReading()) { serial(len); cont.clear(); } else { len= (sint32)cont.size(); serial(len); } // Close the header xmlPushEnd (); serialSTLContLen(cont, len); // Close the node xmlPop (); } protected: /** * special version for serializing a vector. * Support up to sint32 length containers. */ template void serialVector(T &cont) { typedef typename T::value_type __value_type; typedef typename T::iterator __iterator; // Open a node header xmlPushBegin ("VECTOR"); // Attrib size xmlSetAttrib ("size"); sint32 len=0; if(isReading()) { serial(len); // check stream holds enough bytes (avoid STL to crash on resize) checkStreamSize(len); // Open a node header xmlPushEnd (); // special version for vector: adjut good size. contReset(cont); cont.resize (len); // Read the vector for(sint i=0;i(*it)); xmlPop (); } } // Close the node xmlPop (); } private: /** * standard STL containers serialisation. Don't work with map<> and multimap<>. Ptr version. * Support up to sint32 length containers. serialize just len element of the container. */ template void serialSTLContLenPtr(T &cont, sint32 len) { typedef typename T::value_type __value_type; typedef typename T::iterator __iterator; if(isReading()) { // check stream holds enough bytes (avoid STL to crash on resize) checkStreamSize(len); for(sint i=0;i(*it)); } } } /** * standard STL containers serialisation. Don't work with map<> and multimap<>. Ptr version. * Support up to sint32 length containers. */ template void serialSTLContPtr(T &cont) { // Open a node header xmlPushBegin ("CONTAINER"); // Attrib size xmlSetAttrib ("size"); sint32 len=0; if(isReading()) { serial(len); cont.clear(); } else { len= cont.size(); serial(len); } // Close the node header xmlPushEnd (); serialSTLContLenPtr(cont, len); // Close the node xmlPop (); } /** * special version for serializing a vector. Ptr version. * Support up to sint32 length containers. */ template void serialVectorPtr(T &cont) { typedef typename T::value_type __value_type; typedef typename T::iterator __iterator; // Open a node header xmlPushBegin ("VECTOR"); // Attrib size xmlSetAttrib ("size"); sint32 len=0; if(isReading()) { serial(len); // special version for vector: adjut good size. contReset(cont); // check stream holds enough bytes (avoid STL to crash on resize) checkStreamSize(len); cont.reserve(len); } else { len= (sint32)cont.size(); serial(len); } // Close the node header xmlPushEnd (); serialSTLContLenPtr(cont, len); // Close the node xmlPop (); } private: /** * standard STL containers serialisation. Don't work with map<> and multimap<>. PolyPtr version * Support up to sint32 length containers. serialize just len element of the container. */ template void serialSTLContLenPolyPtr(T &cont, sint32 len) { typedef typename T::value_type __value_type; typedef typename T::iterator __iterator; if(isReading()) { // check stream holds enough bytes (avoid STL to crash on resize) checkStreamSize(len); for(sint i=0;i(*it)); } } } /** * Map serialisation. PolyPtr version * Support up to sint32 length containers. serialize just len element of the container. */ template void serialMapContLenPolyPtr(T &cont, sint32 len) { typedef typename T::key_type __key_type; typedef typename T::data_type __data_type; typedef typename T::iterator __iterator; if(isReading()) { // check stream holds enough bytes (avoid STL to crash on resize) checkStreamSize(len); // Close the node header xmlPushEnd (); for(sint i=0;i((*it).first) ); xmlPop (); xmlPush ("ELM"); __data_type v= const_cast<__data_type&>(it->second); v.serialPolyPtr(*this); xmlPop (); } } } /** * standard STL containers serialisation. Don't work with map<> and multimap<>. PolyPtr version * Support up to sint32 length containers. */ template void serialSTLContPolyPtr(T &cont) { sint32 len=0; if(isReading()) { serial(len); cont.clear(); } else { len= cont.size(); serial(len); } serialSTLContLenPolyPtr(cont, len); } /** * special version for serializing a vector. PolyPtr version * Support up to sint32 length containers. */ template void serialVectorPolyPtr(T &cont) { typedef typename T::value_type __value_type; typedef typename T::iterator __iterator; // Open a node header xmlPushBegin ("VECTOR"); // Attrib size xmlSetAttrib ("size"); sint32 len=0; if(isReading()) { serial(len); // special version for vector: adjut good size. contReset(cont); // check stream holds enough bytes (avoid STL to crash on resize) checkStreamSize(len); cont.reserve(len); } else { len= (sint32)cont.size(); serial(len); } // Close the node header xmlPushEnd (); serialSTLContLenPolyPtr(cont, len); // Close the node xmlPop (); } /** * special version for serializing a map. PolyPtr version * Support up to sint32 length containers. */ template void serialMapPolyPtr(std::map &cont) { // Open a node header xmlPushBegin ("MAP"); // Attrib size xmlSetAttrib ("size"); sint32 len=0; if(isReading()) { serial(len); cont.clear(); } else { len= cont.size(); serial(len); } serialMapContLenPolyPtr(cont, len); // Close the node xmlPop (); } private: /** * STL map<> and multimap<> serialisation. * Support up to sint32 length containers. * * the object T must provide: * \li typedef iterator; (providing operator++() and operator*()) * \li typedef value_type; (must be a std::pair<>) * \li typedef key_type; (must be the type of the key) * \li void clear(); * \li size_type size() const; * \li iterator begin(); * \li iterator end(); * \li iterator insert(iterator it, const value_type& x); * * Known Supported containers: map<>, multimap<>. * \param cont a STL map<> or multimap<> container. */ template void serialMultimap(T &cont) { typedef typename T::value_type __value_type; typedef typename T::key_type __key_type; typedef typename T::iterator __iterator; // Open a node header xmlPushBegin ("MULTIMAP"); // Attrib size xmlSetAttrib ("size"); sint32 len; if(isReading()) { cont.clear(); serial(len); // check stream holds enough bytes (avoid STL to crash on resize) checkStreamSize(len); // Close the node header xmlPushEnd (); for(sint i=0;i(v.first) ); xmlPop (); xmlPush ("ELM"); serial (v.second); xmlPop (); cont.insert(cont.end(), v); } } else { len= (sint32)cont.size(); serial(len); __iterator it= cont.begin(); // Close the node header xmlPushEnd (); for(sint i=0;i((*it).first) ); xmlPop (); xmlPush ("ELM"); serial((*it).second); xmlPop (); } } // Close the node xmlPop (); } /** * STL map<> * Support up to sint32 length containers. * * the object T must provide: * \li typedef iterator; (providing operator++() and operator*()) * \li typedef value_type; (must be a std::pair<>) * \li typedef key_type; (must be the type of the key) * \li void clear(); * \li size_type size() const; * \li iterator begin(); * \li iterator end(); * \li iterator insert(iterator it, const value_type& x); * * Known Supported containers: map<> * \param cont a STL map<> container. */ template void serialMap(T &cont) { typedef typename T::value_type __value_type; typedef typename T::key_type __key_type; typedef typename T::iterator __iterator; // Open a node header xmlPushBegin ("MAP"); // Attrib size xmlSetAttrib ("size"); sint32 len; if(isReading()) { cont.clear(); serial(len); // check stream holds enough bytes (avoid STL to crash on resize) checkStreamSize(len); // Close the node header xmlPushEnd (); for(sint i=0;i((*it).first) ); xmlPop (); xmlPush ("ELM"); serial((*it).second); xmlPop (); } } // Close the node xmlPop (); } /** * STL map<> * Support up to sint32 length containers. Container must contain NeL smart pointers. * * the object T must provide: * \li typedef iterator; (providing operator++() and operator*()) * \li typedef value_type; (must be a std::pair<>) * \li typedef key_type; (must be the type of the key) * \li void clear(); * \li size_type size() const; * \li iterator begin(); * \li iterator end(); * \li iterator insert(iterator it, const value_type& x); * * Known Supported containers: map<> * \param cont a STL map<> container. */ template void serialPtrMap(T &cont) { typedef typename T::value_type::second_type __ptr_type; typedef typename __ptr_type::element_type __value_type; typedef typename T::key_type __key_type; typedef typename T::iterator __iterator; // Open a node header xmlPushBegin ("MAP"); // Attrib size xmlSetAttrib ("size"); sint32 len; if(isReading()) { cont.clear(); serial(len); // check stream holds enough bytes (avoid STL to crash on resize) checkStreamSize(len); // Close the node header xmlPushEnd (); for(sint i=0;i((*it).first) ); xmlPop (); xmlPush ("ELM"); serial(*(*it).second); xmlPop (); } } // Close the node xmlPop (); } // Mode XML bool _XML; }; // ====================================================================================================== // ====================================================================================================== // Handle for streaming Polymorphic classes. // ====================================================================================================== // ====================================================================================================== // ====================================================================================================== /** * An Object Streamable interface. Any polymorphic class which want to use serial() in a polymorphic way, must derive * from this interface. * \author Lionel Berenguier * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ class IStreamable : public IClassable { public: virtual void serial(IStream &f) =0; }; } // NLMISC. // Inline Implementation. #include "stream_inline.h" #endif // NL_STREAM_H /* End of stream.h */ ================================================ FILE: code/nel/include/nel/misc/stream_inline.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_STREAM_INLINE_H #define NL_STREAM_INLINE_H #include "types_nl.h" #include "debug.h" #include namespace NLMISC { // ====================================================================================================== // ====================================================================================================== // IBasicStream Inline Implementation. // ====================================================================================================== // ====================================================================================================== // ====================================================================================================== // ====================================================================================================== // ====================================================================================================== // ====================================================================================================== inline IStream::IStream(bool inputStream) { _InputStream= inputStream; _XML = false; resetPtrTable(); } // ====================================================================================================== inline bool IStream::isReading() const { return _InputStream; } // ====================================================================================================== // ====================================================================================================== // ====================================================================================================== // ====================================================================================================== inline void IStream::serial(uint8 &b) { serialBuffer((uint8 *)&b, 1); } // ====================================================================================================== inline void IStream::serial(sint8 &b) { serialBuffer((uint8 *)&b, 1); } // ====================================================================================================== inline void IStream::serial(uint16 &b) { #ifdef NL_LITTLE_ENDIAN serialBuffer((uint8 *)&b, 2); #else // NL_LITTLE_ENDIAN uint16 v; if(isReading()) { serialBuffer((uint8 *)&v, 2); NLMISC_BSWAP16(v); b=v; } else { v=b; NLMISC_BSWAP16(v); serialBuffer((uint8 *)&v, 2); } #endif // NL_LITTLE_ENDIAN } // ====================================================================================================== inline void IStream::serial(sint16 &b) { #ifdef NL_LITTLE_ENDIAN serialBuffer((uint8 *)&b, 2); #else // NL_LITTLE_ENDIAN uint16 v; if(isReading()) { serialBuffer((uint8 *)&v, 2); NLMISC_BSWAP16(v); b=v; } else { v=b; NLMISC_BSWAP16(v); serialBuffer((uint8 *)&v, 2); } #endif // NL_LITTLE_ENDIAN } // ====================================================================================================== inline void IStream::serial(uint32 &b) { #ifdef NL_LITTLE_ENDIAN serialBuffer((uint8 *)&b, 4); #else // NL_LITTLE_ENDIAN uint32 v; if(isReading()) { serialBuffer((uint8 *)&v, 4); NLMISC_BSWAP32(v); b=v; } else { v=b; NLMISC_BSWAP32(v); serialBuffer((uint8 *)&v, 4); } #endif // NL_LITTLE_ENDIAN } // ====================================================================================================== inline void IStream::serial(sint32 &b) { #ifdef NL_LITTLE_ENDIAN serialBuffer((uint8 *)&b, 4); #else // NL_LITTLE_ENDIAN uint32 v; if(isReading()) { serialBuffer((uint8 *)&v, 4); NLMISC_BSWAP32(v); b=v; } else { v=b; NLMISC_BSWAP32(v); serialBuffer((uint8 *)&v, 4); } #endif // NL_LITTLE_ENDIAN } // ====================================================================================================== inline void IStream::serial(uint64 &b) { #ifdef NL_LITTLE_ENDIAN serialBuffer((uint8 *)&b, 8); #else // NL_LITTLE_ENDIAN uint64 v; if(isReading()) { serialBuffer((uint8 *)&v, 8); NLMISC_BSWAP64(v); b=v; } else { v=b; NLMISC_BSWAP64(v); serialBuffer((uint8 *)&v, 8); } #endif // NL_LITTLE_ENDIAN } // ====================================================================================================== inline void IStream::serial(sint64 &b) { #ifdef NL_LITTLE_ENDIAN serialBuffer((uint8 *)&b, 8); #else // NL_LITTLE_ENDIAN uint64 v; if(isReading()) { serialBuffer((uint8 *)&v, 8); NLMISC_BSWAP64(v); b=v; } else { v=b; NLMISC_BSWAP64(v); serialBuffer((uint8 *)&v, 8); } #endif // NL_LITTLE_ENDIAN } // ====================================================================================================== inline void IStream::serial(float &b) { #ifdef NL_LITTLE_ENDIAN serialBuffer((uint8 *)&b, 4); #else // NL_LITTLE_ENDIAN uint32 v; if(isReading()) { serialBuffer((uint8 *)&v, 4); NLMISC_BSWAP32(v); b=*((float*)&v); } else { v=*((uint32*)&b); NLMISC_BSWAP32(v); serialBuffer((uint8 *)&v, 4); } #endif // NL_LITTLE_ENDIAN } // ====================================================================================================== inline void IStream::serial(double &b) { #ifdef NL_LITTLE_ENDIAN serialBuffer((uint8 *)&b, 8); #else // NL_LITTLE_ENDIAN uint64 v; if(isReading()) { serialBuffer((uint8 *)&v, 8); NLMISC_BSWAP64(v); b=*((double*)&v); } else { v=*((uint64*)&b); NLMISC_BSWAP64(v); serialBuffer((uint8 *)&v, 8); } #endif // NL_LITTLE_ENDIAN } // ====================================================================================================== inline void IStream::serial(bool &b) { serialBit(b); } #ifndef NL_OS_CYGWIN // ====================================================================================================== inline void IStream::serial(char &b) { serialBuffer((uint8 *)&b, 1); } #endif // ====================================================================================================== inline void IStream::serial(std::string &b) { uint32 len=0; // Read/Write the length. if(isReading()) { serial(len); // check stream holds enough bytes (avoid STL to crash on resize) checkStreamSize(len); b.resize(len); } else { len= uint32(b.size()); if (len>1000000) throw NLMISC::EInvalidDataStream( "IStream: Trying to write a string of %u bytes", len ); serial(len); } /* // Read/Write the string. for(sint i=0;i 0) serialBuffer((uint8*)(&(b[0])), len); } // ====================================================================================================== inline void IStream::serial(ucstring &b) { uint32 len=0; // Read/Write the length. if(isReading()) { serial(len); // check stream holds enough bytes (avoid STL to crash on resize) checkStreamSize(len); b.resize(len); } else { len= uint32(b.size()); if (len>1000000) throw NLMISC::EInvalidDataStream( "IStream: Trying to write an ucstring of %u bytes", len ); serial(len); } // Read/Write the string. for(uint i=0;i!=len;++i) serial(b[i]); } // ====================================================================================================== inline uint8 IStream::serialBitField8(uint8 bf) { serial(bf); return bf; } // ====================================================================================================== inline uint16 IStream::serialBitField16(uint16 bf) { serial(bf); return bf; } // ====================================================================================================== inline uint32 IStream::serialBitField32(uint32 bf) { serial(bf); return bf; } } #endif // NL_STREAM_INLINE_H /* End of stream_inline.h */ ================================================ FILE: code/nel/include/nel/misc/string_common.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_STRING_COMMON_H #define NL_STRING_COMMON_H #include "types_nl.h" #include #include #include namespace NLMISC { // get a string and add \r before \n if necessary std::string addSlashR (std::string str); std::string removeSlashR (std::string str); /** * \def MaxCStringSize * * The maximum size allowed for C string (zero terminated string) buffer. * This value is used when we have to create a standard C string buffer and we don't know exactly the final size of the string. */ const int MaxCStringSize = 2048; /** * \def NLMISC_CONVERT_VARGS(dest,format) * * This macro converts variable arguments into C string (zero terminated string). * This function takes care to avoid buffer overflow. * * Example: *\code void MyFunction(const char *format, ...) { string str; NLMISC_CONVERT_VARGS (str, format, NLMISC::MaxCStringSize); // str contains the result of the conversion } *\endcode * * \param _dest \c string or \c char* that contains the result of the convertion * \param _format format of the string, it must be the last argument before the \c '...' * \param _size size of the buffer that will contain the C string */ #define NLMISC_CONVERT_VARGS(_dest,_format,_size) \ char _cstring[_size]; \ va_list _args; \ va_start (_args, _format); \ int _res = vsnprintf (_cstring, _size-1, _format, _args); \ if (_res == -1 || _res == _size-1) \ { \ _cstring[_size-1] = '\0'; \ } \ va_end (_args); \ _dest = _cstring /** sMart sprintf function. This function do a sprintf and add a zero at the end of the buffer * if there no enough room in the buffer. * * \param buffer a C string * \param count Size of the buffer * \param format of the string, it must be the last argument before the \c '...' */ sint smprintf( char *buffer, size_t count, const char *format, ... ); #ifdef NL_OS_WINDOWS // // These functions are needed by template system to failed the compilation if you pass bad type on nlinfo... // inline void _check(int /* a */) { } inline void _check(unsigned int /* a */) { } inline void _check(char /* a */) { } inline void _check(unsigned char /* a */) { } inline void _check(long /* a */) { } inline void _check(unsigned long /* a */) { } #ifdef NL_COMP_VC6 inline void _check(uint8 /* a */) { } #endif // NL_COMP_VC6 inline void _check(sint8 /* a */) { } inline void _check(uint16 /* a */) { } inline void _check(sint16 /* a */) { } #ifdef NL_COMP_VC6 inline void _check(uint32 /* a */) { } inline void _check(sint32 /* a */) { } #endif // NL_COMP_VC6 inline void _check(uint64 /* a */) { } inline void _check(sint64 /* a */) { } inline void _check(float /* a */) { } inline void _check(double /* a */) { } inline void _check(const char * /* a */) { } inline void _check(const void * /* a */) { } #define CHECK_TYPES(__a,__b) \ inline __a(const char *fmt) { __b(fmt); } \ template __a(const char *fmt, A a) { _check(a); __b(fmt, a); } \ template __a(const char *fmt, A a, B b) { _check(a); _check(b); __b(fmt, a, b); } \ template __a(const char *fmt, A a, B b, C c) { _check(a); _check(b); _check(c); __b(fmt, a, b, c); } \ template __a(const char *fmt, A a, B b, C c, D d) { _check(a); _check(b); _check(c); _check(d); __b(fmt, a, b, c, d); } \ template __a(const char *fmt, A a, B b, C c, D d, E e) { _check(a); _check(b); _check(c); _check(d); _check(e); __b(fmt, a, b, c, d, e); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); __b(fmt, a, b, c, d, e, f); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); __b(fmt, a, b, c, d, e, f, g); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); __b(fmt, a, b, c, d, e, f, g, h); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); __b(fmt, a, b, c, d, e, f, g, h, i); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); __b(fmt, a, b, c, d, e, f, g, h, i, j); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); __b(fmt, a, b, c, d, e, f, g, h, i, j, k); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); _check(x); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x, Y y) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); _check(x); _check(y); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y); } \ template __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x, Y y, Z z) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); _check(x); _check(y); _check(z); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z); } #endif #ifdef NL_OS_WINDOWS inline std::string _toString(const char *format, ...) #else inline std::string toString(const char *format, ...) #endif { std::string Result; NLMISC_CONVERT_VARGS(Result, format, NLMISC::MaxCStringSize); return Result; } #ifdef NL_OS_WINDOWS CHECK_TYPES(std::string toString, return _toString) #endif // NL_OS_WINDOWS template std::string toStringPtr(const T *val) { return toString("%p", val); } template std::string toStringEnum(const T &val) { return toString("%u", (uint32)val); } /** * Template Object toString. * \param obj any object providing a "std::string toString()" method. The object doesn't have to derive from anything. * * the VC++ error "error C2228: left of '.toString' must have class/struct/union type" means you don't provide * a toString() method to your object. */ #ifndef NL_COMP_CLANG template std::string toString(const T &obj) { return obj.toString(); } #endif //inline std::string toString(const char *val) { return toString("%s", val); } inline std::string toString(const uint8 val) { return toString("%hu", (uint16)val); } inline std::string toString(const sint8 val) { return toString("%hd", (sint16)val); } inline std::string toString(const uint16 val) { return toString("%hu", val); } inline std::string toString(const sint16 val) { return toString("%hd", val); } inline std::string toString(const uint32 val) { return toString("%u", val); } inline std::string toString(const sint32 val) { return toString("%d", val); } inline std::string toString(const uint64 val) { return toString("%" NL_I64 "u", val); } inline std::string toString(const sint64 val) { return toString("%" NL_I64 "d", val); } #ifdef NL_COMP_GCC # if GCC_VERSION == 40102 // error fix for size_t? gcc 4.1.2 requested this type instead of size_t ... inline std::string toString(const long unsigned int &val) { if (sizeof(long unsigned int) == 8) return toString((uint64)val); return toString((uint32)val); } # endif #endif #if (SIZEOF_SIZE_T) == 8 inline std::string toString(const size_t &val) { return toString("%" NL_I64 "u", val); } #else #ifdef NL_OS_MAC inline std::string toString(const size_t &val) { return toString("%u", val); } #endif #endif inline std::string toString(const float &val) { return toString("%f", val); } inline std::string toString(const double &val) { return toString("%lf", val); } inline std::string toString(const bool &val) { return toString("%u", val?1:0); } inline std::string toString(const std::string &val) { return val; } // stl vectors of bool use bit reference and not real bools, so define the operator for bit reference #ifdef NL_COMP_VC6 inline std::string toString(const uint &val) { return toString("%u", val); } inline std::string toString(const sint &val) { return toString("%d", val); } #endif // NL_COMP_VC6 template bool fromString(const std::string &str, T &obj) { return obj.fromString(str); } inline bool fromString(const std::string &str, uint32 &val) { if (str.find('-') != std::string::npos) { val = 0; return false; } char *end; unsigned long v; errno = 0; v = strtoul(str.c_str(), &end, 10); if (errno || v > UINT_MAX || end == str.c_str()) { val = 0; return false; } else { val = (uint32)v; return true; } } inline bool fromString(const std::string &str, sint32 &val) { char *end; long v; errno = 0; v = strtol(str.c_str(), &end, 10); if (errno || v > INT_MAX || v < INT_MIN || end == str.c_str()) { val = 0; return false; } else { val = (sint32)v; return true; } } inline bool fromString(const std::string &str, uint8 &val) { char *end; long v; errno = 0; v = strtol(str.c_str(), &end, 10); if (errno || v > UCHAR_MAX || v < 0 || end == str.c_str()) { val = 0; return false; } else { val = (uint8)v; return true; } } inline bool fromString(const std::string &str, sint8 &val) { char *end; long v; errno = 0; v = strtol(str.c_str(), &end, 10); if (errno || v > SCHAR_MAX || v < SCHAR_MIN || end == str.c_str()) { val = 0; return false; } else { val = (sint8)v; return true; } } inline bool fromString(const std::string &str, uint16 &val) { char *end; long v; errno = 0; v = strtol(str.c_str(), &end, 10); if (errno || v > USHRT_MAX || v < 0 || end == str.c_str()) { val = 0; return false; } else { val = (uint16)v; return true; } } inline bool fromString(const std::string &str, sint16 &val) { char *end; long v; errno = 0; v = strtol(str.c_str(), &end, 10); if (errno || v > SHRT_MAX || v < SHRT_MIN || end == str.c_str()) { val = 0; return false; } else { val = (sint16)v; return true; } } inline bool fromString(const std::string &str, uint64 &val) { bool ret = sscanf(str.c_str(), "%" NL_I64 "u", &val) == 1; if (!ret) val = 0; return ret; } inline bool fromString(const std::string &str, sint64 &val) { bool ret = sscanf(str.c_str(), "%" NL_I64 "d", &val) == 1; if (!ret) val = 0; return ret; } inline bool fromString(const std::string &str, float &val) { bool ret = sscanf(str.c_str(), "%f", &val) == 1; if (!ret) val = 0.0f; return ret; } inline bool fromString(const std::string &str, double &val) { bool ret = sscanf(str.c_str(), "%lf", &val) == 1; if (!ret) val = 0.0; return ret; } inline bool fromString(const std::string &str, bool &val) { if( str.length() == 1 ) { if( str[ 0 ] == '1' ) val = true; else if( str[ 0 ] == '0' ) val = false; else return false; } else { if( str == "true" ) val = true; else if( str == "false" ) val = false; else return false; } return true; } inline bool fromString(const char *str, uint32 &val) { if (strstr(str, "-") != NULL) { val = 0; return false; } char *end; unsigned long v; errno = 0; v = strtoul(str, &end, 10); if (errno || v > UINT_MAX || end == str) { val = 0; return false; } else { val = (uint32)v; return true; } } inline bool fromString(const char *str, sint32 &val) { char *end; long v; errno = 0; v = strtol(str, &end, 10); if (errno || v > INT_MAX || v < INT_MIN || end == str) { val = 0; return false; } else { val = (sint32)v; return true; } } inline bool fromString(const char *str, uint8 &val) { char *end; long v; errno = 0; v = strtol(str, &end, 10); if (errno || v > UCHAR_MAX || v < 0 || end == str) { val = 0; return false; } else { val = (uint8)v; return true; } } inline bool fromString(const char *str, sint8 &val) { char *end; long v; errno = 0; v = strtol(str, &end, 10); if (errno || v > SCHAR_MAX || v < SCHAR_MIN || end == str) { val = 0; return false; } else { val = (sint8)v; return true; } } inline bool fromString(const char *str, uint16 &val) { char *end; long v; errno = 0; v = strtol(str, &end, 10); if (errno || v > USHRT_MAX || v < 0 || end == str) { val = 0; return false; } else { val = (uint16)v; return true; } } inline bool fromString(const char *str, sint16 &val) { char *end; long v; errno = 0; v = strtol(str, &end, 10); if (errno || v > SHRT_MAX || v < SHRT_MIN || end == str) { val = 0; return false; } else { val = (sint16)v; return true; } } inline bool fromString(const char *str, uint64 &val) { bool ret = sscanf(str, "%" NL_I64 "u", &val) == 1; if (!ret) val = 0; return ret; } inline bool fromString(const char *str, sint64 &val) { bool ret = sscanf(str, "%" NL_I64 "d", &val) == 1; if (!ret) val = 0; return ret; } inline bool fromString(const char *str, float &val) { bool ret = sscanf(str, "%f", &val) == 1; if (!ret) val = 0.0f; return ret; } inline bool fromString(const char *str, double &val) { bool ret = sscanf(str, "%lf", &val) == 1; if (!ret) val = 0.0; return ret; } inline bool fromString(const char *str, bool &val) { switch (str[0]) { case '1': case 't': case 'y': case 'T': case 'Y': val = true; return true; case '0': case 'f': case 'n': case 'F': case 'N': val = false; return true; } return false; } inline bool fromString(const std::string &str, std::string &val) { val = str; return true; } // stl vectors of bool use bit reference and not real bools, so define the operator for bit reference #ifdef NL_COMP_VC6 inline bool fromString(const std::string &str, uint &val) { return sscanf(str.c_str(), "%u", &val) == 1; } inline bool fromString(const std::string &str, sint &val) { return sscanf(str.c_str(), "%d", &val) == 1; } #endif // NL_COMP_VC6 } // NLMISC #endif // NL_STRING_COMMON_H ================================================ FILE: code/nel/include/nel/misc/string_conversion.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_STRING_CONVERSION_H #define NL_STRING_CONVERSION_H #include "types_nl.h" #include "common.h" #include namespace NLMISC { // a predicate use to do unsensitive string comparison (with operator <) struct CUnsensitiveStrLessPred { bool operator()(const std::string &lhs, const std::string &rhs) const { return nlstricmp(lhs, rhs) < 0; } }; /** This class allow simple mapping between string and other type (such as integral types or enum) * In fact this primarily intended to make a string / enum correspondance * Example of use : * * // An enumerated type * enum TMyType { Foo = 0, Bar, FooBar, Unknown }; * * // The conversion table * static const CStringConversion::CPair stringTable [] = * { * { "Foo", Foo }, * { "Bar", Bar }, * { "FooBar", FooBar } * }; * * // The helper object for conversion (instance of this class) * static const CStringConversion conversion(stringTable, sizeof(stringTable) / sizeof(stringTable[0]), Unknown); * * // Some conversions request * TMyType value1 = conversion.fromString("foo"); // returns 'foo' * value1 = conversion.fromString("Foo"); // returns 'foo' (this is case unsensitive by default) * std::string str = conversion.toString(Bar) // returns "Bar" * * NB : Please note that that helpers macros are provided to build such a table in an easy way * \see NL_BEGIN_STRING_CONVERSION_TABLE * \see NL_END_STRING_CONVERSION_TABLE * * * NB: by default this class behaves in a case unsensitive way. To change this, just change the 'Pred' template parameter * to std::less * * \author Nicolas Vizerie * \author Nevrax France * \date 2003 */ template class CStringConversion { public: typedef DestType TDestType; typedef Pred TPred; struct CPair { const char *Str; TDestType Value; }; public: // init from pairs of string / value CStringConversion(const CPair *pairs, uint numPairs, const DestType ¬FoundValue); // add a pair in the array void insert(const char *str, TDestType value); // From a string, retrieve the associated value, or the 'notFoundValue' provided to the ctor of this object if the string wasn't found const TDestType &fromString(const std::string &str) const; // From a value, retrieve the associated string, or an empty string if not found const std::string &toString(const TDestType &value) const; // nb of pairs in the map inline uint16 getNbPairs() const { return (uint16)_String2DestType.size(); } // Check a value against the list a value, return true if the value exist in the container bool isValid(const DestType &value) const; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private: typedef std::map TString2DestType; typedef std::map TDestType2String; private: TString2DestType _String2DestType; TDestType2String _DestType2String; TDestType _NotFoundValue; }; /** This macro helps building a string conversion table * Example of use : * * // The enumerated type for which a conversion should be defined * enum TMyType { Foo = 0, Bar, FooBar, Unknown }; * * // The conversion table * NL_BEGIN_STRING_CONVERSION_TABLE(TMyType) * NL_STRING_CONVERSION_TABLE_ENTRY(Foo) * NL_STRING_CONVERSION_TABLE_ENTRY(Bar) * NL_STRING_CONVERSION_TABLE_ENTRY(FooBar) * NL_END_STRING_CONVERSION_TABLE(TMyType, myConversionTable, Unknown) * * // Now, we can use the 'myConversionTable' intance * * std::string str = myConversionTable.toString(Bar) // returns "Bar" * */ #define NL_BEGIN_STRING_CONVERSION_TABLE(__type) \ static const NLMISC::CStringConversion<__type>::CPair __type##_nl_string_conversion_table[] = \ { #define NL_END_STRING_CONVERSION_TABLE(__type, __tableName, __defaultValue) \ }; \ NLMISC::CStringConversion<__type> \ __tableName(__type##_nl_string_conversion_table, sizeof(__type##_nl_string_conversion_table) \ / sizeof(__type##_nl_string_conversion_table[0]), __defaultValue); #define NL_STRING_CONVERSION_TABLE_ENTRY(val) { #val, val}, ////////////////////////////////////// // CStringConversion implementation // ////////////////////////////////////// //================================================================================================================= /** CStringConversion ctor */ template CStringConversion::CStringConversion(const CPair *pairs, uint numPairs, const DestType ¬FoundValue) { for(uint k = 0; k < numPairs; ++k) { _String2DestType[pairs[k].Str] = pairs[k].Value; _DestType2String[pairs[k].Value] = pairs[k].Str; } _NotFoundValue = notFoundValue; } // template void CStringConversion::insert(const char *str, TDestType value) { _String2DestType[str] = value; _DestType2String[value] = str; } //================================================================================================================= template const DestType &CStringConversion::fromString(const std::string &str) const { typename TString2DestType::const_iterator it = _String2DestType.find(str); if (it == _String2DestType.end()) { return _NotFoundValue; } else { return it->second; } } //================================================================================================================= template const std::string &CStringConversion::toString(const DestType &value) const { typename TDestType2String::const_iterator it = _DestType2String.find(value); if (it == _DestType2String.end()) { static std::string emptyString; return emptyString; } else { return it->second; } } //================================================================================================================= template bool CStringConversion::isValid(const DestType &value) const { typename TDestType2String::const_iterator it = _DestType2String.find(value); return it != _DestType2String.end(); } } // NLMISC #endif ================================================ FILE: code/nel/include/nel/misc/string_id_array.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_STRING_ID_ARRAY_H #define NL_STRING_ID_ARRAY_H #include "types_nl.h" #include "debug.h" #include #include #include #include #include namespace NLMISC { /** * The goal of this class is to associate number and string. It is used in the * CCallbackNetBase for message id<->string associations. * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CStringIdArray { public: typedef sint16 TStringId; CStringIdArray () : _IgnoreAllUnknownId(false) { } /// Adds a string in the string in the array void addString(const std::string &str, TStringId id) { nlassert (id >= 0 && id < pow(2.0, (sint)sizeof (TStringId)*8)); nlassert (!str.empty()); if (id >= (sint32) _StringArray.size()) _StringArray.resize(id+1); _StringArray[id] = str; if (!_IgnoreAllUnknownId) { _AskedStringArray.erase (str); _NeedToAskStringArray.erase (str); } } /// Adds a string in the string at the end of the array void addString(const std::string &str) { nlassert (_StringArray.size () < pow(2.0, (sint)sizeof (TStringId)*8)); nlassert (!str.empty()); // add at the end addString (str, (TStringId)_StringArray.size ()); } /** Returns the id associated to string str. If the id is not found, the string will be added in * _NeedToAskStringArray if ignoreAllUnknownId is false and IgnoreIfUnknown is false too. */ TStringId getId (const std::string &str, bool IgnoreIfUnknown = false) { nlassert (!str.empty()); // sorry for this bullshit but it's the simplest way ;) if (this == NULL) return -1; for (TStringId i = 0; i < (TStringId) _StringArray.size(); i++) { if (_StringArray[i] == str) return i; } if (!_IgnoreAllUnknownId && !IgnoreIfUnknown) { // the string is not found, add it to the _AskedStringArray if necessary if (_NeedToAskStringArray.find (str) == _NeedToAskStringArray.end ()) { if (_AskedStringArray.find (str) == _AskedStringArray.end ()) { //nldebug ("String '%s' not found, add it to _NeedToAskStringArray", str.c_str ()); _NeedToAskStringArray.insert (str); } else { //nldebug ("Found '%s' in the _AskedStringArray", str.c_str ()); } } else { //nldebug ("Found '%s' in the _NeedToAskStringArray", str.c_str ()); } } else { //nldebug ("Ignoring unknown association ('%s')", str.c_str ()); } return -1; } /// Returns the string associated to this id std::string getString (TStringId id) const { // sorry for this bullshit but it's the simplest way ;) if (this == NULL) return ""; nlassert (id >= 0 && id < (TStringId)_StringArray.size()); return _StringArray[id]; } /// Set the size of the _StringArray void resize (TStringId size) { _StringArray.resize (size); } /// Returns the size of the _StringArray TStringId size () const { return (TStringId)_StringArray.size (); } /// Returns all string in the _NeedToAskStringArray const std::set &getNeedToAskedStringArray () const { return _NeedToAskStringArray; } /// Returns all string in the _AskedStringArray const std::set &getAskedStringArray () const { return _AskedStringArray; } /// Moves string from _NeedToAskStringArray to _AskedStringArray void moveNeedToAskToAskedStringArray () { if (!_IgnoreAllUnknownId) { _AskedStringArray.insert (_NeedToAskStringArray.begin(), _NeedToAskStringArray.end()); _NeedToAskStringArray.clear (); } } /// If set to true, when we ask a string with no id, we don't put it in the _NeedToAskStringArray array void ignoreAllUnknownId (bool b) { _IgnoreAllUnknownId = b; } /// Clears the string id array void clear () { _StringArray.clear (); _NeedToAskStringArray.clear (); _AskedStringArray.clear (); } /// Displays all association of the array in a C style (useful to copy/paste in your C code) void display () { nlinfo ("static const char *OtherSideAssociations[] = {"); for (uint i = 0; i < _StringArray.size(); i++) { nlinfo(" \"%s\",", _StringArray[i].c_str()); } nlinfo ("};"); } private: bool _IgnoreAllUnknownId; std::vector _StringArray; std::set _NeedToAskStringArray; std::set _AskedStringArray; }; } // NLMISC #endif // NL_STRING_ID_ARRAY_H /* End of string_id_array.h */ ================================================ FILE: code/nel/include/nel/misc/string_mapper.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef STRING_MAPPER_H #define STRING_MAPPER_H #include "types_nl.h" #include "stream.h" #include "mutex.h" #include #include namespace NLMISC { // const string * as uint (the TStringId returned by CStringMapper is a pointer to a string object) //#ifdef HAVE_X86_64 //typedef uint64 TStringId; //#else //typedef uint TStringId; //#endif typedef const std::string *TStringId; // Traits for hash_map using CStringId struct CStringIdHashMapTraits { enum { bucket_size = 4, min_buckets = 8, }; CStringIdHashMapTraits() { } size_t operator() (const NLMISC::TStringId &stringId) const { return (size_t)stringId; } bool operator() (const NLMISC::TStringId &strId1, const NLMISC::TStringId &strId2) const { return (size_t)strId1 < (size_t)strId2; } }; /** A static class that map string to integer and vice-versa * Each different string is tranformed into an unique integer identifier. * If the same string is submited twice, the same id is returned. * The class can also return the string associated with an id. * * \author Boris Boucher * \author Nevrax France * \date 2003 */ class CStringMapper { class CCharComp { public: bool operator()(std::string *x, std::string *y) const { return (*x) < (*y); } }; class CAutoFastMutex { CFastMutex *_Mutex; public: CAutoFastMutex(CFastMutex *mtx) : _Mutex(mtx) {_Mutex->enter();} ~CAutoFastMutex() {_Mutex->leave();} }; // Local Data std::set _StringTable; std::string* _EmptyId; CFastMutex _Mutex; // Must be thread-safe (Called by CPortal/CCluster, each of them called by CInstanceGroup) // The 'singleton' for static methods static CStringMapper _GlobalMapper; // private constructor. CStringMapper(); public: ~CStringMapper() { localClear(); } /// Globaly map a string into a unique Id. ** This method IS Thread-Safe ** static TStringId map(const std::string &str) { return _GlobalMapper.localMap(str); } /// Globaly unmap a string. ** This method IS Thread-Safe ** static const std::string &unmap(const TStringId &stringId) { return _GlobalMapper.localUnmap(stringId); } /// Globaly helper to serial a string id. ** This method IS Thread-Safe ** static void serialString(NLMISC::IStream &f, TStringId &id) {_GlobalMapper.localSerialString(f, id);} /// Return the global id for the empty string (helper function). NB: Works with every instance of CStringMapper static TStringId emptyId() { return 0; } // ** This method IS Thread-Safe ** static void clear() { _GlobalMapper.localClear(); } /// Create a local mapper. You can dispose of it by deleting it. static CStringMapper * createLocalMapper(); /// Localy map a string into a unique Id TStringId localMap(const std::string &str); /// Localy unmap a string const std::string &localUnmap(const TStringId &stringId) { return (stringId==0)?*_EmptyId:*((std::string*)stringId); } /// Localy helper to serial a string id void localSerialString(NLMISC::IStream &f, TStringId &id); void localClear(); }; // linear from 0 (0 is empty string) (The TSStringId returned by CStaticStringMapper // is an index in the vector and begin at 0) typedef uint TSStringId; /** * After endAdd you cannot add strings anymore or it will assert * \author Matthieu Besson * \author Nevrax France * \date November 2003 */ class CStaticStringMapper { std::map _TempStringTable; std::map _TempIdTable; uint32 _IdCounter; char *_AllStrings; std::vector _IdToStr; bool _MemoryCompressed; // If false use the 2 maps public: CStaticStringMapper() { _IdCounter = 0; _AllStrings = NULL; _MemoryCompressed = false; add(""); } ~CStaticStringMapper() { clear(); } /// Globaly map a string into a unique Id TSStringId add(const std::string &str); // see if a string is already present in the map bool isAdded(const std::string &str) const; void memoryCompress(); // Uncompress the map. void memoryUncompress(); /// Globaly unmap a string const char * get(TSStringId stringId); /// Return the global id for the empty string (helper function) static TSStringId emptyId() { return 0; } void clear(); uint32 getCount() { return _IdCounter; } // helper serialize a string id as a string void serial(NLMISC::IStream &f, TSStringId &strId) throw(EStream); // helper serialize a string id vector void serial(NLMISC::IStream &f, std::vector &strIdVect) throw(EStream); }; } //namespace NLMISC #endif // STRING_MAPPER_H ================================================ FILE: code/nel/include/nel/misc/string_stream.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_STRING_STREAM_H #define NL_STRING_STREAM_H #include "types_nl.h" #include "mem_stream.h" namespace NLMISC { /** * Memory stream that is serialized from/to plain text (human-readable). * not any comparaison with the stl class std::stringstream * * OBSOLETE! Now, use CMemStream in string mode. * \author Olivier Cado * \author Nevrax France * \date 2001 */ class CStringStream : public CMemStream { public: /// Initialization constructor CStringStream( bool inputStream=false, uint32 defaultcapacity=0 ) : CMemStream( inputStream, false, defaultcapacity ) {} /// Copy constructor CStringStream( const CStringStream& other ) : CMemStream( other ) {} /// Assignment operator CStringStream& operator=( const CStringStream& other ) { CMemStream::operator=( other ); return *this; } /// Input: read len bytes at most from the stream until the next separator, and return the number of bytes read. The separator is then skipped. uint serialSeparatedBufferIn( uint8 *buf, uint len ); /// Output: writes len bytes from buf into the stream void serialSeparatedBufferOut( uint8 *buf, uint len ); /// Method inherited from IStream virtual void serialBit(bool &bit); /// Template serialisation (should take the one from IStream) template void serial(T &obj) { obj.serial(*this); } template void serialCont(std::vector &cont) {CMemStream::serialCont(cont);} template void serialCont(std::list &cont) {CMemStream::serialCont(cont);} template void serialCont(std::deque &cont) {CMemStream::serialCont(cont);} template void serialCont(std::set &cont) {CMemStream::serialCont(cont);} template void serialCont(std::multiset &cont) {CMemStream::serialCont(cont);} template void serialCont(std::map &cont) {CMemStream::serialCont(cont);} template void serialCont(std::multimap &cont) {CMemStream::serialCont(cont);} template void serial(T0 &a, T1 &b) { serial(a); serial(b);} template void serial(T0 &a, T1 &b, T2 &c) { serial(a); serial(b); serial(c);} template void serial(T0 &a, T1 &b, T2 &c, T3 &d) { serial(a); serial(b); serial(c); serial(d);} template void serial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e) { serial(a); serial(b); serial(c); serial(d); serial(e);} template void serial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e, T5 &f) { serial(a); serial(b); serial(c); serial(d); serial(e); serial(f);} /** \name Base type serialisation. * Those method are a specialisation of template method "void serial(T&)". */ //@{ virtual void serial(uint8 &b) ; virtual void serial(sint8 &b) ; virtual void serial(uint16 &b) ; virtual void serial(sint16 &b) ; virtual void serial(uint32 &b) ; virtual void serial(sint32 &b) ; virtual void serial(uint64 &b) ; virtual void serial(sint64 &b) ; virtual void serial(float &b) ; virtual void serial(double &b) ; virtual void serial(bool &b) ; #ifndef NL_OS_CYGWIN virtual void serial(char &b) ; #endif virtual void serial(std::string &b) ; virtual void serial(ucstring &b) ; //@} /// Specialisation of serialCont() for vector virtual void serialCont(std::vector &cont) { serialVector(cont); } /// Specialisation of serialCont() for vector virtual void serialCont(std::vector &cont) { serialVector(cont); } /// Specialisation of serialCont() for vector virtual void serialCont(std::vector &cont); /// Serialisation in hexadecimal virtual void serialHex(uint32 &b); }; } // NLMISC #endif // NL_STRING_STREAM_H /* End of string_stream.h */ ================================================ FILE: code/nel/include/nel/misc/system_info.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_SYSTEM_INFO_H #define NL_SYSTEM_INFO_H #include "types_nl.h" #include namespace NLMISC { /** * This class provides general system-level information about the local machine. * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ class CSystemInfo { public: static std::string getOS (); static std::string getProc (); /** Gives an evaluation of the processor frequency, in hertz * \param quick true to do quick frequency evaluation * \warning Supports only Intel architectures for now. Returns 0 if not implemented. */ static uint64 getProcessorFrequency (bool quick = false); /** Tests whether the CPUID instruction is supported * (always false on non Intel architectures) */ static bool hasCPUID (); /** Helps to know whether the processor features MMX instruction set * This is initialized at started, so its fast * (always false on non 0x86 architecture ...) */ static bool hasMMX () {return _HaveMMX;} /** Helps to know whether the processor has streaming SIMD instructions (the OS must supports it) * This is initialized at started, so its fast * (always false on non 0x86 architecture ...) */ static bool hasSSE () {return _HaveSSE;} /** Gets the CPUID (if available). Useful for debug info */ static uint32 getCPUID(); /** true if the Processor has HyperThreading */ static bool hasHyperThreading(); /** true if running under NT */ static bool isNT(); /** Returns the space left on the hard drive that contains the filename */ static std::string availableHDSpace (const std::string &filename); /** Returns all the physical memory available on the computer (in bytes) */ static uint64 availablePhysicalMemory (); /** Returns the physical memory on the computer (in bytes) */ static uint64 totalPhysicalMemory (); /** Returns the amount of allocated system memory (in bytes) */ static uint64 getAllocatedSystemMemory (); /** Returns all the virtual memory used by this process (in bytes) */ static uint64 virtualMemory (); /** Returns the main video card name and the video driver version */ static bool getVideoInfo (std::string &deviceName, uint64 &driverVersion); private: static bool _HaveMMX; static bool _HaveSSE; }; } // NLMISC #endif // NL_SYSTEM_INFO_H /* End of system_info.h */ ================================================ FILE: code/nel/include/nel/misc/system_utils.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_SYSTEM_UTILS_H #define NL_SYSTEM_UTILS_H #include "types_nl.h" #include "ucstring.h" namespace NLMISC { /* * Operating system miscellaneous functions (all methods and variables should be static) * \author Kervala * \date 2010 */ class CSystemUtils { static nlWindow s_window; public: /// Initialize data which needs it before using them. static bool init(); /// Uninitialize data when they won't be used anymore. static bool uninit(); /// Set the window which will be used by some functions. static void setWindow(nlWindow window); /// Create/update a progress bar with an appearance depending on system. static bool updateProgressBar(uint value, uint total); /// Copy a string to system clipboard. static bool copyTextToClipboard(const ucstring &text); /// Paste a string from system clipboard. static bool pasteTextFromClipboard(ucstring &text); /// Check if system supports unicode. static bool supportUnicode(); /// Check if keyboard layout is AZERTY. static bool isAzertyKeyboard(); /// Check if screensaver is enabled. static bool isScreensaverEnabled(); /// Enable or disable screeensaver. static bool enableScreensaver(bool screensaver); /// Get the ROOT registry key used by getRegKey and setRegKey. static std::string getRootKey(); /// Set the ROOT registry key used by getRegKey and setRegKey. static void setRootKey(const std::string &root); /// Read a value from registry. static std::string getRegKey(const std::string &Entry); /// Write a value to registry. static bool setRegKey(const std::string &ValueName, const std::string &Value); /// Get desktop current color depth without using UDriver. static uint getCurrentColorDepth(); }; } // NLMISC #endif // NL_SYSTEM_UTILS_H ================================================ FILE: code/nel/include/nel/misc/task_manager.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_TASK_MANAGER_H #define NL_TASK_MANAGER_H #include "types_nl.h" #include "vector.h" #include #include #include "mutex.h" #include "thread.h" namespace NLMISC { /** * A class derived from IRunnable to get a position */ class IRunnablePos : public NLMISC::IRunnable { public: NLMISC::CVector Position; }; /** * CTaskManager is a class that manage a list of Task with one Thread * \author Alain Saffray * \author Nevrax France * \date 2000 */ class CTaskManager : public IRunnable { public: /// Constructor CTaskManager(); /// Destructor ~CTaskManager(); /// Manage TaskQueue void run(void); /// Add a task to TaskManager and its priority void addTask(IRunnable *, float priority=0); /// Delete a task, only if task is not running, return true if found and deleted bool deleteTask(IRunnable *r); /// Sleep a Task void sleepTask(void) { nlSleep(10); } /// Task list size uint taskListSize(void); /// return false if exit() is required. task added with addTask() should test this flag. bool isThreadRunning() const {return _ThreadRunning;} /// Dump task list void dump (std::vector &result); /// Clear the dump of Done files void clearDump(); /// Get number of waiting task uint getNumWaitingTasks(); /// Is there a current task ? bool isTaskRunning() const {return _IsTaskRunning;} /// A callback to modify the task priority class IChangeTaskPriority { public: virtual ~IChangeTaskPriority() {} virtual float getTaskPriority(const IRunnable &runable) = 0; }; /// Register task priority callback void registerTaskPriorityCallback (IChangeTaskPriority *callback); private: /// Register task priority callback void changeTaskPriority (); /// The callback IChangeTaskPriority *_ChangePriorityCallback; protected: /** If any, wait the current running task to complete * this function MUST be called in a 'accessor to the _TaskQueue' statement because a mutex is required * eg: * \code * { * CSynchronized >::CAccessor acces(&_TaskQueue); * waitCurrentTaskToComplete(); * } * \endcode */ void waitCurrentTaskToComplete (); protected: // A task in the waiting queue with its parameters class CWaitingTask { public: CWaitingTask (IRunnable *task, float priority) { Task = task; Priority = priority; } IRunnable *Task; float Priority; // For the sort bool operator< (const CWaitingTask &other) const { return Priority < other.Priority; } }; /// queue of tasks, using list container instead of queue for DeleteTask methode CSynchronized _RunningTask; CSynchronized > _TaskQueue; CSynchronized > _DoneTaskQueue; /// thread pointer IThread *_Thread; /// flag indicate thread loop, if false cause thread exit volatile bool _ThreadRunning; private: volatile bool _IsTaskRunning; }; } // NLMISC #endif // NL_TASK_MANAGER_H /* End of task_manager.h */ ================================================ FILE: code/nel/include/nel/misc/tds.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_TDS_H #define NL_TDS_H #include "types_nl.h" namespace NLMISC { /** * Thread dependant storage class * * This class provides a thread specific (void*). * It is initialized at NULL. * * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2002 */ class CTDS { public: /// Constructor. The pointer is initialized with NULL. CTDS (); /// Destructor ~CTDS (); /// Get the thread specific pointer void *getPointer () const; /// Set the thread specific pointer void setPointer (void* pointer); private: #ifdef NL_OS_WINDOWS uint32 _Handle; #else // NL_OS_WINDOWS pthread_key_t _Key; #endif // NL_OS_WINDOWS }; } // NLMISC #endif // NL_TDS_H /* End of tds.h */ ================================================ FILE: code/nel/include/nel/misc/thread.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_THREAD_H #define NL_THREAD_H #include "types_nl.h" #include "common.h" namespace NLMISC { /** * Thread callback interface. * When a thread is created, it will call run() in its attached IRunnable interface. * *\code #include "thread.h" class HelloLoopThread : public IRunnable { void run () { for(;;) printf("Hello World\n"); } }; IThread *thread = IThread::create (new HelloLoopThread); thread->start (); *\endcode * * * * * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ class IRunnable { public: // Called when a thread is run. virtual void run()=0; virtual ~IRunnable() { } // Return the runnable name virtual void getName (std::string &result) const { result = "NoName"; } }; /// Thread priorities, numbering follows Win32 for now enum TThreadPriority { ThreadPriorityLowest = -2, ThreadPriorityLow = -1, ThreadPriorityNormal = 0, ThreadPriorityHigh = 1, ThreadPriorityHighest = 2, }; /** * Thread base interface, must be implemented for all OS * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ class IThread { public: /** * Create a new thread. * Implemented in the derived class. */ static IThread *create(IRunnable *runnable, uint32 stackSize = 0); /** * Return a pointer on the current thread. * Implemented in the derived class. */ static IThread *getCurrentThread (); virtual ~IThread () { } // Starts the thread. virtual void start()=0; // Check if the thread is still running virtual bool isRunning() =0; // Terminate the thread (risky method, use only in extreme cases) virtual void terminate()=0; // In the calling program, wait until the specified thread has exited. After wait() has returned, you can delete the thread object. virtual void wait()=0; /// Return a pointer to the runnable object virtual IRunnable *getRunnable()=0; /** * Set the CPU mask of this thread. Thread must have been started before. * The mask must be a subset of the CPU mask returned by IProcess::getCPUMask() thread process. */ virtual bool setCPUMask(uint64 cpuMask)=0; /** * Get the CPU mask of this thread. Thread must have been started before. * The mask should be a subset of the CPU mask returned by IProcess::getCPUMask() thread process. */ virtual uint64 getCPUMask()=0; /// Set the thread priority. Thread must have been started before. virtual void setPriority(TThreadPriority priority) = 0; /** * Get the thread user name. * Under Linux return thread owner, under windows return the name of the logon user. */ virtual std::string getUserName()=0; }; /* * Thread exception */ struct EThread : public Exception { EThread (const char* message) : Exception (message) {} }; /** * Process base interface, must be implemented for all OS * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2000 */ class IProcess { public: virtual ~IProcess() {} /** * Return a pointer on the current process. * Implemented in the derived class. */ static IProcess *getCurrentProcess (); /** * Return process CPU mask. Each bit stand for a CPU usable by the process threads. */ virtual uint64 getCPUMask()=0; /** * Set the process CPU mask. Each bit stand for a CPU usable by the process threads. */ virtual bool setCPUMask(uint64 mask)=0; }; } // NLMISC #endif // NL_THREAD_H /* End of thread.h */ ================================================ FILE: code/nel/include/nel/misc/time_nl.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_TIME_H #define NL_TIME_H #include "types_nl.h" #ifdef NL_OS_WINDOWS // automatically add the win multimedia library if you use CTime class # pragma comment(lib, "winmm.lib") #endif namespace NLMISC { /// New time types typedef double TGameTime; // Time according to the game (used for determining day, night...) (double in seconds) typedef sint64 TGameCycle; // Integer game cycle count from the game (in game ticks) typedef double TLocalTime; // Time according to the machine's local clock (double in seconds) typedef sint64 TCPUCycle; // Integer cycle count from the CPU (for profiling in cpu ticks) /// Old time type typedef sint64 TTime; typedef sint64 TTicks; /** * This class provide a independant local time system. * \author Vianney Lecroart, Olivier Cado * \author Nevrax France * \date 2000-2005 */ class CTime { public: struct CTimerInfo { /// Returns if there is a high precision timer that can be used. bool IsHighPrecisionAvailable; /// If a CPU specific timer is used and the values are not consistent accross threads. bool RequiresSingleCore; /// The resolution of the high resolution timer. TTicks HighPrecisionResolution; }; /** Get advanced information on the used timers. */ static void probeTimerInfo(CTimerInfo &result); /** Return the number of second since midnight (00:00:00), January 1, 1970, * coordinated universal time, according to the system clock. * The time returned is local, ie. it has the local time ajustement, including * daylight saving if applicable. * This values is the same on all computer if computers are synchronized (with NTP for example). */ static uint32 getSecondsSince1970 (); /** Return the number of second since midnight (00:00:00), January 1, 1970, * coordinated universal time, according to the system clock. * The time returned is UTC (aka GMT+0), ie it does not have the local time ajustement * nor it have the daylight saving ajustement. * This values is the same on all computer if computers are synchronized (with NTP for example). */ // static uint32 getSecondsSince1970UTC (); /** Return the local time in milliseconds. * Use it only to measure time difference, the absolute value does not mean anything. * On Unix, getLocalTime() will try to use the Monotonic Clock if available, otherwise * the value can jump backwards if the system time is changed by a user or a NTP time sync process. * The value is different on 2 different computers; use the CUniTime class to get a universal * time that is the same on all computers. * \warning On Win32, the value is on 32 bits only, and uses the low-res timer unless probeTimerInfo was called and a high resolution timer can be used. It wraps around to 0 every about 49.71 days. */ static TTime getLocalTime(); /** Return the time in processor ticks. Use it for profile purpose. * If the performance time is not supported on this hardware, it returns 0. * \warning On a multiprocessor system, the value returned by each processor may * be different. The only way to workaround this is to set a processor affinity * to the measured thread. * \warning The speed of tick increase can vary (especially on laptops or CPUs with * power management), so profiling several times and computing the average could be * a wise choice. */ static TTicks getPerformanceTime (); /** Convert a ticks count into second. If the performance time is not supported on this * hardware, it returns 0.0. */ static double ticksToSecond (TTicks ticks); /** Build a human readable string of a time difference in second. * The result will be of the form '1 years 2 months 2 days 10 seconds' */ static std::string getHumanRelativeTime(sint32 nbSeconds); #ifdef NL_OS_WINDOWS /** Return the offset in 10th of micro sec between the windows base time ( * 01-01-1601 0:0:0 UTC) and the unix base time (01-01-1970 0:0:0 UTC). * This value is used to convert windows system and file time back and * forth to unix time (aka epoch) */ static uint64 getWindowsToUnixBaseTimeOffset(); #endif }; } // NLMISC #endif // NL_TIME_H /* End of time_nl.h */ ================================================ FILE: code/nel/include/nel/misc/timeout_assertion_thread.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_TIMEOUT_ASSERTION_THREAD_H #define NL_TIMEOUT_ASSERTION_THREAD_H #include "common.h" #include "thread.h" /* example: Encapsulation of message callbacks // in init CTimeoutAssertionThread *myTAT = new CTimeoutAssertionThread(1000); IThread::create(myTAT)->start(); ... // in callback management myTAT->activate(); msg->callback(); myTAT->disactivate(); // if the callback call is too slow, an assertion will happen */ class CTimeoutAssertionThread: public NLMISC::IRunnable { public: enum TControl { ACTIVE, INACTIVE, QUIT }; CTimeoutAssertionThread(uint32 timeout = 0) : _Control(INACTIVE), _Counter(0), _Timeout(timeout) { } void run() { uint32 lastCounter; while(_Control != QUIT) { if(_Control != ACTIVE || _Timeout == 0) { //nldebug("not active, sleep"); NLMISC::nlSleep(1000); } else { //nldebug("active, enter sleep"); lastCounter = _Counter; uint32 cummuledSleep = 0; // do sleep until cumulated time reached timeout value while (cummuledSleep < _Timeout) { // sleep 1 s NLMISC::nlSleep(std::min((uint32)(1000), (uint32)(_Timeout-cummuledSleep))); cummuledSleep += 1000; // check if exit is required if (_Control == QUIT) return; } //nldebug("active, leave sleep, test assert"); // If this assert occured, it means that a checked part of the code was // to slow and then I decided to assert to display the problem. nlassert(!(_Control==ACTIVE && _Counter==lastCounter)); } } } void activate() { if(_Control == QUIT) return; nlassert(_Control == INACTIVE); _Counter++; _Control = ACTIVE; //nldebug("activate"); } void deactivate() { if(_Control == QUIT) return; nlassert(_Control == ACTIVE); _Control = INACTIVE; //nldebug("deactivate"); } void quit() { nlassert(_Control != QUIT); _Control = QUIT; //nldebug("quit"); } void timeout(uint32 to) { _Timeout = to; //nldebug("change timeout to %d", to); } private: volatile TControl _Control; volatile uint32 _Counter; volatile uint32 _Timeout; // in millisecond }; #endif // NL_TIMEOUT_ASSERTION_THREAD_H /* End of timeout_assertion_thread.h */ ================================================ FILE: code/nel/include/nel/misc/traits_nl.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_TRAITS_H #define NL_TRAITS_H #include "rgba.h" #include "vector.h" namespace NLMISC { /** Class that gives information about a type. Useful to do some optimization in templates functions / class * This class is intended to be specialized and taylored for each type of interest * * \author Nicolas Vizerie * \author Nevrax France * \date 2004 */ template struct CTraits { enum { HasTrivialCtor = false }; // if true, the default ctor does nothing useful (example : built-in types or Plain Old Datas structs) enum { HasTrivialDtor = false }; // the dtor does nothing useful and is not worth calling. Useful to optimize containers clean-up enum { SupportRawCopy = false }; // the object supports raw copy with memcpy // to be completed .. }; #define NL_TRIVIAL_TYPE_TRAITS(type) \ template <> \ struct CTraits \ { \ enum { HasTrivialCtor = true }; \ enum { HasTrivialDtor = true }; \ enum { SupportRawCopy = true }; \ }; // integral types NL_TRIVIAL_TYPE_TRAITS(bool); #ifdef NL_COMP_VC6 NL_TRIVIAL_TYPE_TRAITS(sint8); NL_TRIVIAL_TYPE_TRAITS(uint8); #endif // NL_COMP_VC6 NL_TRIVIAL_TYPE_TRAITS(sint16); NL_TRIVIAL_TYPE_TRAITS(uint16); NL_TRIVIAL_TYPE_TRAITS(sint32); NL_TRIVIAL_TYPE_TRAITS(uint32); NL_TRIVIAL_TYPE_TRAITS(sint64); NL_TRIVIAL_TYPE_TRAITS(uint64); #ifdef NL_COMP_VC6 NL_TRIVIAL_TYPE_TRAITS(sint); NL_TRIVIAL_TYPE_TRAITS(uint); #endif // NL_COMP_VC6 // characters NL_TRIVIAL_TYPE_TRAITS(char); NL_TRIVIAL_TYPE_TRAITS(unsigned char); // numeric types NL_TRIVIAL_TYPE_TRAITS(float); NL_TRIVIAL_TYPE_TRAITS(double); // misc NL_TRIVIAL_TYPE_TRAITS(CVector); NL_TRIVIAL_TYPE_TRAITS(CRGBA); //.. to be completed } // NLMISC #endif ================================================ FILE: code/nel/include/nel/misc/triangle.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_TRIANGLE_H #define NL_TRIANGLE_H #include "types_nl.h" #include "vector.h" namespace NLMISC { class CPlane; class CMatrix; } namespace NLMISC { // *************************************************************************** /** * A simple triangles of 3 points. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CTriangle { public: CVector V0,V1,V2; public: /// Constructor CTriangle() {} /// Constructor CTriangle(const CVector &a, const CVector &b, const CVector &c) : V0(a), V1(b), V2(c) {} /** * Intersection detection with a segment. You must pass the normalized plane of the triangle as parameter. * * \param p0 is the first point of the segment. * \param p1 is the second point of the segment. * \param hit will receive the coordinate of the intersection if the method returns true. * \param plane is the plane of the triangle. Build it like this: * \code * CPlane plane; * plane.make (triangle.V0, triangle.V1, triangle.V2); * \endcode * \return true if the segement [p0,p1] intersects the triangle else false. */ bool intersect (const CVector& p0, const CVector& p1, CVector& hit, const class NLMISC::CPlane& plane) const; /** 3D Gradient computation. * Given 3 values at the 3 corners 'ci' (gouraud, uv....), this method compute the gradients Grad. * The formula to compute the interpolated value according to a 3d position 'v' in space is then simply: \n * c(v)= c0 + grad*(v-V0) */ void computeGradient(float c0, float c1, float c2, CVector &grad) const; // transform triangle void applyMatrix(const CMatrix &m, CTriangle &dest) const; // compute the minimal corner of this triangle inline void getMinCorner(NLMISC::CVector &dest) const; // compute the minimal corner of this triangle inline void getMaxCorner(NLMISC::CVector &dest) const; }; // inlines inline void CTriangle::getMinCorner(NLMISC::CVector &dest) const { dest.set(minof(V0.x, V1.x, V2.x), minof(V0.y, V1.y, V2.y), minof(V0.z, V1.z, V2.z)); } inline void CTriangle::getMaxCorner(NLMISC::CVector &dest) const { dest.set(maxof(V0.x, V1.x, V2.x), maxof(V0.y, V1.y, V2.y), maxof(V0.z, V1.z, V2.z)); } } // NLMISC #endif // NL_TRIANGLE_H /* End of triangle.h */ ================================================ FILE: code/nel/include/nel/misc/twin_map.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_TWIN_MAP_H #define NL_TWIN_MAP_H #include "nel/misc/debug.h" #include namespace NLMISC { /** Bidirectionnal association between values * Behaves like a map, but key can be used as value and vice-versa * * Association must be bijective or assertions are raised * * * Example of use : * * CTwinMap tm; * tm.add("foo", 1); * tm.add("bar", 2); * tm.add("foorbar", 3); * tm.get("foo"); // returns 1 * tm.get(1); // returns "foo" * tm.remove(1); // removes ("foo", 1) couple * tm.remove("bar") // removes ("bar", 2) couple * tm.add("foobar", 4); // assert ! * tm.add("foo", 3); // assrt! (3 associated with foobar) * * \author Nicolas Vizerie * \author Nevrax France * \date 2004 */ template class CTwinMap { public: typedef std::map TAToBMap; typedef std::map TBToAMap; public: // add a couple in the twin map. An assertion is raised if either valueA or valueB were already present in the map inline void add(const TypeA &valueA, const TypeB &valueB); // retrieves value of type 'TypeB' associated with 'valueA', or NULL if not found inline const TypeA *getA(const TypeB &valueB) const; // retrieves value of type 'TypeB' associated with 'valueA', or NULL if not found inline const TypeB *getB(const TypeA &valueA) const; // removes a couple from its TypeA value inline void removeWithA(const TypeA &valueA); // removes a couple from its TypeB value inline void removeWithB(const TypeB &valueB); // Direct read access to 'TypeA to TypeB' map const TAToBMap &getAToBMap() const { return _AToB; } // Direct read access to 'TypeB to TypeA' map const TBToAMap &getBToAMap() const { return _BToA; } // clear the twin map inline void clear(); private: TAToBMap _AToB; TBToAMap _BToA; }; //////////////////// // IMPLEMENTATION // //////////////////// //================================================================================================== template inline void CTwinMap::clear() { _AToB.clear(); _BToA.clear(); } //================================================================================================== template inline void CTwinMap::add(const TypeA &valueA, const TypeB &valueB) { nlassert(!getB(valueA)); nlassert(!getA(valueB)); _AToB[valueA] = valueB; _BToA[valueB] = valueA; } //================================================================================================== template inline const TypeA *CTwinMap::getA(const TypeB &valueB) const { typename TBToAMap::const_iterator it = _BToA.find(valueB); if (it == _BToA.end()) return NULL; else return &(it->second); } //================================================================================================== template inline const TypeB *CTwinMap::getB(const TypeA &valueA) const { typename TAToBMap::const_iterator it = _AToB.find(valueA); if (it == _AToB.end()) return NULL; else return &(it->second); } //================================================================================================== template inline void CTwinMap::removeWithA(const TypeA &valueA) { typename TAToBMap::iterator itA = _AToB.find(valueA); nlassert(itA != _AToB.end()); typename TBToAMap::iterator itB = _BToA.find(itA->second); nlassert(itB != _BToA.end()); _AToB.erase(itA); _BToA.erase(itB); } //================================================================================================== template inline void CTwinMap::removeWithB(const TypeB &valueB) { typename TBToAMap::iterator itB = _BToA.find(valueB); nlassert(itB != _BToA.end()); typename TAToBMap::iterator itA = _AToB.find(itB->second); nlassert(itA != _AToB.end()); _AToB.erase(itA); _BToA.erase(itB); } } // NLMISC #endif ================================================ FILE: code/nel/include/nel/misc/types_nl.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_TYPES_H #define NL_TYPES_H // Wrapper for the clib time function #define nl_time time #define nl_mktime mktime #define nl_gmtime gmtime #define nl_localtime localtime #define nl_difftime difftime // nelconfig.h inclusion, file generated by autoconf #ifdef HAVE_NELCONFIG_H # include "nelconfig.h" #endif // HAVE_NELCONFIG_H #ifdef FINAL_VERSION // If the FINAL_VERSION is defined externally, check that the value is 0 or 1 # if FINAL_VERSION != 1 && FINAL_VERSION != 0 # error "Bad value for FINAL_VERSION, it must be 0 or 1" # endif #else // If you want to compile in final version just put 1 instead of 0 // WARNING: never comment this #define # define FINAL_VERSION 0 #endif // FINAL_VERSION // This way we know about _HAS_TR1 and _STLPORT_VERSION #include // Operating systems definition #ifdef _WIN32 # define NL_OS_WINDOWS # define NL_LITTLE_ENDIAN # define NL_CPU_INTEL # ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0500 // Minimal OS = Windows 2000 (NeL is not supported on Windows 95/98) # endif # ifdef _MSC_VER # define NL_COMP_VC # if _MSC_VER >= 1800 # define NL_COMP_VC12 # define NL_COMP_VC_VERSION 120 # elif _MSC_VER >= 1700 # define NL_COMP_VC11 # define NL_COMP_VC_VERSION 110 # elif _MSC_VER >= 1600 # define NL_COMP_VC10 # define NL_COMP_VC_VERSION 100 # elif _MSC_VER >= 1500 # define NL_COMP_VC9 # define NL_COMP_VC_VERSION 90 # elif _MSC_VER >= 1400 # define NL_COMP_VC8 # define NL_COMP_VC_VERSION 80 # undef nl_time # define nl_time _time32 // use the old 32 bit time function # undef nl_mktime # define nl_mktime _mktime32 // use the old 32 bit time function # undef nl_gmtime # define nl_gmtime _gmtime32 // use the old 32 bit time function # undef nl_localtime # define nl_localtime _localtime32 // use the old 32 bit time function # undef nl_difftime # define nl_difftime _difftime32 // use the old 32 bit time function # elif _MSC_VER >= 1310 # define NL_COMP_VC71 # define NL_COMP_VC_VERSION 71 # elif _MSC_VER >= 1300 # define NL_COMP_VC7 # define NL_COMP_VC_VERSION 70 # elif _MSC_VER >= 1200 # define NL_COMP_VC6 # define NL_COMP_VC_VERSION 60 # define NL_COMP_NEED_PARAM_ON_METHOD # endif # elif defined(__MINGW32__) # define NL_COMP_MINGW # define NL_COMP_GCC # define NL_NO_ASM # endif # if defined(_HAS_TR1) && (_HAS_TR1 + 0) // VC9 TR1 feature pack or later # define NL_ISO_STDTR1_AVAILABLE # define NL_ISO_STDTR1_HEADER(header)
# define NL_ISO_STDTR1_NAMESPACE std::tr1 # endif # ifdef _DEBUG # ifndef NL_DEBUG # define NL_DEBUG # endif # elif defined (NDEBUG) # ifndef NL_RELEASE # define NL_RELEASE # endif # else # error "Don't know the compilation mode" # endif # ifdef _WIN64 # define NL_OS_WIN64 # ifndef NL_NO_ASM // Windows 64bits platform SDK compilers doesn't support inline assembler # define NL_NO_ASM # endif # undef _WIN32_WINNT # define _WIN32_WINNT 0x0600 // force VISTA minimal version in 64 bits # endif // define NOMINMAX to be sure that windows includes will not define min max macros, but instead, use the stl template # ifndef NL_COMP_MINGW # define NOMINMAX # endif #else # ifdef __APPLE__ # define NL_OS_MAC # ifdef __BIG_ENDIAN__ # define NL_BIG_ENDIAN # elif defined(__LITTLE_ENDIAN__) # define NL_LITTLE_ENDIAN # else # error "Cannot detect the endianness of this Mac" # endif # else # ifdef WORDS_BIGENDIAN # define NL_BIG_ENDIAN # else # define NL_LITTLE_ENDIAN # endif # endif // these define are set the GNU/Linux and Mac OS # define NL_OS_UNIX # ifdef __FreeBSD__ # define NL_OS_FREEBSD # endif # ifdef __clang__ # define NL_COMP_CLANG # else # define NL_COMP_GCC # endif #endif #if defined(_HAS_CPP0X) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define NL_ISO_CPP0X_AVAILABLE #endif // gcc 3.4 introduced ISO C++ with tough template rules // // NL_ISO_SYNTAX can be used using #if NL_ISO_SYNTAX or #if !NL_ISO_SYNTAX // // NL_ISO_TEMPLATE_SPEC can be used in front of an instanciated class-template member data definition, // because sometimes MSVC++ 6 produces an error C2908 with a definition with template <>. #if defined(NL_COMP_VC) || (defined(__GNUC__) && ((__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ <= 3))) # define NL_ISO_SYNTAX 0 # define NL_ISO_TEMPLATE_SPEC #else # define NL_ISO_SYNTAX 1 # define NL_ISO_TEMPLATE_SPEC template <> #endif #ifdef NL_COMP_CLANG //# define NL_ISO_STDTR1_AVAILABLE //# define NL_ISO_STDTR1_HEADER(header)
#endif // gcc 4.1+ provides std::tr1 #ifdef NL_COMP_GCC # define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) # if GCC_VERSION > 40100 // new libc++ bundled with clang under Mac OS X 10.9+ doesn't define __GLIBCXX__ # ifdef __GLIBCXX__ # define NL_ISO_STDTR1_AVAILABLE # define NL_ISO_STDTR1_HEADER(header) # define NL_ISO_STDTR1_NAMESPACE std::tr1 # else # define NL_ISO_STDTR1_AVAILABLE # define NL_ISO_STDTR1_HEADER(header)
# define NL_ISO_STDTR1_NAMESPACE std # endif # endif #endif // Remove stupid Visual C++ warnings #ifdef NL_OS_WINDOWS # pragma warning (disable : 4503) // STL: Decorated name length exceeded, name was truncated # pragma warning (disable : 4786) // STL: too long identifier # pragma warning (disable : 4290) // throw() not implemented warning # pragma warning (disable : 4250) // inherits via dominance (informational warning). # pragma warning (disable : 4390) // don't warn in empty block "if(exp) ;" # pragma warning (disable : 4996) // 'vsnprintf': This function or variable may be unsafe. Consider using vsnprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. // Debug : Sept 01 2006 # if defined(NL_COMP_VC8) || defined(NL_COMP_VC9) || defined(NL_COMP_VC10) # pragma warning (disable : 4005) // don't warn on redefinitions caused by xp platform sdk # endif // NL_COMP_VC8 || NL_COMP_VC9 #endif // NL_OS_WINDOWS // Standard include #include #include // Setup extern asm functions. #ifndef NL_NO_ASM // If NL_NO_ASM is externely defined, don't override it. # ifndef NL_CPU_INTEL // If not on an Intel compatible plateforme (BeOS, 0x86 Linux, Windows) # define NL_NO_ASM // Don't use extern ASM. Full C++ code. # endif // NL_CPU_INTEL #endif // NL_NO_ASM // Define this if you want to use GTK for gtk_displayer //#define NL_USE_GTK //#undef NL_USE_GTK // Define this if you want to remove all assert, debug code... // You should never need to define this since it's always good to have assert, even in release mode //#define NL_NO_DEBUG #undef NL_NO_DEBUG // Standard types /* * correct numeric types: sint8, uint8, sint16, uint16, sint32, uint32, sint64, uint64, sint, uint * correct char types: char, string, ucchar, ucstring * correct misc types: void, bool, float, double * */ /** * \typedef uint8 * An unsigned 8 bits integer (use char only as \b character and not as integer) **/ /** * \typedef sint8 * An signed 8 bits integer (use char only as \b character and not as integer) */ /** * \typedef uint16 * An unsigned 16 bits integer (don't use short) **/ /** * \typedef sint16 * An signed 16 bits integer (don't use short) */ /** * \typedef uint32 * An unsigned 32 bits integer (don't use int or long) **/ /** * \typedef sint32 * An signed 32 bits integer (don't use int or long) */ /** * \typedef uint64 * An unsigned 64 bits integer (don't use long long or __int64) **/ /** * \typedef sint64 * An signed 64 bits integer (don't use long long or __int64) */ /** * \typedef uint * An unsigned integer, at least 32 bits (used only for internal loops or speedy purpose, processor dependent) **/ /** * \typedef sint * An signed integer at least 32 bits (used only for internal loops or speedy purpose, processor dependent) */ /** * \def NL_I64 * Used to display a int64 in a platform independent way with printf like functions. \code sint64 myint64 = SINT64_CONSTANT(0x123456781234); printf("This is a 64 bits int: %" NL_I64 "u", myint64); \endcode */ #ifdef NL_OS_WINDOWS typedef signed __int8 sint8; typedef unsigned __int8 uint8; typedef signed __int16 sint16; typedef unsigned __int16 uint16; typedef signed __int32 sint32; typedef unsigned __int32 uint32; typedef signed __int64 sint64; typedef unsigned __int64 uint64; typedef int sint; // at least 32bits (depend of processor) typedef unsigned int uint; // at least 32bits (depend of processor) //#define NL_I64 "I64" #define NL_I64 "ll" #elif defined (NL_OS_UNIX) #include #include #include typedef int8_t sint8; typedef uint8_t uint8; typedef int16_t sint16; typedef uint16_t uint16; typedef int32_t sint32; typedef uint32_t uint32; typedef int64_t sint64; typedef uint64_t uint64; typedef int sint; // at least 32bits (depend of processor) typedef unsigned int uint; // at least 32bits (depend of processor) // used for macro PRI*64 #define __STDC_FORMAT_MACROS #include #if defined(__PRI_64_LENGTH_MODIFIER__) # define NL_I64 __PRI_64_LENGTH_MODIFIER__ #elif defined(__PRI64_PREFIX) # define NL_I64 __PRI64_PREFIX #else # ifdef _LP64 # define NL_I64 "l" # else # define NL_I64 "ll" # endif // _LP64 #endif #endif // NL_OS_UNIX // #ifdef NL_ENABLE_FORCE_INLINE # ifdef NL_COMP_VC # define NL_FORCE_INLINE __forceinline # elif defined(NL_COMP_GCC) # define NL_FORCE_INLINE inline __attribute__((always_inline)) # else # define NL_FORCE_INLINE inline # endif // #else // # define NL_FORCE_INLINE inline // #endif #ifdef NL_COMP_VC #define NL_ALIGN(nb) __declspec(align(nb)) #else #define NL_ALIGN(nb) __attribute__((aligned(nb))) #endif #ifdef NL_OS_WINDOWS #include #include #include inline void *aligned_malloc(size_t size, size_t alignment) { return _aligned_malloc(size, alignment); } inline void aligned_free(void *ptr) { _aligned_free(ptr); } #elif defined(NL_OS_MAC) // under Mac OS X, malloc is already aligned for SSE and Altivec (16 bytes alignment) inline void *aligned_malloc(size_t size, size_t alignment) { return malloc(size); } inline void aligned_free(void *ptr) { free(ptr); } #elif defined(NL_OS_FREEBSD) #include inline void *aligned_malloc(size_t size, size_t alignment) { void *buf; posix_memalign(&buf,alignment,size); return buf; } inline void aligned_free(void *ptr) { free(ptr); } #else #include inline void *aligned_malloc(size_t size, size_t alignment) { return memalign(alignment, size); } inline void aligned_free(void *ptr) { free(ptr); } #endif /* NL_COMP_ */ #ifdef NL_HAS_SSE2 #define NL_DEFAULT_MEMORY_ALIGNMENT 16 #define NL_ALIGN_SSE2 NL_ALIGN(NL_DEFAULT_MEMORY_ALIGNMENT) extern void *operator new(size_t size) throw(std::bad_alloc); extern void *operator new[](size_t size) throw(std::bad_alloc); extern void operator delete(void *p) throw(); extern void operator delete[](void *p) throw(); #else /* NL_HAS_SSE2 */ #define NL_DEFAULT_MEMORY_ALIGNMENT 4 #define NL_ALIGN_SSE2 #endif /* NL_HAS_SSE2 */ // CHashMap, CHashSet and CHashMultiMap definitions #if defined(_STLPORT_VERSION) // STLport detected # include # include # ifdef _STLP_HASH_MAP # define CHashMap ::std::hash_map # define CHashSet ::std::hash_set # define CHashMultiMap ::std::hash_multimap # endif // _STLP_HASH_MAP #elif defined(NL_ISO_STDTR1_AVAILABLE) // use std::tr1 for CHash* classes, if available (gcc 4.1+ and VC9 with TR1 feature pack) # include NL_ISO_STDTR1_HEADER(unordered_map) # include NL_ISO_STDTR1_HEADER(unordered_set) # define CHashMap NL_ISO_STDTR1_NAMESPACE::unordered_map # define CHashSet NL_ISO_STDTR1_NAMESPACE::unordered_set # define CHashMultiMap NL_ISO_STDTR1_NAMESPACE::unordered_multimap #elif defined(NL_COMP_VC) && (NL_COMP_VC_VERSION >= 70 && NL_COMP_VC_VERSION <= 110) // VC7 through 9 # include # include # define CHashMap stdext::hash_map # define CHashSet stdext::hash_set # define CHashMultiMap stdext::hash_multimap #elif defined(NL_COMP_VC) && (NL_COMP_VC_VERSION >= 120) # include # include # define CHashMap std::unordered_map # define CHashSet std::unordered_set # define CHashMultiMap std::unordered_multimap #elif defined(NL_COMP_GCC) // GCC4 # include # include # define CHashMap ::__gnu_cxx::hash_map # define CHashSet ::__gnu_cxx::hash_set # define CHashMultiMap ::__gnu_cxx::hash_multimap namespace __gnu_cxx { template<> struct hash { size_t operator()(const std::string &s) const { return __stl_hash_string(s.c_str()); } }; template<> struct hash { size_t operator()(const uint64 x) const { return x; } }; } // END NAMESPACE __GNU_CXX #elif defined(NL_COMP_CLANG) # include # include # define CHashMap std::unordered_map # define CHashSet std::unordered_set # define CHashMultiMap std::unordered_multimap #else # pragma error("You need to update your compiler") #endif // _STLPORT_VERSION /** * \typedef ucchar * An Unicode character (16 bits) */ typedef uint16 ucchar; // To define a 64bits constant; ie: UINT64_CONSTANT(0x123456781234) #ifdef NL_COMP_VC # if (NL_COMP_VC_VERSION >= 120) # define INT64_CONSTANT(c) (c##LL) # define SINT64_CONSTANT(c) (c##LL) # define UINT64_CONSTANT(c) (c##ULL) # elif (NL_COMP_VC_VERSION >= 80) # define INT64_CONSTANT(c) (c##LL) # define SINT64_CONSTANT(c) (c##LL) # define UINT64_CONSTANT(c) (c##LL) # else # define INT64_CONSTANT(c) (c) # define SINT64_CONSTANT(c) (c) # define UINT64_CONSTANT(c) (c) # endif #else # define INT64_CONSTANT(c) (c##LL) # define SINT64_CONSTANT(c) (c##LL) # define UINT64_CONSTANT(c) (c##ULL) #endif // Define a macro to write template function according to compiler weakness #ifdef NL_COMP_NEED_PARAM_ON_METHOD # define NL_TMPL_PARAM_ON_METHOD_1(p1) # define NL_TMPL_PARAM_ON_METHOD_2(p1, p2) #else # define NL_TMPL_PARAM_ON_METHOD_1(p1) # define NL_TMPL_PARAM_ON_METHOD_2(p1, p2) #endif #if !defined(MAX_PATH) && !defined(NL_OS_WINDOWS) # define MAX_PATH 255 #endif #ifdef NL_DEBUG const std::string nlMode("NL_DEBUG"); #else const std::string nlMode("NL_RELEASE"); #endif // Sanity checks #if defined (NL_DEBUG) && defined (NL_RELEASE) # error "NeL cannot be configured for debug and release in the same time" #endif #if !defined (NL_DEBUG) && !defined (NL_RELEASE) # error "NeL must be configured for debug or release" #endif #ifdef NL_RELEASE_DEBUG # error "NL_RELEASE_DEBUG doesn't exist anymore, please remove it" #endif #ifdef NL_DEBUG_FAST # error "NL_DEBUG_FAST doesn't exist anymore, please remove it" #endif #endif // NL_TYPES_H ================================================ FILE: code/nel/include/nel/misc/ucstring.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_UCSTRING_H #define NL_UCSTRING_H #include "types_nl.h" #include "debug.h" #include /** * \typedef ucstring * An unicode string class (16 bits per character). * Add features to convert and assign \c ucstring to \c string and \c string to \c ucstring. */ typedef std::basic_string ucstringbase; class ucstring : public ucstringbase { public: ucstring () {} ucstring (const ucstringbase &str) : ucstringbase (str) {} ucstring (const std::string &str) : ucstringbase () { rawCopy(str); } ~ucstring () {} ucstring &operator= (ucchar c) { resize (1); operator[](0) = c; return *this; } ucstring &operator= (const char *str) { resize (strlen (str)); for (uint i = 0; i < strlen (str); i++) { operator[](i) = uint8(str[i]); } return *this; } ucstring &operator= (const std::string &str) { resize (str.size ()); for (uint i = 0; i < str.size (); i++) { operator[](i) = uint8(str[i]); } return *this; } ucstring &operator= (const ucstringbase &str) { ucstringbase::operator =(str); return *this; } ucstring& operator= (const ucchar *str) { ucstringbase::operator =(str); return *this; } ucstring &operator+= (ucchar c) { resize (size() + 1); operator[](size()-1) = c; return *this; } ucstring &operator+= (const char *str) { size_t s = size(); resize (s + strlen(str)); for (uint i = 0; i < strlen(str); i++) { operator[](s+i) = uint8(str[i]); } return *this; } ucstring &operator+= (const std::string &str) { size_t s = size(); resize (s + str.size()); for (uint i = 0; i < str.size(); i++) { operator[](s+i) = uint8(str[i]); } return *this; } ucstring &operator+= (const ucstringbase &str) { ucstringbase::operator +=(str); return *this; } const ucchar *c_str() const { const ucchar *tmp = ucstringbase::c_str(); const_cast(tmp)[size()] = 0; return tmp; } /// Converts the controlled ucstring to a string str void toString (std::string &str) const { str.resize (size ()); for (uint i = 0; i < str.size (); i++) { if (operator[](i) > 255) str[i] = '?'; else str[i] = (char) operator[](i); } } /// Converts the controlled ucstring and returns the resulting string std::string toString () const { std::string str; toString(str); return str; } /// Convert this ucstring (16bits char) into a utf8 string std::string toUtf8() const { std::string res; ucstring::const_iterator first(begin()), last(end()); for (; first != last; ++first) { //ucchar c = *first; uint nbLoop = 0; if (*first < 0x80) res += char(*first); else if (*first < 0x800) { ucchar c = *first; c = c >> 6; c = c & 0x1F; res += char(c) | 0xC0; nbLoop = 1; } else /*if (*first < 0x10000)*/ { ucchar c = *first; c = c >> 12; c = c & 0x0F; res += char(c) | 0xE0; nbLoop = 2; } for (uint i=0; i> ((nbLoop - i - 1) * 6); c = c & 0x3F; res += char(c) | 0x80; } } return res; } ucstring substr(size_type pos = 0, size_type n = npos) const { return ucstringbase::substr(pos, n); } // for luabind (can't bind to 'substr' else ...) ucstring luabind_substr(size_type pos = 0, size_type n = npos) const { return ucstringbase::substr(pos, n); } /// Convert the utf8 string into this ucstring (16 bits char) void fromUtf8(const std::string &stringUtf8) { // clear the string erase(); uint8 c; ucchar code; sint iterations = 0; std::string::const_iterator first(stringUtf8.begin()), last(stringUtf8.end()); for (; first != last; ) { c = *first++; code = c; if ((code & 0xFE) == 0xFC) { code &= 0x01; iterations = 5; } else if ((code & 0xFC) == 0xF8) { code &= 0x03; iterations = 4; } else if ((code & 0xF8) == 0xF0) { code &= 0x07; iterations = 3; } else if ((code & 0xF0) == 0xE0) { code &= 0x0F; iterations = 2; } else if ((code & 0xE0) == 0xC0) { code &= 0x1F; iterations = 1; } else if ((code & 0x80) == 0x80) { // If it's not a valid UTF8 string, just copy the line without utf8 conversion rawCopy(stringUtf8); return; } else { push_back(code); iterations = 0; } if (iterations) { for (sint i = 0; i < iterations; i++) { if (first == last) { // If it's not a valid UTF8 string, just copy the line without utf8 conversion rawCopy(stringUtf8); return; } uint8 ch; ch = *first ++; if ((ch & 0xC0) != 0x80) { // If it's not a valid UTF8 string, just copy the line without utf8 conversion rawCopy(stringUtf8); return; } code <<= 6; code |= (ucchar)(ch & 0x3F); } push_back(code); } } } static ucstring makeFromUtf8(const std::string &stringUtf8) { ucstring ret; ret.fromUtf8(stringUtf8); return ret; } private: void rawCopy(const std::string &str) { // We need to convert the char into 8bits unsigned int before promotion to 16 bits // otherwise, as char are signed on some compiler (MSCV for ex), the sign bit is extended to 16 bits. resize(str.size()); std::string::const_iterator first(str.begin()), last(str.end()); iterator dest(begin()); for (;first != last; ++first, ++dest) { *dest = uint8(*first); } } }; inline ucstring operator+(const ucstringbase &ucstr, ucchar c) { ucstring ret; ret= ucstr; ret+= c; return ret; } inline ucstring operator+(const ucstringbase &ucstr, const char *c) { ucstring ret; ret= ucstr; ret+= c; return ret; } inline ucstring operator+(const ucstringbase &ucstr, const std::string &c) { ucstring ret; ret= ucstr; ret+= c; return ret; } inline ucstring operator+(ucchar c, const ucstringbase &ucstr) { ucstring ret; ret= c; ret += ucstr; return ret; } inline ucstring operator+(const char *c, const ucstringbase &ucstr) { ucstring ret; ret= c; ret += ucstr; return ret; } inline ucstring operator+(const std::string &c, const ucstringbase &ucstr) { ucstring ret; ret= c; ret += ucstr; return ret; } namespace NLMISC { // Traits for hash_map using CEntityId struct CUCStringHashMapTraits { enum { bucket_size = 4, min_buckets = 8, }; CUCStringHashMapTraits() { } size_t operator() (const ucstring &id ) const { return id.size(); } bool operator() (const ucstring &id1, const ucstring &id2) const { return id1.size() < id2.size(); } }; /** Convert an unicode string in lower case. * Characters with accent are converted in a lowercase character with accent * \param a string or a char to transform to lower case */ ucstring toLower (const ucstring &str); void toLower (ucchar *str); ucchar toLower (ucchar c); /** Convert an unicode string in upper case. * Characters with accent are converted in a uppercase character without accent * \param a string or a char to transform to upper case */ ucstring toUpper (const ucstring &str); void toUpper (ucchar *str); ucchar toUpper (ucchar c); }; #endif // NL_UCSTRING_H ================================================ FILE: code/nel/include/nel/misc/uv.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_UV_H #define NL_UV_H #include "types_nl.h" #include "stream.h" namespace NLMISC { // *************************************************************************** /** * 2d UV. * */ /* *** IMPORTANT ******************** * *** IF YOU MODIFY THE STRUCTURE OF THIS CLASS, PLEASE INCREMENT IDriver::InterfaceVersion TO INVALIDATE OLD DRIVER DLL * ********************************** */ class CUV { public: float U,V; public: CUV() {} CUV(float u, float v) : U(u), V(v) {} // modify uv's void set(float u, float v) { U = u; V = v; } // bin operators. CUV operator+(const CUV &v) const { return CUV(U+v.U, V+v.V);} // binary - CUV operator-(const CUV &v) const { return CUV(U-v.U, V-v.V);} // unary - CUV operator-() const { return CUV(-U, -V); } // = operators. CUV &operator*=(float f) { U*=f;V*=f; return *this;} CUV &operator+=(const CUV &v) { U+=v.U;V+=v.V; return *this;} CUV &operator-=(const CUV &v) { U-=v.U;V-=v.V; return *this;} /// This operator is here just for map/set insertion (no meaning). comparison order is U,V. bool operator<(const CUV &o) const { if(U!=o.U) return U // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_VALUE_SMOOTHER_H #define NL_VALUE_SMOOTHER_H #include "types_nl.h" #include namespace NLMISC { // *************************************************************************** /** * A smoother of values. * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ template class CValueSmootherTemplate { public: /// Constructor explicit CValueSmootherTemplate(uint n=16) { init(n); } /// reset the ValueSmoother, and set the number of frame to smooth. void init(uint n) { // reset all the array to 0. _LastFrames.clear(); if (n > 0) _LastFrames.resize(n, 0); _CurFrame = 0; _NumFrame = 0; _FrameSum = 0; _CurrentValue = 0; } /// reset only the ValueSmoother void reset() { std::fill(_LastFrames.begin(), _LastFrames.end(), T(0)); _CurFrame = 0; _NumFrame = 0; _FrameSum = 0; _CurrentValue = 0; } /// add a new value to be smoothed. void addValue(T dt) { if (_LastFrames.empty()) return; // update the frame sum. NB: see init(), at start, array is full of 0. so it works even for un-inited values. _FrameSum-= _LastFrames[_CurFrame]; _FrameSum+= dt; // backup this value in the array. _LastFrames[_CurFrame]= dt; _CurrentValue = dt; // next frame. _CurFrame++; // _CurFrame%=_LastFrames.size(); if (_CurFrame >= _LastFrames.size()) _CurFrame -= (uint)_LastFrames.size(); // update the number of frames added. _NumFrame++; _NumFrame= (std::min)(_NumFrame, (uint)_LastFrames.size()); } /// get the smoothed value. T getSmoothValue() const { if(_NumFrame>0) return T(_FrameSum) / T(_NumFrame); else return T(0); } T getCurrentValue() const { if (_NumFrame>0) return T(_CurrentValue); else return T(0); } uint getNumFrame() const { return _NumFrame; } uint getCurrentFrame() const { return _CurFrame; } const std::vector &getLastFrames() const { return _LastFrames; } private: std::vector _LastFrames; uint _CurFrame; uint _NumFrame; T _FrameSum; T _CurrentValue; }; // *************************************************************************** /** * A smoother replacement for boolean. * \author Boris Boucher * \author Nevrax France * \date 2003 */ template <> class CValueSmootherTemplate { public: /// Constructor explicit CValueSmootherTemplate(uint n=1) { init(n); } /// reset the ValueSmoother, and set the number of frame to smooth. void init(uint n) { // reset all the array to 0. _LastFrames.clear(); if (n>0) _LastFrames.resize(n, false); _NumFrame = 0; } /// reset only the ValueSmoother void reset() { std::fill(_LastFrames.begin(), _LastFrames.end(), false); _NumFrame = 0; } /// add a new value to be smoothed. void addValue(bool dt) { if(_NumFrame>0) _LastFrames[0] = dt; } /// get the smoothed value. bool getSmoothValue() const { if(_NumFrame>0) return _LastFrames[0]; else return false; } uint getNumFrame() const { return _NumFrame; } uint getCurrentFrame() const { return 0; } const std::vector &getLastFrames() const { return _LastFrames; } private: std::vector _LastFrames; uint _NumFrame; }; class CValueSmoother : public CValueSmootherTemplate { public: /// Constructor explicit CValueSmoother(uint n=16) : CValueSmootherTemplate(n) { } }; } // NLMISC #endif // NL_VALUE_SMOOTHER_H /* End of value_smoother.h */ ================================================ FILE: code/nel/include/nel/misc/variable.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_VARIABLE_H #define NL_VARIABLE_H #include "types_nl.h" #include "command.h" #include "value_smoother.h" #include "sstring.h" namespace NLMISC { /** WARNING: * This is POSIX C/C++ linker behavior: object files * that are not referenced from outside are discarded. The * file in which you run your constructor is thus simply * thrown away by the linker, which explains why the constructor * is not run. */ /** * Add a variable that can be modified in realtime. The variable must be global. If you must access the variable with * function, use NLMISC_DYNVARIABLE * * Example: * \code // I want to look and change the variable 'foobar' in realtime, so, first i create it: uint8 foobar; // and then, I add it NLMISC_VARIABLE(uint8, FooBar, "this is a dummy variable"); * \endcode * * Please use the same casing than for the variable (first letter of each word in upper case) * ie: MyVariable, NetSpeedLoop, Time * * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ #define NLMISC_VARIABLE(__type,__var,__help) NLMISC_CATEGORISED_VARIABLE(variables,__type,__var,__help) #define NLMISC_CATEGORISED_VARIABLE(__category,__type,__var,__help) \ NLMISC::CVariablePtr<__type> __var##Instance(#__category,#__var, __help " (" #__type ")", &__var) /** * Add a variable that can be modified in realtime. The code profide the way to access to the variable in the read * and write access (depending on the \c get boolean value) * * Example: * \code // a function to read the variable uint8 getVar() { return ...; } // a function to write the variable void setVar(uint8 val) { ...=val; } // I want to look and change the variable in realtime: NLMISC_DYNVARIABLE(uint8, FooBar, "this is a dummy variable") { // read or write the variable if (get) *pointer = getVar(); else setVar(*pointer); } * \endcode * * Please use the same casing than for the variable (first letter of each word in upper case) * ie: MyVariable, NetSpeedLoop, Time * * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ #define NLMISC_DYNVARIABLE(__type,__name,__help) NLMISC_CATEGORISED_DYNVARIABLE(variables,__type,__name,__help) #define NLMISC_CATEGORISED_DYNVARIABLE(__category,__type,__name,__help) \ class __name##Class : public NLMISC::IVariable \ { \ public: \ __name##Class () : IVariable(#__category, #__name, __help) { } \ \ virtual bool fromString(const std::string &val, bool human=false) \ { \ /*std::stringstream ss (val);*/ \ __type p; \ /*ss >> p;*/ \ bool ret = NLMISC::fromString(val, p) ; \ ptr (&p, false, human); \ return ret; \ } \ \ virtual std::string toString(bool human) const \ { \ __type p; \ ptr (&p, true, human); \ /*std::stringstream ss;*/ \ /*ss << p;*/ \ /*return ss.str();*/ \ return NLMISC::toString(p); \ } \ \ void ptr(__type *pointer, bool get, bool human) const; \ }; \ __name##Class __name##Instance; \ void __name##Class::ptr(__type *pointer, bool get, bool human) const /** Helper to declare a variable as friend of a class. * Useful when you want to declare variable that need to access private data to act on or display internal state of the class */ #define NLMISC_DYNVARIABLE_FRIEND(__name) NLMISC_CATEGORISED_DYNVARIABLE_FRIEND(variables, __name) #define NLMISC_CATEGORISED_DYNVARIABLE_FRIEND(__category, __name) friend class __name##Class // // // // class IVariable : public ICommand { friend class CCommandRegistry; public: IVariable(const char *categoryName, const char *commandName, const char *commandHelp, const char *commandArgs = "[]", bool useConfigFile = false, void (*cc)(IVariable &var)=NULL) : ICommand(categoryName,commandName, commandHelp, commandArgs), _UseConfigFile(useConfigFile), ChangeCallback(cc) { Type = Variable; } virtual bool fromString(const std::string &val, bool human=false) = 0; virtual std::string toString(bool human=false) const = 0; virtual bool execute(const std::string &/* rawCommandString */, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human) { if (args.size() > 1) return false; if (args.size() == 1) { // set the value fromString (args[0], human); } // display the value if (quiet) { log.displayNL(toString(human).c_str()); } else { log.displayNL("Variable %s = %s", _CommandName.c_str(), toString(human).c_str()); } return true; } static void init (CConfigFile &configFile); private: bool _UseConfigFile; protected: // TODO: replace by interface (see IVariableChangedCallback) void (*ChangeCallback)(IVariable &var); }; template class CVariablePtr : public IVariable { public: CVariablePtr (const char *categoryName, const char *commandName, const char *commandHelp, T *valueptr, bool useConfigFile = false, void (*cc)(IVariable &var)=NULL) : IVariable (categoryName, commandName, commandHelp, "[]", useConfigFile, cc), _ValuePtr(valueptr) { } virtual bool fromString (const std::string &val, bool /* human */=false) { //std::stringstream ss (val); //ss >> *_ValuePtr; bool ret = NLMISC::fromString(val, *_ValuePtr); if (ChangeCallback) ChangeCallback (*this); return ret; } virtual std::string toString (bool /* human */) const { //std::stringstream ss; //ss << *_ValuePtr; //return ss.str(); return NLMISC::toString(*_ValuePtr); } private: T *_ValuePtr; }; template class CVariable : public IVariable { public: CVariable ( const char *categoryName, const char *commandName, const char *commandHelp, const T &defaultValue, uint nbMeanValue = 0, bool useConfigFile = false, void (*cc)(IVariable &var)=NULL, bool executeCallbackForDefaultValue=false ) : IVariable (categoryName, commandName, commandHelp, "[|stat|mean|min|max]", useConfigFile, cc), _Mean(nbMeanValue), _First(true) { set (defaultValue, executeCallbackForDefaultValue); } virtual bool fromString (const std::string &val, bool /* human */=false) { T v; bool ret = NLMISC::fromString(val, v); // std::stringstream ss (val); // ss >> v; set (v); return ret; } virtual std::string toString (bool /* human */) const { return NLMISC::toString(_Value); // std::stringstream ss; // ss << _Value; // return ss.str(); } CVariable &operator= (const T &val) { set (val); return *this; } operator T () const { return get (); } void set (const T &val, bool executeCallback = true) { _Value = val; _Mean.addValue (_Value); if (_First) { _First = false; _Min = _Value; _Max = _Value; } else { if (_Value > _Max) _Max = _Value; if (_Value < _Min) _Min = _Value; } if (ChangeCallback && executeCallback) ChangeCallback (*this); } const T &get () const { return _Value; } std::string getStat (bool light = false) const { CSString str; str << _CommandName << "=" << _Value << " Min=" << _Min; if (_Mean.getNumFrame()>0) { const std::vector& v = _Mean.getLastFrames(); T theMin = *std::min_element(v.begin(), v.end()); str << " RecentMin=" << theMin; } str << " Max=" << _Max; if (_Mean.getNumFrame()>0) { const std::vector& v = _Mean.getLastFrames(); T theMax = *std::max_element(v.begin(), v.end()); str << " RecentMax=" << theMax; } if (_Mean.getNumFrame()>0) { str << " RecentMean=" << _Mean.getSmoothValue(); if(!light) { str << " RecentValues="; // output the oldest part of the buffer first for (uint i=_Mean.getCurrentFrame(); i<_Mean.getNumFrame(); ++i) { str << (T)_Mean.getLastFrames()[i]; if (i < _Mean.getNumFrame()-1 || _Mean.getCurrentFrame() != 0) str << ","; } // then output the newest part for (uint i = 0; i < _Mean.getCurrentFrame(); i++) { str << (T)_Mean.getLastFrames()[i]; if (i < _Mean.getCurrentFrame()-1) str << ","; } } } return str; } virtual bool execute (const std::string &/* rawCommandString */, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human) { if (args.size() > 1) return false; bool haveVal=false; std::string val; if (args.size() == 1) { if (args[0] == "stat") { // display the stat value std::string stat = getStat(); // cut the stat line in lines of 80 chars std::string::size_type pos = 0; while (pos < stat.size()) { log.displayNL(getStat().substr(pos, 80).c_str()); pos += 80; } return true; } else if (args[0] == "mean") { haveVal = true; val = NLMISC::toString(_Mean.getSmoothValue()); } else if (args[0] == "min") { haveVal = true; val = NLMISC::toString(_Min); } else if (args[0] == "max") { haveVal = true; val = NLMISC::toString(_Max); } else { // set the value fromString (args[0], human); } } // display the value if (!haveVal) { val = toString(human); } if (quiet) { log.displayNL(val.c_str()); } else { log.displayNL("Variable %s = %s", _CommandName.c_str(), val.c_str()); } return true; } private: T _Value; CValueSmootherTemplate _Mean; T _Min, _Max; bool _First; }; template<> class CVariable : public IVariable { public: CVariable (const char *categoryName, const char *commandName, const char *commandHelp, const std::string &defaultValue, uint /* nbMeanValue */ = 0, bool useConfigFile = false, void (*cc)(IVariable &/* var */)=NULL, bool executeCallbackForDefaultValue=false) : IVariable (categoryName, commandName, commandHelp, "[]", useConfigFile, cc) { set (defaultValue, executeCallbackForDefaultValue); } virtual bool fromString (const std::string &val, bool /* human */=false) { set (val); return true; } virtual std::string toString (bool /* human */=false) const { return _Value; } CVariable &operator= (const std::string &val) { set (val); return *this; } operator std::string () const { return get(); } operator const char * () const { return get().c_str(); } const char *c_str () const { return get().c_str(); } void set (const std::string &val, bool executeCallback = true) { _Value = val; static bool RecurseSet = false; if (ChangeCallback && !RecurseSet && executeCallback) { RecurseSet = true; ChangeCallback(*this); RecurseSet = false; } } const std::string &get () const { return _Value; } virtual bool execute (const std::string &/* rawCommandString */, const std::vector &args, NLMISC::CLog &log, bool quiet, bool human) { if (args.size () > 1) return false; if (args.size () == 1) { // set the value fromString (args[0], human); } // convert the string from utf-8 to ascii (thrue unicode) ucstring temp; temp.fromUtf8(toString(human)); std::string disp = temp.toString(); // display the value if (quiet) { log.displayNL (disp.c_str()); } else { log.displayNL ("Variable %s = %s", _CommandName.c_str(), disp.c_str()); } return true; } private: std::string _Value; }; /// This class can provide a callback called when the value of a variable has been changed class IVariableChangedCallback { public: virtual ~IVariableChangedCallback() {} virtual void onVariableChanged(NLMISC::IVariable& var) = 0; }; } // NLMISC #endif // NL_VARIABLE_H /* End of variable.h */ ================================================ FILE: code/nel/include/nel/misc/vector.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_VECTOR_H #define NL_VECTOR_H #include "types_nl.h" #include #include #include "stream.h" namespace NLMISC { class IStream; // ====================================================================================================== /** * A 3D vector of float. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CVector { public: // Attributes. float x,y,z; public: // const. /// Null vector (0,0,0). static const CVector Null; /// I vector (1,0,0). static const CVector I; /// J vector (0,1,0). static const CVector J; /// K vector (0,0,1). static const CVector K; public: // Methods. /// @name Object. //@{ /// Constructor which does nothing. CVector() {} /// Constructor . CVector(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {} /// Copy Constructor. CVector(const CVector &v) : x(v.x), y(v.y), z(v.z) {} //@} /// @name Base Maths. //@{ CVector &operator+=(const CVector &v); CVector &operator-=(const CVector &v); CVector &operator*=(float f); CVector &operator/=(float f); CVector operator+(const CVector &v) const; CVector operator-(const CVector &v) const; CVector operator*(float f) const; CVector operator/(float f) const; CVector operator-() const; //@} /// @name Advanced Maths. //@{ /// Dot product. float operator*(const CVector &v) const; /** Cross product. * compute the cross product *this ^ v. */ CVector operator^(const CVector &v) const; /// Return the norm of the vector. float norm() const; /// Return the square of the norm of the vector. float sqrnorm() const; /// Normalize the vector. void normalize(); /// Return the vector normalized. CVector normed() const; //@} /// @name Misc. //@{ void set(float _x, float _y, float _z); bool operator==(const CVector &v) const; bool operator!=(const CVector &v) const; bool isNull() const; /// This operator is here just for map/set insertion (no meaning). comparison order is x,y,z. bool operator<(const CVector &v) const; /** * Setup the vector with spheric coordinates. * sphericToCartesian(1,0,0) build the I vector ((1,0,0)). * the formula is: \n * x= r*cos(theta)*cos(phi) \n * y= r*sin(theta)*cos(phi) \n * z= r*sin(phi) \n * \sa cartesianToSpheric() */ void sphericToCartesian(float r, float theta,float phi); /** * Get the spheric coordinates of the vector. * See sphericToCartesian() to know coordinates conventions. * \sa sphericToCartesian() */ void cartesianToSpheric(float &r, float &theta,float &phi) const; /// Set all vector x/y/z as minimum of a/b x/y/z (respectively). void minof(const CVector &a, const CVector &b); /// Set all vector x/y/z as maximum of a/b x/y/z (respectively). void maxof(const CVector &a, const CVector &b); /// serial. void serial(IStream &f); //@} /// Returns the contents as a printable string "x y z" /// undeprecated, use the generic function toString() std::string asString() const { return toString(); } /// Returns the contents as a printable string "x y z" std::string toString() const; // friends. friend CVector operator*(float f, const CVector &v0); }; // blend (faster version than the generic version found in algo.h) inline CVector blend(const CVector &v0, const CVector &v1, float lambda) { float invLambda = 1.f - lambda; return CVector(invLambda * v0.x + lambda * v1.x, invLambda * v0.y + lambda * v1.y, invLambda * v0.z + lambda * v1.z); } } #include "vector_inline.h" #endif // NL_VECTOR_H /* End of vector.h */ ================================================ FILE: code/nel/include/nel/misc/vector_2d.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_VECTOR_2D_H #define NL_VECTOR_2D_H #include "types_nl.h" #include #include #include "stream.h" #include "vector_2f.h" namespace NLMISC { // *************************************************************************** /** * A 2D vector of double. * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ class CVector2d { public: public: // Attributes. double x,y; public: // Methods. /// @name Object. //@{ /// Constructor which does nothing. CVector2d() {} /// Constructor . CVector2d(double _x, double _y) : x(_x), y(_y) {} /// Copy Constructor. CVector2d(const CVector2d &v) : x(v.x), y(v.y) {} /// Constructor with a CVector2f. CVector2d(const CVector2f &v) : x(v.x), y(v.y) {} //@} /// @name Base Maths. //@{ CVector2d &operator+=(const CVector2d &v) {x+=v.x; y+=v.y; return *this;} CVector2d &operator-=(const CVector2d &v) {x-=v.x; y-=v.y; return *this;} CVector2d &operator*=(double f) {x*=f; y*=f; return *this;} CVector2d &operator/=(double f) {x/=f; y/=f; return *this;} CVector2d operator+(const CVector2d &v) const {return CVector2d(x+v.x, y+v.y);} CVector2d operator-(const CVector2d &v) const {return CVector2d(x-v.x, y-v.y);} CVector2d operator*(double f) const {return CVector2d(x*f, y*f);} CVector2d operator/(double f) const {return CVector2d(x/f, y/f);} CVector2d operator-() const {return CVector2d(-x, -y);} //@} /// @name Advanced Maths. //@{ /// Dot product. double operator*(const CVector2d &v) const {return x*v.x + y*v.y;} /// Return the norm of the vector. double norm() const {return (double)sqrt(sqrnorm());} /// Return the square of the norm of the vector. double sqrnorm() const {return x*x + y*y;} /// Normalize the vector. void normalize() { double f= norm(); if(f>0) *this/=f; } /// Return the vector normalized. CVector2d normed() const { CVector2d v= *this; v.normalize(); return v; } //@} /// @name Misc. //@{ void set(double _x, double _y) {x= _x; y=_y;} bool operator==(const CVector2d &v) const {return x==v.x && y==v.y;} bool operator!=(const CVector2d &v) const {return !(*this==v);} bool isNull() const {return x==0.0f && y==0.0f;} /// Set all vector x/y/z as minimum of a/b x/y/z (respectively). void minof(const CVector2d &a, const CVector2d &b) { x= std::min(a.x, b.x); y= std::min(a.y, b.y); } /// Set all vector x/y/z as maximum of a/b x/y/z (respectively). void maxof(const CVector2d &a, const CVector2d &b) { x= std::max(a.x, b.x); y= std::max(a.y, b.y); } /// serial. void serial(NLMISC::IStream &f) {f.serial(x,y);} //@} // friends. friend CVector2d operator*(double f, const CVector2d &v0); }; inline CVector2d operator*(double f, const CVector2d &v) { return v*f; } } // NLMISC #endif // NL_VECTOR_2D_H /* End of vector_2d.h */ ================================================ FILE: code/nel/include/nel/misc/vector_2f.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_VECTOR_2F_H #define NL_VECTOR_2F_H #include "types_nl.h" #include "vector.h" #include #include "stream.h" #include namespace NLMISC { // *************************************************************************** /** * A 2D vector of float. * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ class CVector2f { public: public: // Attributes. float x,y; public: // Methods. /// @name Object. //@{ /// Constructor which do nothing. CVector2f() {} /// Constructor. CVector2f(float _x, float _y) : x(_x), y(_y) {} /// Copy Constructor. CVector2f(const CVector2f &v) : x(v.x), y(v.y) {} /// Constructor that uses the (x,y) coordinates of a CVector. CVector2f(const CVector &v) : x(v.x), y(v.y) {} // conversion operator operator CVector() const { return this->asVector(); } // convert to a CVector by setting z to 0 CVector asVector() const { return CVector(x, y, 0); } //@} /// @name Base Maths. //@{ CVector2f &operator+=(const CVector2f &v) {x+=v.x; y+=v.y; return *this;} CVector2f &operator-=(const CVector2f &v) {x-=v.x; y-=v.y; return *this;} CVector2f &operator*=(float f) {x*=f; y*=f; return *this;} CVector2f &operator/=(float f) {x/=f; y/=f; return *this;} CVector2f operator+(const CVector2f &v) const {return CVector2f(x+v.x, y+v.y);} CVector2f operator-(const CVector2f &v) const {return CVector2f(x-v.x, y-v.y);} CVector2f operator*(float f) const {return CVector2f(x*f, y*f);} CVector2f operator/(float f) const {return CVector2f(x/f, y/f);} CVector2f operator-() const {return CVector2f(-x, -y);} //@} /// @name Advanced Maths. //@{ /// Dot product. float operator*(const CVector2f &v) const {return x*v.x + y*v.y;} /// Return the norm of the vector. float norm() const {return (float)sqrt(sqrnorm());} /// Return the square of the norm of the vector. float sqrnorm() const {return x*x + y*y;} /// Normalize the vector. void normalize() { float f= norm(); if(f>0) *this/=f; } /// Return the vector normalized. CVector2f normed() const { CVector2f v= *this; v.normalize(); return v; } //@} /// @name Misc. //@{ void set(float _x, float _y) {x= _x; y=_y;} bool operator==(const CVector2f &v) const {return x==v.x && y==v.y;} bool operator!=(const CVector2f &v) const {return !(*this==v);} bool isNull() const {return x==0.0f && y==0.0f;} /// Set all vector x/y/z as minimum of a/b x/y/z (respectively). void minof(const CVector2f &a, const CVector2f &b) { x= std::min(a.x, b.x); y= std::min(a.y, b.y); } /// Set all vector x/y/z as maximum of a/b x/y/z (respectively). void maxof(const CVector2f &a, const CVector2f &b) { x= std::max(a.x, b.x); y= std::max(a.y, b.y); } /// serial. void serial(NLMISC::IStream &f) {f.serial(x,y);} //@} // friends. friend CVector2f operator*(float f, const CVector2f &v0); /// @name Constants //@{ static const CVector2f Null; //@} }; inline CVector2f operator*(float f, const CVector2f &v) { return v*f; } // for map/set insertion inline bool operator < (const CVector2f &lhs, const CVector2f &rhs) { return (lhs.x != rhs.x) ? lhs.x < rhs.x : lhs.y < rhs.y; } } // NLMISC #endif // NL_VECTOR_2F_H /* End of vector_2f.h */ ================================================ FILE: code/nel/include/nel/misc/vector_h.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_VECTOR_H_H #define NL_VECTOR_H_H #include "types_nl.h" #include "vector.h" namespace NLMISC { /** * Homogeneus vector. * A CVectorH has a fourth value, w. * \author Olivier Cado * \author Nevrax France * \date 2000 */ class CVectorH { public: /// Attributes float x, y, z, w; /// Constructor CVectorH() {} /// Constructor . CVectorH(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) {} /// Copy Constructor. CVectorH(const CVectorH &v) : x(v.x), y(v.y), z(v.z), w(v.w) {} /// Constructor using a vector CVectorH(const CVector &v) : x(v.x), y(v.y), z(v.z), w(1.0f) {} /// Set void set(float _x, float _y, float _z, float _w) { x=_x; y=_y; z=_z; w=_w; } /// Cast operator to a vector (ignoring w) operator CVector() const { return CVector( x, y, z ); } /// @name Misc. //@{ bool operator==(const CVectorH &v) const { return x==v.x && y==v.y && z==v.z && w==v.w; } bool operator!=(const CVectorH &v) const { return !(*this==v); } /// This operator is here just for map/set insertion (no meaning). comparison order is x,y,z,w. bool operator<(const CVectorH &v) const { if(x!=v.x) return x // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_VECTOR_INLINE_H #define NL_VECTOR_INLINE_H #include "types_nl.h" #include "common.h" namespace NLMISC { // ============================================================================================ // Base Maths. inline CVector &CVector::operator+=(const CVector &v) { x+=v.x; y+=v.y; z+=v.z; return *this; } inline CVector &CVector::operator-=(const CVector &v) { x-=v.x; y-=v.y; z-=v.z; return *this; } inline CVector &CVector::operator*=(float f) { x*=f; y*=f; z*=f; return *this; } inline CVector &CVector::operator/=(float f) { return *this*= (1.0f/f); } inline CVector CVector::operator+(const CVector &v) const { CVector ret(x+v.x, y+v.y, z+v.z); return ret; } inline CVector CVector::operator-(const CVector &v) const { CVector ret(x-v.x, y-v.y, z-v.z); return ret; } inline CVector CVector::operator*(float f) const { CVector ret(x*f, y*f, z*f); return ret; } inline CVector CVector::operator/(float f) const { return *this*(1.0f/f); } inline CVector CVector::operator-() const { return CVector(-x,-y,-z); } inline CVector operator*(float f, const CVector &v) { CVector ret(v.x*f, v.y*f, v.z*f); return ret; } // ============================================================================================ // Advanced Maths. inline float CVector::operator*(const CVector &v) const { return x*v.x + y*v.y + z*v.z; } inline CVector CVector::operator^(const CVector &v) const { CVector ret; ret.x= y*v.z - z*v.y; ret.y= z*v.x - x*v.z; ret.z= x*v.y - y*v.x; return ret; } inline float CVector::sqrnorm() const { return (float)(x*x + y*y + z*z); } inline float CVector::norm() const { return (float)sqrt(x*x + y*y + z*z); } inline void CVector::normalize() { float n=norm(); if(n) *this/=n; } inline CVector CVector::normed() const { CVector ret; ret= *this; ret.normalize(); return ret; } // ============================================================================================ // Misc. inline void CVector::set(float _x, float _y, float _z) { x=_x; y=_y; z=_z; } inline bool CVector::operator==(const CVector &v) const { return x==v.x && y==v.y && z==v.z; } inline bool CVector::operator!=(const CVector &v) const { return !(*this==v); } inline bool CVector::isNull() const { return *this==CVector::Null; } inline bool CVector::operator<(const CVector &v) const { if(x!=v.x) return x // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_VECTORD_H #define NL_VECTORD_H #include #include "vector.h" namespace NLMISC { // ====================================================================================================== /** * A 3D vector of double. * \author Lionel Berenguier * \author Nevrax France * \date 2000 */ class CVectorD { public: // Attributes. double x,y,z; public: // const. /// Null vector (0,0,0). static const CVectorD Null; /// I vector (1,0,0). static const CVectorD I; /// J vector (0,1,0). static const CVectorD J; /// K vector (0,0,1). static const CVectorD K; public: // Methods. /// @name Object. //@{ /// Constructor which does nothing. CVectorD() {} /// Constructor . CVectorD(double _x, double _y, double _z) : x(_x), y(_y), z(_z) {} /// Constructor with a CVector. CVectorD(const CVector &v) : x(v.x), y(v.y), z(v.z) {} /// Copy Constructor. CVectorD(const CVectorD &v) : x(v.x), y(v.y), z(v.z) {} //@} /// @name Base Maths. //@{ CVectorD &operator+=(const CVectorD &v); CVectorD &operator-=(const CVectorD &v); CVectorD &operator*=(double f); CVectorD &operator/=(double f); CVectorD operator+(const CVectorD &v) const; CVectorD operator-(const CVectorD &v) const; CVectorD operator*(double f) const; CVectorD operator/(double f) const; CVectorD operator-() const; //@} /// @name Advanced Maths. //@{ /// Dot product. double operator*(const CVectorD &v) const; /** Cross product. * compute the cross product *this ^ v. */ CVectorD operator^(const CVectorD &v) const; /// Return the norm of the vector. double norm() const; /// Return the square of the norm of the vector. double sqrnorm() const; /// Normalize the vector. void normalize(); /// Return the vector normalized. CVectorD normed() const; //@} /// @name Misc. //@{ void set(double _x, double _y, double _z); bool operator==(const CVectorD &v) const; bool operator!=(const CVectorD &v) const; bool isNull() const; /** * Setup the vector with spheric coordinates. * sphericToCartesian(1,0,0) build the I vector ((1,0,0)). * the formula is: \n * x= r*cos(theta)*cos(phi) \n * y= r*sin(theta)*cos(phi) \n * z= r*sin(phi) \n * \sa cartesianToSpheric() */ void sphericToCartesian(double r, double theta,double phi); /** * Get the sphreic coordinates of the vector. * See sphericToCartesian() to know coordinates conventions. * \sa sphericToCartesian() */ void cartesianToSpheric(double &r, double &theta,double &phi) const; void serial(IStream &f); CVectorD &operator=(const CVector &v); operator CVector() const; // copy content into a CVector void copyTo(CVector &dest) const; // conersion to a CVector CVector asVector() const; //@} // friends. friend CVectorD operator*(double f, const CVectorD &v0); }; } #include "vectord_inline.h" #endif // NL_VECTOR_H /* End of vector.h */ ================================================ FILE: code/nel/include/nel/misc/vectord_inline.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_VECTORD_INLINE_H #define NL_VECTORD_INLINE_H #include "common.h" namespace NLMISC { // ============================================================================================ // Base Maths. inline CVectorD &CVectorD::operator+=(const CVectorD &v) { x+=v.x; y+=v.y; z+=v.z; return *this; } inline CVectorD &CVectorD::operator-=(const CVectorD &v) { x-=v.x; y-=v.y; z-=v.z; return *this; } inline CVectorD &CVectorD::operator*=(double f) { x*=f; y*=f; z*=f; return *this; } inline CVectorD &CVectorD::operator/=(double f) { return *this*= (1.0f/f); } inline CVectorD CVectorD::operator+(const CVectorD &v) const { CVectorD ret(x+v.x, y+v.y, z+v.z); return ret; } inline CVectorD CVectorD::operator-(const CVectorD &v) const { CVectorD ret(x-v.x, y-v.y, z-v.z); return ret; } inline CVectorD CVectorD::operator*(double f) const { CVectorD ret(x*f, y*f, z*f); return ret; } inline CVectorD CVectorD::operator/(double f) const { return *this*(1.0f/f); } inline CVectorD CVectorD::operator-() const { return CVectorD(-x,-y,-z); } inline CVectorD operator*(double f, const CVectorD &v) { CVectorD ret(v.x*f, v.y*f, v.z*f); return ret; } // ============================================================================================ // Advanced Maths. inline double CVectorD::operator*(const CVectorD &v) const { return x*v.x + y*v.y + z*v.z; } inline CVectorD CVectorD::operator^(const CVectorD &v) const { CVectorD ret; ret.x= y*v.z - z*v.y; ret.y= z*v.x - x*v.z; ret.z= x*v.y - y*v.x; return ret; } inline double CVectorD::sqrnorm() const { return (double)(x*x + y*y + z*z); } inline double CVectorD::norm() const { return (double)sqrt(x*x + y*y + z*z); } inline void CVectorD::normalize() { double n=norm(); if(n) *this/=n; } inline CVectorD CVectorD::normed() const { CVectorD ret; ret= *this; ret.normalize(); return ret; } // ============================================================================================ // Misc. inline void CVectorD::set(double _x, double _y, double _z) { x=_x; y=_y; z=_z; } inline bool CVectorD::operator==(const CVectorD &v) const { return x==v.x && y==v.y && z==v.z; } inline bool CVectorD::operator!=(const CVectorD &v) const { return !(*this==v); } inline bool CVectorD::isNull() const { return *this==CVectorD::Null; } inline void CVectorD::cartesianToSpheric(double &r, double &theta,double &phi) const { CVectorD v; r= norm(); v= normed(); // phi E [-PI/2 et PI/2] clamp(v.z, -1.0, 1.0); phi=asin(v.z); // theta [-PI,PI] theta=atan2(v.y,v.x); } inline void CVectorD::sphericToCartesian(double r, double theta,double phi) { x= r*cos(theta)*cos(phi); y= r*sin(theta)*cos(phi); z= r*sin(phi); } inline CVectorD &CVectorD::operator=(const CVector &v) { x=v.x; y=v.y; z=v.z; return *this; } inline CVectorD::operator CVector() const { return CVector((float)x, (float)y, (float)z); } inline void CVectorD::serial(IStream &f) { f.serial(x,y,z); } inline void CVectorD::copyTo(CVector &dest) const { dest.set((float) x, (float) y, (float) z); } inline CVector CVectorD::asVector() const { return CVector((float) x, (float) y, (float) z); } } #endif ================================================ FILE: code/nel/include/nel/misc/voter.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef XML_PACK_H #define XML_PACK_H #include "types_nl.h" #include "string_mapper.h" #include "sstring.h" namespace NLMISC { /** The xml pack is a data format to store a great number of XML file * in a simple pseudo XML format. * The primary goal was to support the greate number of XML file * that we handle for Ryzom in a convenient and efficient way (mainly * in the CVS point of view). * * In a xml pack file, all xml files are concatenated inside * XML elements. * In the header of each subfile, there is only the file name. * So, it is possible to easily edit the file by hand, compare it * and add or remove file. * * NB : we use xml pack file as an intermediate format between the * level design team and the runtime data (that are ganarated by * the loadForm function of george) that are a binary extraction of * the content of the xml files. */ class CXMLPack { NLMISC_SAFE_SINGLETON_DECL(CXMLPack); CXMLPack(){} ~CXMLPack() {} public: // Add an xml pack to the manager bool add (const std::string &xmlPackFileName); // List all files in an xml_pack file void list (const std::string &xmlPackFileName, std::vector &allFiles); // Used by CIFile to get information about the files within the xml pack FILE* getFile (const std::string &sFileName, uint32 &rFileSize, uint32 &rFileOffset, bool &rCacheFileOnOpen, bool &rAlwaysOpened); private: ///@name parser functions ///@{ /// Consume space and tab characters (but NOT newlines) void skipWS(std::string::iterator &it, std::string::iterator end); /** Try to match the specified text at current position. Return false if no match * return true and advance the it iterator if match is found. */ bool matchString(std::string::iterator &it, std::string::iterator end, const char *text); /// Advance up to the begining of the next line, incrementing the in/out param lineCount void skipLine(std::string::iterator &it, std::string::iterator end, uint32 &lineCount); ///@} /// the name of the xml_pack file std::string XMLPackFileName; /// A descriptor for one file inside the pack struct TXMLFileInfo { /// The name of the file, mapped in the string mapper TStringId FileName; /// The start position of the data for this file uint32 FileOffset; /// The size of this file uint32 FileSize; }; /// A descriptor for the content of an xml pack file struct TXMLPackInfo { typedef std::map TFileList; /// the content of the xml pack TFileList _XMLFiles; /// The xml pack file handler (we keep it open) // FILE *FileHandler; // TXMLPackInfo() // : FileHandler(NULL) // { // } // // // ~TXMLPackInfo() // { // if (FileHandler != NULL) // fclose(FileHandler); // } }; typedef std::map TPackList; /// The list of xml pack file already parsed TPackList _XMLPacks; }; } // namespace NLMISC #endif // XML_PACK_H ================================================ FILE: code/nel/include/nel/misc/win32_util.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_WIN32_UTIL_H #define NL_WIN32_UTIL_H #include "types_nl.h" #ifdef NL_OS_WINDOWS #include namespace NLMISC { struct CWin32Util { /** replace all occurence of 'uiIdentifier' in a window with their localized versions * (from CI18N) */ static void localizeWindow(HWND wnd); // Append all child windows of a parent window into a vector static void appendChildWindows(HWND parentWnd, std::vector &childWindows); }; } // NLMISC #endif // NL_OS_WINDOWS #endif ================================================ FILE: code/nel/include/nel/misc/win_displayer.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_WIN_DISPLAYER_H #define NL_WIN_DISPLAYER_H #include "types_nl.h" #ifdef NL_OS_WINDOWS #ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif #ifndef _WIN32_WINDOWS # define _WIN32_WINDOWS 0x0410 #endif #ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0400 #endif #ifndef WINVER # define WINVER 0x0400 #endif #ifndef NOMINMAX # define NOMINMAX #endif #include #include "displayer.h" #include "reader_writer.h" #include "window_displayer.h" namespace NLMISC { /** * this displayer displays on a win32 windows. * MT = Main Thread, DT = Display Thread * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CWinDisplayer : public NLMISC::CWindowDisplayer { public: CWinDisplayer(const char *displayerName = ""); virtual ~CWinDisplayer (); #ifdef NL_OS_WINDOWS HWND getHWnd () const { return _HWnd; } #endif // NL_OS_WINDOWS private: // called by DT only void resizeLabels (); // called by DT only void updateLabels (); // called by DT only void open (std::string titleBar, bool iconified, sint x, sint y, sint w, sint h, sint hs, sint fs, const std::string &fn, bool ww, CLog *log); // called by DT only void clear (); // called by DT only void display_main (); virtual void setTitleBar (const std::string &titleBar); virtual void getWindowPos (uint32 &x, uint32 &y, uint32 &w, uint32 &h); // all these variables above is used only by the DT HWND _HEdit, _HWnd, _HInputEdit; HFONT _HFont; HMODULE _HLibModule; CLog *Log; // the MT must set the value to true to exit the thread bool Exit; friend LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); }; } // NLMISC #endif // NL_OS_WINDOWS #endif // NL_WIN_DISPLAYER_H /* End of win_displayer.h */ ================================================ FILE: code/nel/include/nel/misc/win_event_emitter.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_WIN_EVENT_EMITTER_H #define NL_WIN_EVENT_EMITTER_H #include "types_nl.h" #include "event_emitter.h" #include "events.h" #ifdef NL_OS_WINDOWS namespace NLMISC { /** * CWinEventEmitter * CEventEmitter Windows implementation */ class CWinEventEmitter : public IEventEmitter { public: CWinEventEmitter () : _MouseEventsEnabled(true), _KeyboardEventsEnabled(true), _IMEEventsEnabled(true) { _HWnd=NULL; resetButtonFlagState (); } void setHWnd (HWND hWnd) { _HWnd=hWnd; resetButtonFlagState (); } /** * sends all events to server * (should call CEventServer method postEvent() ) * \param server */ virtual void submitEvents(CEventServer & server, bool allWindows); /// Build the flags of the current buttons state TMouseButton buildFlags() const; // Reset button flag state void resetButtonFlagState (); // enable / disable mouse events to be processed. The default is enabled. void enableMouseEvents(bool enabled = true) { _MouseEventsEnabled = enabled; } // enable / disable keyboard events to be processed. The default is enabled. void enableKeyboardEvents(bool enabled = true) { _KeyboardEventsEnabled = enabled; } // enable / disable other events to be processed. The default is enabled. void enableIMEEvents(bool enabled = true) { _IMEEventsEnabled = enabled; } // Test whether mouse events are enabled. bool areMouseEventsEnabled() const { return _MouseEventsEnabled; } // Test whether keyboard events are enabled. bool areKeyboardEventsEnabled() const { return _KeyboardEventsEnabled; } private: // Private internal server message class CWinEventServer : CEventServer { friend class CWinEventEmitter; public: void setServer (CEventServer *server) { _Server=server; } private: virtual bool pumpEvent(CEvent* event) { CEventServer::pumpEvent(event); _Server->postEvent (event); return false; } private: CEventServer *_Server; }; public: /** Process a win32 message. * Return true if the message must be trapped, false if DefWindowProc must be called afterwards */ bool processMessage (HWND hWnd, uint32 msg, WPARAM wParam, LPARAM lParam, CEventServer *server=NULL); private: CWinEventServer _InternalServer; HWND _HWnd; public: // private: may need to be in sync with direct input flags however... bool _CtrlButton; bool _ShiftButton; bool _AltButton; bool _MouseButtons[3]; bool _MouseEventsEnabled; bool _KeyboardEventsEnabled; bool _IMEEventsEnabled; private: NLMISC::TMouseButton getButtons() const; }; } // NLMISC #endif // NL_OS_WINDOWS #endif // NL_WIN_EVENT_EMITTER_H /* End of win_event_emitter.h */ ================================================ FILE: code/nel/include/nel/misc/win_thread.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_WIN_THREAD_H #define NL_WIN_THREAD_H #include "types_nl.h" #include "thread.h" #ifdef NL_OS_WINDOWS namespace NLMISC { /** * Windows implementation of CThread class (look thread.h) * \author Vianney Lecroart * \author Nevrax France * \date 2000 */ class CWinThread : public IThread { public: /// Constructor CWinThread(IRunnable *runnable, uint32 stackSize); /// Don't use this constructor, only used to initialise the main thread class CWinThread (void* threadHandle, uint32 threadId); virtual ~CWinThread(); virtual void start(); virtual bool isRunning(); virtual void terminate(); virtual void wait(); virtual bool setCPUMask(uint64 cpuMask); virtual uint64 getCPUMask(); virtual void setPriority(TThreadPriority priority); virtual std::string getUserName(); virtual IRunnable *getRunnable() { return Runnable; } // Win32 specific // Get the suspend count. Will be -1 is the thread hasn't been started yet int getSuspendCount() const { return _SuspendCount; } // Increment the suspend count, a suspend count >= 1 means the thread is suspended void incSuspendCount(); /** Descrement the suspend count. Reaching 0 will resume the thread * An assertion is raised is the suspend count is already 0 */ void decSuspendCount(); // Suspend the thread. No-op if already suspended void suspend(); // Resume the thread. No-op if already resumed void resume(); // Priority boost void enablePriorityBoost(bool enabled); /// private use IRunnable *Runnable; private: int _SuspendCount; uint32 _StackSize; void *ThreadHandle; // HANDLE don't put it to avoid including windows.h uint32 ThreadId; // DWORD don't put it to avoid including windows.h bool _MainThread; // true if ths thread is the main thread, else false }; /** * Windows Process * \author Cyril 'Hulud' Corvazier * \author Nicolas Vizerie * \author Nevrax France * \date 2001, 2007 */ class CWinProcess : public IProcess { public: CWinProcess (void *handle); virtual ~CWinProcess() {} // TODO do something with _ProcessHandle? virtual uint64 getCPUMask(); virtual bool setCPUMask(uint64 mask); // processes helpers static bool enumProcessesId(std::vector &processesId); // get fully qualified path for all modules used by a given process static bool enumProcessModules(uint32 processId, std::vector &moduleNames); static uint32 getProcessIdFromModuleFilename(const std::string &moduleFileName); static bool terminateProcess(uint32 processId, uint exitCode = 0); static bool terminateProcessFromModuleName(const std::string &moduleName, uint exitCode = 0); private: void *_ProcessHandle; }; /* // I didn't use and test that code, enventually, but maybe useful in the future // // Utility class to launch a process and check if it is still running. // Implemented under windows only for now // class CProcessWatch { public: CProcessWatch(); ~CProcessWatch(); // launch a process with the given name and arguments, return true on success bool launch(const std::string &programName, const std::string &arguments); // return true if the process is still runing bool isRunning() const; private: class CProcessWatchImpl *_PImpl; }; */ } // NLMISC #endif // NL_OS_WINDOWS #endif // NL_WIN_THREAD_H /* End of win_thread.h */ ================================================ FILE: code/nel/include/nel/misc/win_tray.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . ================================================ FILE: code/nel/include/nel/misc/window_displayer.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_WINDOW_DISPLAYER_H #define NL_WINDOW_DISPLAYER_H #include "types_nl.h" #include "common.h" #include "debug.h" #include "displayer.h" #include "mutex.h" #include "thread.h" namespace NLMISC { /** * this displayer displays on a win32 windows. * MT = Main Thread, DT = Display Thread * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CWindowDisplayer : public NLMISC::IDisplayer { public: CWindowDisplayer (const char *displayerName = "") : IDisplayer(displayerName), _Buffer("CWindowDisplayer::_Buffer"), _Labels("CWindowDisplayer::_Labels"), _CommandsToExecute("CWindowDisplayer::_CommandsToExecute"), _Continue(true), _PosInHistory(0), _Init(false), _HistorySize(0), _ToolBarHeight(22), _InputEditHeight(25), _Thread(0), Log(0) { } virtual ~CWindowDisplayer (); // open the window and run the display thread (MT) void create (std::string titleBar = "", bool iconified = false, sint x = -1, sint y = -1, sint w = -1, sint h = -1, sint hs = -1, sint fs = 0, const std::string &fn = "", bool ww = false, CLog *log = InfoLog); // create a new label. empty string mean separator. start with @ means that is a command (MT) uint createLabel (const char *value = "?"); // change the value of a label (MT) void setLabel (uint label, const std::string &value); // execute user commands (MT) return false to quit bool update (); // set a special title to the window bar virtual void setTitleBar (const std::string &/* titleBar */) { } virtual void getWindowPos (uint32 &x, uint32 &y, uint32 &w, uint32 &h) { x=y=w=h=0; } protected: // display a string (MT) virtual void doDisplay (const NLMISC::CLog::TDisplayInfo &args, const char *message); // true for windows bool needSlashR; struct CLabelEntry { CLabelEntry (const std::string &value) : Hwnd(NULL), Value(value), NeedUpdate(true) { } void *Hwnd; std::string Value; bool NeedUpdate; }; // buffer that contains the text that the DT will have to display // uint32 is the color of the string CSynchronized > > _Buffer; CSynchronized > _Labels; CSynchronized > _CommandsToExecute; // called by DT only virtual void open (std::string titleBar, bool iconified, sint x, sint y, sint w, sint h, sint hs, sint fs, const std::string &fn, bool ww, CLog *log) = 0; // called by DT only virtual void display_main () = 0; // all these variables above is used only by the DT bool _Continue; std::vector _History; uint _PosInHistory; bool _Init; sint _HistorySize; sint _ToolBarHeight; sint _InputEditHeight; // the thread used to update the display NLMISC::IThread *_Thread; CLog *Log; friend class CUpdateThread; }; } // NLMISC #endif // NL_WINDOW_DISPLAYER_H /* End of window_displayer.h */ ================================================ FILE: code/nel/include/nel/misc/words_dictionary.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_WORDS_DICTIONARY_H #define NL_WORDS_DICTIONARY_H #include "types_nl.h" #include "sstring.h" namespace NLMISC { /** * Words dictionary: allows to search for keys and words in _words_.txt * Unicode files. All searches are case not-sensitive. * * \author Olivier Cado * \author Nevrax France * \date 2003 */ class CWordsDictionary { NL_INSTANCE_COUNTER_DECL(CWordsDictionary); public: /// Constructor CWordsDictionary(); /** Load the config file and the related words files. Return false in case of failure. * Config file variables: * - WordsPath: where to find _words_.txt * - LanguageCode: language code (ex: en for English) * - Utf8: results are in UTF8, otherwise in ANSI string * - Filter: "*" for all files (default) or a name (ex: "item"). * - AdditionalFiles/AdditionalFileColumnTitles */ bool init( const std::string& configFileName="words_dic.cfg" ); /** * Set the result vector with strings corresponding to the input string: * - If inputStr is partially or completely found in the keys, all the matching are returned; * - If inputStr is partially or completely in the words, all the matching are returned. * The following tags can modify the behaviour of the search algorithm: * - ^mystring returns mystring only if it is at the beginning of a key or word * - mystring$ returns mystring only if it is at the end of a key or word * All returned words are in UTF8 string or ANSI string, depending of the config file. */ void lookup( const CSString& inputStr, CVectorSString& resultVec )const; /// Set the result vector with the word(s) corresponding to the key void exactLookupByKey( const CSString& key, CVectorSString& resultVec ); /// Return the key contained in the provided string returned by lookup() (without extension) CSString getWordsKey( const CSString& resultStr ); // Accessors const CVectorSString& getKeys() { return _Keys; } const CVectorSString& getWords() { return _Words; } /// Return the list of input file loaded at init const std::vector& getFileList() const { return _FileList; } protected: /// Make a result string static CSString makeResult( const CSString &key, const CSString &word ); private: /// Keys (same indices as in _Words) CVectorSString _Keys; /// Words (same indices as in _Keys) CVectorSString _Words; /// Input file list std::vector _FileList; }; } // NLMISC #endif // NL_WORDS_DICTIONARY_H /* End of words_dictionary.h */ ================================================ FILE: code/nel/include/nel/misc/xml_auto_ptr.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef XML_AUTO_PTR_H #define XML_AUTO_PTR_H #include /** Simple auto pointer for xml pointers */ class CXMLAutoPtr { public: CXMLAutoPtr(const char *value = NULL) : _Value(value) {} CXMLAutoPtr(const unsigned char *value) : _Value((const char *) value) {} ~CXMLAutoPtr() { destroy(); } operator const char *() const { return _Value; } operator bool() const { return _Value != NULL; } inline std::string str() const { return _Value; } bool operator ! () const { return _Value == NULL; } operator const unsigned char *() const { return (const unsigned char *) _Value; } char operator * () const { nlassert(_Value); return *_Value; } /// NB : This remove previous owned pointer with xmlFree CXMLAutoPtr &operator = (const char *other) { if (other == _Value) return *this; destroy(); _Value = other; return *this; } CXMLAutoPtr &operator = (const unsigned char *other) { *this = (const char *) other; return *this; } char *getDatas() const { return const_cast(_Value); } ////////////////////////////////////////////////// private: const char *_Value; private: void destroy() { if (_Value) { xmlFree(const_cast(_Value)); _Value = NULL; } } // We'd rather avoid problems CXMLAutoPtr(const CXMLAutoPtr &/* other */) { nlassert(0); } CXMLAutoPtr&operator = (const CXMLAutoPtr &/* other */) { nlassert(0); return *this; } }; #endif ================================================ FILE: code/nel/include/nel/misc/xml_pack.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef XML_PACK_H #define XML_PACK_H #include "types_nl.h" #include "string_mapper.h" #include "sstring.h" namespace NLMISC { /** The xml pack is a data format to store a great number of XML file * in a simple pseudo XML format. * The primary goal was to support the greate number of XML file * that we handle for Ryzom in a convenient and efficient way (mainly * in the CVS point of view). * * In a xml pack file, all xml files are concatenated inside * XML elements. * In the header of each subfile, there is only the file name. * So, it is possible to easily edit the file by hand, compare it * and add or remove file. * * NB : we use xml pack file as an intermediate format between the * level design team and the runtime data (that are ganarated by * the loadForm function of george) that are a binary extraction of * the content of the xml files. */ class CXMLPack { NLMISC_SAFE_SINGLETON_DECL(CXMLPack); CXMLPack(){} ~CXMLPack() {} public: // Add an xml pack to the manager bool add (const std::string &xmlPackFileName); // List all files in an xml_pack file void list (const std::string &xmlPackFileName, std::vector &allFiles); // Used by CIFile to get information about the files within the xml pack FILE* getFile (const std::string &sFileName, uint32 &rFileSize, uint32 &rFileOffset, bool &rCacheFileOnOpen, bool &rAlwaysOpened); private: ///@name parser functions ///@{ /// Consume space and tab characters (but NOT newlines) void skipWS(std::string::iterator &it, std::string::iterator end); /** Try to match the specified text at current position. Return false if no match * return true and advance the it iterator if match is found. */ bool matchString(std::string::iterator &it, std::string::iterator end, const char *text); /// Advance up to the beginning of the next line, incrementing the in/out param lineCount void skipLine(std::string::iterator &it, std::string::iterator end, uint32 &lineCount); ///@} /// the name of the xml_pack file std::string XMLPackFileName; /// A descriptor for one file inside the pack struct TXMLFileInfo { /// The name of the file, mapped in the string mapper TStringId FileName; /// The start position of the data for this file uint32 FileOffset; /// The size of this file uint32 FileSize; }; /// A descriptor for the content of an xml pack file struct TXMLPackInfo { typedef std::map TFileList; /// the content of the xml pack TFileList _XMLFiles; /// The xml pack file handler (we keep it open) // FILE *FileHandler; // TXMLPackInfo() // : FileHandler(NULL) // { // } // // // ~TXMLPackInfo() // { // if (FileHandler != NULL) // fclose(FileHandler); // } }; typedef std::map TPackList; /// The list of xml pack file already parsed TPackList _XMLPacks; }; } // namespace NLMISC #endif // XML_PACK_H ================================================ FILE: code/nel/include/nel/net/CMakeLists.txt ================================================ FILE(GLOB HEADERS *.h) INSTALL(FILES ${HEADERS} DESTINATION include/nel/net COMPONENT headers) ================================================ FILE: code/nel/include/nel/net/admin.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_ADMIN_H #define NL_ADMIN_H // // Inlcudes // #include #include namespace NLNET { // // Structures // struct CAlarm { CAlarm (const std::string &n, sint l, bool gt) : Name(n), Limit(l), GT(gt), Activated(false) { } std::string Name; // variable name int Limit; // limit value where the alarm is setted bool GT; // true if the error is produce when var is greater than bound bool Activated; // true if the limit is exceeded (mail is send everytimes the actived bool change from false to true) }; struct CGraphUpdate { CGraphUpdate (const std::string &n, sint u) : Name(n), Update(u), LastUpdate(0) { } std::string Name; // variable name int Update; // delta time in second when we have to check variable uint32 LastUpdate; // in second }; typedef void (*TRemoteClientCallback) (uint32 rid, const std::string &cmd, const std::string &entityNames); // // Externals // extern std::vector GraphUpdates; extern std::vector Alarms; // // Types // typedef std::vector TAdminViewVarNames; typedef std::vector TAdminViewValues; struct SAdminViewRow { TAdminViewVarNames VarNames; TAdminViewValues Values; SAdminViewRow() {} SAdminViewRow(const TAdminViewVarNames& varNames, const TAdminViewValues& values): VarNames(varNames), Values(values) {} }; typedef std::vector< SAdminViewRow > TAdminViewResult; // // Functions // void initAdmin (bool dontUseAES); void updateAdmin (); void setInformation (const std::vector &alarms, const std::vector &graphupdate); void serviceGetView (uint32 rid, const std::string &rawvarpath, TAdminViewResult& answer, bool async=false); void setRemoteClientCallback (TRemoteClientCallback cb); void addRequestAnswer (uint32 rid, const TAdminViewVarNames& varNames, const TAdminViewValues& values); } // NLNET #endif // NL_ALARMS_H /* End of email.h */ ================================================ FILE: code/nel/include/nel/net/buf_client.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BUF_CLIENT_H #define NL_BUF_CLIENT_H #include "nel/misc/types_nl.h" #include "buf_net_base.h" #include "tcp_sock.h" #include "buf_sock.h" namespace NLNET { class CInetAddress; class CBufClient; /** * Code of receiving thread for clients */ class CClientReceiveTask : public NLMISC::IRunnable { public: /// Constructor (increments the reference to the object pointed to by the smart pointer sockid) CClientReceiveTask( CBufClient *client, CNonBlockingBufSock *bufsock ) : NbLoop(0), _Client(client), _NBBufSock(bufsock) {} // CHANGED: non-blocking client connection /// Run virtual void run(); /// Returns a pointer to the bufsock object CNonBlockingBufSock *bufSock() { return _NBBufSock; } // CHANGED: non-blocking client connection (previously, returned _SockId->Sock) /// Returns the socket identifier TSockId sockId() { return (TSockId)_NBBufSock; } uint32 NbLoop; private: CBufClient *_Client; CNonBlockingBufSock *_NBBufSock; // CHANGED: non-blocking client connection }; /** * Client class for layer 1 * * Active connection with packet scheme and buffering. * The provided buffers are sent raw (no endianness conversion). * By default, the size time trigger is disabled, the time trigger is set to 20 ms. * * Where do the methods take place: * \code * send() -> send buffer -> update(), flush(), * bytesUploaded(), newBytesUploaded() * * receive(), <- receive buffer <- receive thread, * dataAvailable(), bytesDownloaded(), newBytesDownloaded() * disconnection callback * \endcode * * \author Olivier Cado * \author Nevrax France * \date 2001 */ class CBufClient : public CBufNetBase { public: /** Constructor. Set nodelay to true to disable the Nagle buffering algorithm (see CTcpSock documentation) * initPipeForDataAvailable is for Linux only. Set it to false if you provide an external pipe with * setExternalPipeForDataAvailable(). */ CBufClient( bool nodelay=true, bool replaymode=false, bool initPipeForDataAvailable=true ); /// Destructor virtual ~CBufClient(); /// Connects to the specified host void connect( const CInetAddress& addr ); /** Disconnects the remote host and empties the receive queue. * Before that, tries to flush pending data to send unless quick is true. * In case of network congestion, the entire pending data may not be flushed. * If this is a problem, call flush() multiple times until it returns 0 before calling disconnect(). * The disconnection callback will *not* be called. * Do not call if the socket is not connected. */ void disconnect( bool quick=false ); /** Sends a message to the remote host (in fact the message is buffered into the send queue) */ //void send( const std::vector& buffer ); void send( const NLMISC::CMemStream& buffer ); /** Checks if there is some data to receive. Returns false if the receive queue is empty. * This is where the connection/disconnection callbacks can be called */ bool dataAvailable(); #ifdef NL_OS_UNIX /** Wait until the receive queue contains something to read (implemented with a select()). * This is where the connection/disconnection callbacks can be called. * If you use this method (blocking scheme), don't use dataAvailable() (non-blocking scheme). * \param usecMax Max time to wait in microsecond (up to 1 sec) */ void sleepUntilDataAvailable( uint usecMax=100000 ); #endif /** Receives next block of data in the specified buffer (resizes the vector) * You must call dataAvailable() before every call to receive() */ //void receive( std::vector& buffer ); void receive( NLMISC::CMemStream& buffer ); /// Update the network (call this method evenly) void update(); // Returns the size in bytes of the data stored in the send queue. uint32 getSendQueueSize() const { return _BufSock->SendFifo.size(); } void displaySendQueueStat (NLMISC::CLog *log = NLMISC::InfoLog) { _BufSock->SendFifo.displayStats(log); } void displayThreadStat (NLMISC::CLog *log); /** Sets the time flush trigger (in millisecond). When this time is elapsed, * all data in the send queue is automatically sent (-1 to disable this trigger) */ void setTimeFlushTrigger( sint32 ms ) { _BufSock->setTimeFlushTrigger( ms ); } /** Sets the size flush trigger. When the size of the send queue reaches or exceeds this * calue, all data in the send queue is automatically sent (-1 to disable this trigger ) */ void setSizeFlushTrigger( sint32 size ) { _BufSock->setSizeFlushTrigger( size ); } /** Force to send data pending in the send queue now. If all the data could not be sent immediately, * the returned nbBytesRemaining value is non-zero. * \param nbBytesRemaining If the pointer is not NULL, the method sets the number of bytes still pending after the flush attempt. * \returns False if an error has occured (e.g. the remote host is disconnected). * To retrieve the reason of the error, call CSock::getLastError() and/or CSock::errorString() */ bool flush( uint *nbBytesRemaining=NULL ) { return _BufSock->flush( nbBytesRemaining ); } /** Returns true if the connection is still connected (changed when a disconnection * event has reached the front of the receive queue, just before calling the disconnection callback * if there is one) */ bool connected() const { return _BufSock->connectedState(); } /// Returns the address of the remote host const CInetAddress& remoteAddress() const { return _BufSock->Sock->remoteAddr(); } /// Returns the number of bytes downloaded (read or still in the receive buffer) since the latest connection uint64 bytesDownloaded() const { return _BufSock->Sock->bytesReceived(); } /// Returns the number of bytes uploaded (flushed) since the latest connection uint64 bytesUploaded() const { return _BufSock->Sock->bytesSent(); } /// Returns the number of bytes downloaded since the previous call to this method uint64 newBytesDownloaded(); /// Returns the number of bytes uploaded since the previous call to this method uint64 newBytesUploaded(); /*//Not right because we add callbacks in the receive queue /// Returns the number of bytes popped by receive() since the beginning (mutexed on the receive queue) uint64 bytesReceived() { } /// Returns the number of bytes pushed by send() since the beginning uint64 bytesSent() { return bytesUploaded() + getSendQueueSize(); } /// Returns the number of bytes popped by receive() since the previous call to this method uint64 newBytesReceived(); /// Returns the number of bytes pushed by send() since the previous call to this method uint64 newBytesSent(); */ /// Returns the id of the connection TSockId id() const { return _BufSock; /*_RecvTask->sockId();*/ } protected: friend class CClientReceiveTask; /// Send buffer and connection CNonBlockingBufSock *_BufSock; // ADDED: non-blocking client connection /// True when the Nagle algorithm must be disabled (TCP_NODELAY) bool _NoDelay; /// Previous number of bytes downloaded uint64 _PrevBytesDownloaded; /// Previous number of bytes uploaded uint64 _PrevBytesUploaded; /* /// Previous number of bytes received uint32 _PrevBytesReceived; /// Previous number of bytes sent uint32 _PrevBytesSent; */ private: /// Receive task CClientReceiveTask *_RecvTask; /// Receive thread NLMISC::IThread *_RecvThread; }; } // NLNET #endif // NL_BUF_CLIENT_H /* End of buf_client.h */ ================================================ FILE: code/nel/include/nel/net/buf_net_base.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BUF_NET_BASE_H #define NL_BUF_NET_BASE_H #include "nel/misc/types_nl.h" #include "nel/misc/mutex.h" #include "nel/misc/buf_fifo.h" #include "nel/misc/thread.h" #include "nel/misc/debug.h" #include "nel/misc/common.h" namespace NLNET { class CBufSock; /// Socket identifier typedef CBufSock *TSockId; static const TSockId InvalidSockId = (TSockId) NULL; /// Callback function for message processing typedef void (*TNetCallback) ( TSockId from, void *arg ); /// Storing a TNetCallback call for future call typedef std::pair TStoredNetCallback; /// Synchronized FIFO buffer typedef NLMISC::CSynchronized CSynchronizedFIFO; /// Accessor of mutexed FIFO buffer typedef CSynchronizedFIFO::CAccessor CFifoAccessor; /// Size of a block typedef uint32 TBlockSize; extern uint32 NbNetworkTask; #ifdef NL_OS_UNIX /// Access to the wake-up pipe (Unix only) enum TPipeWay { PipeRead, PipeWrite }; #endif /** * Layer 1 * * Base class for CBufClient and CBufServer. * The max block sizes for sending and receiving are controlled by setMaxSentBlockSize() * and setMaxExpectedBlockSize(). Their default value is the maximum number contained in a sint32, * that is 2^31-1 (i.e. 0x7FFFFFFF). The limit for sending is checked only in debug mode. * * \author Nevrax France * \date 2001 */ class CBufNetBase { public: /// Type of incoming events (max 256) enum TEventType { User = 'U', Connection = 'C', Disconnection = 'D' }; /// Destructor virtual ~CBufNetBase(); #ifdef NL_OS_UNIX /** Init the pipe for data available with an external pipe. * Call it only if you set initPipeForDataAvailable to false in the constructor. * Then don't call sleepUntilDataAvailable() but use select() on the pipe. * The pipe will be written one byte when receiving a message. */ void setExternalPipeForDataAvailable( int *twoPipeHandles ) { _DataAvailablePipeHandle[PipeRead] = twoPipeHandles[PipeRead]; _DataAvailablePipeHandle[PipeWrite] = twoPipeHandles[PipeWrite]; } #endif /// Sets callback for detecting a disconnection (or NULL to disable callback) void setDisconnectionCallback( TNetCallback cb, void* arg ) { _DisconnectionCallback = cb; _DisconnectionCbArg = arg; } /// Returns the size of the receive queue (mutexed) uint32 getReceiveQueueSize() { CFifoAccessor syncfifo( &_RecvFifo ); return syncfifo.value().size(); } void displayReceiveQueueStat (NLMISC::CLog *log = NLMISC::InfoLog) { CFifoAccessor syncfifo( &_RecvFifo ); syncfifo.value().displayStats(log); } /** * Sets the max size of the received messages. * If receiving a message bigger than the limit, the connection will be dropped. * * Default value: CBufNetBase::DefaultMaxExpectedBlockSize * If you put a negative number as limit, the max size is reseted to the default value. * Warning: you can call this method only at initialization time, before connecting (for a client) * or calling init() (for a server) ! */ void setMaxExpectedBlockSize( sint32 limit ) { if ( limit < 0 ) _MaxExpectedBlockSize = DefaultMaxExpectedBlockSize; else _MaxExpectedBlockSize = (uint32)limit; } /** * Sets the max size of the sent messages. * Any bigger sent block will produce an assertion failure, currently. * * Default value: CBufNetBase::DefaultMaxSentBlockSize * If you put a negative number as limit, the max size is reseted to the default value. * Warning: you can call this method only at initialization time, before connecting (for a client) * or calling init() (for a server) ! */ void setMaxSentBlockSize( sint32 limit ) { if ( limit < 0 ) _MaxSentBlockSize = DefaultMaxSentBlockSize; else _MaxSentBlockSize = (uint32)limit; } /// Returns the max size of the received messages (default: 2^31-1) uint32 maxExpectedBlockSize() const { return _MaxExpectedBlockSize; } /// Returns the max size of the sent messages (default: 2^31-1) uint32 maxSentBlockSize() const { return _MaxSentBlockSize; } #ifdef NL_OS_UNIX /** * Return the handle for reading the 'data available pipe'. Use it if you want to do a select on * multiple CBufNetClient/CBufNetServer objects (then, don't call sleepUntilDataAvailable() on them). */ int dataAvailablePipeReadHandle() const { return _DataAvailablePipeHandle[PipeRead]; } #endif /// The value that will be used if setMaxExpectedBlockSize() is not called (or called with a negative argument) static uint32 DefaultMaxExpectedBlockSize; /// The value that will be used if setMaxSentBlockSize() is not called (or called with a negative argument) static uint32 DefaultMaxSentBlockSize; std::string m_SslCA; std::string m_SslCrt; std::string m_SslPrvKey; //protected: public: friend class NLNET::CBufSock; #ifdef NL_OS_UNIX /// Constructor CBufNetBase( bool isDataAvailablePipeSelfManaged ); #else /// Constructor CBufNetBase(); #endif /// Access to the receive queue CSynchronizedFIFO& receiveQueue() { return _RecvFifo; } /// Returns the disconnection callback TNetCallback disconnectionCallback() const { return _DisconnectionCallback; } /// Returns the argument of the disconnection callback void* argOfDisconnectionCallback() const { return _DisconnectionCbArg; } /// Push message into receive queue (mutexed) // TODO OPTIM never use this function void pushMessageIntoReceiveQueue( const std::vector& buffer ); /// Push message into receive queue (mutexed) void pushMessageIntoReceiveQueue( const uint8 *buffer, uint32 size ); /// Sets _DataAvailable void setDataAvailableFlag( bool da ) { _DataAvailable = da; } /// Return _DataAvailable bool dataAvailableFlag() const { return _DataAvailable; } #ifdef NL_OS_UNIX /// Pipe to select() on data available int _DataAvailablePipeHandle [2]; #endif private: /// The receive queue, protected by a mutex-like device CSynchronizedFIFO _RecvFifo; /// Callback for disconnection TNetCallback _DisconnectionCallback; /// Argument of the disconnection callback void* _DisconnectionCbArg; /// Max size of received messages (limited by the user) uint32 _MaxExpectedBlockSize; /// Max size of sent messages (limited by the user) uint32 _MaxSentBlockSize; /// True if there is data available (avoids locking a mutex) volatile bool _DataAvailable; #ifdef NL_OS_UNIX bool _IsDataAvailablePipeSelfManaged; #endif }; } // NLNET #endif // NL_BUF_NET_BASE_H /* End of buf_net_base.h */ ================================================ FILE: code/nel/include/nel/net/buf_server.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BUF_SERVER_H #define NL_BUF_SERVER_H #include "nel/misc/types_nl.h" #include "buf_net_base.h" #include "listen_sock.h" #include "buf_sock.h" #include "net_log.h" #include #include // POLL1 (ignore POLL comments) namespace NLNET { class CInetAddress; class CBufServer; /** * Common part of CListenTask and CServerReceiveTask */ class CServerTask { public: /// Destructor virtual ~CServerTask(); /// Tells the task to exit void requireExit() { _ExitRequired = true; } #ifdef NL_OS_UNIX /// Wake the thread up, when blocked in select (Unix only) void wakeUp(); #endif uint32 NbLoop; protected: /// Constructor CServerTask(); /// Returns true if the requireExit() has been called bool exitRequired() const { return _ExitRequired; } #ifdef NL_OS_UNIX /// Pipe for select wake-up (Unix only) int _WakeUpPipeHandle [2]; #endif private: volatile bool _ExitRequired; }; /** * Code of listening thread */ class CListenTask : public NLMISC::IRunnable, public CServerTask { public: /// Constructor CListenTask( CBufServer *server ) : CServerTask(), _Server(server) {} /// Begins to listen on the specified port (call before running thread) void init( uint16 port, sint32 maxExpectedBlockSize ); /// Run (exits when the listening socket disconnects) virtual void run(); /// Close listening socket void close(); /// Returns the listening address const CInetAddress& localAddr() { return _ListenSock.localAddr(); } private: CBufServer *_Server; CListenSock _ListenSock; uint32 _MaxExpectedBlockSize; }; typedef std::vector CThreadPool; // Mode: Small server #undef PRESET_BIG_SERVER #ifdef PRESET_BIG_SERVER // Big server #define DEFAULT_STRATEGY SpreadSockets #define DEFAULT_MAX_THREADS 64 #define DEFAULT_MAX_SOCKETS_PER_THREADS 64 #else // Small server #define DEFAULT_STRATEGY FillThreads #define DEFAULT_MAX_THREADS 64 #define DEFAULT_MAX_SOCKETS_PER_THREADS 16 #endif /** * Server class for layer 1 * * Listening socket and accepted connections, with packet scheme. * The provided buffers are sent raw (no endianness conversion). * By default, the size time trigger is disabled, the time trigger is set to 20 ms. * * Where do the methods take place: * \code * send(), -> send buffer -> update(), flush() * bytesSent(), newBytesSent() * * receive(), dataAvailable(), <- receive buffer <- receive thread, * dataAvailable(), * bytesReceived(), newBytesReceived(), * connection callback, disconnection callback * \endcode * * \author Olivier Cado * \author Nevrax France * \date 2001 */ class CBufServer : public CBufNetBase { public: enum TThreadStategy { SpreadSockets, FillThreads }; /** Constructor * Set nodelay to true to disable the Nagle buffering algorithm (see CTcpSock documentation) * initPipeForDataAvailable is for Linux only. Set it to false if you provide an external pipe with * setExternalPipeForDataAvailable(). */ CBufServer( TThreadStategy strategy=DEFAULT_STRATEGY, uint16 max_threads=DEFAULT_MAX_THREADS, uint16 max_sockets_per_thread=DEFAULT_MAX_SOCKETS_PER_THREADS, bool nodelay=true, bool replaymode=false, bool initPipeForDataAvailable=true ); /// Destructor virtual ~CBufServer(); /// Listens on the specified port void init( uint16 port ); /** Disconnect a connection * Set hostid to InvalidSockId to disconnect all connections. * If hostid is not InvalidSockId and the socket is not connected, the method does nothing. * If quick is true, any pending data will not be sent before disconnecting. * If quick is false, a flush() will be called. In case of network congestion, the entire pending * data may not be flushed. If this is a problem, call flush() multiple times until it returns 0 * before calling disconnect(). */ void disconnect( TSockId hostid, bool quick=false ); /// Sets callback for incoming connections (or NULL to disable callback) void setConnectionCallback( TNetCallback cb, void* arg ) { _ConnectionCallback = cb; _ConnectionCbArg = arg; } /** Send a message to the specified host, or to all hosts if hostid is InvalidSockId */ //void send( const std::vector& buffer, TSockId hostid ); void send( const NLMISC::CMemStream& buffer, TSockId hostid ); /** Checks if there is some data to receive. Returns false if the receive queue is empty. * This is where the connection/disconnection callbacks can be called. */ bool dataAvailable(); #ifdef NL_OS_UNIX /** Wait until the receive queue contains something to read (implemented with a select()). * This is where the connection/disconnection callbacks can be called. * If you use this method (blocking scheme), don't use dataAvailable() (non-blocking scheme). * \param usecMax Max time to wait in microsecond (up to 1 sec) */ void sleepUntilDataAvailable( uint usecMax=100000 ); #endif /** Receives next block of data in the specified (resizes the vector) * You must call dataAvailable() or sleepUntilDataAvailable() before every call to receive() */ void receive( NLMISC::CMemStream& buffer, TSockId* hostid ); /// Update the network (call this method evenly) void update(); // Returns the size in bytes of the data stored in the send queue. uint32 getSendQueueSize( TSockId destid ); void displaySendQueueStat( NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId); void displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog); /** Sets the time flush trigger (in millisecond). When this time is elapsed, * all data in the send queue is automatically sent (-1 to disable this trigger) */ void setTimeFlushTrigger( TSockId destid, sint32 ms ); /** Sets the size flush trigger. When the size of the send queue reaches or exceeds this * value, all data in the send queue is automatically sent (-1 to disable this trigger ) */ void setSizeFlushTrigger( TSockId destid, sint32 size ); /** Force to send data pending in the send queue now. If all the data could not be sent immediately, * the returned nbBytesRemaining value is non-zero. * \param destid The identifier of the destination connection. * \param nbBytesRemaining If the pointer is not NULL, the method sets the number of bytes still pending after the flush attempt. * \returns False if an error has occured (e.g. the remote host is disconnected). * To retrieve the reason of the error, call CSock::getLastError() and/or CSock::errorString() */ bool flush( TSockId destid, uint *nbBytesRemaining=NULL ); /// Returns the internet address of the listening socket const CInetAddress& listenAddress() const { return _ListenTask->localAddr(); } /// Returns the address of the specified host const CInetAddress& hostAddress( TSockId hostid ); /* /// Returns the number of bytes pushed into the receive queue since the beginning (mutexed) uint32 bytesDownloaded() { NLMISC::CSynchronized::CAccessor syncbpi ( &_BytesPushedIn ); return syncbpi.value(); } /// Returns the number of bytes downloaded since the previous call to this method uint32 newBytesDownloaded(); */ /// Returns the number of bytes popped by receive() since the beginning uint64 bytesReceived() const { return _BytesPoppedIn; } /// Returns the number of bytes popped by receive() since the previous call to this method uint64 newBytesReceived(); /// Returns the number of bytes pushed by send() since the beginning uint64 bytesSent() const { return _BytesPushedOut; } /// Returns the number of bytes pushed by send() since the previous call to this method uint64 newBytesSent(); /// Returns the number of connections (at the last update()) uint32 nbConnections() const { return _NbConnections; } protected: friend class CServerBufSock; friend class CListenTask; friend class CServerReceiveTask; /// Returns the TCP_NODELAY flag bool noDelay() const { return _NoDelay; } /** Binds a new socket and send buffer to an existing or a new thread (that starts) * Note: this method is called in the listening thread. */ void dispatchNewSocket( CServerBufSock *bufsock ); /// Returns the receive task corresponding to a particular thread CServerReceiveTask *receiveTask( std::vector::iterator ipt ) { return ((CServerReceiveTask*)((*ipt)->getRunnable())); } /// Pushes a buffer to the specified host's send queue and update (unless not connected) /*void pushBufferToHost( const std::vector& buffer, TSockId hostid ) { if ( hostid->pushBuffer( buffer ) ) { _BytesPushedOut += buffer.size() + sizeof(TBlockSize); // statistics } }*/ void pushBufferToHost( const NLMISC::CMemStream& buffer, TSockId hostid ) { nlassert( hostid != InvalidSockId ); if ( hostid->pushBuffer( buffer ) ) { _BytesPushedOut += buffer.length() + sizeof(TBlockSize); // statistics } } // Creates a new task and run a new thread for it void addNewThread( CThreadPool& threadpool, CServerBufSock *bufsock ); /// Returns the connection callback TNetCallback connectionCallback() const { return _ConnectionCallback; } /// Returns the argument of the connection callback void* argOfConnectionCallback() const { return _ConnectionCbArg; } /*/// Returns the synchronized number of bytes pushed into the receive queue NLMISC::CSynchronized& syncBytesPushedIn() { return _BytesPushedIn; } */ private: typedef std::set TClientSet; /// List of currently connected client TClientSet _ConnectedClients; /// Thread socket-handling strategy TThreadStategy _ThreadStrategy; /// Max number of threads uint16 _MaxThreads; /// Max number of sockets handled by one thread uint16 _MaxSocketsPerThread; /// Listen task CListenTask *_ListenTask; /// Listen thread NLMISC::IThread *_ListenThread; /* Vector of receiving threads. * Thread: thread control * Thread->Runnable: access to the CServerReceiveTask object * Thread->getRunnable()->sock(): access to the socket * The purpose of this list is to delete the objects after use. */ NLMISC::CSynchronized _ThreadPool; /// Connection callback TNetCallback _ConnectionCallback; /// Argument of the connection callback void* _ConnectionCbArg; /// Number of bytes pushed by send() since the beginning uint64 _BytesPushedOut; /// Number of bytes popped by receive() since the beginning uint64 _BytesPoppedIn; /// Previous number of bytes received uint64 _PrevBytesPoppedIn; /// Previous number of bytes sent uint64 _PrevBytesPushedOut; /// Number of connections (debug stat) uint32 _NbConnections; /// TCP_NODELAY bool _NoDelay; /// Replay mode flag bool _ReplayMode; /* /// Number of bytes pushed into the receive queue (by the receive threads) since the beginning. NLMISC::CSynchronized _BytesPushedIn; /// Previous number of bytes received uint32 _PrevBytesPushedIn; */ }; typedef std::set CConnections; // POLL2 /** * Code of receiving threads for servers. * Note: the methods locations in the classes do not correspond to the threads where they are * executed, but to the data they use. */ class CServerReceiveTask : public NLMISC::IRunnable, public CServerTask { public: /// Constructor CServerReceiveTask( CBufServer *server ) : CServerTask(), _Server(server), _Connections("CServerReceiveTask::_Connections"), _RemoveSet("CServerReceiveTask::_RemoveSet") {} /// Run virtual void run(); /// Returns the number of connections handled by the thread (mutexed on _Connections) uint numberOfConnections() { uint nb; { NLMISC::CSynchronized::CAccessor connectionssync( &_Connections ); nb = (uint)connectionssync.value().size(); } return nb; } /// Add a new connection into this thread (mutexed on _Connections) void addNewSocket( TSockId sockid ) { //nlnettrace( "CServerReceiveTask::addNewSocket" ); nlassert( sockid != InvalidSockId ); { NLMISC::CSynchronized::CAccessor connectionssync( &_Connections ); connectionssync.value().insert( sockid ); } // POLL3 } // POLL4 /** Add connection to the remove set (mutexed on _RemoveSet) * Note: you must not call this method within a mutual exclusion on _Connections, or * there will be a deadlock (see clearClosedConnection()) */ void addToRemoveSet( TSockId sockid ) { nlnettrace( "CServerReceiveTask::addToRemoveSet" ); nlassert( sockid != InvalidSockId ); { // Three possibilities : // - The value is inserted into the set. // - The value is already present in the set. // - The set is locked by a receive thread which is removing the closed connections. // When the set gets unlocked, it is empty so the value is inserted. It means the // value could be already in the set before it was cleared. // Note: with a fonction such as tryAcquire(), we could avoid to enter the mutex // when it is already locked // See clearClosedConnections(). NLMISC::CSynchronized::CAccessor removesetsync( &_RemoveSet ); removesetsync.value().insert( sockid ); //LNETL1_DEBUG( "LNETL1: ic: %p - RemoveSet.size(): %d", ic, removesetsync.value().size() ); } #ifdef NL_OS_UNIX wakeUp(); #endif } /// Delete all connections referenced in the remove list (mutexed on _RemoveSet and on _Connections) void clearClosedConnections(); /// Access to the server CBufServer *server() { return _Server; } friend class CBufServer; private: CBufServer *_Server; /* List of sockets and send buffer. * A TSockId is a pointer to a CBufSock object */ NLMISC::CSynchronized _Connections; // Connections to remove NLMISC::CSynchronized _RemoveSet; // POLL5 }; } // NLNET #endif // NL_BUF_SERVER_H /* End of buf_server.h */ ================================================ FILE: code/nel/include/nel/net/buf_server_tcp.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BUF_SERVER_TCP_H #define NL_BUF_SERVER_TCP_H #include "nel/misc/types_nl.h" #include "nel/misc/mutex.h" #include "buf_net_base.h" #include "listen_sock.h" #include "buf_sock.h" #include "net_log.h" #include #include // POLL1 (ignore POLL comments) struct evconnlistener; struct event_base; namespace NLNET { class CInetAddress; class CBufServerTcp; class CTcpReceiveTask; /** * Server class for layer 1 * * Listening socket and accepted connections, with packet scheme. * The provided buffers are sent raw (no endianness conversion). * By default, the size time trigger is disabled, the time trigger is set to 20 ms. * * Where do the methods take place: * \code * send(), -> send buffer -> update(), flush() * bytesSent(), newBytesSent() * * receive(), dataAvailable(), <- receive buffer <- receive thread, * dataAvailable(), * bytesReceived(), newBytesReceived(), * connection callback, disconnection callback * \endcode * * \author li9chuan@qq.com * \date 2018 */ class CBufServerTcp : public CBufNetBase { public: enum TThreadStategy { SpreadSockets, FillThreads }; /** Constructor * Set nodelay to true to disable the Nagle buffering algorithm (see CTcpSock documentation) * initPipeForDataAvailable is for Linux only. Set it to false if you provide an external pipe with * setExternalPipeForDataAvailable(). */ CBufServerTcp(); /// Destructor virtual ~CBufServerTcp(); /// Listens on the specified port void init( uint16 port ); /** Disconnect a connection * Set hostid to InvalidSockId to disconnect all connections. * If hostid is not InvalidSockId and the socket is not connected, the method does nothing. * If quick is true, any pending data will not be sent before disconnecting. * If quick is false, a flush() will be called. In case of network congestion, the entire pending * data may not be flushed. If this is a problem, call flush() multiple times until it returns 0 * before calling disconnect(). */ void disconnect( TSockId hostid, bool quick=false ); /// Sets callback for incoming connections (or NULL to disable callback) void setConnectionCallback( TNetCallback cb, void* arg ) { _ConnectionCallback = cb; _ConnectionCbArg = arg; } /** Send a message to the specified host, or to all hosts if hostid is InvalidSockId */ //void send( const std::vector& buffer, TSockId hostid ); void send( const NLMISC::CMemStream& buffer, TSockId hostid ); /** Checks if there is some data to receive. Returns false if the receive queue is empty. * This is where the connection/disconnection callbacks can be called. */ bool dataAvailable(); #ifdef NL_OS_UNIX /** Wait until the receive queue contains something to read (implemented with a select()). * This is where the connection/disconnection callbacks can be called. * If you use this method (blocking scheme), don't use dataAvailable() (non-blocking scheme). * \param usecMax Max time to wait in microsecond (up to 1 sec) */ void sleepUntilDataAvailable( uint usecMax=100000 ); #endif /** Receives next block of data in the specified (resizes the vector) * You must call dataAvailable() or sleepUntilDataAvailable() before every call to receive() */ void receive( NLMISC::CMemStream& buffer, TSockId* hostid ); /// Update the network (call this method evenly) void update(); // Returns the size in bytes of the data stored in the send queue. uint32 getSendQueueSize( TSockId destid ); void displaySendQueueStat( NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId); void displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog); /** Sets the time flush trigger (in millisecond). When this time is elapsed, * all data in the send queue is automatically sent (-1 to disable this trigger) */ void setTimeFlushTrigger( TSockId destid, sint32 ms ); /** Sets the size flush trigger. When the size of the send queue reaches or exceeds this * value, all data in the send queue is automatically sent (-1 to disable this trigger ) */ void setSizeFlushTrigger( TSockId destid, sint32 size ); /** Force to send data pending in the send queue now. If all the data could not be sent immediately, * the returned nbBytesRemaining value is non-zero. * \param destid The identifier of the destination connection. * \param nbBytesRemaining If the pointer is not NULL, the method sets the number of bytes still pending after the flush attempt. * \returns False if an error has occured (e.g. the remote host is disconnected). * To retrieve the reason of the error, call CSock::getLastError() and/or CSock::errorString() */ bool flush( TSockId destid, uint *nbBytesRemaining=NULL ); /// Returns the internet address of the listening socket const CInetAddress& listenAddress() const { return _ListenSock.localAddr(); } /// Returns the address of the specified host const CInetAddress& hostAddress( TSockId hostid ); /* /// Returns the number of bytes pushed into the receive queue since the beginning (mutexed) uint32 bytesDownloaded() { NLMISC::CSynchronized::CAccessor syncbpi ( &_BytesPushedIn ); return syncbpi.value(); } /// Returns the number of bytes downloaded since the previous call to this method uint32 newBytesDownloaded(); */ /// Returns the number of bytes popped by receive() since the beginning uint64 bytesReceived() const { return _BytesPoppedIn; } /// Returns the number of bytes popped by receive() since the previous call to this method uint64 newBytesReceived(); /// Returns the number of bytes pushed by send() since the beginning uint64 bytesSent() const { return _BytesPushedOut; } /// Returns the number of bytes pushed by send() since the previous call to this method uint64 newBytesSent(); /// Returns the number of connections (at the last update()) uint32 nbConnections() const { return _NbConnections; } protected: friend class CTcpReceiveTask; /// Returns the receive task corresponding to a particular thread CServerReceiveTask *receiveTask( std::vector::iterator ipt ) { return ((CServerReceiveTask*)((*ipt)->getRunnable())); } /// Pushes a buffer to the specified host's send queue and update (unless not connected) /*void pushBufferToHost( const std::vector& buffer, TSockId hostid ) { if ( hostid->pushBuffer( buffer ) ) { _BytesPushedOut += buffer.size() + sizeof(TBlockSize); // statistics } }*/ //void pushBufferToHost( const NLMISC::CMemStream& buffer, TSockId hostid ) //{ // nlassert( hostid != InvalidSockId ); // if ( hostid->pushBuffer( buffer ) ) // { // _BytesPushedOut += buffer.length() + sizeof(TBlockSize); // statistics // } //} /// Returns the connection callback TNetCallback connectionCallback() const { return _ConnectionCallback; } /// Returns the argument of the connection callback void* argOfConnectionCallback() const { return _ConnectionCbArg; } /*/// Returns the synchronized number of bytes pushed into the receive queue NLMISC::CSynchronized& syncBytesPushedIn() { return _BytesPushedIn; } */ private: CListenSock _ListenSock; uint32 _MaxExpectedBlockSize; CTcpReceiveTask *_WebSocketReceiveTask; typedef std::set TClientSet; /// List of currently connected client TClientSet _ConnectedClients; std::vector _RmDisConnectSockids; /// Thread socket-handling strategy TThreadStategy _ThreadStrategy; /// Max number of threads uint16 _MaxThreads; /// Max number of sockets handled by one thread uint16 _MaxSocketsPerThread; /// Connection callback TNetCallback _ConnectionCallback; /// Argument of the connection callback void* _ConnectionCbArg; /// Number of bytes pushed by send() since the beginning uint64 _BytesPushedOut; /// Number of bytes popped by receive() since the beginning uint64 _BytesPoppedIn; /// Previous number of bytes received uint64 _PrevBytesPoppedIn; /// Previous number of bytes sent uint64 _PrevBytesPushedOut; /// Number of connections (debug stat) uint32 _NbConnections; /* /// Number of bytes pushed into the receive queue (by the receive threads) since the beginning. NLMISC::CSynchronized _BytesPushedIn; /// Previous number of bytes received uint32 _PrevBytesPushedIn; */ }; typedef std::set CConnections; class CTcpReceiveTask : public NLMISC::IRunnable { public: /// Constructor CTcpReceiveTask() : _Connections("CTcpReceiveTask::_Connections"), _RemoveSet("CTcpReceiveTask::_RemoveSet") {} void init( CBufServerTcp*, uint16 port ); bool start(); void close(); /// Run virtual void run(); /// Returns the number of connections handled by the thread (mutexed on _Connections) uint numberOfConnections() { uint nb; { NLMISC::CSynchronized::CAccessor connectionssync( &_Connections ); nb = (uint)connectionssync.value().size(); } return nb; } /// Add a new connection into this thread (mutexed on _Connections) void addNewSocket( TSockId sockid ) { //nlnettrace( "CServerReceiveTask::addNewSocket" ); nlassert( sockid != InvalidSockId ); { NLMISC::CSynchronized::CAccessor connectionssync( &_Connections ); connectionssync.value().insert( sockid ); } // POLL3 } // POLL4 /** Add connection to the remove set (mutexed on _RemoveSet) * Note: you must not call this method within a mutual exclusion on _Connections, or * there will be a deadlock (see clearClosedConnection()) */ void addToRemoveSet( TSockId sockid ) { nlnettrace( "CTcpReceiveTask::addToRemoveSet" ); nlassert( sockid != InvalidSockId ); { // Three possibilities : // - The value is inserted into the set. // - The value is already present in the set. // - The set is locked by a receive thread which is removing the closed connections. // When the set gets unlocked, it is empty so the value is inserted. It means the // value could be already in the set before it was cleared. // Note: with a fonction such as tryAcquire(), we could avoid to enter the mutex // when it is already locked // See clearClosedConnections(). NLMISC::CSynchronized::CAccessor removesetsync( &_RemoveSet ); removesetsync.value().insert( sockid ); //LNETL1_DEBUG( "LNETL1: ic: %p - RemoveSet.size(): %d", ic, removesetsync.value().size() ); } } /// Access to the server CBufServerTcp *server() { return _Server; } friend class CBufServerTcp; protected: /// Returns true if the requireExit() has been called bool exitRequired() const { return _ExitRequired; } private: CBufServerTcp *_Server; NLMISC::IThread* _ProcTableThread; volatile bool _ExitRequired; event_base *pEventBase; evconnlistener *pEvListener; /* List of sockets and send buffer. * A TSockId is a pointer to a CBufSock object */ NLMISC::CSynchronized _Connections; // Connections to remove NLMISC::CSynchronized _RemoveSet; }; } // NLNET #endif // NL_BUF_SERVER_TCP_H /* End of buf_server_tcp.h */ ================================================ FILE: code/nel/include/nel/net/buf_server_tcp_func.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BUF_SERVER_TCP_FUNC_H #define NL_BUF_SERVER_TCP_FUNC_H #include "nel/misc/types_nl.h" #include "nel/misc/sstring.h" #include "event2/event.h" #include "event2/listener.h" #include "event2/bufferevent.h" namespace NLNET { class CBufServerTcp; class CServerBufSock; struct TcpListenArgs { event_base* pEventBase; CBufServerTcp* pServer; TcpListenArgs( event_base* eventbase, CBufServerTcp* bufsvr ) : pEventBase(eventbase), pServer(bufsvr) {} }; void tcp_socket_event_cb( bufferevent *bev, short events, void *args ); void tcp_socket_read_cb( bufferevent *bev, void *args ); void tcp_listener_cb( evconnlistener *listener, evutil_socket_t fd, sockaddr *sock, int socklen, void *args ); } #endif // NL_BUF_SERVER_TCP_FUNC_H /* End of buf_server_tcp_func.h */ ================================================ FILE: code/nel/include/nel/net/buf_server_websocket.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BUF_SERVER_WEBSOCKET_H #define NL_BUF_SERVER_WEBSOCKET_H #include "nel/misc/types_nl.h" #include "nel/misc/mutex.h" #include "buf_net_base.h" #include "listen_sock.h" #include "buf_sock.h" #include "net_log.h" #include #include // POLL1 (ignore POLL comments) struct evconnlistener; struct event_base; namespace NLNET { class CInetAddress; class CBufServerWebsocket; class CWebSocketReceiveTask; /** * Server class for layer 1 * * Listening socket and accepted connections, with packet scheme. * The provided buffers are sent raw (no endianness conversion). * By default, the size time trigger is disabled, the time trigger is set to 20 ms. * * Where do the methods take place: * \code * send(), -> send buffer -> update(), flush() * bytesSent(), newBytesSent() * * receive(), dataAvailable(), <- receive buffer <- receive thread, * dataAvailable(), * bytesReceived(), newBytesReceived(), * connection callback, disconnection callback * \endcode * * \author li9chuan@qq.com * \date 2018 */ class CBufServerWebsocket : public CBufNetBase { public: enum TThreadStategy { SpreadSockets, FillThreads }; /** Constructor * Set nodelay to true to disable the Nagle buffering algorithm (see CTcpSock documentation) * initPipeForDataAvailable is for Linux only. Set it to false if you provide an external pipe with * setExternalPipeForDataAvailable(). */ CBufServerWebsocket(); /// Destructor virtual ~CBufServerWebsocket(); /// Listens on the specified port void init( uint16 port ); void setupSsl( std::string& ssl_ca, std::string& ssl_crt, std::string& ssl_prvkey ); void* getSslCtx() { return _SslCtx; } /** Disconnect a connection * Set hostid to InvalidSockId to disconnect all connections. * If hostid is not InvalidSockId and the socket is not connected, the method does nothing. * If quick is true, any pending data will not be sent before disconnecting. * If quick is false, a flush() will be called. In case of network congestion, the entire pending * data may not be flushed. If this is a problem, call flush() multiple times until it returns 0 * before calling disconnect(). */ void disconnect( TSockId hostid, bool quick=false ); /// Sets callback for incoming connections (or NULL to disable callback) void setConnectionCallback( TNetCallback cb, void* arg ) { _ConnectionCallback = cb; _ConnectionCbArg = arg; } /** Send a message to the specified host, or to all hosts if hostid is InvalidSockId */ //void send( const std::vector& buffer, TSockId hostid ); void send( const NLMISC::CMemStream& buffer, TSockId hostid ); /** Checks if there is some data to receive. Returns false if the receive queue is empty. * This is where the connection/disconnection callbacks can be called. */ bool dataAvailable(); #ifdef NL_OS_UNIX /** Wait until the receive queue contains something to read (implemented with a select()). * This is where the connection/disconnection callbacks can be called. * If you use this method (blocking scheme), don't use dataAvailable() (non-blocking scheme). * \param usecMax Max time to wait in microsecond (up to 1 sec) */ void sleepUntilDataAvailable( uint usecMax=100000 ); #endif /** Receives next block of data in the specified (resizes the vector) * You must call dataAvailable() or sleepUntilDataAvailable() before every call to receive() */ void receive( NLMISC::CMemStream& buffer, TSockId* hostid ); /// Update the network (call this method evenly) void update(); // Returns the size in bytes of the data stored in the send queue. uint32 getSendQueueSize( TSockId destid ); void displaySendQueueStat( NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId); void displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog); /** Sets the time flush trigger (in millisecond). When this time is elapsed, * all data in the send queue is automatically sent (-1 to disable this trigger) */ void setTimeFlushTrigger( TSockId destid, sint32 ms ); /** Sets the size flush trigger. When the size of the send queue reaches or exceeds this * value, all data in the send queue is automatically sent (-1 to disable this trigger ) */ void setSizeFlushTrigger( TSockId destid, sint32 size ); /** Force to send data pending in the send queue now. If all the data could not be sent immediately, * the returned nbBytesRemaining value is non-zero. * \param destid The identifier of the destination connection. * \param nbBytesRemaining If the pointer is not NULL, the method sets the number of bytes still pending after the flush attempt. * \returns False if an error has occured (e.g. the remote host is disconnected). * To retrieve the reason of the error, call CSock::getLastError() and/or CSock::errorString() */ bool flush( TSockId destid, uint *nbBytesRemaining=NULL ); /// Returns the internet address of the listening socket const CInetAddress& listenAddress() const { return _ListenSock.localAddr(); } /// Returns the address of the specified host const CInetAddress& hostAddress( TSockId hostid ); /* /// Returns the number of bytes pushed into the receive queue since the beginning (mutexed) uint32 bytesDownloaded() { NLMISC::CSynchronized::CAccessor syncbpi ( &_BytesPushedIn ); return syncbpi.value(); } /// Returns the number of bytes downloaded since the previous call to this method uint32 newBytesDownloaded(); */ /// Returns the number of bytes popped by receive() since the beginning uint64 bytesReceived() const { return _BytesPoppedIn; } /// Returns the number of bytes popped by receive() since the previous call to this method uint64 newBytesReceived(); /// Returns the number of bytes pushed by send() since the beginning uint64 bytesSent() const { return _BytesPushedOut; } /// Returns the number of bytes pushed by send() since the previous call to this method uint64 newBytesSent(); /// Returns the number of connections (at the last update()) uint32 nbConnections() const { return _NbConnections; } protected: friend class CWebSocketReceiveTask; /// Returns the receive task corresponding to a particular thread CServerReceiveTask *receiveTask( std::vector::iterator ipt ) { return ((CServerReceiveTask*)((*ipt)->getRunnable())); } /// Pushes a buffer to the specified host's send queue and update (unless not connected) /*void pushBufferToHost( const std::vector& buffer, TSockId hostid ) { if ( hostid->pushBuffer( buffer ) ) { _BytesPushedOut += buffer.size() + sizeof(TBlockSize); // statistics } }*/ //void pushBufferToHost( const NLMISC::CMemStream& buffer, TSockId hostid ) //{ // nlassert( hostid != InvalidSockId ); // if ( hostid->pushBuffer( buffer ) ) // { // _BytesPushedOut += buffer.length() + sizeof(TBlockSize); // statistics // } //} /// Returns the connection callback TNetCallback connectionCallback() const { return _ConnectionCallback; } /// Returns the argument of the connection callback void* argOfConnectionCallback() const { return _ConnectionCbArg; } /*/// Returns the synchronized number of bytes pushed into the receive queue NLMISC::CSynchronized& syncBytesPushedIn() { return _BytesPushedIn; } */ private: CListenSock _ListenSock; uint32 _MaxExpectedBlockSize; CWebSocketReceiveTask *_WebSocketReceiveTask; typedef std::set TClientSet; /// List of currently connected client TClientSet _ConnectedClients; std::vector _RmDisConnectSockids; /// Thread socket-handling strategy TThreadStategy _ThreadStrategy; /// Max number of threads uint16 _MaxThreads; /// Max number of sockets handled by one thread uint16 _MaxSocketsPerThread; /// Connection callback TNetCallback _ConnectionCallback; /// Argument of the connection callback void* _ConnectionCbArg; /// Number of bytes pushed by send() since the beginning uint64 _BytesPushedOut; /// Number of bytes popped by receive() since the beginning uint64 _BytesPoppedIn; /// Previous number of bytes received uint64 _PrevBytesPoppedIn; /// Previous number of bytes sent uint64 _PrevBytesPushedOut; /// Number of connections (debug stat) uint32 _NbConnections; void* _SslCtx; /* /// Number of bytes pushed into the receive queue (by the receive threads) since the beginning. NLMISC::CSynchronized _BytesPushedIn; /// Previous number of bytes received uint32 _PrevBytesPushedIn; */ }; typedef std::set CConnections; class CWebSocketReceiveTask : public NLMISC::IRunnable { public: /// Constructor CWebSocketReceiveTask() : _Connections("CWebSocketReceiveTask::_Connections"), _RemoveSet("CWebSocketReceiveTask::_RemoveSet") {} void init( CBufServerWebsocket*, uint16 port ); bool start(); void close(); /// Run virtual void run(); /// Returns the number of connections handled by the thread (mutexed on _Connections) uint numberOfConnections() { uint nb; { NLMISC::CSynchronized::CAccessor connectionssync( &_Connections ); nb = (uint)connectionssync.value().size(); } return nb; } /// Add a new connection into this thread (mutexed on _Connections) void addNewSocket( TSockId sockid ) { //nlnettrace( "CServerReceiveTask::addNewSocket" ); nlassert( sockid != InvalidSockId ); { NLMISC::CSynchronized::CAccessor connectionssync( &_Connections ); connectionssync.value().insert( sockid ); } // POLL3 } // POLL4 /** Add connection to the remove set (mutexed on _RemoveSet) * Note: you must not call this method within a mutual exclusion on _Connections, or * there will be a deadlock (see clearClosedConnection()) */ void addToRemoveSet( TSockId sockid ) { nlnettrace( "CWebSocketReceiveTask::addToRemoveSet" ); nlassert( sockid != InvalidSockId ); { // Three possibilities : // - The value is inserted into the set. // - The value is already present in the set. // - The set is locked by a receive thread which is removing the closed connections. // When the set gets unlocked, it is empty so the value is inserted. It means the // value could be already in the set before it was cleared. // Note: with a fonction such as tryAcquire(), we could avoid to enter the mutex // when it is already locked // See clearClosedConnections(). NLMISC::CSynchronized::CAccessor removesetsync( &_RemoveSet ); removesetsync.value().insert( sockid ); //LNETL1_DEBUG( "LNETL1: ic: %p - RemoveSet.size(): %d", ic, removesetsync.value().size() ); } } /// Access to the server CBufServerWebsocket *server() { return _Server; } friend class CBufServerWebsocket; protected: /// Returns true if the requireExit() has been called bool exitRequired() const { return _ExitRequired; } private: CBufServerWebsocket *_Server; NLMISC::IThread* _ProcTableThread; volatile bool _ExitRequired; event_base *pEventBase; evconnlistener *pEvListener; /* List of sockets and send buffer. * A TSockId is a pointer to a CBufSock object */ NLMISC::CSynchronized _Connections; // Connections to remove NLMISC::CSynchronized _RemoveSet; }; } // NLNET #endif // NL_BUF_SERVER_WEBSOCKET_H /* End of buf_server_websocket.h */ ================================================ FILE: code/nel/include/nel/net/buf_server_websocket_func.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_WEBSOCKET_FUN_H #define NL_WEBSOCKET_FUN_H #include "nel/misc/types_nl.h" #include "nel/misc/sstring.h" #include "nel/misc/object_vector.h" #include "event2/event.h" #include "event2/listener.h" #include "event2/bufferevent.h" namespace NLNET { #define WEBSOCK_FRAME_HAVE_NEXT (0x0) /// ʾһ֡OpcodeΪ0ʱʾݴݷƬǰյ֡ΪһݷƬ #define WEBSOCK_FRAME_TEXT (0x1) /// %x1ʾһı֡frame %x2ʾһ֡frame #define WEBSOCK_FRAME_BIN (0x2) #define WEBSOCK_FRAME_DIS_CONNECT (0x8) #define WEBSOCK_FRAME_PING (0x9) #define WEBSOCK_FRAME_PONG (0xa) inline uint16 myhtons(uint16 n) { return ((n & 0xff00) >> 8) | ((n & 0x00ff) << 8); } inline uint16 myntohs(uint16 n) { return ((n & 0xff00) >> 8) | ((n & 0x00ff) << 8); } inline uint32 myhtonl(uint32 n) { return ((n & 0xff000000) >> 24) | ((n & 0x00ff0000) >> 8) | ((n & 0x0000ff00) << 8) | ((n & 0x000000ff) << 24); } inline uint32 myntohl(uint32 n) { return ((n & 0xff000000) >> 24) | ((n & 0x00ff0000) >> 8) | ((n & 0x0000ff00) << 8) | ((n & 0x000000ff) << 24); } inline uint64 myhtonll(uint64 n) { return (uint64)myhtonl(n >> 32) | ((uint64)myhtonl(n) << 32); } inline uint64 myntohll(uint64 n) { return (uint64)myhtonl(n >> 32) | ((uint64)myhtonl(n) << 32); } class CBufServerWebsocket; class CServerBufSock; struct WSListenArgs { event_base* pEventBase; CBufServerWebsocket* pServer; void* pSslCtx; WSListenArgs( event_base* eventbase, CBufServerWebsocket* bufsvr ) : pEventBase(eventbase), pServer(bufsvr), pSslCtx(NULL) {} }; struct WebSocketFrame { uint8 fin; uint8 opcode; uint8 mask; uint64 payload_len; unsigned char masking_key[4]; }; NLMISC::CSString generate_key(const NLMISC::CSString &key); NLMISC::CSString generate_websocket_response( NLMISC::CSString& sec_websocket_key ); sint32 parse_frame_header( const uint8 *buf, WebSocketFrame& frame ); inline void unmask_payload_data( WebSocketFrame& frame, uint8* buff ) { for ( uint32 i = 0; i < frame.payload_len; ++i ) { *(buff + i) = *(buff + i) ^ *(frame.masking_key + i % 4); } } void fill_frame_buffer( const uint8* payload_data, uint32 payload_len, NLMISC::CObjectVector& out_frame, uint8 opcode, uint8 fin=1 ); void ws_socket_event_cb( bufferevent *bev, short events, void *args ); void ws_socket_read_cb( bufferevent *bev, void *args ); //һ¿ͻϷ //˺ʱlibeventѾacceptͻˡÿͻ˵ //ļΪfd void ws_listener_cb( evconnlistener *listener, evutil_socket_t fd, sockaddr *sock, int socklen, void *args ); } #endif // NL_WEBSOCKET_FUN_H /* End of web_sock_fun.h */ ================================================ FILE: code/nel/include/nel/net/buf_sock.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_BUF_SOCK_H #define NL_BUF_SOCK_H #include "nel/misc/types_nl.h" #include "nel/misc/hierarchical_timer.h" #include "buf_net_base.h" #include "tcp_sock.h" #include "net_log.h" //#include struct bufferevent; namespace NLNET { #define nlnettrace(__msg) //LNETL1_DEBUG("LNETL1: %s",__msg); class CTcpSock; class CServerReceiveTask; class CBufNetBase; /** * CBufSock * A socket and its sending buffer */ class CBufSock { public: /// Destructor virtual ~CBufSock(); /// Sets the application identifier void setAppId( uintptr_t id ) { _AppId = id; } /// Returns the application identifier uintptr_t appId() const { return _AppId; } /// Returns a string with the characteristics of the object std::string asString() const; /// get the TCP sock object const CTcpSock *getTcpSock() const { return Sock;} /// Little tricky but this string is used by Layer4 to know which callback is authorized. /// This is empty when all callback are authorized. std::string AuthorizedCallback; public: friend class CBufClient; friend class CBufServer; friend class CBufServerWebsocket; friend class CClientReceiveTask; friend class CServerReceiveTask; friend class CCallbackClient; friend class CCallbackServer; friend class CCallbackServerWebSocket; friend class CCallbackNetBase; /** Constructor * \param sock To provide an external socket. Set it to NULL to create it internally. */ CBufSock( CTcpSock *sock=NULL ); ///@name Sending data //@{ /// Update the network sending (call this method evenly). Returns false if an error occured. bool update(); /** Sets the time flush trigger (in millisecond). When this time is elapsed, * all data in the send queue is automatically sent (-1 to disable this trigger) */ void setTimeFlushTrigger( sint32 ms ); /** Sets the size flush trigger. When the size of the send queue reaches or exceeds this * calue, all data in the send queue is automatically sent (-1 to disable this trigger ) */ void setSizeFlushTrigger( sint32 size ) { _TriggerSize = size; } /** Force to send data pending in the send queue now. In the case of a non-blocking socket * (see CNonBlockingBufSock), if all the data could not be sent immediately, * the returned nbBytesRemaining value is non-zero. * \param nbBytesRemaining If the pointer is not NULL, the method sets the number of bytes still pending after the flush attempt. * \returns False if an error has occured (e.g. the remote host is disconnected). * To retrieve the reason of the error, call CSock::getLastError() and/or CSock::errorString() */ bool flush( uint *nbBytesRemaining=NULL ); //@} /// Returns "CLT " (client) virtual std::string typeStr() const { return "CLT "; } /** Pushes a disconnection message into bnb's receive queue, if it has not already been done * (returns true in this case). You can either specify a sockid (for server) or InvalidSockId (for client) */ bool advertiseDisconnection( CBufNetBase *bnb, TSockId sockid ) { #ifdef NL_DEBUG if ( sockid != InvalidSockId ) { nlassert( sockid == this ); } #endif return advertiseSystemEvent( bnb, sockid, _KnowConnected, true, CBufNetBase::Disconnection ); } /** Pushes a system message into bnb's receive queue, if the flags meets the condition, then * resets the flag and returns true. You can either specify a sockid (for server) or InvalidSockId (for client). */ bool advertiseSystemEvent( CBufNetBase *bnb, TSockId sockid, bool& flag, bool condition, CBufNetBase::TEventType event ) { #ifdef NL_DEBUG if ( sockid != InvalidSockId ) { nlassert( sockid == this ); } #endif // Test flag if ( flag==condition ) { LNETL1_DEBUG( "LNETL1: Pushing event to %s", asString().c_str() ); std::vector buffer; if ( sockid == InvalidSockId ) { // Client: event type only buffer.resize( 1 ); buffer[0] = uint8(event); } else { // Server: sockid + event type buffer.resize( sizeof(TSockId) + 1 ); memcpy( &*buffer.begin(), &sockid, sizeof(TSockId) ); buffer[sizeof(TSockId)] = uint8(event); } // Push bnb->pushMessageIntoReceiveQueue( buffer ); // Reset flag flag = !condition; return true; } else { return false; } } /** Pushes a buffer to the send queue and update, * or returns false if the socket is not physically connected the or an error occured during sending */ bool pushBuffer( const NLMISC::CMemStream& buffer ) { nlassert (this != InvalidSockId); // invalid bufsock // LNETL1_DEBUG( "LNETL1: Pushing buffer to %s", asString().c_str() ); static uint32 biggerBufferSize = 64000; if (buffer.length() > biggerBufferSize) { biggerBufferSize = buffer.length(); LNETL1_DEBUG ("LNETL1: new record! bigger network message pushed (sent) is %u bytes", biggerBufferSize); } if ( Sock->connected() ) { // Push into host's send queue SendFifo.push( buffer ); // Update sending bool res = update (); return res; // not checking the result as in CBufServer::update() } return false; } bool SendToLibEvent( const NLMISC::CMemStream& buffer, bool add_ws_head=false ); /// Connects to the specified addr; set connectedstate to true if no connection advertising is needed void connect( const CInetAddress& addr, bool nodelay, bool connectedstate ); /// Disconnects; set connectedstate to false if no disconnection advertising is needed void disconnect( bool connectedstate ); /// Sets the "logically connected" state (changed when processing a connection/disconnection callback) void setConnectedState( bool connectedstate ) { _ConnectedState = connectedstate; } /// Returns the "logically connected" state (changed when processing a connection/disconnection callback) bool connectedState() const { return _ConnectedState; } // Send queue NLMISC::CBufFIFO SendFifo; // Socket (pointer because it can be allocated by an accept()) CTcpSock *Sock; // Prevents from pushing a connection/disconnection event twice bool _KnowConnected; bufferevent* m_BEVHandle; CBufNetBase* m_BufNetHandle; bool m_Handshake; void* m_Ssl; // SSL* private: #ifdef NL_DEBUG enum TFlushTrigger { FTTime, FTSize, FTManual }; TFlushTrigger _FlushTrigger; #endif NLMISC::TTime _LastFlushTime; // updated only if time trigger is enabled (TriggerTime!=-1) NLMISC::TTime _TriggerTime; sint32 _TriggerSize; NLMISC::CObjectVector _ReadyToSendBuffer; TBlockSize _RTSBIndex; uintptr_t _AppId; // Connected state (from the user's point of view, i.e. changed when the connection/disconnection event is at the front of the receive queue) bool _ConnectedState; }; /** * CNonBlockingBufSock * A socket, its send buffer plus a nonblocking receiving system */ class CNonBlockingBufSock : public CBufSock { public: friend class CBufClient; friend class CClientReceiveTask; /** Constructor * \param sock To provide an external socket. Set it to NULL to create it internally. * \maxExpectedBlockSize Default value: receiving limited to 10 M per block) */ CNonBlockingBufSock( CTcpSock *sock=NULL, uint32 maxExpectedBlockSize=10485760 ); /** Call this method after connecting (for a client connection) to set the non-blocking mode. * For a server connection, call it as soon as the object is constructed */ void setNonBlocking() { Sock->setNonBlockingMode( true ); } /// Set the size limit for received blocks void setMaxExpectedBlockSize( sint32 limit ) { _MaxExpectedBlockSize = limit; } /** Receives a part of a message (nonblocking socket only) * \param nbExtraBytes Number of bytes to reserve for extra information such as the event type * \return True if the message has been completely received */ bool receivePart( uint32 nbExtraBytes ); /// Fill the event type byte at pos length()(for a client connection) void fillEventTypeOnly() { _ReceiveBuffer[_Length] = (uint8)CBufNetBase::User; } /** Return the length of the received block (call after receivePart() returns true). * The total size of received buffer is length() + nbExtraBytes (passed to receivePart()). */ uint32 length() const { return _Length; } /** Returns the filled buffer (call after receivePart() returns true). * Its size is length()+1. */ const std::vector receivedBuffer() const { nlnettrace( "CServerBufSock::receivedBuffer" ); return _ReceiveBuffer; } uint32 appendToBuffer( const uint8* buffer, uint32 len ) { _ReceiveBuffer.insert(_ReceiveBuffer.end(), buffer, buffer+len); return _ReceiveBuffer.size(); } uint8* getBuffer( uint32 offset=0 ) { return &*_ReceiveBuffer.begin()+offset; } uint32 leftShiftBuffer( uint32 shift_bits ) { if( shift_bits >= _ReceiveBuffer.size() ) { _ReceiveBuffer.clear(); } else { uint32 surplus_bits = _ReceiveBuffer.size()-shift_bits; NLMISC::CFastMem::memcpy( _ReceiveBuffer.data(), _ReceiveBuffer.data()+shift_bits, surplus_bits ); _ReceiveBuffer.resize(surplus_bits); } return _ReceiveBuffer.size(); } // Buffer for nonblocking receives std::vector _ReceiveBuffer; NLMISC::CMemStream CompleteMsg; // Max payload size than can be received in a block uint32 _MaxExpectedBlockSize; private: // True if the length prefix has already been read bool _NowReadingBuffer; // Counts the number of bytes read for the current element (length prefix or buffer) TBlockSize _BytesRead; // Length of buffer to read TBlockSize _Length; }; class CBufServer; /** * CServerBufSock * A socket, its send buffer plus a nonblocking receiving system for a server connection */ class CServerBufSock : public CNonBlockingBufSock { //protected: public: friend class CBufServer; friend class CBufServerWebsocket; friend class CListenTask; friend class CServerReceiveTask; /** Constructor with an existing socket (created by an accept()). * Don't forget to call setOwnerTask(). */ CServerBufSock( CTcpSock *sock ); /// Sets the task that "owns" the CServerBufSock object void setOwnerTask( CServerReceiveTask* owner ) { _OwnerTask = owner; } /// Returns the task that "owns" the CServerBufSock object CServerReceiveTask *ownerTask() { return _OwnerTask; } /** Pushes a connection message into bnb's receive queue, if it has not already been done * (returns true in this case). */ bool advertiseConnection( CBufNetBase *bnb ) { return advertiseSystemEvent( (CBufNetBase*)bnb, this, _KnowConnected, false, CBufNetBase::Connection ); } /// Returns "SRV " (server) virtual std::string typeStr() const { return "SRV "; } /// Fill the sockid and the event type byte at the end of the buffer void fillSockIdAndEventType( TSockId sockId ) { memcpy( (&*_ReceiveBuffer.begin()) + length(), &sockId, sizeof(TSockId) ); _ReceiveBuffer[length() + sizeof(TSockId)] = (uint8)CBufNetBase::User; } private: /// True after a connection callback has been sent to the user, for this connection bool _Advertised; // The task that "owns" the CServerBufSock object CServerReceiveTask *_OwnerTask; }; } // NLNET #endif // NL_BUF_SOCK_H /* End of buf_sock.h */ ================================================ FILE: code/nel/include/nel/net/callback_client.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CALLBACK_CLIENT_H #define NL_CALLBACK_CLIENT_H #include "nel/misc/types_nl.h" #include "callback_net_base.h" #include "buf_client.h" namespace NLNET { class CInetAddress; /** * Client class for layer 3 * \author Vianney Lecroart, Olivier Cado * \author Nevrax France * \date 2001 */ class CCallbackClient : public CCallbackNetBase, public CBufClient { public: /// Constructor CCallbackClient( TRecordingState rec=Off, const std::string& recfilename="", bool recordall=true, bool initPipeForDataAvailable=true ); ~CCallbackClient(); /// Sends a message to the remote host (the second parameter isn't used) void send (const CMessage &buffer, TSockId hostid = InvalidSockId, bool log = true); /// Force to send all data pending in the send queue. hostid must be InvalidSockId here. See comment in CCallbackNetBase. bool flush (TSockId hostid = InvalidSockId, uint *nbBytesRemaining=NULL); /** Updates the network (call this method evenly). * More info about timeout and mintime in the code of CCallbackNetBase::baseUpdate(). */ void update2 (sint32 timeout=-1, sint32 mintime=0); /// Updates the network (call this method evenly) (legacy) void update (sint32 timeout=0); /// Connects to the specified host void connect( const CInetAddress& addr ); /** Returns true if the connection is still connected (changed when a disconnection * event has reached the front of the receive queue, just before calling the disconnection callback * if there is one) */ virtual bool connected () const { return CBufClient::connected (); } virtual const CInetAddress& hostAddress( TSockId /* hostid */ ) { return remoteAddress(); } /** Disconnect a connection * Unlike in CCallbackClient, you can call disconnect() on a socket that is already disconnected * (it will do nothing) */ void disconnect (TSockId hostid = InvalidSockId); /// Sets callback for disconnections (or NULL to disable callback) void setDisconnectionCallback (TNetCallback cb, void *arg) { CCallbackNetBase::setDisconnectionCallback (cb, arg); } /// Returns the sockid virtual TSockId getSockId (TSockId hostid = InvalidSockId); uint64 getReceiveQueueSize () { return CBufClient::getReceiveQueueSize(); } uint64 getSendQueueSize () { return CBufClient::getSendQueueSize(); } void displayReceiveQueueStat (NLMISC::CLog *log = NLMISC::InfoLog) { CBufClient::displayReceiveQueueStat(log); } void displaySendQueueStat (NLMISC::CLog *log = NLMISC::InfoLog, TSockId /* destid */ = InvalidSockId) { CBufClient::displaySendQueueStat(log); } void displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog) { CBufClient::displayThreadStat(log); } private: /// These function is public in the base class and put it private here because user cannot use it in layer 2 void send (const NLMISC::CMemStream &/* buffer */) { nlstop; } /// Returns true if there are messages to read bool dataAvailable (); virtual bool getDataAvailableFlagV() const { return dataAvailableFlag(); } void receive (CMessage &buffer, TSockId *hostid = NULL); // --------------------------------------- #ifdef USE_MESSAGE_RECORDER virtual bool replaySystemCallbacks(); #endif bool LockDeletion; }; } // NLNET #endif // NL_CALLBACK_CLIENT_H /* End of callback_client.h */ ================================================ FILE: code/nel/include/nel/net/callback_net_base.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CALLBACK_NET_BASE_H #define NL_CALLBACK_NET_BASE_H #undef USE_MESSAGE_RECORDER #include "nel/misc/types_nl.h" #include "nel/misc/time_nl.h" #include "buf_net_base.h" #include "message.h" #include "inet_address.h" #ifdef USE_MESSAGE_RECORDER #include "message_recorder.h" #include #endif #include namespace NLNET { class CCallbackNetBase; /** Callback function type for message processing * * msgin contains parameters of the message * from is the SockId of the connection, for a client, from is always the same value */ typedef void (*TMsgCallback) (CMessage &msgin, TSockId from, CCallbackNetBase &netbase); /// Callback items. See CMsgSocket::update() for an explanation on how the callbacks are called. typedef struct { /// Key C string. It is a message type name, or "C" for connection or "D" for disconnection const char *Key; /// The callback function TMsgCallback Callback; } TCallbackItem; /** * Layer 3 * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CCallbackNetBase { public: virtual ~CCallbackNetBase() {} /** Set the user data */ void setUserData(void *userData); /** Get the user data */ void *getUserData(); /** Sends a message to special connection. * On a client, the hostid isn't used. * On a server, you must provide a hostid. If you hostid = InvalidSockId, the message will be sent to all connected client. */ virtual void send (const CMessage &buffer, TSockId hostid = InvalidSockId, bool log = true) = 0; uint64 getBytesSent () { return _BytesSent; } uint64 getBytesReceived () { return _BytesReceived; } virtual uint64 getReceiveQueueSize () = 0; virtual uint64 getSendQueueSize () = 0; virtual void displayReceiveQueueStat (NLMISC::CLog *log = NLMISC::InfoLog) = 0; virtual void displaySendQueueStat (NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId) = 0; virtual void displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog) = 0; /** Force to send all data pending in the send queue. * On a client, the hostid isn't used and must be InvalidSockId * On a server, you must provide a hostid. * If you provide a non-null pointer for nbBytesRemaining, the value will be filled* * will the number of bytes that still remain in the sending queue after the * non-blocking flush attempt. */ virtual bool flush (TSockId hostid = InvalidSockId, uint *nbBytesRemaining=NULL) = 0; /** Appends callback array with the specified array. You can add callback only *after* adding the server or the client. * \param arraysize is the number of callback items. */ void addCallbackArray (const TCallbackItem *callbackarray, sint arraysize); /// Sets default callback for unknown message types void setDefaultCallback(TMsgCallback defaultCallback) { _DefaultCallback = defaultCallback; } /// Set the pre dispatch callback. This callback is called before each message is dispatched void setPreDispatchCallback(TMsgCallback predispatchCallback) { _PreDispatchCallback = predispatchCallback;} /// Sets callback for disconnections (or NULL to disable callback) void setDisconnectionCallback (TNetCallback cb, void *arg) { _DisconnectionCallback = cb; _DisconnectionCbArg = arg; } /// returns the sockid of a connection. On a server, this function returns the parameter. On a client, it returns the connection. virtual TSockId getSockId (TSockId hostid = InvalidSockId) = 0; /** Sets the callback that you want the other side calls. If it didn't call this callback, it will be disconnected * If cb is NULL, we authorize *all* callback. * On a client, the hostid must be InvalidSockId (or ommited). * On a server, you must provide a hostid. */ void authorizeOnly (const char *callbackName, TSockId hostid = InvalidSockId); /// Returns true if this is a CCallbackServer bool isAServer () const { return _IsAServer; } /// This function is implemented in the client and server class virtual bool dataAvailable () = 0; /// This function is implemented in the client and server class virtual bool getDataAvailableFlagV() const = 0; /// This function is implemented in the client and server class virtual void update2 ( sint32 timeout=0, sint32 mintime=0 ) = 0; /// This function is implemented in the client and server class (legacy) virtual void update ( sint32 timeout=0 ) = 0; /// This function is implemented in the client and server class virtual bool connected () const = 0; /// This function is implemented in the client and server class virtual void disconnect (TSockId hostid = InvalidSockId) = 0; /// Returns the address of the specified host virtual const CInetAddress& hostAddress (TSockId hostid); // Defined even when USE_MESSAGE_RECORDER is not defined enum TRecordingState { Off, Record, Replay }; protected: uint64 _BytesSent, _BytesReceived; /// Used by client and server class TNetCallback _NewDisconnectionCallback; /// Constructor. CCallbackNetBase( TRecordingState rec=Off, const std::string& recfilename="", bool recordall=true ); /** Used by client and server class * More info about timeout and mintime in the code. */ void baseUpdate2 ( sint32 timeout=-1, sint32 mintime=0 ); /// Used by client and server class (legacy) void baseUpdate ( sint32 timeout=0 ); /// Read a message from the network and process it void processOneMessage (); /// On this layer, you can't call directly receive, It s the update() function that receive and call your callaback virtual void receive (CMessage &buffer, TSockId *hostid) = 0; // contains callbacks std::vector _CallbackArray; // called if the received message is not found in the callback array TMsgCallback _DefaultCallback; // If not null, called before each message is dispached to it's callback TMsgCallback _PreDispatchCallback; bool _IsAServer; bool _FirstUpdate; // --------------------------------------- #ifdef USE_MESSAGE_RECORDER bool replayDataAvailable(); virtual bool replaySystemCallbacks() = 0; void noticeDisconnection( TSockId hostid ); TRecordingState _MR_RecordingState; sint64 _MR_UpdateCounter; CMessageRecorder _MR_Recorder; #endif // --------------------------------------- private: void *_UserData; NLMISC::TTime _LastUpdateTime; NLMISC::TTime _LastMovedStringArray; TNetCallback _DisconnectionCallback; void *_DisconnectionCbArg; friend void cbnbMessageAskAssociations (CMessage &msgin, TSockId from, CCallbackNetBase &netbase); friend void cbnbMessageRecvAssociations (CMessage &msgin, TSockId from, CCallbackNetBase &netbase); friend void cbnbNewDisconnection (TSockId from, void *data); }; } // NLNET #endif // NL_CALLBACK_NET_BASE_H /* End of callback_net_base.h */ ================================================ FILE: code/nel/include/nel/net/callback_server.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CALLBACK_SERVER_H #define NL_CALLBACK_SERVER_H #include "nel/misc/types_nl.h" #include "callback_net_base.h" #include "buf_server.h" namespace NLNET { /** * Server class for layer 3 * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CCallbackServer : public CCallbackNetBase, public CBufServer { public: /// Constructor CCallbackServer( TRecordingState rec=Off, const std::string& recfilename="", bool recordall=true, bool initPipeForDataAvailable=true ); /// Sends a message to the specified host void send (const CMessage &buffer, TSockId hostid, bool log = true); /// Force to send all data pending in the send queue. See comment in CCallbackNetBase. bool flush (TSockId destid, uint *nbBytesRemaining=NULL) { nlassert( destid != InvalidSockId ); return CBufServer::flush(destid, nbBytesRemaining); } /** Updates the network (call this method evenly). * More info about timeout and mintime in the code of CCallbackNetBase::baseUpdate(). */ void update2 (sint32 timeout=-1, sint32 mintime=0); /// Updates the network (call this method evenly) (legacy) void update (sint32 timeout=0); /// Sets callback for incoming connections (or NULL to disable callback) void setConnectionCallback (TNetCallback cb, void *arg) { _ConnectionCallback = cb; _ConnectionCbArg = arg; } /// Sets callback for disconnections (or NULL to disable callback) void setDisconnectionCallback (TNetCallback cb, void *arg) { CCallbackNetBase::setDisconnectionCallback (cb, arg); } /// Returns true if the connection is still connected. on server, we always "connected" bool connected () const { return true; } /** Disconnect a connection * Set hostid to InvalidSockId to disconnect all connections. * If hostid is not InvalidSockId and the socket is not connected, the method does nothing. * Before disconnecting, any pending data is actually sent. */ void disconnect (TSockId hostid); /// Returns the address of the specified host const CInetAddress& hostAddress (TSockId hostid) { nlassert(hostid!=InvalidSockId); return CBufServer::hostAddress (hostid); } /// Returns the sockid (cf. CCallbackClient) virtual TSockId getSockId (TSockId hostid = InvalidSockId); uint64 getReceiveQueueSize () { return CBufServer::getReceiveQueueSize(); } uint64 getSendQueueSize () { return CBufServer::getSendQueueSize(0); } void displayReceiveQueueStat (NLMISC::CLog *log = NLMISC::InfoLog) { CBufServer::displayReceiveQueueStat(log); } void displaySendQueueStat (NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId) { CBufServer::displaySendQueueStat(log, destid); } void displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog) { CBufServer::displayThreadStat(log); } private: /// This function is public in the base class and put it private here because user cannot use it in layer 2 void send (const NLMISC::CMemStream &/* buffer */, TSockId /* hostid */) { nlstop; } bool dataAvailable (); virtual bool getDataAvailableFlagV() const { return dataAvailableFlag(); } void receive (CMessage &buffer, TSockId *hostid); void sendAllMyAssociations (TSockId to); TNetCallback _ConnectionCallback; void *_ConnectionCbArg; friend void cbsNewConnection (TSockId from, void *data); // --------------------------------------- #ifdef USE_MESSAGE_RECORDER void noticeConnection( TSockId hostid ); virtual bool replaySystemCallbacks(); std::vector _MR_Connections; std::map _MR_SockIds; // first=sockid in file; second=CBufSock* #endif // --------------------------------------- }; } // NLNET #endif // NL_CALLBACK_SERVER_H /* End of callback_server.h */ ================================================ FILE: code/nel/include/nel/net/callback_server_tcp.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CALLBACK_SERVER_TCP_H #define NL_CALLBACK_SERVER_TCP_H #include "nel/misc/types_nl.h" #include "nel/net/callback_net_base.h" #include "nel/net/buf_server.h" #include "buf_server_tcp.h" namespace NLNET { /** * Server class for layer 3 * \author li9chuan@qq.com * \date 2018 */ class CCallbackServerTcp : public CCallbackNetBase, public CBufServerTcp { public: /// Constructor CCallbackServerTcp( TRecordingState rec=Off, const std::string& recfilename="", bool recordall=true, bool initPipeForDataAvailable=true ); /// Sends a message to the specified host void send (const CMessage &buffer, TSockId hostid, bool log = true); /// Force to send all data pending in the send queue. See comment in CCallbackNetBase. bool flush (TSockId destid, uint *nbBytesRemaining=NULL) { nlassert( destid != InvalidSockId ); return false; /*CBufServer::flush(destid, nbBytesRemaining);*/ } /** Updates the network (call this method evenly). * More info about timeout and mintime in the code of CCallbackNetBase::baseUpdate(). */ void update2 (sint32 timeout=-1, sint32 mintime=0); /// Updates the network (call this method evenly) (legacy) void update (sint32 timeout=0); /// Sets callback for incoming connections (or NULL to disable callback) void setConnectionCallback (TNetCallback cb, void *arg) { _ConnectionCallback = cb; _ConnectionCbArg = arg; } /// Sets callback for disconnections (or NULL to disable callback) void setDisconnectionCallback (TNetCallback cb, void *arg) { CCallbackNetBase::setDisconnectionCallback (cb, arg); } /// Returns true if the connection is still connected. on server, we always "connected" bool connected () const { return true; } /** Disconnect a connection * Set hostid to InvalidSockId to disconnect all connections. * If hostid is not InvalidSockId and the socket is not connected, the method does nothing. * Before disconnecting, any pending data is actually sent. */ void disconnect (TSockId hostid); /// Returns the address of the specified host //const CInetAddress& hostAddress (TSockId hostid) { nlassert(hostid!=InvalidSockId); return CBufServer::hostAddress (hostid); } /// Returns the sockid (cf. CCallbackClient) virtual TSockId getSockId (TSockId hostid = InvalidSockId); uint64 getReceiveQueueSize () { return 0; } uint64 getSendQueueSize () { return 0; } void displayReceiveQueueStat (NLMISC::CLog *log = NLMISC::InfoLog) { /*CBufServer::displayReceiveQueueStat(log);*/ } void displaySendQueueStat (NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId) { /*CBufServer::displaySendQueueStat(log, destid);*/ } void displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog) { /*CBufServer::displayThreadStat(log);*/ } private: /// This function is public in the base class and put it private here because user cannot use it in layer 2 //void send (const NLMISC::CMemStream &/* buffer */, TSockId /* hostid */) { nlstop; } bool dataAvailable (); virtual bool getDataAvailableFlagV() const { return dataAvailableFlag(); } void receive (CMessage &buffer, TSockId *hostid); void sendAllMyAssociations (TSockId to); TNetCallback _ConnectionCallback; void *_ConnectionCbArg; friend void cbsTcpNewConnection (TSockId from, void *data); // --------------------------------------- #ifdef USE_MESSAGE_RECORDER void noticeConnection( TSockId hostid ); virtual bool replaySystemCallbacks(); std::vector _MR_Connections; std::map _MR_SockIds; // first=sockid in file; second=CBufSock* #endif // --------------------------------------- }; } // NLNET #endif // NL_CALLBACK_SERVER_TCP_H /* End of callback_server_tcp.h */ ================================================ FILE: code/nel/include/nel/net/callback_server_websocket.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CALLBACK_SERVER_WEBSOCKET_H #define NL_CALLBACK_SERVER_WEBSOCKET_H #include "nel/misc/types_nl.h" #include "nel/net/callback_net_base.h" #include "nel/net/buf_server.h" #include "buf_server_websocket.h" namespace NLNET { /** * Server class for layer 3 * \author li9chuan@qq.com * \date 2018 */ class CCallbackServerWebSocket : public CCallbackNetBase, public CBufServerWebsocket { public: /// Constructor CCallbackServerWebSocket( TRecordingState rec=Off, const std::string& recfilename="", bool recordall=true, bool initPipeForDataAvailable=true ); /// Sends a message to the specified host void send (const CMessage &buffer, TSockId hostid, bool log = true); /// Force to send all data pending in the send queue. See comment in CCallbackNetBase. bool flush (TSockId destid, uint *nbBytesRemaining=NULL) { nlassert( destid != InvalidSockId ); return false; /*CBufServer::flush(destid, nbBytesRemaining);*/ } /** Updates the network (call this method evenly). * More info about timeout and mintime in the code of CCallbackNetBase::baseUpdate(). */ void update2 (sint32 timeout=-1, sint32 mintime=0); /// Updates the network (call this method evenly) (legacy) void update (sint32 timeout=0); /// Sets callback for incoming connections (or NULL to disable callback) void setConnectionCallback (TNetCallback cb, void *arg) { _ConnectionCallback = cb; _ConnectionCbArg = arg; } /// Sets callback for disconnections (or NULL to disable callback) void setDisconnectionCallback (TNetCallback cb, void *arg) { CCallbackNetBase::setDisconnectionCallback (cb, arg); } /// Returns true if the connection is still connected. on server, we always "connected" bool connected () const { return true; } /** Disconnect a connection * Set hostid to InvalidSockId to disconnect all connections. * If hostid is not InvalidSockId and the socket is not connected, the method does nothing. * Before disconnecting, any pending data is actually sent. */ void disconnect (TSockId hostid); /// Returns the address of the specified host //const CInetAddress& hostAddress (TSockId hostid) { nlassert(hostid!=InvalidSockId); return CBufServer::hostAddress (hostid); } /// Returns the sockid (cf. CCallbackClient) virtual TSockId getSockId (TSockId hostid = InvalidSockId); uint64 getReceiveQueueSize () { return 0; } uint64 getSendQueueSize () { return 0; } void displayReceiveQueueStat (NLMISC::CLog *log = NLMISC::InfoLog) { /*CBufServer::displayReceiveQueueStat(log);*/ } void displaySendQueueStat (NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId) { /*CBufServer::displaySendQueueStat(log, destid);*/ } void displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog) { /*CBufServer::displayThreadStat(log);*/ } private: /// This function is public in the base class and put it private here because user cannot use it in layer 2 //void send (const NLMISC::CMemStream &/* buffer */, TSockId /* hostid */) { nlstop; } bool dataAvailable (); virtual bool getDataAvailableFlagV() const { return dataAvailableFlag(); } void receive (CMessage &buffer, TSockId *hostid); void sendAllMyAssociations (TSockId to); TNetCallback _ConnectionCallback; void *_ConnectionCbArg; friend void cbsWebSktNewConnection (TSockId from, void *data); // --------------------------------------- #ifdef USE_MESSAGE_RECORDER void noticeConnection( TSockId hostid ); virtual bool replaySystemCallbacks(); std::vector _MR_Connections; std::map _MR_SockIds; // first=sockid in file; second=CBufSock* #endif // --------------------------------------- }; } // NLNET #endif // NL_CALLBACK_SERVER_H /* End of callback_server.h */ ================================================ FILE: code/nel/include/nel/net/cvar_log_filter.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_CVAR_LOG_FILTER_H #define NL_CVAR_LOG_FILTER_H #include "nel/misc/config_file.h" #include "nel/net/service.h" /** Declare an info logging function that works as nlinfo but that is activated with the given service config file variable * Example of use : * DECLARE_CVAR_INFO_LOG_FUNCTION(my_info, MyInfoEnabled) * * my_info("my_message"); // no-op if "MyInfoEnabled = 0;" Is found in the service config file */ #ifdef NL_NO_DEBUG #define NL_DECLARE_CVAR_INFO_LOG_FUNCTION(func, cvar, defaultValue) inline void func(const char *format, ...) {} #else #define NL_DECLARE_CVAR_INFO_LOG_FUNCTION(func, cvar, defaultValue) \ inline void func(const char *format, ...) \ { \ bool logWanted = (defaultValue); \ NLMISC::CConfigFile::CVar *logWantedPtr = NLNET::IService::getInstance()->ConfigFile.getVarPtr(#cvar); \ if (logWantedPtr) \ { \ logWanted = logWantedPtr->asInt() != 0; \ } \ if (logWanted) \ { \ char *out; \ NLMISC_CONVERT_VARGS(out, format, 256); \ nlinfo(out); \ } \ } #endif #endif ================================================ FILE: code/nel/include/nel/net/dummy_tcp_sock.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_DUMMY_TCP_SOCK_H #define NL_DUMMY_TCP_SOCK_H #include "nel/misc/types_nl.h" #include "tcp_sock.h" namespace NLNET { /** * Dummy CTcpSock replacement for replay mode * \author Olivier Cado * \author Nevrax France * \date 2001 */ class CDummyTcpSock : public CTcpSock { public: // Constructor CDummyTcpSock( bool logging = true ) : CTcpSock(logging) {} // Dummy connection virtual void connect( const CInetAddress& addr ); // Dummy disconnection virtual void disconnect(); // Nothing virtual void setNoDelay( bool /* value */ ) {} // Nothing virtual void close() {} }; } // NLNET #endif // NL_DUMMY_TCP_SOCK_H /* End of dummy_tcp_sock.h */ ================================================ FILE: code/nel/include/nel/net/email.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_EMAIL_H #define NL_EMAIL_H #include #include "nel/misc/report.h" namespace NLNET { /** Send an email * \param smtpServer must be a smtp email server. * \param from must be a valid email address. If empty, create a fake email address with anonymous@.com * \param to must be a valid email address. * \param subject subject of the email. Can be empty. * \param body body of the email. Can be empty. * \param attachedFile a filename that will be send with the email. Can be empty. * \param onlyCheck If true, It'll not send the mail but only check if it could be send. */ bool sendEmail (const std::string &smtpServer, const std::string &from, const std::string &to, const std::string &subject, const std::string &body, const std::string &attachedFile = "", bool onlyCheck = false); /** If you call this function, the default from (when from is "") used in the sendEmail will be the one * you set by this function */ void setDefaultEmailParams (const std::string &smtpServer, const std::string &from, const std::string &to); } // NLNET #endif // NL_EMAIL_H /* End of email.h */ ================================================ FILE: code/nel/include/nel/net/inet_address.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_INET_ADDRESS_H #define NL_INET_ADDRESS_H #include "nel/misc/types_nl.h" #include #include struct sockaddr_in; struct in_addr; #ifdef NL_OS_WINDOWS // automatically add the win socket library if you use nel network part #pragma comment(lib, "ws2_32.lib") #endif namespace NLMISC { class IStream; } namespace NLNET { struct ESocket; /** * Internet address (IP + port). * The structure sockaddr_in is internally in network byte order * \author Olivier Cado * \author Nevrax France * \date 2000 */ class CInetAddress { public: /// Default Constructor. The address is set to INADDR_ANY CInetAddress(); /// Alternate constructor (calls setByName()) CInetAddress( const std::string& hostName, uint16 port ); /// Alternate constructor (calls setByName()) /// example: CInetAddress("www.nevrax.com:80") CInetAddress( const std::string& hostNameAndPort ); /// Copy constructor CInetAddress( const CInetAddress& other ); /// Assignment operator CInetAddress& operator=( const CInetAddress& other ); /// Comparison == operator friend bool operator==( const CInetAddress& a1, const CInetAddress& a2 ); /// Comparison < operator friend bool operator<( const CInetAddress& a1, const CInetAddress& a2 ); /// Destructor ~CInetAddress(); /// Resolves a name CInetAddress& setByName( const std::string& hostname ); /// Sets port void setPort( uint16 port ); /// Sets hostname and port (ex: www.nevrax.com:80) void setNameAndPort( const std::string& hostNameAndPort ); /** Sets internal socket address directly (contents is copied). * It also retrieves the host name if CInetAddress::RetrieveNames is true. */ void setSockAddr( const sockaddr_in* saddr ); /// Returns if object (address and port) is valid bool isValid() const; /// Returns internal socket address (read only) const sockaddr_in *sockAddr() const; /// Returns internal IP address uint32 internalIPAddress() const; /// Returns the internal network address (it s the network address for example 192.168.0.0 for a C class) uint32 internalNetAddress () const; /// Returns readable IP address. (ex: "195.68.21.195") std::string ipAddress() const; /// Returns hostname. (ex: "www.nevrax.org") const std::string& hostName() const; /// Returns port uint16 port() const; /// Returns hostname and port as a string. (ex: "www.nevrax.org:80 (195.68.21.195)") std::string asString() const; /// Returns IP address and port as a string. (ex: "195.68.21.195:80") std::string asIPString() const; /// Serialize void serial( NLMISC::IStream& s ); /// Returns true if this CInetAddress is 127.0.0.1 bool is127001 () const; /// Creates a CInetAddress object with local host address, port=0 static CInetAddress localHost(); /** Returns the list of the local host addresses (with port=0) * (especially useful if the host is multihomed) */ static std::vector localAddresses(); /// If true, setSockAddr() always tries to retrieve the host name from the address static bool RetrieveNames; protected: /// Constructor with ip address, port=0 CInetAddress( const in_addr *ip, const char *hostname = 0); /// Update _HostName from _SockAddr void updateHostName(); private: // Called in all constructors. Calls CBaseSocket::init(). void init(); std::string _HostName; sockaddr_in *_SockAddr; bool _Valid; }; /// Take a internet dot string and convert it in an uint32 internal format for example "128.64.32.16" -> 0xF0804020 uint32 stringToInternalIPAddress (const std::string &addr); /// Take an internal address and convert it to a internet dot string std::string internalIPAddressToString (uint32 addr); std::string vectorCInetAddressToString(const std::vector &addrs); } #endif // NL_INET_ADDRESS_H /* End of inet_address.h */ ================================================ FILE: code/nel/include/nel/net/listen_sock.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_LISTEN_SOCK_H #define NL_LISTEN_SOCK_H #include "tcp_sock.h" namespace NLNET { /** * CListenSock: listening socket for servers. * How to accept connections in a simple server: * -# Create a CListenSock object * -# Listen on the port you want the clients to connect * -# In a loop, accept a connection and store the new socket * * \author Olivier Cado * \author Nevrax France * \date 2000-2001 */ class CListenSock : public CTcpSock { public: /// Constructor CListenSock(); ///@name Socket setup //@{ /// Prepares to receive connections on a specified port (bind+listen) void init( uint16 port ); /// Prepares to receive connections on a specified address/port (useful when the host has several addresses) void init( const CInetAddress& addr ); /// Sets the number of the pending connections queue, or -1 for the maximum possible value. void setBacklog( sint backlog ); /// Returns the pending connections queue. sint backlog() const { return _BackLog; } //@} /// Blocks until an incoming connection is requested, accepts it, and creates a new socket (you have to delete it after use) CTcpSock *accept(); private: bool _Bound; sint _BackLog; }; } // NLNET #endif // NL_LISTEN_SOCK_H /* End of listen_sock.h */ ================================================ FILE: code/nel/include/nel/net/login_client.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_LOGIN_CLIENT_H #define NL_LOGIN_CLIENT_H #include "nel/misc/types_nl.h" #include #include #include "callback_client.h" #include "udp_sim_sock.h" namespace NLNET { class CLoginCookie; class CUdpSock; class IDisplayer; /** * \author Vianney Lecroart * \author Nevrax France * \date 2002 */ class CLoginClient { public: struct CShardEntry { CShardEntry() { NbPlayers = 0; Id = -1; } CShardEntry(const ucstring &name, uint8 nbp, sint32 sid) : Id(sid), Name(name), NbPlayers(nbp) { } sint32 Id; ucstring Name; uint8 NbPlayers; }; typedef std::vector TShardList; // This list is filled after a successful authenticate call static TShardList ShardList; /** Try to login with login and password. cpassword must be md5 crypted (that's why it's a string and not an ucstring) * application is the name of the application. the LS will return all shards that is available for this application (sample, snowballs, ...) * If the authentication is ok, the function return an empty string else it returns the reason of the failure. */ static std::string authenticate(const std::string &loginServiceAddr, const ucstring &login, const std::string &cpassword, const std::string &application); static std::string authenticateBegin(const std::string &loginServiceAddr, const ucstring &login, const std::string &cpassword, const std::string &application); static bool authenticateUpdate(std::string &error); /** Todo: fix comment. */ static std::string wantToConnectToShard (sint32 shardId, std::string &ip, std::string &cookie); static std::string selectShardBegin(sint32 shardId); static bool selectShardUpdate(std::string &error, std::string &ip, std::string &cookie); /** Try to connect to the shard and return a TCP connection to the shard. */ static std::string connectToShard (CLoginCookie &lc, const std::string &addr, CCallbackClient &cnx); /** Try to connect to the shard and return an UDP connection to the shard. */ static std::string connectToShard (const std::string &addr, CUdpSock &cnx); /** Try to connect to the shard and return an UDP simulate connection to the shard. */ static std::string connectToShard (const std::string &addr, CUdpSimSock &cnx); private: static std::string confirmConnection (sint32 sharId); static CLoginClient::CShardEntry *getShard (sint32 shardId); static NLNET::CCallbackClient *_LSCallbackClient; }; } // NLNET #endif // NL_LOGIN_CLIENT_H /* End of login_client.h */ ================================================ FILE: code/nel/include/nel/net/login_cookie.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_LOGIN_COOKIE_H #define NL_LOGIN_COOKIE_H #include "nel/misc/types_nl.h" #include "nel/misc/stream.h" #include "nel/misc/common.h" namespace NLNET { /** * Manage cookie during the authenticate procedure. * * _UserAddr is the ipv4 address of the client in uint32 * _UserKey is an uint32 generated by the login_service at each login password verification * _UserId is an uint32 uniq for each account (an account could have more than one avatar) * * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CLoginCookie { public: CLoginCookie (uint32 addr, uint32 id); CLoginCookie () : _Valid(false) { } void serial (NLMISC::IStream &s) { // verify that we initialized the cookie before writing it if (!s.isReading() && !_Valid) nlwarning ("LC: serialize a non valid cookie"); s.serial (_UserAddr); s.serial (_UserKey); s.serial (_UserId); if (s.isReading()) _Valid = true; } std::string setToString () const { if (_Valid) { char cstr[8*3+2+1]; NLMISC::smprintf(cstr, 8*3+2+1, "%08X|%08X|%08X", _UserAddr, _UserKey, _UserId); nlinfo ("LC: setToString %s -> %s", toString().c_str (), cstr); return cstr; } else { return "0|0|0"; } } void setFromString (const std::string &str) { sscanf(str.c_str(), "%08X|%08X|%08X", &_UserAddr, &_UserKey, &_UserId); if(str.empty () || (_UserAddr==0 && _UserKey==0 && _UserId==0)) _Valid = 0; else _Valid = 1; //nlinfo ("LC: setFromString %s -> %s, isValid: %d", str.c_str (), toString().c_str (), _Valid); } std::string toString () const { if (_Valid) return "'" + NLMISC::toString("%08X", (unsigned int)_UserAddr) + "|" + NLMISC::toString("%08X", (unsigned int)_UserKey) + "|" + NLMISC::toString("%08X", (unsigned int)_UserId) + "'"; else return ""; } uint32 getUserAddr () const { nlassert (_Valid); return _UserAddr; } uint32 getUserKey () const { nlassert (_Valid); return _UserKey; } uint32 getUserId () const { nlassert (_Valid); return _UserId; } void set (uint32 ua, uint32 uk, uint32 ui) { _Valid = true; _UserAddr = ua; _UserKey = uk; _UserId = ui; } bool isValid() const { return _Valid; } void clear () { _Valid = false; } uint32 generateKey(); /// Comparison == operator friend bool operator== (const CLoginCookie &c1, const CLoginCookie &c2); /// Strict weak ordering operator bool operator <(const CLoginCookie &other) const { if(_UserAddr != other._UserAddr) return _UserAddr < other._UserAddr; if(_UserKey != other._UserKey) return _UserKey < other._UserKey; return _UserId < other._UserId; } private: bool _Valid; uint32 _UserAddr; uint32 _UserKey; uint32 _UserId; }; /* * Comparison == operator */ bool operator== (const CLoginCookie &c1, const CLoginCookie &c2); /* * Comparison != operator */ bool operator!= (const CLoginCookie &c1, const CLoginCookie &c2); } // NLNET #endif // NL_LOGIN_COOKIE_H /* End of login_cookie.h */ ================================================ FILE: code/nel/include/nel/net/login_server.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_LOGIN_SERVER_H #define NL_LOGIN_SERVER_H #include "nel/misc/types_nl.h" #include #include #include "callback_server.h" #include "login_cookie.h" namespace NLMISC { class CConfigFile; } namespace NLNET { /// Callback function type called when a new client is identified (with the login password procedure) typedef void (*TNewClientCallback) (TSockId from, const CLoginCookie &cookie); /// Callback function type called when a new cookie is acceptable (aka as 'a player can connect with this cookie') typedef void (*TNewCookieCallback) (const CLoginCookie &cookie); /// Callback function type called when a client need to be disconnected (double login...) typedef void (*TDisconnectClientCallback) (uint32 userId, const std::string &reqServiceName); class CUdpSock; class IDisplayer; /** This class is the server part of the Login System. It is used in the Front End Service. * At the beginning, it connects to the WS. When a new player comes in and is authenticated, a * callback is called to warn the user code that a new player is here. * Example: * \code * \endcode * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CLoginServer { public: /// Create the connection to the Welcome Service and install callbacks to the callback server (for a TCP connection) /// init() will try to find the ListenAddress in the config file and it will be used to say to the client /// the address to connect to this frontend (using the login system). You can modify this in real time in /// the config file or with the ls_listen_address command /// The ListenAddress must be in the form of "itsalive.nevrax.org:38000" (ip+port) static void init (CCallbackServer &server, TNewClientCallback ncl); /// Create the connection to the Welcome Service for an UDP connection /// the dc will be call when the Welcome Service decides to disconnect a player (double login...) static void init (CUdpSock &server, TDisconnectClientCallback dc); /// Create the connection to the Welcome Service for a connection /// the dc will be call when the Welcome Service decides to disconnect a player (double login...) static void init (const std::string &listenAddr, TDisconnectClientCallback dc); /// Add a callback to be warned when a new cookie become acceptable static void addNewCookieCallback(TNewCookieCallback newCookieCb); /// Used only in UDP, check if the cookie is valid. return empty string if valid, reason otherwise static std::string isValidCookie (const CLoginCookie &lc, std::string &userName, std::string &userPriv, std::string &userExtended, uint32 &instanceId, uint32 &charSlot); /// Call this method when a user is disconnected or the server disconnect the user. /// This method will warn the login system that the user is not here anymore static void clientDisconnected (uint32 userId); /// Call this method to retrieve the listen address static const std::string &getListenAddress(); /// Return true if we are in 'dev' mode static bool acceptsInvalidCookie(); /// Set the actual listen address static void setListenAddress(const std::string &la); /// Return the number of pending client connection. static uint32 getNbPendingUsers(); /// Refresh the list of pending cookies to remove outdated one /// (i.e. cookies for users that never connect) static void refreshPendingList(); private: /// This function is used by init() to create the connection to the Welcome Service static void connectToWS (); // called by other init() static void init (const std::string &listenAddress); }; } // NLNET #endif // NL_LOGIN_SERVER_H /* End of login_server.h */ ================================================ FILE: code/nel/include/nel/net/message.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_MESSAGE_H #define NL_MESSAGE_H #include "nel/misc/types_nl.h" #include "nel/misc/mem_stream.h" #include namespace NLNET { extern const char *LockedSubMessageError; /** * Message memory stream for network. Can be serialized to/from (see SerialBuffer()). Can be sent or received * over a network, using the NeL network engine. * If MESSAGES_PLAIN_TEXT is defined, the messages will be serialized to/from plain text (human-readable), * instead of binary. * * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CMessage : public NLMISC::CMemStream { public: enum TStreamFormat { UseDefault, Binary, String }; enum TMessageType { OneWay, Request, Response, Except}; struct TFormat { uint8 StringMode : 1, // true if the message body is string encoded, binary encoded if false otherwise LongFormat : 1, // true if the message format is long (d'ho ? all message are long !?!, always true) MessageType : 2; // type of the message (from TMessageType), classical message are 'OneWay' TFormat() { StringMode = 0; LongFormat = 0; MessageType = 0; } void serial(NLMISC::IStream &s) { if (s.isReading()) { // decode the bit field in a network independant manner uint8 b; s.serial(b); LongFormat = b & 1; StringMode = (b>>1) & 1; MessageType = (b>>2) & 3; } else { // encode the bit field in a network independant manner uint8 b = LongFormat | StringMode << 1 | MessageType << 2; s.serial(b); } } }; CMessage (const std::string &name = "", bool inputStream = false, TStreamFormat streamformat = UseDefault, uint32 defaultCapacity = 1000); CMessage (NLMISC::CMemStream &memstr); CMessage ( const uint32 rpc_session, const std::string &name = "", bool inputStream = false, TStreamFormat streamformat = UseDefault, uint32 defaultCapacity = 1000); /// Copy constructor CMessage (const CMessage &other); /// Assignment operator CMessage &operator= (const CMessage &other); /// exchange memory data void swap(CMessage &other); /// Sets the message type as a string and put it in the buffer if we are in writing mode void setType (const std::string &name, TMessageType type=OneWay); void changeType (const std::string &name); /// Returns the size, in byte of the header that contains the type name of the message or the type number uint32 getHeaderSize () const; /** The message was filled with an CMemStream, Now, we'll get the message type on this buffer. * This method updates _LengthR with the actual size of the buffer (it calls resetLengthR()). */ void readType (); /// Get the message name (input message only) and advance the current pos std::string readTypeAtCurrentPos() const; // Returns true if the message type was already set bool typeIsSet () const; uint32 session(); void session( uint32 rpc_session ); /** * Returns the length (size) of the message, in bytes. * If isReading(), it is the number of bytes that can be read, * otherwise it is the number of bytes that have been written. * Overloaded because uses a specific version of lengthR(). */ virtual uint32 length() const { if ( isReading() ) { return lengthR(); } else { return lengthS(); } } virtual uint32 lengthS() const { if (!hasLockedSubMessage()) // return _BufPos - _Buffer.getPtr(); return _Buffer.Pos; else // return (_BufPos - _Buffer.getPtr()) - _SubMessagePosR; return _Buffer.Pos - _SubMessagePosR; } /// Returns the "read" message size (number of bytes to read) (note: see comment about _LengthR) uint32 lengthR() const { return _LengthR; } virtual sint32 getPos () const throw(NLMISC::EStream) { // return (_BufPos - _Buffer.getPtr()) - _SubMessagePosR; return _Buffer.Pos - _SubMessagePosR; } // virtual sint32 getPos() const // { // return (_BufPos - _Buffer.getPtr()) - _SubMessagePosR; // } /** * Set an input message to look like, from a message callback's scope, as if it began at the current * pos and ended at the current pos + msgSize, and read the header and return the name of the sub message. * * This method provides a way to pass a big message containing a set of sub messages to their message * callback, without copying each sub message to a new message. If you need to perform some actions * that are not allowed with a locked message (see postconditions), use assignFromSubMessage(): * the locked sub message in M1 can be copied to a new message M2 with 'M2.assignFromSubMessage( M1 )'. * * Preconditions: * - The message is an input message (isReading()) * - msgEndPos <= length() * - getPos() >= getHeaderSize() * * Postconditions: * - The sub message is ready to be read from * - length() returns the size of the sub message * - getName() return the name of the sub message * - Unless you call unlockSubMessage(), the following actions will assert or raise an exception: * Serializing more than the sub message size, clear(), operator=() (from/to), invert(). */ std::string lockSubMessage( uint32 subMsgSize ) const { nlassert(!hasLockedSubMessage()); uint32 subMsgBeginPos = getPos(); uint32 subMsgEndPos = subMsgBeginPos + subMsgSize; nlassertex( isReading() && (subMsgEndPos <= lengthR()), ("%s %u %u", isReading()?"R":"W", subMsgEndPos, lengthR()) ); std::string name = unconst(*this).readTypeAtCurrentPos(); _SubMessagePosR = subMsgBeginPos; // _LengthR = subMsgEndPos; _LengthR = subMsgSize; return name; } /** * Exit from sub message locking, and skip the whole sub message. * * Preconditions: * - The message is an input message (isReading()) and has been locked using lockSubMessage() * - The reading pos is within or at the end of the previous sub message (if any) (see nlassertex) * * Postconditions: * - The current pos is the next byte after the sub message */ void unlockSubMessage() const { nlassert( isReading() && hasLockedSubMessage() ); nlassertex( getPos() <= sint32(_SubMessagePosR+_LengthR), ("The callback for msg %s read more data than there is in the message (pos=%d len=%u)", getName().c_str(), getPos(), _LengthR) ); uint32 subMsgEndPos = _SubMessagePosR + _LengthR; resetSubMessageInternals(); seek( subMsgEndPos, IStream::begin ); } /// Return true if a sub message has been locked bool hasLockedSubMessage() const { return (_SubMessagePosR != 0); } /** If a sub message is locked, return the sub message part */ virtual const uint8 *buffer() const { if (hasLockedSubMessage()) { // return _Buffer.getPtr() + _SubMessagePosR; return _Buffer.getBuffer().getPtr() + _SubMessagePosR; } else return CMemStream::buffer(); } /** * Similar to operator=, but makes the current message contain *only* the locked sub message in msgin * or the whole msgin if it is not locked * * Preconditions: * - msgin is an input message (isReading()) * - The current message is blank (new or reset with clear()) * * Postconditions: * - If msgin has been locked using lockSubMessage(), the current message contains only the locked * sub message in msgin, otherwise the current message is exactly msgin * - The current message is an input message, it is not locked */ void assignFromSubMessage( const CMessage& msgin ); /** * Transforms the message from input to output or from output to input */ void invert() { nlassertex( (!isReading()) || (!hasLockedSubMessage()), ("Inverting %s", LockedSubMessageError) ); CMemStream::invert(); if ( isReading() ) { // Write -> Read: skip the header _TypeSet = false; // if ( _Buffer.size() != 0 ) if ( _Buffer.getBuffer().size() != 0 ) readType(); } // For Read -> Write, please use clear() } // Clear the message. With this function, you can reuse a message to create another message void clear (); /** Returns the type name in string if available. Be sure that the message have the name of the message type * In a callback driven by message name, getName() does not necessarily return the right name. */ std::string getName () const; /** Return the type of the message. */ TMessageType getType() const; /** Returns a readable string to display it to the screen. It's only for debugging purpose! * Don't use it for anything else than to debugging, the string format could change in the future. * \param hexFormat If true, display all bytes in hexadecimal * \param textFormat If true, display all bytes as chars (above 31, otherwise '.') */ std::string toString ( bool hexFormat=false, bool textFormat=false ) const; /// Set default stream mode static void setDefaultStringMode( bool stringmode ) { _DefaultStringMode = stringmode; } /// Return an input stream containing the stream beginning in the message at the specified pos NLMISC::CMemStream extractStreamFromPos( sint32 pos ); /// Encapsulate/decapsulate another message inside the current message void serialMessage( CMessage& msg ); protected: /// Utility method void init( const std::string &name, TStreamFormat streamformat ); /// Utility method void resetSubMessageInternals() const { _SubMessagePosR = 0; // _LengthR = _Buffer.size(); _LengthR = _Buffer.getBuffer().size(); } private: std::string _Name; mutable TMessageType _Type; // When sub message lock mode is enabled, beginning position of sub message to read (before header) mutable uint32 _SubMessagePosR; // Length (can be smaller than _Buffer.size() if limitLength() is used) (updated in reading mode only) mutable uint32 _LengthR; // Size of the header (that contains the name type or number type) uint32 _HeaderSize; bool _TypeSet; // Default stream format static bool _DefaultStringMode; }; } #endif // NL_MESSAGE_H /* End of message.h */ ================================================ FILE: code/nel/include/nel/net/message_recorder.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_MESSAGE_RECORDER_H #define NL_MESSAGE_RECORDER_H #include "nel/misc/types_nl.h" #include "buf_net_base.h" //#include "callback_net_base.h" #include "message.h" #include "nel/misc/time_nl.h" #include "nel/misc/mem_stream.h" #include #include #include namespace NLNET { class CInetAddress; /// Type of network events (if changed, don't forget to change EventToString() and StringToEvent() enum TNetworkEvent { Sending, Receiving, Connecting, ConnFailing, Accepting, Disconnecting, Error }; /// TNetworkEvent -> string std::string EventToString( TNetworkEvent e ); /// string -> TNetworkEvent TNetworkEvent StringToEvent( std::string& s ); /* * TMessageRecord */ struct TMessageRecord { /// Default constructor TMessageRecord( bool input = false ) : UpdateCounter(0), SockId(InvalidSockId), Message( "", input ) {} /// Alt. constructor TMessageRecord( TNetworkEvent event, TSockId sockid, CMessage& msg, sint64 updatecounter ) : UpdateCounter(updatecounter), Event(event), SockId(sockid), Message(msg) {} /// Serial to string stream void serial( NLMISC::CMemStream& stream ) { nlassert( stream.stringMode() ); uint32 len; std::string s_event; stream.serial( UpdateCounter ); if ( stream.isReading() ) { stream.serial( s_event ); Event = StringToEvent( s_event ); uint32 sockId = (uint32)(size_t)SockId; stream.serialHex( sockId ); stream.serial( len ); stream.serialBuffer( Message.bufferToFill( len ), len ); } else { s_event = EventToString( Event ); stream.serial( s_event ); uint32 sockId; stream.serialHex( sockId ); SockId = (NLNET::TSockId)(size_t)sockId; len = Message.length(); stream.serial( len ); stream.serialBuffer( const_cast(Message.buffer()), len ); // assumes the message contains plain text } } //NLMISC::TTime Time; sint64 UpdateCounter; TNetworkEvent Event; TSockId SockId; CMessage Message; }; /** * Message recorder. * The service performs sends normally. They are intercepted and the recorder * plays the receives back. No communication with other hosts. * Warning: it works only with messages as plain text. * \author Olivier Cado * \author Nevrax France * \date 2001 */ class CMessageRecorder { public: /// Constructor CMessageRecorder(); /// Destructor ~CMessageRecorder(); /// Start recording bool startRecord( const std::string& filename, bool recordall=true ); /// Add a record void recordNext( sint64 updatecounter, TNetworkEvent event, TSockId sockid, CMessage& message ); /// Stop recording void stopRecord(); /// Start replaying bool startReplay( const std::string& filename ); /// Push the received blocks for this counter into the receive queue void replayNextDataAvailable( sint64 updatecounter ); /** * Returns the event type if the counter of the next event is updatecounter, * and skip it; otherwise return Error. */ TNetworkEvent checkNextOne( sint64 updatecounter ); /// Get the first stored connection attempt corresponding to addr TNetworkEvent replayConnectionAttempt( const CInetAddress& addr ); /// Stop playback void stopReplay(); /// Receive queue (corresponding to one update count). Use empty(), front(), pop(). std::queue ReceivedMessages; protected: /// Load the next record from the file (throws EStreamOverflow) bool loadNext( TMessageRecord& record ); /// Get the next record (from the preloaded records, or from the file) bool getNext( TMessageRecord& record, sint64 updatecounter ); private: // Input/output file std::fstream _File; // Filename std::string _Filename; // Preloaded records std::deque _PreloadedRecords; // Connection attempts std::deque _ConnectionAttempts; // If true, record all events including sends bool _RecordAll; }; } // NLNET #endif // NL_MESSAGE_RECORDER_H /* End of message_recorder.h */ ================================================ FILE: code/nel/include/nel/net/module.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_FILE_MODULE_H #define NL_FILE_MODULE_H #include "nel/misc/factory.h" #include "nel/misc/command.h" #include "nel/misc/string_mapper.h" #include "nel/misc/co_task.h" #include "nel/misc/algo.h" #include "nel/net/message.h" #include "nel/net/unified_network.h" #include "module_common.h" namespace NLNET { class CGatewayRoute; class IModuleInterceptable; class IInterceptorRegistrar { public: virtual ~IInterceptorRegistrar() { } virtual void registerInterceptor(IModuleInterceptable *interceptor) =0; virtual void unregisterInterceptor(IModuleInterceptable *interceptor) =0; }; /** This interface contains some module methods that can be intercepted. * This is used to build responsibility chain for message processing * or to intercept module up/down to automatically track a list of * interesting module proxy. */ class IModuleInterceptable { public: IModuleInterceptable(); virtual ~IModuleInterceptable(); void registerInterceptor(IInterceptorRegistrar *registrar); void interceptorUnregistered(IInterceptorRegistrar *registrar); IInterceptorRegistrar *getRegistrar(); /** Building of the manifest string can involve interceptors. * The system will call this function on each interceptor * and concatenate the returned strings to build the manifest string. * A default implementation is given that return an emty string. */ virtual std::string buildModuleManifest() const { return std::string(); } //@name Callback from module sockets //@{ /** Called by a socket to inform this module that another * module has been created OR has been made accessible (due to * a gateway connection). */ virtual void onModuleUp(IModuleProxy *moduleProxy) = 0; /** Called by a socket to inform this module that another * module has been deleted OR has been no more accessible (due to * some gateway disconnection). */ virtual void onModuleDown(IModuleProxy *moduleProxy) =0; /** Called internally by basic module imp to process the message by * application code. * The system will call each interceptor until one return true. */ virtual bool onProcessModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message) =0; /** Called by a socket to inform this module that the security * data attached to a proxy have changed. */ virtual void onModuleSecurityChange(IModuleProxy *moduleProxy) =0; private: IInterceptorRegistrar *_Registrar; }; /** This is the interface for the a module. * It describe interaction with the module itself, * with the module manager, and the module socket. */ class IModule : public NLMISC::CRefCount, public IInterceptorRegistrar, public IModuleInterceptable { friend class IModuleFactory; virtual void setFactory(IModuleFactory *factory) =0; public: /// The module is already plugged in the specified pluging class EModuleAlreadyPluggedHere : public NLMISC::Exception { }; /// An operation invocation has failed (mostly because of lost server module) class EInvokeFailed : public NLMISC::Exception { }; /// An operation invocation has failed because of a bad return type from servant class EInvokeBadReturn : public NLMISC::Exception { }; // Module management ===================== virtual ~IModule() {} /** Module initialization. * If the initialization return false, then the module manager deleted * the module immediately. */ virtual bool initModule(const TParsedCommandLine &initInfo) =0; //@name Basic module information //@{ /** Return the module ID. Each module has a local unique ID assigned * by the manager during module creation. * This ID is local because it is only valid inside a given process. * When module are declared in another process, they receive a * local ID that is different than the ID in their host process. */ virtual TModuleId getModuleId() const =0; /** Return the module name. Each module instance must have a unique * name in the host process. * If no mane is given during module creation, the module manager * build a unique name from the module class and a number. */ virtual const std::string &getModuleName() const =0; /// Return the module class. virtual const std::string &getModuleClassName() const =0; /** Return the module fully qualified name. * the MFQN is the identifier that is used across process to identify * each module. * The MDQNis composed from the computer host name, the process ID and * the module name. * Format : :: * This name is guarantied to be unique (at least, if the host name * is unique !) */ virtual const std::string &getModuleFullyQualifiedName() const =0; /** Return the manifest of the module. * The manifest is a simple string of undefined format. * The manifest is used by a module to expose some intention * or affinity (or whatever else you could imagine) of the * module. * The manifest if transmit along with the module proxy, allowing * any module seeing the proxy to read the manifest. * You should not use manifest to put big string because it is * transmit with proxy information. * Likewise, you should never use manifest to transmit critical data * (such as password) because any module can read it. */ virtual std::string getModuleManifest() const =0; /** Tell if the module implementation support immediate dispatching. * Immediate dispatching is when a message is send between * collocated module (i.e module on the same gateway). In that case, * the gateway forward the module immediately to the addressee module. * In some case, this is not the expected behavior because it give * different result depending if the communicating modules are * collocated or not. * It you module didn't support collocation optimisation, you must * override this method and return false. * In this case, message are stored in a queue and dispatching occur * in the next gateway update, just before the network update. */ virtual bool isImmediateDispatchingSupported() const { return true; } //@} //@name Callback from the module manager //@{ /// A Nel layer 5 service has started. virtual void onServiceUp(const std::string &serviceName, NLNET::TServiceId serviceId) =0; /// A Nel layer 5 service has stopped. virtual void onServiceDown(const std::string &serviceName, NLNET::TServiceId serviceId) = 0; /** Regular update from application. * If the application is a service, then it call CModuleManager::updateModules at each * service loop. * If the application is a regular application, then you have to call manually * CModuleManager::updateModules at regular intervals. */ virtual void onModuleUpdate() =0; /** The service main loop is terminating it job', all module while be * disconnected and removed after this callback. */ virtual void onApplicationExit() = 0; //@} // socket management ===================== //@name module sockets operation //@{ /** Plug this module in the specified socket. * Note that a module can be plugged in several socket at the same * time, but not twice in the same socket. */ virtual void plugModule(IModuleSocket *moduleSocket) throw (EModuleAlreadyPluggedHere) =0; /** Unplug this module from the specified socket. * Note that a module can be plugged in several socket at the same * time, but not twice in the same socket. * Throw an exception if the socket is not currently plug into * the specified socket. */ virtual void unplugModule(IModuleSocket *moduleSocket) throw (EModuleNotPluggedHere) =0; /** Fill resultList vector with the list of socket into * witch this module is currently plugged. * This method don't clear the result vector before filling it. */ virtual void getPluggedSocketList(std::vector &resultList) =0; //@} //@name Callback from module sockets //@{ /** Called by a socket to inform this module that another * module has been created OR has been made accessible (due to * a gateway connection). */ // virtual void onModuleUp(IModuleProxy *moduleProxy) = 0; /** Called by a socket to inform this module that another * module has been deleted OR has been no more accessible (due to * some gateway disconnection). */ // virtual void onModuleDown(IModuleProxy *moduleProxy) =0; /** Called by a socket to receive a message in the module context. * Basic implementation either forward directly to onProcessModuleMessage * or queue the message in the coroutine message queue (when a synchronous * messaging coroutine is started) for later dispatching. */ virtual void onReceiveModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message) =0; /** Called internally by basic module imp to process the message by * application code. */ // virtual void onProcessModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message) =0; /** Called by a socket to inform this module that the security * data attached to a proxy have changed. */ // virtual void onModuleSecurityChange(IModuleProxy *moduleProxy) =0; /** Do a module operation invocation. * Caller MUST be in a module task to call this method. * The call is blocking until receptions of the operation * result message (or detection of the dest module module is down) */ virtual void invokeModuleOperation(IModuleProxy *destModule, const NLNET::CMessage &opMsg, NLNET::CMessage &resultMsg) throw (EInvokeFailed) =0; //@} //@name Callback from module sockets management //@{ enum TModuleSocketEvent { mse_plugged, mse_before_unplug, mse_unplugged, }; virtual void onModuleSocketEvent(IModuleSocket *moduleSocket, TModuleSocketEvent eventType) =0; /// Called just after a module as been effectively plugged into a socket //@} //@{ //@name internal method, should not be used by client code virtual void _onModuleUp(IModuleProxy *removedProxy) =0; virtual void _onModuleDown(IModuleProxy *removedProxy) =0; //@} }; const TModulePtr NullModule; /** Base class for module identification data * Application writer should derive from this * class to create there own security information. * Security information are bound to proxy data * by a secured gateway. */ struct TSecurityData { // for factory system struct TCtorParam { uint8 DataTag; TCtorParam(uint8 dataTag) : DataTag(dataTag) { } }; /// An application defined identifier uint8 DataTag; /// Pointer to next security data item (or NULL) TSecurityData *NextItem; TSecurityData(const TCtorParam ¶ms) : DataTag(params.DataTag), NextItem(NULL) { } virtual ~TSecurityData() { if (NextItem != NULL) delete NextItem; } virtual void serial(NLMISC::CMemStream &s) =0; }; struct TUnknownSecurityData : public TSecurityData { uint8 RealDataTag; std::vector Data; TUnknownSecurityData(uint8 realDataTag, uint32 size) : TSecurityData(TSecurityData::TCtorParam(0xff)), RealDataTag(realDataTag), Data(size) { } void serial(NLMISC::CMemStream &s) { for (uint i=0; i class TModuleTask : public CModuleTask { public: typedef void (T::*TMethodPtr)(); private: T *_Module; TMethodPtr _TaskMethod; // override CTask::run void run() { initMessageQueue(_Module); try { // run the module task command control to module task method (_Module->*_TaskMethod)(); } catch (const NLMISC::Exception &e) { nlwarning("In module task '%s', exception '%e' thrown", typeid(this).name(), e.what()); } catch (...) { nlwarning("In module task '%s', unknown exception thrown", typeid(this).name()); } // finish the dispatch flushMessageQueue(_Module); } public: TModuleTask(T *module, void (T::*taskMethod)()) : CModuleTask(module), _Module(module), _TaskMethod(taskMethod) { } }; // a special macro for easy module task startup #define NLNET_START_MODULE_TASK(className, methodName) \ { \ NLNET::TModuleTask *task = new NLNET::TModuleTask(this, &className::methodName); \ queueModuleTask(task); \ } \ /** Interface for module factory. * Each module MUST provide a factory and * register an instance of the factory in * the module manager. */ class IModuleFactory : public NLMISC::CRefCount { protected: /// The class name of the factored module std::string _ModuleClassName; /// The list of instantiated modules std::set _ModuleInstances; public: /// Constructor, initialize the module class name IModuleFactory(const std::string &moduleClassName); /** Return the class name of the factored module */ virtual const std::string &getModuleClassName() const; /** Return the initialization string helper */ virtual const std::string &getInitStringHelp() const =0; /** Pretty simple method. Module initialization * is done after construction, so there are * no parameter at construction. */ virtual IModule *createModule() =0; /** The module manager call this to delete a module instance.*/ virtual void deleteModule(IModule *module); /** Virtual destructor. * The destructor while unregister the module factory from the * factory registry and ALL module factored * will also be deleted. */ virtual ~IModuleFactory(); /** Called by concrete factory to initialise the factored object */ void registerModuleInFactory(TModulePtr module); }; // const TModuleFactoryPtr NullModuleFactory; template class CModuleFactory : public IModuleFactory { public: CModuleFactory(const std::string &moduleClassName) : IModuleFactory(moduleClassName) {} virtual IModule *createModule() { IModule *module = new moduleClass; registerModuleInFactory(module); return module; } virtual const std::string &getInitStringHelp() const { return moduleClass::getInitStringHelp(); } }; #define NLNET_REGISTER_MODULE_FACTORY(moduleClassName, registrationName) \ class moduleClassName##Factory : public NLNET::CModuleFactory \ { \ public: \ static const std::string &theModuleClassName() \ { \ static const std::string name(registrationName); \ return name; \ } \ \ moduleClassName##Factory() \ : NLNET::CModuleFactory(theModuleClassName()) \ {} \ };\ NLMISC_REGISTER_OBJECT_INDIRECT(NLNET::IModuleFactory, moduleClassName##Factory, std::string, registrationName) //#define NLNET_MAKE_MODULE_FACTORY_TYPENAME(moduleClassName) moduleClassName##Factory #define NLNET_GET_MODULE_FACTORY(moduleClassName) moduleClassName##Factory class CModuleSocket; /** Basic module implementation. * Module implementor should derive from this class * rather than rebuild a complete module from * scratch (from IModule in fact). * This class provide name and module registration, * message dispatching to message handler, * module socket interaction. */ class CModuleBase : public IModule, public NLMISC::ICommandsHandler { // Module manager is our friend coz it need to feed some field here friend class CModuleManager; friend class CModuleTask; typedef std::set TModuleSockets; /// This is the sockets where the module is plugged in TModuleSockets _ModuleSockets; typedef std::list TInterceptors; /// This is the linked list of interceptor TInterceptors _ModuleInterceptors; //@{ //@name Synchronous messaging typedef std::list > TMessageList; /// dynamically allocated list of synchronous message to process TMessageList _SyncMessages; typedef std::list TModuleTasks; /// list of coroutine to run for synchronous messaging (the first in the list is running) TModuleTasks _ModuleTasks; typedef std::vector TInvokeStack; /// stack of server module with pending invocation response TInvokeStack _InvokeStack; /// The current message to process sender IModuleProxy *_CurrentSender; /// The current message to process const NLNET::CMessage *_CurrentMessage; /// True if the current message processing have generated an exception bool _CurrentMessageFailed; /// task for message dispatching CModuleTask *_MessageDispatchTask; //@} virtual void setFactory(IModuleFactory *factory); virtual IModuleFactory *getFactory(); protected: /// Keep track of the module factory IModuleFactory *_ModuleFactory; /// This is the local unique ID assigned to this module. TModuleId _ModuleId; /// This is the module name. std::string _ModuleName; /// This is the fully qualified module name mutable std::string _FullyQualifedModuleName; CModuleBase(); ~CModuleBase(); virtual void registerInterceptor(IModuleInterceptable *interceptor); virtual void unregisterInterceptor(IModuleInterceptable *interceptor); const std::string &getCommandHandlerName() const; TModuleId getModuleId() const; const std::string &getModuleName() const; const std::string &getModuleClassName() const; const std::string &getModuleFullyQualifiedName() const; std::string getModuleManifest() const; /** Called by a socket to receive a message in the module context. * Basic implementation either forward directly to onProcessModuleMessage * or queue the message in the coroutine message queue (when a synchronous * messaging coroutine is started) for later dispatching. */ virtual void onReceiveModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message); /// The message dispatching task void _receiveModuleMessageTask(); void queueModuleTask(CModuleTask *task); CModuleTask *getActiveModuleTask(); public: /// return the default init string (empty) static const std::string &getInitStringHelp(); /** Search an interceptor in the interceptor list. * By default, the method begin to search at the first interceptor. * If 'previous' is set to a valid interceptor, then the search * continue after it. * the search is done by attempting a dynamic cast for * each interceptor. * If no interceptor match the required class, then NULL is * returned. */ template T *getInterceptor(T *dummy, IModuleInterceptable *previous = NULL) { TInterceptors::iterator it(_ModuleInterceptors.begin()); if (previous != NULL) { // advance up to next the previous while (it != _ModuleInterceptors.end() && *it != previous) ++it; if (it != _ModuleInterceptors.end()) ++it; } while (it != _ModuleInterceptors.end()) { IModuleInterceptable *mi = *it; T *inter = dynamic_cast(mi); if (inter != NULL) { dummy = inter; return inter; } ++it; } dummy = NULL; return NULL; } protected: // Init base module, init module name bool initModule(const TParsedCommandLine &initInfo); void plugModule(IModuleSocket *moduleSocket) throw (EModuleAlreadyPluggedHere); void unplugModule(IModuleSocket *moduleSocket) throw (EModuleNotPluggedHere); void getPluggedSocketList(std::vector &resultList); void invokeModuleOperation(IModuleProxy *destModule, const NLNET::CMessage &opMsg, NLNET::CMessage &resultMsg) throw (EInvokeFailed); void _onModuleUp(IModuleProxy *removedProxy); void _onModuleDown(IModuleProxy *removedProxy); bool _onProcessModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message); /// base module command table NLMISC_COMMAND_HANDLER_TABLE_BEGIN(CModuleBase) NLMISC_COMMAND_HANDLER_ADD(CModuleBase, dump, "display information about module instance status", "no args") NLMISC_COMMAND_HANDLER_ADD(CModuleBase, plug, "plug the module in a module socket", "") NLMISC_COMMAND_HANDLER_ADD(CModuleBase, unplug, "unplug the module out of a module socket", "") NLMISC_COMMAND_HANDLER_ADD(CModuleBase, sendPing, "send a ping message to another module using the first available route", "") NLMISC_COMMAND_HANDLER_TABLE_END NLMISC_CLASS_COMMAND_DECL(dump); NLMISC_CLASS_COMMAND_DECL(plug); NLMISC_CLASS_COMMAND_DECL(unplug); NLMISC_CLASS_COMMAND_DECL(sendPing); }; class CGatewayRoute; class CModuleProxy : public IModuleProxy { friend class CModuleManager; friend class CStandardGateway; /// The gateway that received the module information IModuleGateway *_Gateway; /// The route to use for reaching the module CGatewayRoute *_Route; /// The module distance (in term of gateway to cross) uint32 _Distance; /// The module local ID TModuleId _ModuleProxyId; /// The module foreign ID, this is the module ID in case of a local proxy TModuleId _ForeignModuleId; /// the module instance in case of local module, NULL otherwise TModulePtr _LocalModule; /// The module class name; NLMISC::TStringId _ModuleClassName; /// The fully qualified module name. NLMISC::TStringId _FullyQualifiedModuleName; /// The module manifest std::string _Manifest; /// the list of security data TSecurityData *_SecurityData; /// Private constructor, only module manager instantiate module proxies CModuleProxy(TModulePtr localModule, TModuleId localModuleId, const std::string &moduleClassName, const std::string &fullyQualifiedModuleName, const std::string &moduleManifest); public: const CGatewayRoute * getRoute() const { return _Route; } /** Return the module ID. Each module has a local unique ID assigned * by the manager during module creation. * This ID is local because it is only valid inside a given process. * When module are declared in another process, they receive a * local ID that is different than the ID in their host process. */ virtual TModuleId getModuleProxyId() const; virtual TModuleId getForeignModuleId() const; uint32 getModuleDistance() const; IModule *getLocalModule() const; CGatewayRoute *getGatewayRoute() const; /** Return the module name. Each module instance must have a unique * name in the host process. * If no mane is given during module creation, the module manager * build a unique name from the module class and a number. * Distant module name are always the FQMN, ie, it is the same as * getModuleFullyQualifiedName() */ virtual const std::string &getModuleName() const; /// Return the module class. virtual const std::string &getModuleClassName() const; /// return the module manifest virtual const std::string &getModuleManifest() const; /** Return the gateways interface by witch this module is accessible. */ virtual IModuleGateway *getModuleGateway() const; /** Send a message to the module. */ virtual void sendModuleMessage(IModule *senderModule, const NLNET::CMessage &message) throw (EModuleNotReachable); virtual const TSecurityData *getFirstSecurityData() const { return _SecurityData; } virtual const TSecurityData *findSecurityData(uint8 dataTag) const; }; /** Utility class to do broadcast with a container of proxy pointer */ template class TBroadcastModuleMessage { void sendMessage(IModule *sender, const PtrContainer &addresseeProxies, const NLNET::CMessage &message) { typename PtrContainer::iterator first(addresseeProxies.begin()), last(addresseeProxies.end()); for (; first != last; ++first) { IModuleProxy *proxy = static_cast(*first); proxy->sendModuleMessage(sender, message); } } }; } // namespace NLNET #endif // NL_FILE_MODULE_H ================================================ FILE: code/nel/include/nel/net/module_builder_parts.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef MODULE_BUILDER_PARTS_H #define MODULE_BUILDER_PARTS_H #include "nel/misc/types_nl.h" #include "nel/misc/mutable_container.h" #include "module.h" namespace NLNET { template class CEmptyModuleServiceBehav : public T { public: virtual void onServiceUp(const std::string &/* serviceName */, NLNET::TServiceId /* serviceId */) {} virtual void onServiceDown(const std::string &/* serviceName */, NLNET::TServiceId /* serviceId */) {} virtual void onModuleUpdate() {} virtual void onApplicationExit() {} }; template class CEmptyModuleCommBehav : public T { public: std::string buildModuleManifest() const { return ""; } virtual void onModuleUp(IModuleProxy * /* moduleProxy */) {} virtual void onModuleDown(IModuleProxy * /* moduleProxy */) {} virtual void onModuleSecurityChange(IModuleProxy * /* moduleProxy */) {} virtual bool onProcessModuleMessage(IModuleProxy * /* senderModuleProxy */, const CMessage &/* message */) { return false; } }; template class CEmptySocketBehav : public T { public: virtual void onModuleSocketEvent(IModuleSocket * /* moduleSocket */, IModule::TModuleSocketEvent /* eventType */) { } }; /** Interceptor forwarder * The trick is that if you build a module interceptor class * and then you want to inherit this class in a module definition, then * the virtual callbacks are received by the module instead of by your * interceptor (because the base module is also an interceptor and * it eventualy overides the calls). * The workaround consist of having the interceptor implemented in * an inner class with method forwarded to you class with a different * interface. */ template class CInterceptorForwarder : public IModuleInterceptable { ParentClass *_Parent; public: CInterceptorForwarder() : _Parent(NULL) {} void init(ParentClass *parent, IModule *module) { nlassert(parent != NULL); nlassert(module != NULL); _Parent = parent; registerInterceptor(module); } ParentClass *getParent() { return _Parent; } virtual std::string buildModuleManifest() const { return _Parent->fwdBuildModuleManifest(); } virtual void onModuleUp(IModuleProxy *moduleProxy) { _Parent->fwdOnModuleUp(moduleProxy); } virtual void onModuleDown(IModuleProxy *moduleProxy) { _Parent->fwdOnModuleDown(moduleProxy); } virtual bool onProcessModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message) { return _Parent->fwdOnProcessModuleMessage(senderModuleProxy, message); } virtual void onModuleSecurityChange(IModuleProxy *moduleProxy) { _Parent->fwdOnModuleSecurityChange(moduleProxy); } }; /** Callback class used by the CModuleTracker class below and to be * implemented if you want callback when tracked module are up/down. */ class IModuleTrackerCb { public: virtual ~IModuleTrackerCb() { } virtual void onTrackedModuleUp(IModuleProxy *moduleProxy) =0; virtual void onTrackedModuleDown(IModuleProxy *moduleProxy) =0; }; /** A module interceptor that keep of a set of known module that match a given * predicate. * A typical usage is to declare an instance of this class (specialized with * the appropriate predicate) as member of your module. * You can also have more than one tracker with different predicate * if you are interested in different modules. * * NB : don't forget to init() each tracker in order to let it register * in you module interceptor list (typically, call "_MyTracker.init(this, this)" in * your module's constructor). */ template class CModuleTracker { public: typedef NLMISC::TMutableContainer > TTrackedModules; private: /// this is the list of module that match the predicate TTrackedModules _TrackedModules; /// An instance of the predicate class ModulePredicate _ModulePred; /// The callback interface implementation (if any) IModuleTrackerCb *_TrackerCallback; public: CModuleTracker(const ModulePredicate &pred) : _ModulePred(pred), _TrackerCallback(NULL) { } /** Init : set the owner module (to register the interceptor) and the * optional callback interface. */ void init(NLNET::IModule *module, IModuleTrackerCb *trackerCallback = NULL) { _Interceptor.init(this, module); _TrackerCallback = trackerCallback; } /** Return the set of tracked module. * The set is wrapped into a mutable container that allow * to call non const begin() and end() from a const container. */ const TTrackedModules &getTrackedModules() const { return _TrackedModules; } private: // unused interceptors std::string fwdBuildModuleManifest() const { return std::string(); } void fwdOnModuleSecurityChange(NLNET::IModuleProxy * /* moduleProxy */) {} bool fwdOnProcessModuleMessage(NLNET::IModuleProxy * /* sender */, const NLNET::CMessage &/* message */) {return false;} // check module up void fwdOnModuleUp(NLNET::IModuleProxy *moduleProxy) { if (_ModulePred(moduleProxy)) { if (_TrackedModules.insert(moduleProxy).second && _TrackerCallback != NULL) // warn the callback _TrackerCallback->onTrackedModuleUp(moduleProxy); } }; // check module down void fwdOnModuleDown(NLNET::IModuleProxy *moduleProxy) { if (_TrackedModules.find(moduleProxy) != _TrackedModules.end()) { _TrackedModules.erase(moduleProxy); if (_TrackerCallback != NULL) _TrackerCallback->onTrackedModuleDown(moduleProxy); } }; typedef NLNET::CInterceptorForwarder < CModuleTracker> TInterceptor; // declare one interceptor member of the skeleton TInterceptor _Interceptor; // declare the interceptor forwarder as friend of this class friend class NLNET::CInterceptorForwarder < CModuleTracker>; }; /** A canonical module predicate that test a module * for a specified module class name. */ struct TModuleClassPred { private: std::string _ClassName; public:; TModuleClassPred(const std::string &className) : _ClassName(className) { } bool operator () (IModuleProxy *moduleProxy) const { return moduleProxy->getModuleClassName() == _ClassName; } }; } // namespace NLNET #endif // MODULE_BUILDER_PARTS_H ================================================ FILE: code/nel/include/nel/net/module_common.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_MODULE_COMMON_H #define NL_MODULE_COMMON_H #include "nel/misc/smart_ptr.h" #include "nel/misc/common.h" namespace NLNET { /// General type definition /// Module identifier typedef uint32 TModuleId; /// A module ID of 0 mean 'not valid module ID' const TModuleId INVALID_MODULE_ID = 0; /// Forward smart ptr definition class IModule; typedef NLMISC::CSmartPtr TModulePtr; class IModuleProxy; typedef NLMISC::CSmartPtr TModuleProxyPtr; class IModuleSocket; class IModuleFactory; class IModuleGateway; struct TSecurityData; /// The destination module for a message cannot be reached by socket used class EModuleNotReachable : public NLMISC::Exception { }; /// A module use a socket where it is not plugged in class EModuleNotPluggedHere : public NLMISC::Exception { }; /** Structure for pre-parsed command line parameters * Support in memory representation of parameter line like : * 'tag1(x=1 y=2 z=3) tag2=6 tag3(a=abc b=xyz tag4)' */ class TParsedCommandLine { public: // copy constructor is needed because SubParams contains pointers TParsedCommandLine(const TParsedCommandLine& copy); TParsedCommandLine() { }; ~TParsedCommandLine(); /// The parameter name std::string ParamName; /// The parameter value, empty in the case of a sub param header std::string ParamValue; /// The list of sub parameters. Empty in the case of a single param. std::vector SubParams; /// Cleanup void clear(); /// Parse a NeL argument list to build a module init object. bool parseParamList(const std::string &rawParamString); /** Ask the command line for a parameter * If the parameter doesn't exist, the method return NULL. * You can request a sub param directly by * concatenating the header(s) name separated by dot. * e.g. in the param string "a(b(c=4)", you can * query directly with 'a.b.c' to retrieve the value 4. */ const TParsedCommandLine *getParam(const std::string &name) const; /** Add or replace a parameter in the set. * The name can be any valid name (e.g 'a' or 'a.b.c'). * If any sub part of the name didn't exist, the function * will create the appropriate sub object. */ void setParam(const std::string &name, const std::string &value); /** Rebuild the raw command line string */ std::string toString() const; private: bool _parseParamList(const std::string &rawParamString); const TParsedCommandLine *_getParam(std::vector::iterator it, std::vector::iterator end) const; TParsedCommandLine *_getParam(std::vector::iterator it, std::vector::iterator end); }; } // namespace NLNET #endif // NL_MODULE_COMMON_H ================================================ FILE: code/nel/include/nel/net/module_gateway.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_FILE_MODULE_GATEWAY_H #define NL_FILE_MODULE_GATEWAY_H #include "nel/misc/twin_map.h" #include "module_common.h" #include "inet_address.h" #include "message.h" #include "module_message.h" namespace NLNET { class IGatewayTransport; class CGatewayRoute; class CGatewaySecurity; /** Interface for gateway. * A gateway is the part of the module layer that interconnect * module locally and give access to foreign module hosted in * other process. * Gateway can interconnect local module with themselves, as well as * connect with another gateway in another process or host. * * Transport: * --------- * Gateway connectivity is provided by 'transport' that can * be build on any support. * There are available transport for NeL Layer 3 in server * of client mode. * * You can bind at run time, any number of transport to a * gateway. * Each of these transport can then receive specific command * from passed by the gateway. * Transport then create routes that are active connection * to foreign gateways. * * When using the layer 3 transport, you can choose either * to instantiate a client mode transport or a server mode * transport. * In client mode, you can connect to one or more server, each * connection generating a new route. * In server mode, you can put your transport as 'open' on * a specified TCP port, then each client connection will * generate a new route. * * These layer 3 transport are only one type of transport, * it it possible to build any type of transport (on raw TCP * socket, or over UDP, or using named pipe...). * * Unique name generation : * ------------------------ * Gateway need to generate 'fully qualified module name' witch * must be unique in any gateway interconnection scheme. * By default, gateway use the following scheme to build * unique module name : * :: * In some case, you could not be sure that the host name will * be unique (think about your hundreds simultaneously connected * clients, some of them can have set the same name for their * computer !). In this case, you can set register a unique name * generator on you gateway that use another naming scheme. * For example, you can use you customer unique ID (with the * restriction that one ID can be in use once at the same time) * to build unique name : * : * * Advanced transport options (i.e option settable on each transport): * -------------------------- * - peer invisible : if activated on a transport, this option * will mask the modules of the other routes of the same * transport. * This is useful for players modules (you sure don't want * that all players can see all other clients modules), * or for client/server structure where you don't want * all client to see all module, bu only those that are * available from the client side. * Note that any module that come from another transport * will be disclosed to all the route. * * - firewalled : if activated, this option will mask any module * to the connected unsecure route unless some module comming from another * transport (or a local module) will try to send a message * to a module on an unsecure route. In this case, the gateway * will disclose the information about this sender module (and only * this one) to the unsecure route. * In firewall mode, the gateway keep a list of disclosed module * for each route and stop any message that is addressed to an * undisclosed module (that can be considered as a hacking attempt). * Module that are disclosed by the unsecure routes are normaly * seen by all other module. * * The two options above can be used in combination. This is a prefered * way of configuring transport for player connection : we don't want * player to see other player modules, and we don't want player to see * any server side module until one of them started a communication * with a player module. */ class IModuleGateway : public NLMISC::CRefCount { public: // Exception classes =================================== /// The gateway is already open while trying to open it. class EGatewayAlreadyOpen : public NLMISC::Exception { }; /// When trying to open the gateway server, the TCP port is already in use class EGatewayPortInUse : public NLMISC::Exception { }; /// The gateway is not open while trying to close it. class EGatewayNotOpen : public NLMISC::Exception { }; /// A gateway is not connected while trying to communicate with class EGatewayNotConnected : public NLMISC::Exception { }; /// Firewall mode is activated but there is already open route ! class EGatewayFirewallBreak : public NLMISC::Exception { }; virtual ~IModuleGateway() {} /** Register the gateway in the module manager gateway registry */ virtual void registerGateway() =0; /** Unregister the gateway in the module manager gateway registry */ virtual void unregisterGateway() =0; //@{ //@name Gateway general information and control /// Return the local name of the gateway virtual const std::string &getGatewayName() const =0; /// Return the Fully Qualified Gateway Name (FQGN) virtual const std::string &getFullyQualifiedGatewayName() const =0; //@} //@{ //@name Gateway transport management /// Create and bind to this gateway a new transport virtual void createTransport(const std::string &transportClass, const std::string &instanceName) =0; /// Delete a transport (this will close any open route) virtual void deleteTransport(const std::string &transportInstanceName) =0; /// Activate/stop peer invisible mode on a transport virtual void setTransportPeerInvisible(const std::string &transportInstanceName, bool peerInvisible) =0; /// Activate/stop firewalling mode on a transport virtual void setTransportFirewallMode(const std::string &transportInstanceName, bool firewalled) throw (EGatewayFirewallBreak) =0; /// Send a command to a transport virtual void transportCommand(const TParsedCommandLine &commandLine) =0; /// Return a pointer on the named transport interface, or NULL if the transport is unknown. virtual IGatewayTransport *getGatewayTransport(const std::string &transportName) const =0; /// Return the number of transport currently active on this gateway virtual uint32 getTransportCount() const =0; /// Return the number route available virtual uint32 getRouteCount() const =0; /// Return the number of ping received. This is incremented by special "GW_PING" message for unit testing virtual uint32 getReceivedPingCount() const =0; //@} //@{ //@name Gateway transport callback /// A new route a added by a transport virtual void onRouteAdded(CGatewayRoute *route) =0; /// A route is removed by a transport virtual void onRouteRemoved(CGatewayRoute *route) =0; /// A transport have received a message virtual void onReceiveMessage(CGatewayRoute *from, const CMessage &msgin) =0; //@} //@{ //@name Gateway security plug-in management /** create a security plug-in. * There must be no security plug-in currently created. */ virtual void createSecurityPlugin(const std::string &className) = 0; /** Send a command to the security plug-in */ virtual void sendSecurityCommand(const TParsedCommandLine &command) =0; /** Remove the security plug-in. */ virtual void removeSecurityPlugin() = 0; //@} //@{ //@name Module management /** Callback called when the gateway has received some new module * and eventually, need to disclose the module information to * the connected gateway. * The default behavior is to disclose the module to all * connected gateway. */ virtual void onAddModuleProxy(IModuleProxy *addedModule) =0; /** Callback called when a module become unavailable, either * because it is unplugged from it's socket, or, the * gateway that disclosed it has been disconnected. */ virtual void onRemoveModuleProxy(IModuleProxy *removedModule) =0; /** Disclose module information to a connected gateway. * This can also be this gateway itself. */ virtual void discloseModule(IModuleProxy *moduleProxy) throw (EGatewayNotConnected) =0; /** Retrieve the proxy for a locally plugged module. * Each local module plugged in a gateway has an associated * proxy. This method return this proxy or NULL if the * module is not plugged here. */ virtual IModuleProxy *getPluggedModuleProxy(IModule *pluggedModule) =0; /// Return the number of proxies managed by this gateway virtual uint32 getProxyCount() const =0; /// Fill a vector with the list of proxies managed here. The module are filled in ascending proxy id order. virtual void getModuleProxyList(std::vector &resultList) const =0; //@} //@{ //@name Module messaging /** Callback called when a message arrive from a gateway and need * to be dispatched. * The default behavior is to route the message in any case to * the destination module. * You can override this callback to add some message filtering * or hacking feature. */ // virtual void onReceiveModuleMessage(TModuleGatewayProxyPtr &senderGateway, TModuleMessagePtr &message) =0; /** Send a message to a module. */ virtual void sendModuleMessage(IModuleProxy *senderProxy, IModuleProxy *addresseeProxy, const NLNET::CMessage &message) =0; /** Send a message to the module plugged in this gateway. * You can override this method to change the dispatching, add filtering, * message hacking or interceptor. */ virtual void dispatchModuleMessage(IModuleProxy *senderProxy, IModuleProxy *addresseeProxy, const CMessage &message) =0; //@} }; /** Intermediate class must be used as base class * for implementing gateway. */ class CModuleGateway : public IModuleGateway { protected: /** Register the gateway in the module manager gateway registry */ virtual void registerGateway(); /** Unregister the gateway in the module manager gateway registry */ virtual void unregisterGateway(); }; /** Interface class for gateway transport. * A gateway transport is an object associated to a standard gateway * at run time and that provide a mean to interconnect with * other gateway. * As each transport mode as it's own command requirement, * a generic command system is provided for sending command message * to the transport implementation. * * At time of writing, NeL come with 2 transport : one based on layer 3 client, and one * based on layer 3 server. In a short time, there will be transport using layer 5. */ class IGatewayTransport { protected: /// Back pointer to the gateway hosting this transport IModuleGateway *_Gateway; public: /// Invalid transport command class EInvalidCommand : public NLMISC::Exception { public: EInvalidCommand() {} EInvalidCommand(const char *err) : Exception(err) {} }; /// Error in the transport class ETransportError : public NLMISC::Exception { public: ETransportError(const char *err) : Exception(err) {} }; //////////////// property used by gateway (not managed by transport) /// Flag for firewall mode bool Firewalled; /// flag for peer invisible mode bool PeerInvisible; /// Constructor param needed by the factory (see nel/misc/factory.h) struct TCtorParam { IModuleGateway *Gateway; }; /// Constructor, establish link with the associated gateway IGatewayTransport(const TCtorParam ¶m) : Firewalled(false), PeerInvisible(false) { _Gateway = param.Gateway; } virtual ~IGatewayTransport() {} /// Return the class name from the transport factory virtual const std::string &getClassName() const =0; /// The gateway send a command message to the transport virtual void onCommand(const CMessage &command) throw (EInvalidCommand) = 0; /// The gateway send a textual command to the transport virtual bool onCommand(const TParsedCommandLine &command) throw (EInvalidCommand) = 0; /// The gateway update the transport regularly virtual void update() =0; /// Return the number of route currently open by the transport virtual uint32 getRouteCount() const =0; /// Dump debug information in the specified log stream virtual void dump(NLMISC::CLog &log) const =0; }; /** Base class for gateway route. * Route are provided by transport. * Transport provide a mean to build route * between gateway. * Route show the list of foreign gateway that are * reachable with it and are use to send * message to these gateways. * * The route store proxy id translation table, i.e, * for each module proxy that come from this route * we store association of the local proxy ID with * the foreign proxy ID, that is the proxy that * represent the module at the outbound of the route. * * Note that even if the route object is created * by the transport, the translation table is * feed and managed by the gateway implementation. */ class CGatewayRoute { protected: #ifdef NL_DEBUG /// A debug flag that trigger an assert if true and something delete this object. mutable bool _AssertOnDelete; friend struct CAutoAssertSetter; #endif /// The transport that manage this route IGatewayTransport *_Transport; public: /// The local foreign(A) <=> local(B) proxy id translation table // typedef std::map TForeignToLocalIdx; typedef NLMISC::CTwinMap TForeignToLocalIdx; TForeignToLocalIdx ForeignToLocalIdx; enum TPendingEventType { pet_disclose_module, pet_undisclose_module, pet_update_distance, pet_update_security, }; struct TPendingEvent { TPendingEventType EventType; // IModuleProxy *ModuleProxy; TModuleId ModuleId; }; /// A list of pending event on this route std::list PendingEvents; /// A list of module proxy pending disclosure // std::set PendingDisclosure; /// A list of module proxy pending undisclosure // std::set PendingUndisclosure; /// firewall disclosed module (empty in not firewalled mode) std::set FirewallDisclosed; //@{ /// @name Information on the next module message to dispatch /// next message type, set to CModuleMessageHeaderCodec::mt_invalid when no module message are awaited CModuleMessageHeaderCodec::TMessageType NextMessageType; /// Id of the sender proxy TModuleId NextSenderProxyId; /// Id of the addressee proxy TModuleId NextAddresseeProxyId; //@} /// constructor, must provide the transport CGatewayRoute(IGatewayTransport *transport) : _Transport(transport), NextMessageType(CModuleMessageHeaderCodec::mt_invalid) { #ifdef NL_DEBUG _AssertOnDelete = false; #endif } virtual ~CGatewayRoute() { #ifdef NL_DEBUG nlassert(!_AssertOnDelete); #endif } /// Return the transport that hold this route IGatewayTransport *getTransport() { return _Transport; }; /// Send a message via the route virtual void sendMessage(const CMessage &message) const =0; }; #ifdef NL_DEBUG struct CAutoAssertSetter { const CGatewayRoute &GatewayRoute; CAutoAssertSetter(const CGatewayRoute &gwr) : GatewayRoute(gwr) { GatewayRoute._AssertOnDelete = true; } ~CAutoAssertSetter() { GatewayRoute._AssertOnDelete = false; } }; #define NLNET_AUTO_DELTE_ASSERT CAutoAssertSetter __autoDeleteAssert(static_cast(*this)) #else #define NLNET_AUTO_DELTE_ASSERT #endif class CGatewaySecurity { protected: IModuleGateway *_Gateway; public: struct TCtorParam { IModuleGateway *Gateway; }; CGatewaySecurity (const TCtorParam ¶ms) : _Gateway(params.Gateway) { } virtual ~CGatewaySecurity() { } /** the gateway send a command to the security module */ virtual void onCommand(const TParsedCommandLine &/* command */) {} /** A new proxy is available, the security plug-in can add security data */ virtual void onNewProxy(IModuleProxy *proxy) =0; /** A proxy receive new security datas, the security plug-in can * check the data validity, and eventually, reject the one or mode data block * then it must update the proxy security with the new security data. * If the security plug-in reject one or more security data, it has * the duty for deleting the rejected object. * Furthermore, it must free the existing security data on the proxy * if is replace them with the new one. * Any other combination is fine unless the security plug-in do a correct * management of freeing unused security data. */ virtual void onNewSecurityData(CGatewayRoute *from, IModuleProxy *proxy, TSecurityData *firstSecurityData) = 0; /** Called just before delete, the security plug-in must * remove any security data that it added to the proxies. */ virtual void onDelete() =0; /** Set a security data block. If a bloc of the same type * already exist in the list, the new one will replace the * existing one. */ void setSecurityData(IModuleProxy *proxy, TSecurityData *securityData); /** Clear a block of security data * The block is identified by the data tag * Return true if at least one item have been removed, false otherwise. */ bool removeSecurityData(IModuleProxy *proxy, uint8 dataTag); /** Replace the complete set of security data with the new one. * Security data allocated on the proxy are freed, */ void replaceAllSecurityDatas(IModuleProxy *proxy, TSecurityData *securityData); /** Ask the gateway to resend the security data. * The plug-in call this method after having changed * the security info for a plug-in outside of the * onNewProxy call. */ void forceSecurityUpdate(IModuleProxy *proxy); }; } // namespace NLNET #endif // NL_FILE_MODULE_GATEWAY_H ================================================ FILE: code/nel/include/nel/net/module_manager.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef MODULE_MANAGER_H #define MODULE_MANAGER_H #include "nel/misc/factory.h" #include "nel/misc/dynloadlib.h" #include "nel/misc/common.h" #include "module_common.h" namespace NLNET { class CGatewayRoute; /** This is the interface for the module manager. * Module manager is in charge of module factoring and * referencing, * It is also an entry point when you need to retrieve * a module socket or a module gateway. */ class IModuleManager : public NLMISC::CRefCount { public: /// Check that the module manager is initialized static bool isInitialized(); /// The module manager is a singleton static IModuleManager &getInstance(); /// Must be called before releasing the instance, will call IModule::onApplicationExit on all module instance virtual void applicationExit() =0; /// Release the singleton instance static void releaseInstance(); virtual ~IModuleManager() {} /** set the unique name root used for fully qualified name generation * (by default, it is the host name and process id) */ virtual void setUniqueNameRoot(const std::string &uniqueNameRoot) =0; /** get the unique name root used for fully qualified name generation * (by default, it is the host name and process id) */ virtual const std::string &getUniqueNameRoot() =0; /** Load a module library. * Module library are dll or so files that contains * one or more module implementation. * Loading the library add the modules to the module * factory. * If the library can be loaded, the method return true, false otherwise. * * The library name is the base name that will be 'decorated' * with the nel naming standard according to compilation mode * and platform specific file extension (.dll or .so). * * A module library can only be loaded once. If the library * is already loaded, the call is ingored. */ virtual bool loadModuleLibrary(const std::string &libraryName) =0; /** Unload a module library. * Any module that come from the unloaded library * are immediately deleted. * If the specified library is not loaded, the * call is ignored. */ virtual bool unloadModuleLibrary(const std::string &libraryName) =0; /** Unregister a module factory */ virtual void unregisterModuleFactory(class IModuleFactory *moduleFactory) =0; /** Fill the vector with the list of available module. * Note that the vector is not cleared before being filled. */ virtual void getAvailableModuleClassList(std::vector &moduleClassList) =0; /** Create a new module instance. * The method create a module of the specified class with the * specified local name. * The class MUST be available in the factory and the * name MUST be unique OR empty. * If the name is empty, the method generate a name using * the module class and a number. * If the module class could not be found, NULL is returned. * If the module fail to initialize properly, then it * deleted and NULL is returned. */ virtual IModule *createModule(const std::string &className, const std::string &localName, const std::string ¶mString) =0; /** Delete a module instance. * This is the only mean to delete a module instance. */ virtual void deleteModule(IModule *module) =0; /** Lookup in the created module for a module having the * specified local name. * Return NULL if not found. */ virtual IModule *getLocalModule(const std::string &moduleName) =0; /** Call this method to update all module instances. * If the application is a NeL service, then this method * is automaticly called in the service main loop. * If the application is a regular one, then you * have to call manually this method regularly * to update the modules. */ virtual void updateModules() =0; /** Lookup in the created socket for a socket having the * specified local name. */ virtual IModuleSocket *getModuleSocket(const std::string &socketName) =0; /** Register a socket in the manager. * TODO : make this method only available to CModuleSocket to prevent dramatic ERROR */ virtual void registerModuleSocket(IModuleSocket *moduleSocket) =0; /** UrRegister a socket in the manager. * TODO : make this method only available to CModuleSocket to prevent dramatic ERROR */ virtual void unregisterModuleSocket(IModuleSocket *moduleSocket) =0; /** Lookup in the created gateway for a gateway having the * specified local name. */ virtual IModuleGateway *getModuleGateway(const std::string &gatewayName) =0; /** Register a gateway in the manager. */ virtual void registerModuleGateway(IModuleGateway *moduleGateway) =0; /** UrRegister a socket in the manager. */ virtual void unregisterModuleGateway(IModuleGateway *moduleGateway) =0; /** Get a module proxy with the module proxy ID */ virtual TModuleProxyPtr getModuleProxy(TModuleId moduleProxyId) =0; /** Called by the gateway module to create new module proxy * Module proxy are an easy way for implementor to send * message to a module, without having to retrieve * the gateway that discovered the destination module. * When module are created and plugged on a gateway, * the gateway automaticly create a proxy * for each local module and each foreing module. */ virtual IModuleProxy *createModuleProxy( IModuleGateway *gateway, CGatewayRoute *route, uint32 distance, IModule *localModule, const std::string &moduleClassName, const std::string &moduleFullyQualifiedName, const std::string &moduleManifest, // const TModuleGatewayProxyPtr &foreignGateway, TModuleId foreignModuleId) =0; virtual void releaseModuleProxy(TModuleId moduleProxyId) =0; virtual uint32 getNbModule() =0; virtual uint32 getNbModuleProxy() =0; }; typedef NLMISC::CFactoryIndirect TLocalModuleFactoryRegistry; /** Class for pure NeL module library */ class CNelModuleLibrary : public NLMISC::INelLibrary { public: /** Return the local module factory.*/ virtual TLocalModuleFactoryRegistry &getLocalModuleFactoryRegistry() { return TLocalModuleFactoryRegistry::instance(); } virtual void onLibraryLoaded(bool /* firstTime */) {} virtual void onLibraryUnloaded(bool /* lastTime */) {} }; } // namespace NLNET #endif // MODULE_MANAGER_H ================================================ FILE: code/nel/include/nel/net/module_message.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_MODULE_MESSAGE_H #define NL_MODULE_MESSAGE_H #include "nel/misc/enum_bitset.h" #include "nel/net/message.h" #include "module_common.h" namespace NLNET { /** Module message header coder/decoder * Codec for module message header data. */ class CModuleMessageHeaderCodec { public: enum TMessageType { /// Standard one way message mt_oneway, /// Two way request mt_twoway_request, /// Two way response mt_twoway_response, /// A special checking value mt_num_types, /// invalid flag mt_invalid = mt_num_types }; static void encode(CMessage &headerMessage, TMessageType msgType, TModuleId senderProxyId, TModuleId addresseeProxyId) { serial(headerMessage, msgType, senderProxyId, addresseeProxyId); } static void decode(const CMessage &headerMessage, TMessageType &msgType, TModuleId &senderProxyId, TModuleId &addresseeProxyId) { serial(const_cast(headerMessage), msgType, senderProxyId, addresseeProxyId); } private: static void serial(CMessage &headerMessage, TMessageType &msgType, TModuleId &senderProxyId, TModuleId &addresseeProxyId) { uint8 mt; if (headerMessage.isReading()) { headerMessage.serial(mt); msgType = CModuleMessageHeaderCodec::TMessageType(mt); } else { mt = uint8(msgType); headerMessage.serial(mt); } headerMessage.serial(senderProxyId); headerMessage.serial(addresseeProxyId); } }; /** An utility struct to serial binary buffer. * WARNING : you must be aware that using binary buffer serialisation * is not fair with the portability and endiennes problem. * Use it ONLY when you now what you are doing and when * bytes ordering is not an issue. */ struct TBinBuffer { private: uint8 *_Buffer; uint32 _BufferSize; mutable bool _Owner; public: /// default constructor, used to read in stream TBinBuffer() : _Buffer(NULL), _BufferSize(0), _Owner(true) { } TBinBuffer(const uint8 *buffer, uint32 bufferSize) : _Buffer(const_cast(buffer)), _BufferSize(bufferSize), _Owner(false) { } // copy constructor transfere ownership of the buffer (if it is owned) TBinBuffer(const TBinBuffer &other) : _Buffer(other._Buffer), _BufferSize(other._BufferSize), _Owner(other._Owner) { // remove owning on source other._Owner = false; } ~TBinBuffer() { if (_Owner && _Buffer != NULL) delete _Buffer; } void serial(NLMISC::IStream &s) { if (s.isReading()) { nlassert(_Buffer == NULL); s.serial(_BufferSize); _Buffer = new uint8[_BufferSize]; s.serialBuffer(_Buffer, _BufferSize); } else { s.serialBufferWithSize(_Buffer, _BufferSize); } } uint32 getBufferSize() const { return _BufferSize; } uint8 *getBuffer() const { return _Buffer; } /** Release the buffer by returning the pointer to the caller. * The caller is now owner and responsible of the allocated * buffer. */ uint8 *release() { nlassert(_Owner); _Owner = false; return _Buffer; } }; } // namespace NLNET #endif // NL_MODULE_MESSAGE_H ================================================ FILE: code/nel/include/nel/net/module_socket.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_FILE_MODULE_SOCKET_H #define NL_FILE_MODULE_SOCKET_H #include "nel/net/message.h" #include "module_common.h" namespace NLNET { class IModuleSocket { public: virtual ~IModuleSocket() {} /** Register the socket in the module manager socket registry */ virtual void registerSocket() =0; /** Unregister the socket in the module manager socket registry */ virtual void unregisterSocket() =0; /** Ask derived class to obtain the socket name. */ virtual const std::string &getSocketName() =0; /** A plugged module send a message to another module. * If the destination module is not accessible through this socket, * an exception is thrown. */ virtual void sendModuleMessage(IModule *senderModule, TModuleId destModuleProxyId, const NLNET::CMessage &message ) throw (EModuleNotPluggedHere) =0; /** A plugged module send a message to all the module reachable * with this socket. */ virtual void broadcastModuleMessage(IModule *senderModule, const NLNET::CMessage &message) throw (EModuleNotPluggedHere) =0; /** Fill the resultList with the list of module that are * reachable with this socket. * Note that the result vector is not cleared before filling. */ virtual void getModuleList(std::vector &resultList) =0; //@name Callback for socket implementation //@{ /// Called just after a module is plugged in the socket. virtual void onModulePlugged(IModule *pluggedModule) =0; /// Called just before a module is unplugged from the socket. virtual void onModuleUnplugged(IModule *unpluggedModule) =0; //@} }; // const TModuleSocketPtr NullModuleSocket; /** A base class for socket. * It provide plugged module management to * implementors. */ class CModuleSocket : public IModuleSocket { protected: typedef NLMISC::CTwinMap TPluggedModules; /// The list of plugged modules TPluggedModules _PluggedModules; bool _SocketRegistered; friend class CModuleBase; CModuleSocket(); ~CModuleSocket(); virtual void registerSocket(); virtual void unregisterSocket(); virtual void _onModulePlugged(const TModulePtr &pluggedModule); virtual void _onModuleUnplugged(const TModulePtr &pluggedModule); virtual void _sendModuleMessage(IModule *senderModule, TModuleId destModuleProxyId, const NLNET::CMessage &message ) throw (EModuleNotPluggedHere, NLNET::EModuleNotReachable) =0; virtual void _broadcastModuleMessage(IModule *senderModule, const NLNET::CMessage &message) throw (EModuleNotPluggedHere) =0; virtual void sendModuleMessage(IModule *senderModule, TModuleId destModuleProxyId, const NLNET::CMessage &message ) throw (EModuleNotPluggedHere); /** A plugged module send a message to all the module reachable * with this socket. */ virtual void broadcastModuleMessage(IModule *senderModule, const NLNET::CMessage &message) throw (EModuleNotPluggedHere); }; } // namespace NLNET #endif // NL_FILE_MODULE_SOCKET_H ================================================ FILE: code/nel/include/nel/net/naming_client.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_NAMING_CLIENT_H #define NL_NAMING_CLIENT_H #include "nel/misc/types_nl.h" #include #include "nel/misc/mutex.h" #include "inet_address.h" #include "callback_client.h" #include "service.h" namespace NLNET { //typedef uint16 TServiceId; typedef void (*TBroadcastCallback)(const std::string &name, TServiceId sid, const std::vector &addr); /** * Client side of Naming Service. Allows to register/unregister services, and to lookup for * a registered service. * * \warning the Naming Service can be down, it will reconnect when up but if other services try to register during the * NS is offline, it will cause bug * * \author Olivier Cado * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CNamingClient { public: struct CServiceEntry { CServiceEntry (std::string n, TServiceId s, std::vector a) : Name(n), SId (s), Addr(a), RunningState(ServiceOnline) { } // name of the service std::string Name; // id of the service TServiceId SId; // address to send to the service who wants to lookup this service (could have more than one) std::vector Addr; TServiceRunningState RunningState; }; public: /// Connect to the naming service. static void connect( const CInetAddress& addr, CCallbackNetBase::TRecordingState rec, const std::vector &addresses ); /// Return true if the connection to the Naming Service was done. static bool connected () { return _Connection != NULL && _Connection->connected (); } /// Close the connection to the naming service. static void disconnect (); /// Returns information about the naming connection (connected or not, which naming service and so on) static std::string info (); /** Register a service within the naming service. * Returns false if the registration failed. */ static bool registerService (const std::string &name, const std::vector &addr, TServiceId &sid); /** Register a service within the naming service, using a specified service identifier. * Returns false if the service identifier is unavailable i.e. the registration failed. */ static bool registerServiceWithSId (const std::string &name, const std::vector &addr, TServiceId sid); /** If the NS is down and goes up, we have to send it again the registration. But in this case, the NS * must not send a registration broadcast, so we have a special message */ static void resendRegisteration (const std::string &name, const std::vector &addr, TServiceId sid); /// Unregister a service from the naming service, service identifier. static void unregisterService (TServiceId sid); /// Unregister all services registered by this client. You don't have to static void unregisterAllServices (); /** Requests the naming service to choose a port for the service * \return An empty port number */ static uint16 queryServicePort (); /** Returns true and the address of the specified service if it is found, otherwise returns false * \param name [in] Short name of the service to find * \param addr [out] Address of the service * \param validitytime [out] After this number of seconds are elapsed, another lookup will be necessary * before sending a message to the service * \return true if all worked fine */ static bool lookup (const std::string &name, CInetAddress &addr); /// Same as lookup(const string&, CInetAddress&, uint16&) static bool lookup (TServiceId sid, CInetAddress &addr); /** Tells the Naming Service the specified address does not respond for the specified service, * and returns true and another address for the service if available, otherwise returns false * \param name [in] Short name of the service to find * \param addr [in/out] In: Address of the service that does not respond. Out: Alternative address * \param validitytime [out] After this number of seconds are elapsed, another lookup will be necessary * before sending a message to the service * \return true if all worked fine. */ static bool lookupAlternate (const std::string& name, CInetAddress& addr); /** * Returns all services corresponding to the specified short name. * Ex: lookupAll ("AS", addresses); */ static void lookupAll (const std::string &name, std::vector &addresses); /** * Returns all registered services. */ static const std::list &getRegisteredServices() { return RegisteredServices; } /** Obtains a socket connected to a service providing the service \e name. * In case of failure to connect, the method informs the Naming Service and tries to get another service. * \param name [in] Short name of the service to find and connected * \param sock [out] The connected socket. * \param validitytime [out] After this number of seconds are elapsed, another lookup will be necessary * before sending a message to the service. * \return false if the service was not found. */ static bool lookupAndConnect (const std::string &name, CCallbackClient &sock); /// Call it evenly static void update (); /// You can link a callback if you want to know when a new service is registered (NULL to disable callback) static void setRegistrationBroadcastCallback (TBroadcastCallback cb); /// You can link a callback if you want to know when a new service is unregistered (NULL to disable callback) static void setUnregistrationBroadcastCallback (TBroadcastCallback cb); static void displayRegisteredServices (NLMISC::CLog *log = NLMISC::DebugLog) { RegisteredServicesMutex.enter (); log->displayNL ("Display the %d registered services :", RegisteredServices.size()); for (std::list::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) { log->displayNL (" > %s-%hu %d addr", (*it).Name.c_str(), (*it).SId.get(), (*it).Addr.size()); for(uint i = 0; i < (*it).Addr.size(); i++) log->displayNL (" '%s'", (*it).Addr[i].asString().c_str()); } log->displayNL ("End of the list"); RegisteredServicesMutex.leave (); } static void SelfCanAccess (); static bool IsCanAccess( std::vector& service_names ); private: static CCallbackClient *_Connection; // The service Id of this service static TServiceId _MySId; /// Type of map of registered services typedef std::map TRegServices; // this container contains the server that *this* service have registered (often, there's only one) static TRegServices _RegisteredServices; /// Constructor CNamingClient() {} /// Destructor ~CNamingClient() {} static void doReceiveLookupAnswer (const std::string &name, std::vector &addrs); // This container contains the list of other registered services on the shard static std::list RegisteredServices; static NLMISC::CMutex RegisteredServicesMutex; static void find (const std::string &name, std::vector &addrs) { RegisteredServicesMutex.enter (); for (std::list::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) if (name == (*it).Name) addrs.push_back ((*it).Addr[0]); RegisteredServicesMutex.leave (); } static void find (TServiceId sid, std::vector &addrs) { RegisteredServicesMutex.enter (); for (std::list::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++) if (sid == (*it).SId) addrs.push_back ((*it).Addr[0]); RegisteredServicesMutex.leave (); } friend void cbRegisterBroadcast (CMessage &msgin, TSockId from, CCallbackNetBase &netbase); friend void cbUnregisterBroadcast (CMessage &msgin, TSockId from, CCallbackNetBase &netbase); friend void cbUpdateServiceState (CMessage &msgin, TSockId from, CCallbackNetBase &netbase); }; } // NLNET #endif // NL_NAMING_CLIENT_H /* End of naming_client.h */ ================================================ FILE: code/nel/include/nel/net/net_displayer.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_NET_DISPLAYER_H #define NL_NET_DISPLAYER_H #include "nel/misc/log.h" #include "nel/misc/displayer.h" #include "callback_client.h" namespace NLNET { /** * Net Displayer. Sends the strings to a logger server (LOGS). * \ref log_howto * \bug When nlerror is called in a catch block, a connected NetDisplayer becomes an IDisplayer => pure virtual call * \author Olivier Cado * \author Nevrax France * \date 2000 */ class CNetDisplayer : public NLMISC::IDisplayer { public: /// Constructor CNetDisplayer(bool autoConnect = true); /** Sets logging server address. Call this method from outside only if you want to use a LOGS not registered within the NS. * It does nothing if the displayer is already connected to a server. */ void setLogServer( const CInetAddress& logServerAddr ); /** Sets logging server with an already connected server. */ void setLogServer( CCallbackClient *server ); /// Returns true if the displayer is connected to a Logging Service. bool connected () { return _Server->connected(); } /// Destructor virtual ~CNetDisplayer(); protected: /** Sends the string to the logging server * \warning If not connected, tries to connect to the logging server each call. It can slow down your program a lot. */ virtual void doDisplay ( const NLMISC::CLog::TDisplayInfo& args, const char *message); /// Find the server (using the NS) and connect void findAndConnect(); private: CInetAddress _ServerAddr; // CCallbackClient _Server; CCallbackClient *_Server; bool _ServerAllocated; // uint32 _ServerNumber; }; } // NLNET #endif // NL_NET_DISPLAYER_H /* End of net_displayer.h */ ================================================ FILE: code/nel/include/nel/net/net_log.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_NET_LOG_H #define NL_NET_LOG_H #include "nel/misc/types_nl.h" #include "nel/misc/log.h" #include "nel/misc/variable.h" namespace NLNET { // // Macros // // The following macros are here to allow logs generated by networking code to be enabled and dissabled #define LNETL0_INFO if (!VerboseLNETL0.get()) {} else nlinfo #define LNETL1_INFO if (!VerboseLNETL1.get()) {} else nlinfo #define LNETL2_INFO if (!VerboseLNETL2.get()) {} else nlinfo #define LNETL3_INFO if (!VerboseLNETL3.get()) {} else nlinfo #define LNETL4_INFO if (!VerboseLNETL4.get()) {} else nlinfo #define LNETL5_INFO if (!VerboseLNETL5.get()) {} else nlinfo #define LNETL6_INFO if (!VerboseLNETL6.get()) {} else nlinfo #define LNETL0_DEBUG if (!VerboseLNETL0.get()) {} else nldebug #define LNETL1_DEBUG if (!VerboseLNETL1.get()) {} else nldebug #define LNETL2_DEBUG if (!VerboseLNETL2.get()) {} else nldebug #define LNETL3_DEBUG if (!VerboseLNETL3.get()) {} else nldebug #define LNETL4_DEBUG if (!VerboseLNETL4.get()) {} else nldebug #define LNETL5_DEBUG if (!VerboseLNETL5.get()) {} else nldebug #define LNETL6_DEBUG if (!VerboseLNETL6.get()) {} else nldebug extern NLMISC::CVariable VerboseLNETL0; extern NLMISC::CVariable VerboseLNETL1; extern NLMISC::CVariable VerboseLNETL2; extern NLMISC::CVariable VerboseLNETL3; extern NLMISC::CVariable VerboseLNETL4; extern NLMISC::CVariable VerboseLNETL5; extern NLMISC::CVariable VerboseLNETL6; /************************************************************************** ********************* THIS CLASS IS DEPRECATED **************************** **************************************************************************/ /** * Logger for network transfers * \author Olivier Cado * \author Nevrax France * \date 2000 */ class CNetLog : public NLMISC::CLog { public: /// Constructor CNetLog(); /// Sets the name of the running service void setServiceName( const char *name ); /// Log an output transfer (send) void output( const char *srchost, uint8 msgnum, const char *desthost, const char *msgname, uint32 msgsize ); /// Log an input transfer (receive) void input( const char *srchost, uint8 msgnum, const char *desthost ); /*/// Enables or disable logging. void setLogging( bool logging ) { _Logging = logging; }*/ private: std::string _ProcessId; }; extern CNetLog NetLog; #define nlsetnet (servicename,displayer) #define nlnetoutput NetLog.output #define nlnetinput NetLog.input } // NLNET #endif // NL_NET_LOG_H /* End of net_log.h */ ================================================ FILE: code/nel/include/nel/net/net_manager.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /************************************************************************** ********************* THIS CLASS IS DEPRECATED **************************** **************************************************************************/ #ifdef NL_OS_WINDOWS # pragma message(NL_LOC_WRN "You are using a deprecated feature of NeL, consider rewriting your code with replacement feature") #else // NL_OS_UNIX # warning "You are using a deprecated feature of NeL, consider rewriting your code with replacement feature" #endif #ifndef NL_NET_MANAGER_H #define NL_NET_MANAGER_H #include "nel/misc/types_nl.h" #include #include #include #include "nel/misc/time_nl.h" #include "nel/misc/string_id_array.h" #include "callback_net_base.h" #include "naming_client.h" namespace NLNET { /// Callback function type for message processing typedef void (*TNetManagerCallback) (const std::string &serviceName, TSockId from, void *arg); /** Structure used in the second part of the map * If you add a client with his service name, the Name is the service name and ServiceNames is empty. * If you add a client with his ip, Name is the fake service name and ServiceNames[0] is the ip. * If you add a group (of client), Name is the name of the group and ServiceNames is names of all services in the group. * If you add a server, Name is the service name of the server and ServiceNames is empty. */ struct CBaseStruct { CBaseStruct (const std::string &sn) : Name(sn), ConnectionCallback(NULL), ConnectionCbArg(NULL), DisconnectionCallback(NULL), DisconnectionCbArg(NULL), Type(Unknown) { } /// the name used by all function to retrieve a service (in the case of group or ip, this name is a virtual /// name used only to find it to perform action on it std::string Name; enum TBaseStructType { Unknown, Client, ClientWithAddr, Group, Server }; std::vector ServiceNames; /// It could have more than one connection, in this case, the vector contains all connections std::vector NetBase; TNetManagerCallback ConnectionCallback; void *ConnectionCbArg; TNetManagerCallback DisconnectionCallback; void *DisconnectionCbArg; // autoretry is used only when Type is ClientWithAddr. If true, the CNetManager will retry to reconnect if it lost the connection bool AutoRetry; TBaseStructType Type; }; /** * Layer 4 * * In case of addGroup(), messages are *not* associate with id, so the message type is always sent with string. * * \author Vianney Lecroart * \author Nevrax France * \date 2001 */ class CNetManager { public: /** Creates the connection to the Naming Service. * If the connection failed, ESocketConnectionFailed exception is generated. */ static void init (const CInetAddress *addr, CCallbackNetBase::TRecordingState rec ); static void release (); /** Sets up a server on a specific port with a specific service name (create a listen socket, register to naming service and so on) * If servicePort is 0, it will be dynamically determinated by the Naming Service. * If sid id 0, the service id will be dynamically determinated by the Naming Service. */ static void addServer (const std::string &serviceName, uint16 servicePort = 0, bool external = false); static void addServer (const std::string &serviceName, uint16 servicePort, NLNET::TServiceId &sid, bool external = false); /// Creates a connection to a specific IP and associate it this a "fake" serviceName (to enable you to send data for example) static void addClient (const std::string &serviceName, const std::string &addr, bool autoRetry = true); /// Creates a connection to a service using the naming service and the serviceName static void addClient (const std::string &serviceName); /// Creates connections to a group of service static void addGroup (const std::string &groupName, const std::string &serviceName); /// Adds a callback array to a specific service connection. You can add callback only *after* adding the server, the client or the group static void addCallbackArray (const std::string &serviceName, const TCallbackItem *callbackarray, NLMISC::CStringIdArray::TStringId arraysize); /** Call it evenly. the parameter select the timeout value in milliseconds for each update. You are absolutely certain that this * function will not be returns before this amount of time you set. * If you set the update timeout value higher than 0, all messages in queues will be process until the time is greater than the timeout user update(). * If you set the update timeout value to 0, all messages in queues will be process one time before calling the user update(). In this case, we don't nlSleep(1). */ static void update (NLMISC::TTime timeout = 0); /// Sends a message to a specific serviceName static void send (const std::string &serviceName, const CMessage &buffer, TSockId hostid = InvalidSockId); /** Sets callback for incoming connections (or NULL to disable callback) * On a client, the callback will be call when the connection to the server is established (the first connection or after the server shutdown and started) * On a server, the callback is called each time a new client is connected to him */ static void setConnectionCallback (const std::string &serviceName, TNetManagerCallback cb, void *arg); /** Sets callback for disconnections (or NULL to disable callback) On a client, the callback will be call each time the connection to the server is lost On a server, the callback is called each time a client is disconnected */ static void setDisconnectionCallback (const std::string &serviceName, TNetManagerCallback cb, void *arg); /// Returns the connection if you want to do specific calls static CCallbackNetBase *getNetBase (const std::string &serviceName); static void setUpdateTimeout (uint32 timeout); static void createConnection(CBaseStruct &Base, const CInetAddress &Addr, const std::string& name); static uint64 getBytesSent (); static uint64 getBytesReceived (); static uint64 getReceiveQueueSize (); static uint64 getSendQueueSize (); private: typedef std::map TBaseMap; typedef TBaseMap::iterator ItBaseMap; // Contains all the connections (client and server) static TBaseMap _BaseMap; static CCallbackNetBase::TRecordingState _RecordingState; // used to synchonize the timeout in the update function static NLMISC::TTime _NextUpdateTime; // Finds the service or add it if not found static ItBaseMap find (const std::string &serviceName); friend void RegistrationBroadcast (const std::string &name, TServiceId sid, const std::vector &addr); // It's a static class, you can't instanciate it CNetManager() { } }; } // NLNET #endif // NL_NET_MANAGER_H /* End of net_manager.h */ ================================================ FILE: code/nel/include/nel/net/pacs_client.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_PACS_CLIENT_H #define NL_PACS_CLIENT_H #include "stdnet.h" #include "inet_address.h" #include "callback_client.h" #include "naming_client.h" #include "nel/pacs/u_move_primitive.h" #include "nel/pacs/u_collision_desc.h" #define NLNET_PACS_PROTOCOL_VERSION 1 namespace NLNET { TCallbackItem PacsCallbackArray[]; /** * Client side of Pacs Service. Allows to use PACS functionnality by the networtk. * * \author Cyril 'Hulud' Corvazier * \author Nevrax France * \date 2001 */ class CPacsClient { friend void cbPacsAnswer (CMessage &msgin, TSockId from, CCallbackNetBase &netbase); public: /// Constructor CPacsClient() { // No connexion _Server=NULL; } ~CPacsClient() { disconnect (); } bool connect (); void disconnect () { if (_Server) { _Server->disconnect (); delete _Server; } } /** * Prepare a new message * * You must call this method before do anything before sending the message. */ void initMessage () { _Message.clear (); _Message.setType ("PACS"); _Message.serialCheck ((uint32)NLNET_PACS_PROTOCOL_VERSION); } /** * Send the message * * You must call this method after initMessage and others calls to setup methods. */ void sendMessage () { // Checks nlassert (_Server); // Close the message bool nlFalse=false; _Message.serial (nlFalse); // Send the message _Server->send (_Message); } /** * Update method. Should be called evenly. */ void update () { // Checks nlassert (_Server); _Server->update (); } /// \name Global retriever methods /** * Make a raytrace test on the service. * * The service will answer this message with a rayTestCallback message. * * \param p0 is the first point of the ray. * \param p1 is the second point of the ray. * \param testId is the id of the test. */ void rayTest (double p0, double p1, uint32 testId) { // Append to the current message std::string name="RY"; bool nlTrue=true; _Message.serial (nlTrue, name, p0, p1, testId); } /// \name Move container methods /** * Add a primitive in the service. Set the new primitive as current. * * No answer will be send by the service. * * \param id is the ID to attach to the new primitive. */ void addPrimitive (NLPACS::UMovePrimitive::TUserData id) { // Append to the current message std::string name="AD"; bool nlTrue=true; _Message.serial (nlTrue, name, id); } /** * Remove a primitive from the service. * * No answer will be send by the service. * * \param id is the ID attach to the primitive to remove. */ void removePrimitive (NLPACS::UMovePrimitive::TUserData id) { // Append to the current message std::string name="RV"; bool nlTrue=true; _Message.serial (nlTrue, name, id); } /** * Evaluate the collision on the servive. * * The service will answer this message with a triggerCallback message. * * \param evalId is the id of the evaluation. * \param deltaTime is the delta time used to evaluate the system. */ void evalCollision (uint32 evalId, double deltaTime) { // Append to the current message std::string name="EV"; bool nlTrue=true; _Message.serial (nlTrue, name, evalId, deltaTime); } /** * Test a move of a primitive on the service. * * The service will answer this message with a testMoveCallback message. * * \param id is the id of the primitive to test a move. * \param speed is the speed of the primitive during its move. * \param deltaTime is the time interval of the move to test. */ void testMove (NLPACS::UMovePrimitive::TUserData id, const NLMISC::CVectorD& speed, double deltaTime) { // Append to the current message std::string name="TS"; bool nlTrue=true; _Message.serial (nlTrue, name, id, const_cast (speed), deltaTime); } /// \name Primitives methods /** * Set the current primitive on the service. The primitive stay current * for the current message. * * No answer will be send by the service. * * \param id is the id of the current primitive to use. */ void setCurrentPrimitive (NLPACS::UMovePrimitive::TUserData id) { // Append to the current message std::string name="CU"; bool nlTrue=true; _Message.serial (nlTrue, name, id); } /** * Set the type of the current primitive on the service. * * No answer will be send by the service. * * \param type is the new type for the primitive on the service. */ void setPrimitiveType (NLPACS::UMovePrimitive::TType type) { // Append to the current message std::string name="TY"; uint32 t=(uint32)type; bool nlTrue=true; _Message.serial (nlTrue, name, t); } /** * Set the reaction type of the current primitive on the service. * * No answer will be send by the service. * * \param type is the newreaction type for the primitive on the service. */ void setReactionType (NLPACS::UMovePrimitive::TReaction type) { // Append to the current message std::string name="RT"; uint32 t=(uint32)type; bool nlTrue=true; _Message.serial (nlTrue, name, t); } /** * Set the trigger type of the current primitive on the service. * * No answer will be send by the service. * * \param type is the new trigger type for the primitive on the service. */ void setTriggerType (NLPACS::UMovePrimitive::TTrigger type) { // Append to the current message std::string name="TT"; uint32 t=(uint32)type; bool nlTrue=true; _Message.serial (nlTrue, name, t); } /** * Set the collision mask of the current primitive on the service. * * No answer will be send by the service. * * \param mask is the new collision mask for the primitive on the service. */ void setCollisionMask (NLPACS::UMovePrimitive::TCollisionMask mask) { // Append to the current message std::string name="CT"; bool nlTrue=true; _Message.serial (nlTrue, name, mask); } /** * Set the occlusion mask of the current primitive on the service. * * No answer will be send by the service. * * \param mask is the new occlusion mask for the primitive on the service. */ void setOcclusionMask (NLPACS::UMovePrimitive::TCollisionMask mask) { // Append to the current message std::string name="OT"; bool nlTrue=true; _Message.serial (nlTrue, name, mask); } /** * Set the obstacle flag of the current primitive on the service. * * No answer will be send by the service. * * \param obstacle is the new obstacle flag for the primitive on the service. */ void setObstacle (bool obstacle) { // Append to the current message std::string name="OB"; bool nlTrue=true; _Message.serial (nlTrue, name, obstacle); } /** * Set the orientation the current primitive on the service. * * No answer will be send by the service. * * \param orientation is the new orientation for the primitive on the service. */ void setOrientation (double orientation) { // Append to the current message std::string name="OR"; bool nlTrue=true; _Message.serial (nlTrue, name, orientation); } /** * Set the attenuation factor of the current primitive on the service. * * No answer will be send by the service. * * \param absorption is the new attenuation factor for the primitive on the service. */ void setAbsorption (float absorption) { // Append to the current message std::string name="AB"; bool nlTrue=true; _Message.serial (nlTrue, name, absorption); } /** * Set the size of the current primitive on the service. Only for boxes primitives. * * No answer will be send by the service. * * \param width is the new size on X axis factor for the primitive on the service. * \param depth is the new size on Y axis factor for the primitive on the service. */ void setSize (float width, float depth) { // Append to the current message std::string name="SZ"; bool nlTrue=true; _Message.serial (nlTrue, name, width, depth); } /** * Set the height of the current primitive on the service. For boxes and cylinders primitives. * * No answer will be send by the service. * * \param height is the new size on Z axis factor for the primitive on the service. */ void setHeight (float height) { // Append to the current message std::string name="HE"; bool nlTrue=true; _Message.serial (nlTrue, name, height); } /** * Set the radius of the current primitive on the service. For cylinders primitives. * * No answer will be send by the service. * * \param height is the new size on Z axis factor for the primitive on the service. */ void setRadius (float radius) { // Append to the current message std::string name="RD"; bool nlTrue=true; _Message.serial (nlTrue, name, radius); } /** * Make the current primitive a global move. This move is slow. * Use it only for the first placement and for teleporting. * * No answer will be send by the service. * * \param position is the new position for the primitive on the service. */ void globalMove (const NLMISC::CVectorD& position) { // Append to the current message std::string name="GM"; bool nlTrue=true; _Message.serial (nlTrue, name, const_cast (position)); } /** * Make the current primitive a relative move. This move is fast. * Use it for current move. Make first a relative move of all your * primitives, then put a evalCollision message. Then you can * query position and speed by posting getPositionSpeed message. * * No answer will be send by the service. * * \param position is the new position for the primitive on the service. */ void relativeMove (const NLMISC::CVectorD& speed) { // Append to the current message std::string name="RM"; bool nlTrue=true; _Message.serial (nlTrue, name, const_cast (speed)); } /** * Query the position and the speed of the primitive after an evalCollision message. * * The service will answer with a getPositionSpeedCallback message. * * \param id is the id of the primitive to get the position and the speed. */ void getPositionSpeed (NLPACS::UMovePrimitive::TUserData id) { // Append to the current message std::string name="PS"; bool nlTrue=true; _Message.serial (nlTrue, name, id); } protected: /// \name Callbacks /** * This call back is called when a message is coming. Used for synchronisation. */ virtual void messageCallback () {} /** * This message is send by the service to answer the rayTest request. * * \param testId is the test ID passed to rayTest(). * \param testResult is false if the ray is not clipped, else true. */ virtual void rayTestCallback (uint32 testId, bool testResult) {} /** * This message is send by the service to answer the evalCollision request. * * \param evalId is the id of the evaluation passed to evalCollision. * \param triggerInfo is an array of trigger descriptor. Each entry of the array is * a new trigger raised by evalCollision. */ virtual void triggerCallback (uint32 evalId, const std::vector& triggerInfo) {} /** * This message is send by the service to answer the testMove request. * * \param id is the id of the primitive tested. * \param testResult is true if the primitive can do that move, else false. */ virtual void testMoveCallback (NLPACS::UMovePrimitive::TUserData id, bool testResult) {} /** * This message is send by the service to answer the getPositionSpeed request. * * \param id is the id of the primitive. * \param position is the new position of the primitive. * \param speed is the new speed of the primitive. */ virtual void getPositionSpeedCallback (NLPACS::UMovePrimitive::TUserData id, const NLMISC::CVectorD &position, const NLMISC::CVectorD &speed) {} private: CCallbackClient *_Server; CMessage _Message; }; // Callback to listen to the server static void cbPacsAnswer (CMessage &msgin, TSockId from, CCallbackNetBase &netbase) { // Get the client pointer CPacsClient *client=(CPacsClient*)(uint)from->appId (); // Check stream msgin.serialCheck ((uint32)NLNET_PACS_PROTOCOL_VERSION); // Message callback client->messageCallback (); bool again; msgin.serial (again); while (again) { // Read the message sub string std::string subMessage; msgin.serial (subMessage); // This code can work only if sizeof (uint) == sizeof (void*) nlassert (sizeof (uint)==sizeof (void*)); // Raytrace callback ? if (subMessage=="RY") { // Read test id and test result uint32 testId; bool testResult; msgin.serial (testId, testResult); // Call the callback client->rayTestCallback (testId, testResult); } // Trigger callback ? else if (subMessage=="TR") { // Read eval id and trigger info uint32 evalId; std::vector triggerInfo; msgin.serial (evalId); msgin.serialCont (triggerInfo); // Call the callback client->triggerCallback (evalId, triggerInfo); } // Test move callback ? else if (subMessage=="TM") { // Read the primitive id and test result NLPACS::UMovePrimitive::TUserData id; bool testResult; msgin.serial (id, testResult); // Call the callback client->testMoveCallback (id, testResult); } // Test move callback ? else if (subMessage=="PS") { // Read the primitive id and test result NLPACS::UMovePrimitive::TUserData id; NLMISC::CVectorD position; NLMISC::CVectorD speed; msgin.serial (id, position, speed); // Call the callback client->getPositionSpeedCallback (id, position, speed); } else NLMISC::nlError ("Pacs client: unkown sub message string"); // Next message ? msgin.serial (again); } } static TCallbackItem PacsCallbackArray[] = { { "PACS_ASW", cbPacsAnswer } }; inline bool CPacsClient::connect () { // Create a connexion _Server = new CCallbackClient; // Look up for PACS service CNamingClient::lookupAndConnect ("PS", *_Server); if (_Server->connected()) { // Add callback array _Server->addCallbackArray (PacsCallbackArray, sizeof (PacsCallbackArray) / sizeof (PacsCallbackArray[0])); // This code can work only if sizeof (uint) == sizeof (void*) nlassert (sizeof (uint)==sizeof (void*)); _Server->id ()->setAppId ((uint64)(uint)this); // Return ok return true; } else { return false; } } } // NLNET #endif // NL_PACS_CLIENT_H /* End of pacs_client.h */ ================================================ FILE: code/nel/include/nel/net/service.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_SERVICE_H #define NL_SERVICE_H // // Includes // #include "nel/misc/types_nl.h" #include "nel/misc/config_file.h" #include "nel/misc/entity_id.h" #include "nel/misc/variable.h" #include "nel/misc/command.h" #include "nel/misc/entity_id.h" #include "nel/misc/cpu_time_stat.h" #include "nel/misc/sstring.h" #include "unified_network.h" #include #include namespace NLMISC { class CWindowDisplayer; } #if defined(NL_OS_WINDOWS) && defined(_WINDOWS) #ifndef WINAPI #define WINAPI __stdcall #endif #ifndef APIENTRY #define APIENTRY WINAPI #endif struct HINSTANCE__; typedef struct HINSTANCE__ *HINSTANCE; typedef char CHAR; typedef CHAR *LPSTR; #endif namespace NLNET { class CCallbackServer; class IServiceUpdatable; enum TServiceRunningState { ServiceClose, ServiceOnline, ServiceCanAccess, }; // // Macros // /** * The goal of this macro is to simplify the service creation, it creates the main body function. * * If you don't want to give a callback array, just put EmptyCallbackArray in the last argument * * Example: *\code // Create the Test Service class class CTestService : public IService { public: void init () { nlinfo("init()"); } bool update () { nlinfo ("update();"); return true; } void release () { nlinfo("release()"); } }; // Create the main() function that create a test service instance and execute it. // "TS" is the short service name and "test_service" is the long one. // The name of the config file is based on the long name! // EmptyCallbackArray means that you don't provide right now the callback // the last 2 path are where is the config file is (directory) and where to log info (directory) NLNET_SERVICE_MAIN(CTestService, "TS", "test_service", 0, EmptyCallbackArray, "", ""); *\endcode * * If you want the port to not be auto-assigned by the naming service, set the port to a number different than 0. * * Args used by service are always in lower case: * * -A followed by the path where to execute the service (it uses chdir()) * -B followed by the IP address where the naming service is * -C followed by the path where we can find the config file * -D followed by the client listening address of the frontend for the login system (FS only) * -I to start the service iconified * -L followed by the directory where we have to log * -N followed by the alias name (used by the admin system) * -P followed by the listen port (ListenAddress) * -Q to make the service quit immediately after the first update * -S followed by the shard Id (sint32) (WS only) * -T followed by the IP address where the login service is (WS only) * -W followed by the path where to save all shard data (SaveFilesDirectory) * -Z[u] to just init the config file then return (used for test), use Zu to not release the service * * */ #if defined(NL_OS_WINDOWS) && defined(_WINDOWS) #define NLNET_SERVICE_MAIN(__ServiceClassName, __ServiceShortName, __ServiceLongName, __ServicePort, __ServiceCallbackArray, __ConfigDir, __LogDir) \ \ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) \ { \ NLMISC::CApplicationContext serviceContext; \ __ServiceClassName *scn = new __ServiceClassName; \ scn->setArgs (lpCmdLine); \ NLMISC::createDebug(NULL,!scn->haveLongArg("nolog"));\ scn->setCallbackArray (__ServiceCallbackArray, sizeof(__ServiceCallbackArray)/sizeof(__ServiceCallbackArray[0])); \ sint retval = scn->main (__ServiceShortName, __ServiceLongName, __ServicePort, __ConfigDir, __LogDir, __DATE__" "__TIME__); \ delete scn; \ return retval; \ } #else #define NLNET_SERVICE_MAIN(__ServiceClassName, __ServiceShortName, __ServiceLongName, __ServicePort, __ServiceCallbackArray, __ConfigDir, __LogDir) \ \ int main(int argc, const char **argv) \ { \ NLMISC::CApplicationContext serviceContext; \ __ServiceClassName *scn = new __ServiceClassName; \ scn->setArgs (argc, argv); \ NLMISC::createDebug(NULL,!scn->haveLongArg("nolog"));\ scn->setCallbackArray (__ServiceCallbackArray, sizeof(__ServiceCallbackArray)/sizeof(__ServiceCallbackArray[0])); \ sint retval = scn->main (__ServiceShortName, __ServiceLongName, __ServicePort, __ConfigDir, __LogDir, __DATE__ " " __TIME__); \ delete scn; \ return retval; \ } #endif #define DEFAULT_SHARD_ID 666 // // Typedefs // //typedef uint16 TServiceId; /// Callback where you can return true for direct clearance, or false for later clearance. typedef bool (*TRequestClosureClearanceCallback) (); // // Variables provided to application and unused in the NeL library itself. // extern TUnifiedCallbackItem EmptyCallbackArray[1]; // // Classes // /** * Base class for all network services. * You must inherite from this class to create your own service. You must not * create ctor and dtor but implement init() and release() methods. * You have to create a global callback array called CallbackArray. * * \ref service_howto * * Temporary command line arguments : * \li -n * * \author Vianney Lecroart * \author Olivier Cado * \author Nevrax France * \date 2000 */ class IService { public: /// \name User overload methods. These methods can be overload by the user do handle init, update and release operation. // @{ /** Called before the displayer is created, no displayer or network connection are built. Use this callback to check some args and perform some command line based stuff */ virtual void commandStart () {} /// Initializes the service (must be called before the first call to update()) virtual void init () {} /// This function is called every "frame" (you must call init() before). It returns false if the service is stopped. virtual bool update () { return true; } /// Finalization. Release the service. For example, this function frees all allocations made in the init() function. virtual void release () {} //@} /// \name get methods. These methods provide a way to read internal service variables. // @{ /// Returns the instance of the service to access to methods/variables class static IService *getInstance (); /// Returns true if the service singleton has been initialized static bool isServiceInitialized() { return _Instance != NULL; } /// Returns the current service short name (ie: TS) const std::string &getServiceShortName () const { return _ShortName; } /// Returns the current service long name (ie: test_serivce) const std::string &getServiceLongName () const { return _LongName; } /// Returns the current service alias name setted by AES const std::string &getServiceAliasName () const { return _AliasName; } /// Returns the current service unified name that is alias/short-id or short-id if alias is empty std::string getServiceUnifiedName () const; /// Returns the service identifier TServiceId getServiceId () const { return _SId; } /// Return the host name of the host machine const std::string &getHostName() const { return _HostName; } /// Returns the status sint getExitStatus () const { return _ExitStatus; } /// Returns the date of launch of the service. Unit: see CTime::getSecondsSince1970() uint32 getLaunchingDate () const; /// Return true if this service don't use the NS (naming service) bool getDontUseNS() const { return _DontUseNS; } /// Return true if this service don't use the AES (admin executor service) bool getDontUseAES() const { return _DontUseAES; } /// Returns arguments of the program pass from the user to the program using parameters (ie: "myprog param1 param2") const NLMISC::CVectorSString &getArgs () const { return _Args; } /// Returns true if the argument if present in the command line (ie: haveArg('p') will return true if -p is in the command line) bool haveArg (char argName) const; /** Returns the parameter linked to an option * getArg('p') will return toto if -ptoto is in the command line * getArg('p') will return C:\Documents and Settings\toto.tmp if -p"C:\Documents and Settings\toto.tmp" is in the command line * It'll thrown an Exception if the argName is not found */ std::string getArg (char argName) const; /// return true if named long arg is present on the commandline /// eg haveLongArg("toto") returns true if "--toto" or "--toto=xxx" can be found on commandline bool haveLongArg (const char* argName) const; /// returns the value associated with the given named argument /// both "--toto=xxx" and "--toto xxx" are acceptable /// quotes round arguments are stripped std::string getLongArg (const char* argName) const; /// Returns an uniq id for an entities on this service. /*uint64 getEntityId (uint8 type) { return NLMISC::CEntityId::getNewEntityId( type ).getRawId(); }*/ /// Returns the recording state (don't needed if you use layer5) CCallbackNetBase::TRecordingState getRecordingState() const { return _RecordingState; } //@} /// \name set methods. These methods provide a way to modify internal service variables. // @{ /** Sets the status of the service, this status is return to the application. EXIT_SUCCESS is the default status * You can set it to EXIT_FAILURE or any value you want. It's useful when you use the service in a script and you * want to know the return value of the application to do the appropriate things. */ void setExitStatus (sint exitStatus) { _ExitStatus = exitStatus; } /** Call this function if you want the service quits next loop. The code will be returned outside of the application. * \warning If you set the code to 0, it ll NOT exit the service */ void exit (sint code = 0x10); /** Selects timeout value in seconds for each update. You are absolutely certain that your update() * function will not be called before this amount of time you set. * If you set the update timeout value higher than 0, all messages in queues will be process until the time greater than the timeout user update(). * If you set the update timeout value to 0, all messages in queues will be process one time before calling the user update(). * * The default value is 100 (100ms) or the value found in the config file (UpdateTimeout) */ void setUpdateTimeout (NLMISC::TTime timeout) { /*if (timeout>1.0) nlerror ("IServer::setUpdateTimeout is now a double in SECOND and not ms");*/ _UpdateTimeout = timeout; } //@} //@{ //@name Service status management methods /// Push a new status on the status stack. void setCurrentStatus(const std::string &status); /// Remove a status from the status stack. If this status is at top of stack, the next status become the current status void clearCurrentStatus(const std::string &status); /// Add a tag in the status string void addStatusTag(const std::string &statusTag); /// Remove a tag from the status string void removeStatusTag(const std::string &statusTag); /// Get the current status with attached tags std::string getFullStatus() const; //@} /// \name variables. These variables can be read/modified by the user. // @{ NLMISC::CConfigFile ConfigFile; // use to display result of command (on file and windows displayer) **without** filter NLMISC::CLog CommandLog; //@} /// \name private methods. These methods are used by internal system but can't be put in private, don't use them. // @{ /// This main is called by the macro (service5 says if we have to use layer5 or not) sint main (const char *serviceShortName, const char *serviceLongName, uint16 servicePort, const char *configDir, const char *logDir, const char *compilationDate); /// Sets the command line and init _Args variable. You must call this before calling main() void setArgs (int argc, const char **argv); /// Sets the command line and init _Args variable. You must call this before calling main() void setArgs (const char *args); /// Sets the default callback array given from the macro void setCallbackArray (TUnifiedCallbackItem *array, uint nbelem) { _CallbackArray = array; _CallbackArraySize = nbelem; } /// Require to reset the hierarchical timer void requireResetMeasures(); /// Ctor. You must not inherit ctor but overload init() function IService (); /// Dtor. You must not inherit dtor but overload release() function virtual ~IService (); //@} //@{ /// \name Updatable are object that require an update at each service loop /// Register an updatable interface void registerUpdatable(IServiceUpdatable *updatable); /// Unregister an updatable interface void unregisterUpdatable(IServiceUpdatable *updatable); //@} /// The window displayer instance NLMISC::CWindowDisplayer *WindowDisplayer; /// Directory where to store files that the services will write but are the same for all shard instance (for example: packet_sheets) /// Use .toString() to access to the value NLMISC::CVariable WriteFilesDirectory; /// Directory where to store files that the services will write during the exploitation of the game (for example: player backup, string cache) /// Use .toString() to access to the value NLMISC::CVariable SaveFilesDirectory; /// If true (default), the provided SaveFilesDirectory will be converted to a full path (ex: "saves" -> "/home/dir/saves") NLMISC::CVariable ConvertSavesFilesDirectoryToFullPath; /** You can provide a callback interface (only one) that will be called if any of the directory variables * (WriteFilesDirectory, SaveFilesDirectory, ConfigDirectory, LogDirectory, RunningDirectory) is changed * (also called for the first setting read from the .cfg file). Default is NULL. */ void setDirectoryChangeCallback( NLMISC::IVariableChangedCallback *cbi ) { _DirectoryChangedCBI = cbi; } void setVersion (const std::string &version) { Version = version; } uint16 getPort() { return ListeningPort; } // Warning: can take a moment to be received from the WS. The default value (when not received yet) is DEFAULT_SHARD_ID. uint32 getShardId() const { return _ShardId; } const NLMISC::CCPUTimeStat& getCPUUsageStats() const { return _CPUUsageStats; } /// Allow the service to return a status string with important value virtual std::string getServiceStatusString() const; /** * If your service needs a delay when it is asked to quit, provide a callback here (optional). * Then, when the service will be asked to quit, this callback will be called. Then you can * either return true to allow immediate closure, or false to delay the closure. The closure * will then happen after you call clearForClosure(). * * If you don't provide a callback here, or if you call with NULL, the service will exit * immediately when asked to quit. */ void setClosureClearanceCallback( TRequestClosureClearanceCallback cb ) { _RequestClosureClearanceCallback = cb; } /** * If using clearance for closure (see setClosureClearanceCallback()), you can call this method * to allow the service to quit. If calling it while your callback has not be called yet, the * callback will be bypassed and the service will quit immediately when asked to quit. If calling it * after you callback was called (and you returned false), the service will quit shortly. */ void clearForClosure() { _ClosureClearanceStatus = CCClearedForClosure; } /** Set the shard id (by the user code), when known before IService receives it by the WS). * If a non-default value is already set and different than shardId => nlerror. * If later IService receives a different value from the WS => nlerror. */ void anticipateShardId( uint32 shardId ); private: /// \name methods. These methods are used by internal system. // @{ /// Changes the recording state (use if you know what you are doing) void setRecordingState( CCallbackNetBase::TRecordingState rec ) { _RecordingState = rec; } /** Set the shard id (received from the WS). See also anticipateShardId(). */ void setShardId( uint32 shardId ); //@} /// \name variables. These variables are used by the internal system. // @{ /// Array of arguments pass from the command line NLMISC::CVectorSString _Args; /// Host name of the host machine that run the service std::string _HostName; /// Listening port of this service NLMISC::CVariable ListeningPort; /// Recording state CCallbackNetBase::TRecordingState _RecordingState; /// Current service name sets by the actual service when declaring NLNET_SERVICE_MAIN std::string _ShortName; // ie: "NS" std::string _LongName; // ie: "naming_service" std::string _AliasName; // this name is initialized by the admin executor service via the args /// Instance of this service (singleton) static IService *_Instance; /// Select timeout value in milliseconds between to call of user update() NLMISC::TTime _UpdateTimeout; /// the service id of this sevice TServiceId _SId; /// the exit status of this service (the status is returned by the service at the release time) sint _ExitStatus; /// true if the service initialisation is passed bool _Initialized; /// The directory where the configfile is NLMISC::CVariable ConfigDirectory; /// The directory where the logfiles are NLMISC::CVariable LogDirectory; /// The directory where the service is running NLMISC::CVariable RunningDirectory; NLMISC::CVariable Version; TUnifiedCallbackItem *_CallbackArray; uint _CallbackArraySize; /// true if the service don't use the naming service bool _DontUseNS; /// true if the service don't use the admin executor service bool _DontUseAES; /// Require to reset the hierarchical timer bool _ResetMeasures; /// Shard Id uint32 _ShardId; /// CPU usage stats NLMISC::CCPUTimeStat _CPUUsageStats; /// Registered updatable interface std::set _Updatables; //@{ //@name Service running status management /// The status stack is used to display the most recent set status. std::vector _ServiceStatusStack; /// The status tags. All added tags are displayed. std::set _ServiveStatusTags; //@} enum TClosureClearanceStatus { CCMustRequestClearance, CCWaitingForClearance, CCClearedForClosure, CCCallbackThenClose=256 }; /// Closure clearance state (either CCMustRequestClearance, CCWaitingForClearance, CCClearedForClosure or CCCallbackThenClose + any other as a backup value) uint _ClosureClearanceStatus; /// Closure clearance callback (NULL if no closure clearance required) TRequestClosureClearanceCallback _RequestClosureClearanceCallback; /// Directory changed callback NLMISC::IVariableChangedCallback* _DirectoryChangedCBI; friend void serviceGetView (uint32 rid, const std::string &rawvarpath, std::vector &vara, std::vector &vala); friend void cbAESConnection (const std::string &serviceName, TServiceId sid, void *arg); friend struct nel_serviceInfoClass; friend struct nel_getWinDisplayerInfoClass; friend void cbDirectoryChanged (NLMISC::IVariable &var); friend void cbReceiveShardId (NLNET::CMessage& msgin, const std::string &serviceName, TServiceId serviceId); NLMISC_CATEGORISED_DYNVARIABLE_FRIEND(nel, State); }; /** Interface class for object that need an update call during each service loop. */ class IServiceUpdatable { public: IServiceUpdatable() { if (IService::isServiceInitialized()) { IService::getInstance()->registerUpdatable(this); } else { nlwarning("IServiceUpdatable : IService is not initialized, IUpdatable will not be called"); } } virtual ~IServiceUpdatable() { if (IService::isServiceInitialized()) { IService *service = IService::getInstance(); service->unregisterUpdatable(this); } } /// implemente this virtual in you derived class virtual void serviceLoopUpdate() =0; }; inline IService *IService::getInstance() { if (_Instance == NULL) { /* the nel context MUST be initialised */ nlassertex(NLMISC::INelContext::isContextInitialised(), ("You are trying to access a safe singleton without having initialized a NeL context. The simplest correction is to add 'NLMISC::CApplicationContext myApplicationContext;' at the very beginning of your application.")); // try to retrieve the safe singleton pointer _Instance = reinterpret_cast(NLMISC::INelContext::getInstance().getSingletonPointer("IService")); } return _Instance; } }; // NLNET #endif // NL_SERVICE_H /* End of service.h */ ================================================ FILE: code/nel/include/nel/net/sock.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_SOCK_H #define NL_SOCK_H #include "nel/misc/common.h" #include "nel/misc/mutex.h" #include "inet_address.h" //#include /// This namespace contains all network class namespace NLNET { /** * Network exceptions * \author Olivier Cado * \author Nevrax France * \date 2000 */ struct ESocket : public NLMISC::Exception { /** Constructor * You can provide an internet address. If so, reason *must* contain "%s" * where the address should be written. Moreover, the length of reason plus * the length of the address when displayed by asString() should no exceed 256. */ ESocket( const char *reason="", bool systemerror=true, CInetAddress *addr=NULL ); }; /// Exception raised when connect() fails struct ESocketConnectionFailed : public ESocket { ESocketConnectionFailed( CInetAddress addr ) : ESocket( "Connection to %s failed", true, &addr ) {} }; /// Exception raised when a connection is gracefully closed by peer struct ESocketConnectionClosed : public ESocket { ESocketConnectionClosed() : ESocket( "Connection closed" ) {} }; /// Exception raised when an unauthorized access has been done struct EAccessDenied : public ESocket { EAccessDenied( std::string s ): ESocket( (std::string("Access denied: ")+s).c_str(), false ) {} }; /// Exception raised when a the NS does not find the service looked-up struct EServiceNotFound : public ESocket { EServiceNotFound( std::string s ): ESocket( (std::string("Service not found: ")+s).c_str(), false ) {} }; //typedef SOCKET; #ifdef NL_OS_WINDOWS typedef uint SOCKET; #elif defined NL_OS_UNIX typedef int SOCKET; #endif /** * CSock: base socket class. * One CSock object represents a communication between two hosts, the local one and the remote one. * This class implements layer 0 of the NeL Network Engine. * This class does not handle conversion between big endian and little endian ; the provided * buffers are sent raw. * * The "logging" boolean value is necessary because in this implementation we always log * to one single global CLog object : there is not one CLog object per socket. Therefore * we must prevent the socket used in CNetDisplayer from logging itself... otherwise we * would have an infinite recursion. * * The "connected" property may have a different meaning whether the socket is a stream socket * (e.g. using TCP) or it is a connectionless datagram socket (e.g. using UDP). In the latter, * "connected" only means that the local and the remote addresses have been set. * * Important note: this class is thread-safe, meaning you can access to a CSock object * from multiple threads BUT the only things you are allow to do in parallel are * receive/send and read the connected() property. * * You must call CSock::initNetwork() before using any network class (even CInetAddress). * You must call CSock::releaseNetwork() at the end of your program. * * By default, a socket is in blocking mode. Call setNonBlockingMode() to change this * behaviour. * \author Olivier Cado * \author Nevrax France * \date 2000-2001 */ class CSock { public: enum TSockResult { Ok, WouldBlock, ConnectionClosed, Error }; /// Initialize the network engine, if it is not already done static void initNetwork(); /// Releases the network engine static void releaseNetwork(); /** Returns the code of the last error that has occured. * Note: This code is platform-dependant. On Unix, it is errno; on Windows it is the Winsock error code. * See also errorString() */ static uint getLastError(); /// Returns a string explaining the network error (see getLastError()) static std::string errorString( uint errorcode ); /// Change the time out value used in getDataAvailable(), which is 0 by default void setTimeOutValue( long sec, long ms ) { _TimeoutS = sec; if ( ms > 999 ) ms = 999; _TimeoutUs = ms * 1000; } /// @name Socket setup //@{ /** Connection. * This method does not return a boolean, otherwise a programmer could ignore the result and no * exception would be thrown if connection fails : * - If addr is not valid, an exception ESocket is thrown * - If connect() fails for another reason, an exception ESocketConnectionFailed is thrown */ virtual void connect( const CInetAddress& addr ); /** Sets the socket in nonblocking mode. Call this method *after* connect(), otherwise you will get * an "would block" error (10035 on Windows). In nonblocking mode, use received() and sent() instead of receive() and send() */ void setNonBlockingMode ( bool bm ); /// Returns the nonblocking mode bool nonBlockingMode() const { return _NonBlocking; } /** Closes the socket (without shutdown) * In general you don't need to call this method. But you can call it to: * - close a listening socket (i.e. stop accepting connections), or * - stop a select() in progress in another thread (in this case, just calling the destructor is not enough) */ virtual void close(); /// Destructor (shutdown + close) virtual ~CSock(); //@} /// @name Receiving data //@{ /// Checks if there is some data to receive, waiting (blocking) at most for the time out value. bool dataAvailable(); /** Receive a partial or an entire block of data, depending on nonblocking mode. * * In blocking mode: the method waits until 'len' bytes have been received. * * In nonblocking mode: the method reads the bytes that have already been received only, and * resets 'len' to the number of bytes read. The actual length may be smaller than the demanded * length. In no data is available, the return value is CSock::WouldBlock. If dataAvailable() * returns true, you are sure that receive() will not return CSock::WouldBlock. * * In case of graceful disconnection: * - connected() become false * - the return value is CSock::ConnectionClosed or an ESocketConnectionClosed exception is thrown. * * In case of failure (e.g. connection reset by peer) : * - the return value is CSock::Error or an ESocket exception is thrown. * You may want to close the connection manually. */ CSock::TSockResult receive( uint8 *buffer, uint32& len, bool throw_exception=true ); //@} /// @name Sending data //@{ /** Sends a message. * * In blocking mode: the method waits until 'len' bytes have been sent. * * In nonblocking mode : the method resets len to the actual number of bytes sent. * Even if less bytes than expected have been sent, it returns CSock::Ok. The caller * is expected to test the actual len to check if the remaining data must be resent. * * \return CSock::Ok or CSock::Error (in case of failure). * When throw_exception is true, the method throws an ESocket exception in case of failure. */ CSock::TSockResult send( const uint8 *buffer, uint32& len, bool throw_exception=true ); //@} /// @name Properties //@{ /// Returns if the socket is connected (volatile) bool connected() { return _Connected; } /// Returns a const reference on the local address const CInetAddress& localAddr() const { return _LocalAddr; } /// Returns the address of the remote host const CInetAddress& remoteAddr() const { return _RemoteAddr; } /// Returns the socket descriptor SOCKET descriptor() const { return _Sock; } /// Returns the time out value in millisecond uint32 timeOutValue() const { return _TimeoutS*1000 + _TimeoutUs/1000; } //@} /// Returns the number of bytes received since the latest connection uint64 bytesReceived() const { return _BytesReceived; } /// Returns the number of bytes sent since the latest connection uint64 bytesSent() const { return _BytesSent; } /// Sets the send buffer size void setSendBufferSize( sint32 size ); /// Gets the send buffer size sint32 getSendBufferSize(); /// Returns true if the network engine is initialized static bool initialized() { return CSock::_Initialized; } protected: /** * Constructor. * \param logging Disable logging if the server socket object is used by the logging system, to avoid infinite recursion */ CSock( bool logging = true ); /// Construct a CSock object using an existing connected socket descriptor and its associated remote address CSock( SOCKET sock, const CInetAddress& remoteaddr ); /// Creates the socket and get a valid descriptor void createSocket( int type, int protocol ); /// Sets the local address void setLocalAddress(); /// Socket descriptor SOCKET _Sock; /// Address of local host (valid if connected) CInetAddress _LocalAddr; /// Address of the remote host (valid if connected) CInetAddress _RemoteAddr; /// If false, do not log any information bool _Logging; /// If true, the socket is in nonblocking mode bool _NonBlocking; /// True after calling connect() //NLMISC::CSynchronized _SyncConnected; volatile bool _Connected; /// Number of bytes received on this socket uint64 _BytesReceived; /// Number of bytes sent on this socket uint64 _BytesSent; /// Main time out value (sec) for select in dataAvailable() long _TimeoutS; /// Secondary time out value (microsec) for select in dataAvailable() long _TimeoutUs; private: /// True if the network library has been initialized static bool _Initialized; // Test: send & receive duration (ms) uint32 _MaxReceiveTime; uint32 _MaxSendTime; /// Flag used to determine the moments at which sends atrta an stop blocking bool _Blocking; }; } // NLNET #endif // NL_SOCK_H /* End of sock.h */ ================================================ FILE: code/nel/include/nel/net/tcp_sock.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_TCP_SOCK_H #define NL_TCP_SOCK_H #include "sock.h" namespace NLNET { /** * CTcpSock: Reliable socket via TCP. * See base class CSock. * * When to set No Delay mode on ? * Set TCP_NODELAY (call setNoDelay(true)) *only* if you have to send small buffers that need to * be sent *immediately*. It should only be set for applications that send frequent small bursts * of information without getting an immediate response, where timely delivery of data is * required (the canonical example is mouse movements). Setting TCP_NODELAY on increases * the network traffic (more overhead). * In the normal behavior of CSock, TCP_NODELAY is off i.e. the Nagle buffering algorithm is enabled. * * \author Olivier Cado * \author Nevrax France * \date 2000-2001 */ class CTcpSock : public CSock { public: /// @name Socket setup //@{ /** * Constructor. * \param logging Disable logging if the server socket object is used by the logging system, to avoid infinite recursion */ CTcpSock( bool logging = true ); /// Construct a CTcpSock object using an already connected socket descriptor and its associated remote address CTcpSock( SOCKET sock, const CInetAddress& remoteaddr ); /** Connection. You can reconnect a socket after being disconnected. * This method does not return a boolean, otherwise a programmer could ignore the result and no * exception would be thrown if connection fails : * - If addr is not valid, an exception ESocket is thrown * - If connect() fails for another reason, an exception ESocketConnectionFailed is thrown */ virtual void connect( const CInetAddress& addr ); /** Sets a custom TCP Window size (SO_RCVBUF and SO_SNDBUF). * You must close the socket is necessary, before calling this method. * * See http://www.ncsa.uiuc.edu/People/vwelch/net_perf/tcp_windows.html */ void connectWithCustomWindowSize( const CInetAddress& addr, int windowsize ); /// Returns the TCP Window Size for the current socket uint32 getWindowSize(); /** Sets/unsets SO_KEEPALIVE (true by default). */ void setKeepAlive( bool keepAlive); /** Sets/unsets TCP_NODELAY (by default, it is off, i.e. the Nagle buffering algorithm is enabled). * You must call this method *after* connect(). */ virtual void setNoDelay( bool value ); /// Active disconnection for download way only (partial shutdown) void shutdownReceiving(); /// Active disconnection for upload way only (partial shutdown) void shutdownSending(); /// Active disconnection (shutdown) (mutexed). connected() becomes false. virtual void disconnect(); //@} }; } // NLNET #endif // NL_TCP_SOCK_H /* End of tcp_sock.h */ ================================================ FILE: code/nel/include/nel/net/transport_class.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_TRANSPORT_CLASS_H #define NL_TRANSPORT_CLASS_H // // Includes // #include "nel/misc/types_nl.h" #include "nel/misc/stream.h" #include "nel/misc/entity_id.h" #include "nel/misc/sheet_id.h" #include "nel/misc/variable.h" #include "unified_network.h" #include "message.h" #include #include namespace NLNET { // // Macros // /** * Use this macro to register a class that can be transported in the init of your program. */ #define TRANSPORT_CLASS_REGISTER(_c) \ static _c _c##Instance; \ CTransportClass::registerClass (_c##Instance); #define NETTC_INFO if (!VerboseNETTC.get()) {} else nlinfo #define NETTC_DEBUG if (!VerboseNETTC.get()) {} else nldebug extern NLMISC::CVariable VerboseNETTC; // // Classes // /** * You have to inherit this class and implement description() and callback() method. * For an example of use, take a look at nel/samples/class_transport sample. * \author Vianney Lecroart * \author Nevrax France * \date 2002 */ class CTransportClass { public: virtual ~CTransportClass() {} /** Different types that we can use in a Transport class * warning: if you add/change a prop, change also in CTransportClass::init() * warning: PropUKN must be the last value (used to resize a vector) */ enum TProp { PropUInt8, PropUInt16, PropUInt32, PropUInt64, PropSInt8, PropSInt16, PropSInt32, PropSInt64, PropBool, PropFloat, PropDouble, PropString, PropDataSetRow, PropSheetId, PropUCString, PropUKN }; // PropBool, PropFloat, PropDouble, PropString, PropDataSetRow, PropEntityId, PropSheetId, PropUKN }; // // Static methods // /// Init the transport class system (must be called one time, in the IService5::init() for example) static void init (); /// Release the transport class system (must be called one time, in the IService5::release() for example) static void release (); /** Call this function to register a new transport class. * \param instance A reference to a GLOBAL space of the instance of this transport class. It will be used when receive this class from network. */ static void registerClass (CTransportClass &instance); /// Display registered transport class (debug purpose) static void displayLocalRegisteredClass (); // // Virtual methods // /** You have to implement this function with the description of your class. This description * is used to send the class accross the network and read it. It must contains a class name and * a set properties. * Example: *\code virtual void description () { className ("SharedClass"); property ("i1", PropUInt32, (uint32)11, i1); } *\endcode */ virtual void description () = 0; /** This function will be call when we receive this class from the network. It will use the instance given at the * registration process. By default, it does nothing. */ virtual void callback (const std::string &/* name */, NLNET::TServiceId /* sid */) { } // // Other methods // /// send the transport class to a specified service using the service id void send (NLNET::TServiceId sid); /// send the transport class to a specified service using the service name void send (const std::string &serviceName); /** The name of the transport class. Must be unique for each class. */ void className (const std::string &name); /** Return the name of the transport class. * The result is valid only AFTER calling of REGISTER_TRANSPORT_CLASS. */ const std::string &className() { return Name; } /** One property of the class. Look description() for an example of use. * \param name The name of the property * \param type Type of the property * \param defaultValue The value you want to be set when a message comes without this property * \param value Reference to the value where the property will be read or write */ template void property (const std::string &name, TProp type, T defaultValue, T &value) { switch (type) { case PropUInt8: case PropSInt8: case PropBool: nlassert(sizeof(T) == sizeof (uint8)); break; case PropUInt16: case PropSInt16: nlassert(sizeof(T) == sizeof (uint16)); break; case PropUInt32: case PropSInt32: case PropDataSetRow: nlassert(sizeof(T) == sizeof (uint32)); break; case PropUInt64: case PropSInt64: nlassert(sizeof(T) == sizeof (uint64)); break; case PropFloat: nlassert(sizeof(T) == sizeof (float)); break; case PropDouble: nlassert(sizeof(T) == sizeof (double)); break; case PropString: nlassert(sizeof(T) == sizeof (std::string)); break; // case PropEntityId: nlassert(sizeof(T) == sizeof (NLMISC::CEntityId)); break; case PropSheetId: nlassert(sizeof(T) == sizeof (NLMISC::CSheetId)); break; case PropUCString: nlassert(sizeof(T) == sizeof (ucstring)); break; default: nlerror ("property %s have unknown type %d", name.c_str(), type); } if (Mode == 2) // write { // send only if needed // todo manage unknown prop TempMessage.serial (value); } else if (Mode == 3) // register { // add a new prop to the current class nlassert (TempRegisteredClass.Instance != NULL); TempRegisteredClass.Instance->Prop.push_back (new CRegisteredProp (name, type, defaultValue, &value)); } else if (Mode == 4) // display { std::string val; val = "defval: "; val += NLMISC::toString (defaultValue); val += " val: "; val += NLMISC::toString (value); NETTC_DEBUG ("NETTC: prop %s %d: %s", name.c_str(), type, val.c_str()); } else { nlstop; } } template void propertyVector (const std::string &name, TProp type, std::vector &value) { if (Mode == 2) // write { // send only if needed // todo manage unknown prop TempMessage.serialCont (value); } else if (Mode == 3) // register { // add a new prop to the current class nlassert (TempRegisteredClass.Instance != NULL); TempRegisteredClass.Instance->Prop.push_back (new CRegisteredPropCont > (name, type, &value)); } else if (Mode == 4) // display { typedef typename std::vector::iterator __iterator; std::string val; for (__iterator it = value.begin (); it != value.end(); it++) { val += NLMISC::toString (T(*it)); val += " "; } NETTC_DEBUG ("NETTC: prop %s %d: %d elements ( %s)", name.c_str(), type, value.size(), val.c_str()); } else { nlstop; } } template void propertyCont (const std::string &name, TProp type, T &value) { if (Mode == 2) // write { // send only if needed // todo manage unknown prop TempMessage.serialCont (value); } else if (Mode == 3) // register { // add a new prop to the current class nlassert (TempRegisteredClass.Instance != NULL); TempRegisteredClass.Instance->Prop.push_back (new CRegisteredPropCont (name, type, &value)); } else if (Mode == 4) // display { typedef typename T::iterator __iterator; std::string val; for (__iterator it = value.begin (); it != value.end(); it++) { val += NLMISC::toString (*it); val += " "; } NETTC_DEBUG ("NETTC: prop %s %d: %d elements ( %s)", name.c_str(), type, value.size(), val.c_str()); } else { nlstop; } } // Read the header (first part of the transport class message, currently only className) static void readHeader(CMessage& msgin, std::string& className) { msgin.serial(className); } /// Display with nlinfo the content of the class (debug purpose) void display (); protected: // // Structures // struct CRegisteredBaseProp { CRegisteredBaseProp () : Type(PropUKN) { } virtual ~CRegisteredBaseProp() {} CRegisteredBaseProp (const std::string &name, TProp type) : Name(name), Type(type) { } std::string Name; TProp Type; virtual void serialDefaultValue (NLMISC::IStream &/* f */) { } virtual void serialValue (NLMISC::IStream &/* f */) { } virtual void setDefaultValue () { } }; typedef std::vector > > TOtherSideRegisteredClass; struct CRegisteredClass { CTransportClass *Instance; CRegisteredClass () { clear (); } void clear () { Instance = NULL; } }; typedef std::map TRegisteredClass; template struct CRegisteredProp : public CRegisteredBaseProp { CRegisteredProp () : Value(NULL) { } CRegisteredProp (const std::string &name, TProp type, T defaultValue, T *value = NULL) : CRegisteredBaseProp (name, type), DefaultValue(defaultValue), Value (value) { } T DefaultValue, *Value; virtual void serialDefaultValue (NLMISC::IStream &f) { f.serial (DefaultValue); } virtual void serialValue (NLMISC::IStream &f) { nlassert (Value != NULL); f.serial (*Value); } virtual void setDefaultValue () { nlassert (Value != NULL); *Value = DefaultValue; } }; template struct CRegisteredPropCont : public CRegisteredBaseProp { CRegisteredPropCont () : Value(NULL) { } CRegisteredPropCont (const std::string &name, TProp type, T *value = NULL) : CRegisteredBaseProp (name, type), Value (value) { } T *Value; virtual void serialDefaultValue (NLMISC::IStream &/* f */) { // nothing } virtual void serialValue (NLMISC::IStream &f) { nlassert (Value != NULL); f.serialCont (*Value); } virtual void setDefaultValue () { nlassert (Value != NULL); Value->clear (); } }; // // Variables // // Name of the class std::string Name; // States to decode the stream from the network std::vector > > States; // Contains all propterties for this class std::vector Prop; // // Methods // // Read the TempMessage and call the callback bool read (const std::string &name, NLNET::TServiceId sid); // Used to create a TempMessage with this class NLNET::CMessage &write (); // // Static Variables // // Used to serialize unused properties from the TempMessage static std::vector DummyProp; // Select what the description() must do static uint Mode; // 0=nothing 1=read 2=write 3=register 4=display // Contains all registered transport class static TRegisteredClass LocalRegisteredClass; // registered class that are in my program // The registered class that is currently filled (before put in LocalRegisteredClass) static CRegisteredClass TempRegisteredClass; // The message that is currently filled/emptyed static NLNET::CMessage TempMessage; static bool Init; // // Static methods // // Called by release() to delete all structures static void unregisterClass (); // Fill the States merging local and other side class static void registerOtherSideClass (NLNET::TServiceId sid, TOtherSideRegisteredClass &osrc); // Create a message with local transport classes to send to the other side static void createLocalRegisteredClassMessage (); // Send the local transport classes to another service using the service id static void sendLocalRegisteredClass (NLNET::TServiceId sid) { nlassert (Init); NETTC_DEBUG ("NETTC: sendLocalRegisteredClass to %hu", sid.get()); createLocalRegisteredClassMessage (); NLNET::CUnifiedNetwork::getInstance()->send (sid, TempMessage); } // Display a specific registered class (debug purpose) static void displayLocalRegisteredClass (CRegisteredClass &c); static void displayDifferentClass (NLNET::TServiceId sid, const std::string &className, const std::vector &otherClass, const std::vector &myClass); // // Friends // friend void cbTCReceiveMessage (NLNET::CMessage &msgin, const std::string &name, NLNET::TServiceId sid); friend void cbTCUpService (const std::string &serviceName, NLNET::TServiceId sid, void *arg); friend void cbTCReceiveOtherSideClass (NLNET::CMessage &msgin, const std::string &name, NLNET::TServiceId sid); }; /** * Get the name of message (for displaying), or extract the class name if it is a transport class. * * Preconditions: * - msgin is an input message that contains a valid message * * Postconditions: * - msgin.getPos() was modified * - msgName contains "msg %s" or "transport class %s" where %s is the name of message, or the name * transport class is the message is a CT_MSG */ void getNameOfMessageOrTransportClass( NLNET::CMessage& msgin, std::string& msgName ); // // Inlines // inline void CTransportClass::className (const std::string &name) { if (Mode == 2) // write { TempMessage.serial (const_cast (name)); } else if (Mode == 3) // register { // add a new entry in my registered class nlassert (TempRegisteredClass.Instance != NULL); TempRegisteredClass.Instance->Name = name; } else if (Mode == 4) // display { NETTC_DEBUG ("NETTC: class %s:", name.c_str()); } else { nlstop; } } inline void CTransportClass::send (NLNET::TServiceId sid) { nlassert (Init); NLNET::CUnifiedNetwork::getInstance()->send (sid, write ()); } inline void CTransportClass::send (const std::string &serviceName) { nlassert (Init); NLNET::CUnifiedNetwork::getInstance()->send (serviceName, write ()); } inline void CTransportClass::display () { nlassert (Mode == 0); // set the mode to register Mode = 4; description (); // set to mode none Mode = 0; } inline NLNET::CMessage &CTransportClass::write () { nlassert (Init); nlassert (Mode == 0); #ifndef FINAL_VERSION // Did the programmer forget to register the transport class? Forbid sending then. nlassert( LocalRegisteredClass.find( className() ) != LocalRegisteredClass.end() ); #endif // set the mode to register Mode = 2; TempMessage.clear (); if (TempMessage.isReading()) TempMessage.invert(); TempMessage.setType ("CT_MSG"); description (); // set to mode none Mode = 0; display (); return TempMessage; } inline bool CTransportClass::read (const std::string &name, NLNET::TServiceId sid) { nlassert (Init); nlassert (Mode == 0); // there's no info about how to read this message from this sid, give up if (sid.get() >= States.size()) return false; // set flag of all prop std::vector bitfield; bitfield.resize (Prop.size(), 0); // init prop from the stream uint i; for (i = 0; i < States[sid.get()].size(); i++) { if (States[sid.get()][i].first == -1) { // skip the value from the stream DummyProp[States[sid.get()][i].second]->serialDefaultValue (TempMessage); } else { // get the good value Prop[States[sid.get()][i].first]->serialValue (TempMessage); bitfield[States[sid.get()][i].first] = 1; } } // set default value for unknown prop for (i = 0; i < Prop.size(); i++) { if (bitfield[i] == 0) { Prop[i]->setDefaultValue (); } } display (); // call the user callback callback (name, sid); return true; } } // NLNET #endif // NL_TRANSPORT_CLASS_H /* End of transport_class.h */ ================================================ FILE: code/nel/include/nel/net/udp_sim_sock.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_UDP_SIM_SOCK_H #define NL_UDP_SIM_SOCK_H #include "nel/misc/config_file.h" #include #include "sock.h" #include "udp_sock.h" namespace NLNET { struct CBufferizedOutPacket; /** * CUdpSimSock: Unreliable datagram socket via UDP but packet lost, lag simulation. * See class CUdpSock. * * Notes: InLag must be >0 to use the InPacketLoss variable * * \author Vianney Lecroart * \author Nevrax France * \date 2002 */ class CUdpSimSock { public: CUdpSimSock (bool logging = true) : UdpSock(logging) { } // this function is to call to set the simulation values static void setSimValues (NLMISC::CConfigFile &cf); // CUdpSock functions wrapping void connect( const CInetAddress& addr ); void close(); bool dataAvailable(); bool receive( uint8 *buffer, uint32& len, bool throw_exception=true ); CSock::TSockResult send( const uint8 *buffer, uint32& len, bool throw_exception=true ); void sendTo (const uint8 *buffer, uint32& len, const CInetAddress& addr); bool connected(); const CInetAddress& localAddr() const { return UdpSock.localAddr(); } // Used to call CUdpSock functions that are not wrapped in this class CUdpSock UdpSock; private: std::queue _BufferizedOutPackets; std::queue _BufferizedInPackets; static uint32 _InLag; static uint8 _InPacketLoss; static uint32 _OutLag; static uint8 _OutPacketLoss; static uint8 _OutPacketDuplication; static uint8 _OutPacketDisordering; void updateBufferizedPackets (); void sendUDP (const uint8 *buffer, uint32& len, const CInetAddress *addr = NULL); void sendUDPNow (const uint8 *buffer, uint32 len, const CInetAddress *addr = NULL); friend void cbSimVar (NLMISC::CConfigFile::CVar &var); }; } // NLNET #endif // NL_SIM_SOCK_H /* End of udp_sim_sock.h */ ================================================ FILE: code/nel/include/nel/net/udp_sock.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_UDP_SOCK_H #define NL_UDP_SOCK_H #include "sock.h" namespace NLNET { /** * CUdpSock: Unreliable datagram socket via UDP. * See base class CSock. * \author Olivier Cado * \author Nevrax France * \date 2000-2001 */ class CUdpSock : public CSock { public: /// @name Socket setup //@{ /** * Constructor. * \param logging Disable logging if the server socket object is used by the logging system, to avoid infinite recursion */ CUdpSock( bool logging = true ); /** Binds the socket to the specified port. Call bind() for an unreliable socket if the host acts as a server and expects to receive * messages. If the host acts as a client, call directly sendTo(), in this case you need not bind the socket. */ void bind( uint16 port ); /// Same as bind(uint16) but binds on a specified address/port (useful when the host has several addresses) void bind( const CInetAddress& addr ); //@} /// @name Receiving data //@{ /** Receives data from the peer. (blocking function) * The socket must be pseudo-connected. */ bool receive( uint8 *buffer, uint32& len, bool throw_exception=true ); /** Receives data and say who the sender is. (blocking function) * The socket must have been bound before, by calling either bind() or sendTo(). * \param buffer [in] Address of buffer * \param len [in/out] Requested length of buffer, and actual number of bytes received * \param addr [out] Address of sender */ bool receivedFrom( uint8 *buffer, uint& len, CInetAddress& addr, bool throw_exception=true ); //@} /// @name Sending data //@{ /// Sends data to the specified host (unreliable sockets only) void sendTo( const uint8 *buffer, uint len, const CInetAddress& addr ); //@} private: /// True after calling bind() or sendTo() bool _Bound; }; } // NLNET #endif // NL_UDP_SOCK_H /* End of udp_sock.h */ ================================================ FILE: code/nel/include/nel/net/unified_network.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_UNIFIED_NETWORD_H #define NL_UNIFIED_NETWORD_H #include "nel/misc/types_nl.h" #include #include #include "nel/misc/command.h" #include "nel/misc/time_nl.h" #include "callback_client.h" #include "callback_server.h" namespace NLNET { /** This class encapsulate the serviceId format. */ class TServiceId { /// Service are identified by a 16 bits integer uint16 _ServiceId; public: typedef uint16 size_type; /// A constant for the invalid service id static const TServiceId InvalidId; /// Default constructor, set the id to 0 (no service should have 0) TServiceId() : _ServiceId(0) { } /// Copy constructor TServiceId(const TServiceId &other) : _ServiceId(other._ServiceId) { } /// Only explicit construction from an integer are allowed explicit TServiceId(uint16 sid) : _ServiceId(sid) { } bool operator == (const TServiceId &other) const { return _ServiceId == other._ServiceId; } bool operator != (const TServiceId &other) const { return !(*this == other); } bool operator < (const TServiceId &other) const { return _ServiceId < other._ServiceId; } /// Getter, return the integer value of the service id uint16 get() const { return _ServiceId; } /// Setter, set the value of the service id void set(uint16 sid) { _ServiceId = sid; } void serial(NLMISC::IStream &s) { s.serial(_ServiceId); } std::string toString() const { return NLMISC::toString(_ServiceId); } bool fromString(const std::string &str) { return NLMISC::fromString(str, _ServiceId); } }; /** This class encapsulate the 8 bits service id. * 8 bits service id are used by service register on the naming service. * This service can be used in a NLMISC::CEntityId. * Implicit constructor and conversion are provided with the 16 bits * version above, but the constructor will assert if the 8 bits range is * overflowed. */ class TServiceId8 { /// The 8bits service id uint8 _ServiceId; public: typedef uint8 size_type; /// Default constructor, set the id to 0 (no service should have 0) TServiceId8() : _ServiceId(0) {} /// Copy constructor TServiceId8(const TServiceId8 &other) : _ServiceId(other._ServiceId) {} /// Only explicit construction from an integer are allowed TServiceId8(const TServiceId &other) { nlassert(other.get() < 256); _ServiceId = uint8(other.get()); } explicit TServiceId8(uint8 sid) : _ServiceId(sid) {} /// implicit up cast to TServiceId (16bits) operator TServiceId () const { return TServiceId(_ServiceId); } bool operator == (const TServiceId8 &other) const { return _ServiceId == other._ServiceId; } bool operator != (const TServiceId8 &other) const { return !(*this == other); } bool operator == (const TServiceId &other) const { return _ServiceId == other.get(); } bool operator != (const TServiceId &other) const { return !(*this == other); } bool operator < (const TServiceId8 &other) const { return _ServiceId < other._ServiceId; } /// Getter, return the integer value of the service id uint8 get() const { return _ServiceId;} /// Setter, set the value of the service id void set(uint8 sid) { _ServiceId = sid;} void serial(NLMISC::IStream &s) { s.serial(_ServiceId); } std::string toString() const { return NLMISC::toString(_ServiceId); } bool fromString(const std::string &str) { return NLMISC::fromString(str, _ServiceId); } }; /** Callback function type for service up/down processing * \param serviceName name of the service that is un/registered to the naming service * \param arg a pointer initialized by the user */ typedef void (*TUnifiedNetCallback) (const std::string &serviceName, TServiceId sid, void *arg); /** Callback function type for message processing * \param msgin message received * \param serviceName name of the service that sent the message * \param sid id of the service that sent the message */ typedef void (*TUnifiedMsgCallback) (CMessage &msgin, const std::string &serviceName, TServiceId sid); /// Callback items. See CMsgSocket::update() for an explanation on how the callbacks are called. struct TUnifiedCallbackItem { /// Key C string. It is a message type name, or "C" for connection or "D" for disconnection const char *Key; /// The callback function TUnifiedMsgCallback Callback; }; /** * Layer 5 * * When calling send(), a message is stored in a queue. It will be effectively sent * when a flush is done. By default, the variable FlushSendsBeforeSleep is on so that * the message is sent in the same update cycle as the send() call. If FlushSendsBeforeSleep * is set to off, more messages will be sent together, but with a greater delay. * * Handling network congestion: * When a destination service is not fast enough to process the incoming messages, * the uploading stream can get saturated. As a result, a single flush will not manage to send the * entire data at a time. The NeL Network Layer 5 will silently continue streaming up the remaining * parts of the unsent data, as long as update() is called evenly. * More in depth: * - Either let the layer 5 handle network congestions. If the destination service is slow or * stuck and the source service still has data to send, the delivery may be delayed for a long * time. If your source service is shut down (calling release()) while some data is still pending, * a call to release(true) may take a while or even not exit while the destination service is stuck. * - Or handle yourself network congestions by calling tryFlushAllQueues() multiple times. Then you can display * the progression of sending, abort it if too long, etc. * * \author Vianney Lecroart, Benjamin Legros, Olivier Cado * \author Nevrax France * \date 2002-2004 */ class CUnifiedNetwork : public NLMISC::ICommandsHandler { NLMISC_SAFE_SINGLETON_DECL_PTR(CUnifiedNetwork); public: virtual const std::string &getCommandHandlerName() const { static const std::string name("unifiedNetwork"); return name; } /** Returns the singleton instance of the CUnifiedNetwork class. */ // static CUnifiedNetwork *getInstance (); /** Returns true if the application called getInstance(). This function is used to know if the user is using layer 4 or layer 5 */ static bool isUsed (); /** Creates the connection to the Naming Service. * If the connection failed, ESocketConnectionFailed exception is generated. * This function is called automatically called by the service class at the beginning. * * \param addr address of the naming service (0 is you don't want to use the naming service) * \param rec recording state to know if we have to record or replay messages * \return false if the instance startup was denied by the naming service */ bool init (const CInetAddress *addr, CCallbackNetBase::TRecordingState rec, const std::string &shortName, uint16 port, TServiceId &sid ); /** Registers to the Naming Service, and connects to the present services */ void connect(); /** Closes the connection to the naming service, every other connection and free. * \param mustFlushSendQueues If true, all send queues or only queues in namesOfOnlyServiceToFlushSending * will be really sent before disconnecting. In some cases disconnect(true) can take a while. * \param namesOfOnlyServiceToFlushSending When mustFlushSendQueues is true, this param can hold * a list of service short names. Only the send queues to the services specified * will be flushed (and waited) at exit. If the list is empty (and mustFlushSendQueues is true), * all the queues will be flushed (and waited). * See also "Handling network congestion" in CUnifiedNetwork above comments, and tryFlushAllQueues(). */ void release (bool mustFlushSendQueues=true, const std::vector& namesOfOnlyServiceToFlushSending=std::vector() ); /** Adds a specific service to the list of connected services. * * If the connection succeeds immediately (i.e. the specified service is already online), * service up callbacks (for this service and for "*") will be called from within addService(). * If the service is not available, the connection will be attempted evently in a background thread. * Then when it will become available, the service up callbacks will be called. * * Warning: currently, this method must not be called within a network callback. */ void addService(const std::string &name, const CInetAddress &addr, bool sendId = true, bool external = true, TServiceId sid=TServiceId(), bool autoRetry = true, bool shouldBeAlreayInserted = false); void addService(const std::string &name, const std::vector &addr, bool sendId = true, bool external = true, TServiceId sid=TServiceId(), bool autoRetry = true, bool shouldBeAlreayInserted = false); /** Adds a callback array in the system. You can add callback only *after* adding the server, the client or the group. */ void addCallbackArray (const TUnifiedCallbackItem *callbackarray, sint arraysize); /** Call it evenly. the parameter select the timeout value in seconds for each update. You are absolutely certain that this * function will not be returns before this amount of time you set. * If you set the update timeout value higher than 0, all messages in queues will be process until the time is greater than the timeout user update(). * If you set the update timeout value to 0, all messages in queues will be process one time before calling the user update(). In this case, we don't nlSleep(1). */ void update (NLMISC::TTime timeout = 0); /** Sends a message to a specific serviceName. If there's more than one service with this name, all services of this name will receive the message. * \param serviceName name of the service you want to send the message (may not be unique.) * \param msg the message you want to send. * \param nid Network Id specify to which network the message must pass throw (0xFF mean the default network) * \return the number of service instances found (may be counter even if the sending failed) */ uint send (const std::string &serviceName, const CMessage &msg, bool warnIfNotFound=true, uint8 nid=0xFF); /** Sends a message to a specific serviceId. * \param serviceId Id of the service you want to send the message. * \param msg the message you want to send. * \param nid Network Id specify to which network the message must pass throw (0xFF mean the default network) * \return true if the service was found (may return true even if the sending failed) */ bool send (TServiceId serviceId, const CMessage &msg, uint8 nid=0xFF); /** Broadcasts a message to all connected services. * \param msg the message you want to send. * \param nid Network Id specify to which network the message must pass throw (0xFF mean the default network) */ void sendAll (const CMessage &msg, uint8 nid=0xFF); /** Flush all or part of the sending queues, and report the number of bytes still pending. * To ensure manually all data are sent before stopping a service, you may want * to repeat calling this method evenly until it returns 0. The default release(false) of * CUnifiedNetwork only flushes each connection once, but if the network is * congested (when there are big streams to send) the first flush may not * succeed to send entire buffers. * \param namesOfOnlyServiceToFlushSending If not empty, only the send queues to the * services specified (by short name) will be flushed. * See also "Handling network congestion" in CUnifiedNetwork above comments. */ uint tryFlushAllQueues(const std::vector& namesOfOnlyServiceToFlushSending=std::vector()); /** Sets callback for incoming connections. * On a client, the callback will be called when the connection to the server is established (the first connection or after the server shutdown and started) * On a server, the callback is called each time a new client is connected to him * * You can set more than one callback, each one will be called one after one. * If the serviceName is "*", the callback will be call for any services, including 'external' services * (i.e. services not in the NS address space, usually connected by calling addService() manually) * If you set the same callback for a specific service S and for "*", the callback might be * called twice (in case the service S is up) * * \param back if true, put the callback at the end of the callback array, otherwise but on the beginning. You should always use true */ void setServiceUpCallback (const std::string &serviceName, TUnifiedNetCallback cb, void *arg = 0, bool back=true); /** Remove a service up callback */ void removeServiceUpCallback (const std::string &serviceName, TUnifiedNetCallback cb, void *arg = 0); /** Sets callback for disconnections. * On a client, the callback will be call each time the connection to the server is lost. * On a server, the callback is called each time a client is disconnected. * * You can set more than one callback, each one will be called one after one. * If the serviceName is "*", the callback will be call for any services, including 'external' services * (i.e. services not in the NS address space, usually connected by calling addService() manually) * If you set the same callback for a specific service S and for "*", the callback might be * called twice (in case the service S is down) * * \param back if true, put the callback at the end of the callback array, otherwise but on the beginning. You should always use true */ void setServiceDownCallback (const std::string &serviceName, TUnifiedNetCallback cb, void *arg = 0, bool back=true); /** Remove a service down callback */ void removeServiceDownCallback (const std::string &serviceName, TUnifiedNetCallback cb, void *arg = 0); /** Associate a string with a network id * If the send don't set a specific nid, it ll use the 0, so be sure that the nid 0 is set to a network. * You must call this function before the connect() function. * \param networkName must be in a xxx.xxx.xxx.xxx format. The low value will be ignore depending of the network class. * \param nid a number (used as an index in a vector for constant access so numbers should be contiguous) that will be use to send to this network. */ void addNetworkAssociation (const std::string &networkName, uint8 nid); /** Clear all network association */ void clearNetworkAssociation () { _NetworkAssociations.clear (); } /** This array says to which network we need to send the message for the default nid. * For example you can says that message for AES will use the network 0 and message for LS will use the network 1. * To do that, just call the function with string "AES0" and "LS1" the number is the nid (look at addNetworkAssociation()) * addNetworkAssociation("192.168.0.0", 0); addNetworkAssociation("192.168.1.0", 1); * In this case if you send a message to AES with default nid, it'll be send to 192.168.0.x * In this case if you send a message to LS with default nid, it'll be send to 192.168.1.y */ void addDefaultNetwork (const std::string &defnet) { nlinfo ("HNETL5: Add default network '%s'", defnet.c_str()); _DefaultNetwork.push_back (defnet); } /// Clear all default network void clearDefaultNetwork () { _DefaultNetwork.clear (); } /// Returns true if the sid service is on the same computer than this service bool isServiceLocal (TServiceId sid); /// Returns true if the serviceName service is on the same computer than this service bool isServiceLocal (const std::string &serviceName); /// Return the name of the specified service, or "" if not found std::string getServiceName(TServiceId sid); /// Return a string identifying the service, using the format "NAME-sid" (or "sid" only if not found) std::string getServiceUnifiedName(TServiceId sid); /// \warning You should not use getNetBase functions because it could have more than one connection to a service and in this case /// it ll return the first connection /// Gets the CCallbackNetBase of the service CCallbackNetBase *getNetBase(const std::string &name, TSockId &host, uint8 nid=0xFF); /// Gets the CCallbackNetBase of the service CCallbackNetBase *getNetBase(TServiceId sid, TSockId &host, uint8 nid=0xFF); /// Gets the total number of bytes sent uint64 getBytesSent (); /// Gets the total number of bytes received uint64 getBytesReceived (); /// Gets the total number of bytes queued for sending uint64 getSendQueueSize (); /// Gets the total number of bytes queued after receiving uint64 getReceiveQueueSize (); /// Find a callback in the array TUnifiedMsgCallback findCallback (const std::string &callbackName); /// Return the service ids of the active connections const std::vector& getConnectionList() const { return _UsedConnection; } /// Return the state of the connection (return true if the connection is fully connected) bool isConnectionConnected(TServiceId sid) const; void displayInternalTables (NLMISC::CLog *log = NLMISC::InfoLog); void displayUnifiedConnection (TServiceId sid, NLMISC::CLog *log = NLMISC::InfoLog) { getUnifiedConnection(sid)->display(false, log); } private: /// A map of service ids, referred by a service name struct TNameMappedConnection : public CHashMultiMap {}; /// A map of callbacks, referred by message name typedef std::map TMsgMappedCallback; /// A callback and its user data typedef std::pair TCallbackArgItem; /// A map of service up/down callbacks with their user data. typedef CHashMap > TNameMappedCallback; /// This may contains a CCallbackClient or a TSockId, depending on which type of connection it is. class CUnifiedConnection { public: /// NotUsed = the unified connection is empty, not used /// Ready = we can use the unified connection enum TState { NotUsed, Ready }; /// The connection structure struct TConnection { /// If the current service is connect to the other service as a server or a client bool IsServerConnection; /// If it s a client connection, it's the client connection otherwise it s the server connection CCallbackNetBase *CbNetBase; /// If it s a server connection, it's the host id, it s InvalidId if it s a client TSockId HostId; TConnection() : IsServerConnection(false), CbNetBase(NULL), HostId(InvalidSockId) { } TConnection(CCallbackClient *cbc) : IsServerConnection(false), CbNetBase(cbc), HostId(InvalidSockId) { } TConnection(CCallbackNetBase *cbnb, TSockId hi) : IsServerConnection(true), CbNetBase(cbnb), HostId(hi) { } void setAppId (uint64 appid) { CbNetBase->getSockId (HostId)->setAppId (appid); } uint64 getAppId () { return CbNetBase->getSockId (HostId)->appId (); } bool valid () { if(IsServerConnection) return CbNetBase != 0 && HostId != InvalidSockId; else return CbNetBase != 0; } void reset () { if (CbNetBase != 0) { if (IsServerConnection) { if (HostId != InvalidSockId) CbNetBase->disconnect (HostId); } else { CbNetBase->disconnect (); delete CbNetBase; } } CbNetBase = 0; IsServerConnection = false; HostId = InvalidSockId; } }; /// The name of the service (may not be unique) std::string ServiceName; /// The id of the service (is unique) TServiceId ServiceId; /// If the service entry is used TState State; /// If the connection is extern to the naming service bool IsExternal; /// Auto-retry mode bool AutoRetry; /// Valid External bool ValidExternal; /// Validation Requested bool ValidRequested; /// Auto identify at connection bool SendId; /// Used for debug purpose uint AutoCheck; /// The external connection address std::vector ExtAddress; /// Connection to the service (me be > 1) std::vector Connections; /// This is used to associate a nid (look addNetworkAssociation) with a TConnection. std::vector NetworkConnectionAssociations; /// This contains the connection id that will be used for default network, it's a connection id used for Connection index uint8 DefaultNetwork; uint32 TotalCallbackCalled; CUnifiedConnection() { reset(); } CUnifiedConnection(const std::string &name, TServiceId id, bool isExternal) { reset (); ServiceName = name; ServiceId = id; State = Ready; IsExternal = isExternal; } CUnifiedConnection(const std::string &name, TServiceId id, CCallbackClient *cbc) { reset (); ServiceName = name; ServiceId = id; State = Ready; Connections.push_back(TConnection (cbc)); } void display (bool full, NLMISC::CLog *log = NLMISC::InfoLog); void reset() { ServiceName = "DEAD"; ServiceId = TServiceId(0xDEAD); State = NotUsed; IsExternal = false; ValidExternal = false; ValidRequested = false; AutoRetry = false; SendId = false; AutoCheck = false; ExtAddress.clear (); for (uint i = 0; i < Connections.size (); i++) Connections[i].reset(); Connections.clear (); DefaultNetwork = 0xDD; NetworkConnectionAssociations.clear(); TotalCallbackCalled = 0; } // this function wrap the global default network and network association with this specific connection because they can have // different index void setupNetworkAssociation (const std::vector &networkAssociations, const std::vector &defaultNetwork) { for (uint i = 0; i < networkAssociations.size (); i++) { uint j; for (j = 0; j < ExtAddress.size (); j++) { if (ExtAddress[j].internalNetAddress() == networkAssociations[i]) { // we found an association, add it if (i >= NetworkConnectionAssociations.size ()) NetworkConnectionAssociations.resize (i+1); NetworkConnectionAssociations[i] = uint8(j); nlinfo ("HNETL5: nid %u will be use connection %u", i, j); break; } } if (j == ExtAddress.size ()) { nlinfo ("HNETL5: nid %u is not found", i); } } // find the default network std::vector::size_type j; for (j = 0; j < defaultNetwork.size (); j++) { std::string::size_type pos = defaultNetwork[j].find(ServiceName); if (pos != std::string::npos && pos == 0 && ServiceName.size() == defaultNetwork[j].size ()-1) { uint8 nid = defaultNetwork[j][defaultNetwork[j].size ()-1] - '0'; DefaultNetwork = NetworkConnectionAssociations[nid]; nlinfo ("HNETL5: default network for '%s' will be nid %hu and connection id %hu", ServiceName.c_str(), (uint16)nid, (uint16)DefaultNetwork); break; } } if (j == defaultNetwork.size ()) { if (NetworkConnectionAssociations.size ()>0) DefaultNetwork = NetworkConnectionAssociations[0]; else DefaultNetwork = 0; if (defaultNetwork.size () > 0) nlwarning ("HNETL5: default network not found in the array, will use connection id %hu", (uint16)DefaultNetwork); } } }; NLMISC_COMMAND_HANDLER_TABLE_BEGIN(CUnifiedNetwork) NLMISC_COMMAND_HANDLER_ADD(CUnifiedNetwork, addService, "Add a service in the unified network", " ( address= [sid=] [sendId] [external] [autoRetry] )") NLMISC_COMMAND_HANDLER_TABLE_END NLMISC_CLASS_COMMAND_DECL(addService); protected: /// Auto-reconnect void autoReconnect( CUnifiedConnection &uc, uint connectionIndex ); #ifdef NL_OS_UNIX /// Sleep (implemented by select()) void sleepUntilDataAvailable( NLMISC::TTime msecMax ); #endif private: /// Vector of connections by service id (sid is the entry in this array, it means that there s some hole) std::vector _IdCnx ; /// Vector of closed connection to reset outside of the client update loop std::vector _ConnectionToReset; /// This vector contains only an index to the unified connection. It is used to have quick access on the available connections std::vector _UsedConnection; /// Map of connections by service name TNameMappedConnection _NamedCnx; /// The callback server CCallbackServer *_CbServer; /// Map of the up/down service callbacks TNameMappedCallback _UpCallbacks; std::vector _UpUniCallback; TNameMappedCallback _DownCallbacks; std::vector _DownUniCallback; /// Recording state CCallbackNetBase::TRecordingState _RecordingState; /// Service name std::string _Name; /// Map of callbacks TMsgMappedCallback _Callbacks; /// The server port uint16 _ServerPort; /// Used for external service TServiceId _ExtSId; /// Last time of retry NLMISC::TTime _LastRetry; /// Time of the theoretical next update NLMISC::TTime _NextUpdateTime; /// The main instance // static CUnifiedNetwork *_Instance; /// Naming service NLNET::CInetAddress _NamingServiceAddr; /// for each nid, which network address std::vector _NetworkAssociations; /// for each services, which network to take std::vector _DefaultNetwork; #ifdef NL_OS_UNIX /// Pipe to select() on data available (shared among all connections) int _MainDataAvailablePipe [2]; #endif /// Service id of the running service TServiceId _SId; /// true if initialization function called bool _Initialised; // CUnifiedNetwork() : ICommandsHandler(), _CbServer(0), _ExtSId(256), _LastRetry(0), _NextUpdateTime(0), _Initialised(false) { } ~CUnifiedNetwork() {} // void autoCheck(); // Return the unified connection if available or NULL. // Don't keep the pointer because it can be invalid if the table is resized. CUnifiedConnection *getUnifiedConnection (TServiceId sid, bool warn=true); bool haveNamedCnx (const std::string &name, TServiceId sid); void addNamedCnx (const std::string &name, TServiceId sid); void removeNamedCnx (const std::string &name, TServiceId sid); // with a sid and a nid, find a good connection to send a message uint8 findConnectionId (TServiceId sid, uint8 nid); void callServiceUpCallback (const std::string &serviceName, TServiceId sid, bool callGlobalCallback = true); void callServiceDownCallback (const std::string &serviceName, TServiceId sid, bool callGlobalCallback = true); friend void uncbConnection(TSockId from, void *arg); friend void uncbDisconnection(TSockId from, void *arg); friend void uncbServiceIdentification(CMessage &msgin, TSockId from, CCallbackNetBase &netbase); friend void uncbMsgProcessing(CMessage &msgin, TSockId from, CCallbackNetBase &netbase); friend void uNetRegistrationBroadcast(const std::string &name, TServiceId sid, const std::vector &addr); friend void uNetUnregistrationBroadcast(const std::string &name, TServiceId sid, const std::vector &addr); friend struct nel_isServiceLocalClass; friend struct nel_l5CallbackClass; friend struct nel_l5QueuesStatsClass; }; } // NLNET #endif // NL_UNIFIED_NETWORK_H /* End of unified_network.h */ ================================================ FILE: code/nel/include/nel/net/unitime.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_UNITIME_H #define NL_UNITIME_H #include "nel/misc/types_nl.h" #include "nel/misc/time_nl.h" #include "nel/misc/debug.h" #include "callback_net_base.h" namespace NLNET { class CInetAddress; class CCallbackServer; class CCallbackClient; /** * This class provide a independant universal time system. * \author Vianney Lecroart * \author Nevrax France * \date 2000 * * THIS CLASS IS DEPRECATED, DON'T USE IT * */ class _CUniTime : public NLMISC::CTime { public: /// Return the time in millisecond. This time is the same on all computers at the \b same moment. static NLMISC::TTime getUniTime (); /// Return the time in a string format to be display static const char *getStringUniTime (); /// Return the time in a string format to be display static const char *getStringUniTime (NLMISC::TTime ut); /** You need to call this function before calling getUniTime or an assert will occured. * This function will connect to the time service and synchronize your computer. * This function assumes that all services run on server that are time synchronized with NTP for example. * If addr is NULL, the function will connect to the Time Service via the Naming Service. In this case, * the CNamingClient must be connected to a Naming Service. * This function can be called *ONLY* by services that are inside of the shard. * Don't use it for a client or a service outside of the shard. */ static void syncUniTimeFromService (CCallbackNetBase::TRecordingState rec=CCallbackNetBase::Off, const CInetAddress *addr = NULL); /** Call this function in the init part of the front end service to enable time syncro between * shard and clients. */ static void installServer (CCallbackServer *server); /** Call this functions in the init part of the client side to synchronize between client and shard. * client is the connection between the client and the front end. The connection must be established before * calling this function. */ static void syncUniTimeFromServer (CCallbackClient *client); /** \internal used by the time service to set the universal time the first time */ static void setUniTime (NLMISC::TTime uTime, NLMISC::TTime lTime); /** \internal */ static void setUniTime (NLMISC::TTime uTime); /** * Call this method before to prevent syncUniTimeFromService() from real synchronization: * syncUniTimeFromService() will still communicate with the time service, as usual, * but the local time will not be synchronized. */ static void simulate() { nlstop; _Simulate = true; } static bool Sync; // true if the synchronization occured private: static NLMISC::TTime _SyncUniTime; // time in millisecond when the universal time received static NLMISC::TTime _SyncLocalTime; // time in millisecond when the syncro with universal time occured // If true, do not synchronize static bool _Simulate; }; } // NLNET #endif // NL_UNITIME_H /* End of unitime.h */ ================================================ FILE: code/nel/include/nel/net/varpath.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_VARPATH_H #define NL_VARPATH_H #include "nel/misc/types_nl.h" class CVarPath { public: CVarPath (const std::string &raw) : RawVarPath(raw) { decode (); } void decode (); std::vector > Destination; void display (); /// returns true if there's no more . in the path bool isFinal (); bool empty () { return Destination.empty(); } private: std::string getToken (); std::string RawVarPath; uint32 TokenPos; }; #endif // NL_VARPATH_H /* End of varpath.h */ ================================================ FILE: code/nel/nel-config.in ================================================ #!/bin/sh # # # nel-config # # Script printing NeL's install library/include paths and some other # informations like NeL's version # prefix=@prefix@ exec_prefix=@exec_prefix@ lib_dir="@libdir@" include_dir="@includedir@" enable_ligo=@enable_ligo@ enable_georges=@enable_georges@ enable_net=@enable_net@ enable_3d=@enable_3d@ enable_pacs=@enable_pacs@ enable_sound=@enable_sound@ enable_logic=@enable_logic@ usage() { cat <&2 fi while test $# -gt 0 do case "$1" in -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac case $1 in --prefix=*) prefix=$optarg local_prefix=yes ;; --prefix) echo_prefix=yes ;; --exec-prefix=*) exec_prefix=$optarg exec_prefix_set=yes local_prefix=yes ;; --exec-prefix) echo_exec_prefix=yes ;; --version) echo @VERSION@ exit 0 ;; --cflags) echo_cflags=yes ;; --ldflags) echo_ldflags=yes ;; --libs) echo_libs=yes ;; --libtool) echo_libtool=yes ;; --without-ligo) without_ligo=yes ;; --without-logic) without_logic=yes ;; --without-georges) without_georges=yes ;; --without-net|--without-network) without_net=yes ;; --without-3d) without_3d=yes ;; --without-pacs) without_pacs=yes ;; --without-snd|--without-sound) without_sound=yes ;; *) usage 1 1>&2 ;; esac shift done if test "$local_prefix" = "yes" then if test "$exec_prefix_set" != "yes" then exec_prefix=$prefix fi fi if test "$echo_prefix" = "yes" then echo $prefix fi if test "$echo_exec_prefix" = "yes" then echo $exec_prefix fi if test "$echo_cflags" = "yes" then cflags="-I$include_dir" echo $cflags fi if test "$echo_ldflags" = "yes" then ldflags="-L$lib_dir" echo $ldflags fi if test "$echo_libs" = "yes" then lib_misc="-lnelmisc" lib_ligo="-lnelligo" lib_logic="-lnellogic" lib_georges="-lnelgeorges" lib_net="-lnelnet" lib_3d="-lnel3d" lib_pacs="-lnelpacs" lib_sound="-lnelsound -lnelsnd_lowlevel" lib_ai="-lnelai" libs="$lib_misc" if test "$without_ligo" != "yes" -a '(' "$enable_ligo" = "yes" -o "$enable_ligo" = "ON" ')' then libs="$libs $lib_ligo" fi if test "$without_logic" != "yes" -a '(' "$enable_logic" = "yes" -o "$enable_logic" = "ON" ')' then libs="$libs $lib_logic" fi if test "$without_georges" != "yes" -a '(' "$enable_georges" = "yes" -o "$enable_georges" = "ON" ')' then libs="$libs $lib_georges" fi if test "$without_net" != "yes" -a '(' "$enable_net" = "yes" -o "$enable_net" = "ON" ')' then libs="$libs $lib_net" fi if test "$without_3d" != "yes" -a '(' "$enable_3d" = "yes" -o "$enable_3d" = "ON" ')' then libs="$libs $lib_3d" fi if test "$without_pacs" != "yes" -a '(' "$enable_pacs" = "yes" -o "$enable_pacs" = "ON" ')' then libs="$libs $lib_pacs" fi if test "$without_sound" != "yes" -a '(' "$enable_sound" = "yes" -o "$enable_sound" = "ON" ')' then libs="$libs $lib_sound" fi echo -L@libdir@ $libs fi if test "$echo_libtool" = "yes" then libtool_misc="$lib_dir/libnelmisc.la" libtool_ligo="$lib_dir/libnelligo.la" libtool_logic="$lib_dir/libnellogic.la" libtool_georges="$lib_dir/libnelgeorges.la" libtool_net="$lib_dir/libnelnet.la" libtool_3d="$lib_dir/libnel3d.la" libtool_pacs="$lib_dir/libnelpacs.la" libtool_sound="$lib_dir/libnelsnd.la" libtool="$libtool_misc" if test "$without_ligo" != "yes" then libtool="$libtool $libtool_ligo" fi if test "$without_logic" != "yes" then libtool="$libtool $libtool_logic" fi if test "$without_georges" != "yes" then libtool="$libtool $libtool_georges" fi if test "$without_net" != "yes" then libtool="$libtool $libtool_net" fi if test "$without_3d" != "yes" then libtool="$libtool $libtool_3d" fi if test "$without_pacs" != "yes" then libtool="$libtool $libtool_pacs" fi if test "$without_sound" != "yes" then libtool="$libtool $libtool_sound" fi echo $libtool fi # EOF ================================================ FILE: code/nel/samples/CMakeLists.txt ================================================ ADD_SUBDIRECTORY(misc) IF(WITH_GEORGES) ADD_SUBDIRECTORY(georges) ENDIF(WITH_GEORGES) IF(WITH_NET) ADD_SUBDIRECTORY(net) ENDIF(WITH_NET) ================================================ FILE: code/nel/samples/georges/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp) ADD_EXECUTABLE(nl_sample_georges ${SRC}) ADD_DEFINITIONS(-DGF_DIR="\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_georges/\\"") TARGET_LINK_LIBRARIES(nl_sample_georges nelgeorges nelmisc) NL_DEFAULT_PROPS(nl_sample_georges "NeL, Samples: Georges") NL_ADD_RUNTIME_FLAGS(nl_sample_georges) INSTALL(TARGETS nl_sample_georges RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesgeorges) INSTALL(FILES boolean.typ coolfilesinfo.dfn default.sample_config int.typ positiondata.dfn sample_config.dfn string.typ sheet_id.bin DESTINATION ${NL_SHARE_PREFIX}/nl_sample_georges/ COMPONENT samplesgeorges) ================================================ FILE: code/nel/samples/georges/boolean.typ ================================================ ================================================ FILE: code/nel/samples/georges/coolfilesinfo.dfn ================================================ ================================================ FILE: code/nel/samples/georges/default.sample_config ================================================
================================================ FILE: code/nel/samples/georges/int.typ ================================================ ================================================ FILE: code/nel/samples/georges/log.log ================================================ Log Starting [2012/12/08 11:03:34] 2012/12/08 11:03:34 INF c24 nl_sample_georges.exe path.cpp 936 NLMISC::CFileContainer::addSearchPath : PATH: CPath::addSearchPath("../share/nel/nl_sample_georges/", not recursive, not alternative): '"../share/nel/nl_sample_georges/"' is not a directory, I'll call addSearchFile() 2012/12/08 11:03:34 WRN c24 nl_sample_georges.exe path.cpp 1077 NLMISC::CFileContainer::addSearchFile : PATH: CPath::addSearchFile("../share/nel/nl_sample_georges/", 0, ''): '"../share/nel/nl_sample_georges/"' is not found, skip it (current dir is 'D:/ext/server-0/trunk/server/code/nel/samples/georges' 2012/12/08 11:04:44 WRN c24 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElm::getInternalNodeByName) on node (.) in form (default.sample_config) : Getting the node (.Foobar) : Struct does not contain element named (Foobar). 2012/12/08 11:04:44 WRN c24 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElmStruct::getValueByName) on node () in form (default.sample_config) : Can't find the node (.Foobar). 2012/12/08 11:04:56 INF c24 nl_sample_georges.exe main.cpp 180 main : Test Value 1: 1 2012/12/08 11:04:56 INF c24 nl_sample_georges.exe main.cpp 181 main : Test Value 2: 2 2012/12/08 11:04:57 INF c24 nl_sample_georges.exe main.cpp 182 main : Foo Retrieval was: false 2012/12/08 11:04:58 INF c24 nl_sample_georges.exe main.cpp 189 main : Retrieved Position Data (x,y,z): 1, 1, 2 2012/12/08 11:05:00 INF c24 nl_sample_georges.exe main.cpp 195 main : TestArray retrieval returned: true 2012/12/08 11:05:02 INF c24 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 1 2012/12/08 11:05:03 INF c24 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 2 2012/12/08 11:05:18 INF c24 nl_sample_georges.exe main.cpp 223 main : Retrieving CoolFilesInfo returned: true 2012/12/08 11:05:18 INF c24 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 0: |Tiger Eats Man In One Bite| - Tiger Attack at 55 (9) 2012/12/08 11:05:18 INF c24 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 1: |Tiny Car Jumps Bridge Over River| - Crazy Car Jump at 40 (5) 2012/12/08 11:05:18 INF c24 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 2: |Nevrax Presents Cool Open Source Contributors Awards| - Nevrax Gives Awards at 1 (1) 2012/12/08 11:05:18 INF c24 nl_sample_georges.exe main.cpp 258 main : Bool Backet 1: true, Bool Bracket 2: false 2012/12/08 11:05:18 INF c24 nl_sample_georges.exe main.cpp 267 main : Retrieved .CoolFilesInfo[2].Ranking using bracket and dot notation: 1 2012/12/08 11:05:18 INF c24 nl_sample_georges.exe main.cpp 268 main : Retrieved .CoolFilesInfo[1].ShortName using bracket and dot notation: Crazy Car Jump 2012/12/08 11:05:21 INF c24 nl_sample_georges.exe main.cpp 286 main : Updated WriteVal, it already existed in the form. 2012/12/08 11:06:04 INF c24 nl_sample_georges.exe main.cpp 293 main : Saved sample config file. 2012/12/08 11:06:22 INF c24 nl_sample_georges.exe main.cpp 310 main : Begin loading packed sheets. 2012/12/08 11:07:27 WRN c24 nl_sample_georges.exe file.cpp 265 NLMISC::CIFile::open : Failed to open file 'sample_configs.packed_sheets', error 2 : No such file or directory 2012/12/08 11:07:28 INF c24 nl_sample_georges.exe load_form.h 878 loadForm : loadForm(): Loading packed file 'sample_configs.packed_sheets' 2012/12/08 11:07:32 INF c24 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: Read error in file 'sample_configs.packed_sheets' (End of file?) 2012/12/08 11:07:42 INF c24 nl_sample_georges.exe load_form.h 943 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (Read error in file 'sample_configs.packed_sheets' (End of file?)) 2012/12/08 11:08:57 INF c24 nl_sample_georges.exe main.cpp 312 main : Number of sheets loaded: 0 2012/12/08 11:10:17 INF c24 nl_sample_georges.exe main.cpp 315 main : Load packed sheets using CSheetId and the sheet_id.bin 2012/12/08 11:10:20 INF c24 nl_sample_georges.exe sheet_id.cpp 195 NLMISC::CSheetId::loadSheetId : SHEETID: Removed 2 files on 2 from CSheetId because these files don't exist 2012/12/08 11:10:20 DBG c24 nl_sample_georges.exe sheet_id.cpp 274 NLMISC::CSheetId::loadSheetId : Finished loading sheet_id.bin: 0 entries read 2012/12/08 11:10:20 WRN c24 nl_sample_georges.exe file.cpp 265 NLMISC::CIFile::open : Failed to open file 'sample_configs_sheets.packed_sheets', error 2 : No such file or directory 2012/12/08 11:10:20 INF c24 nl_sample_georges.exe common.cpp 573 NLMISC::Exception::Exception : Exception will be launched: can't open PackedSheet sample_configs_sheets.packed_sheets 2012/12/08 11:10:20 INF c24 nl_sample_georges.exe load_form.h 219 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (can't open PackedSheet sample_configs_sheets.packed_sheets) 2012/12/08 11:10:21 INF c24 nl_sample_georges.exe main.cpp 317 main : Number of sheets loaded with CSheetId's: 0 Log Starting [2012/12/08 11:20:24] 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe path.cpp 936 NLMISC::CFileContainer::addSearchPath : PATH: CPath::addSearchPath("../share/nel/nl_sample_georges/", not recursive, not alternative): '"../share/nel/nl_sample_georges/"' is not a directory, I'll call addSearchFile() 2012/12/08 11:20:24 WRN 1320 nl_sample_georges.exe path.cpp 1077 NLMISC::CFileContainer::addSearchFile : PATH: CPath::addSearchFile("../share/nel/nl_sample_georges/", 0, ''): '"../share/nel/nl_sample_georges/"' is not found, skip it (current dir is 'D:/ext/server-0/trunk/server/code/nel/samples/georges' 2012/12/08 11:20:24 WRN 1320 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElm::getInternalNodeByName) on node (.) in form (default.sample_config) : Getting the node (.Foobar) : Struct does not contain element named (Foobar). 2012/12/08 11:20:24 WRN 1320 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElmStruct::getValueByName) on node () in form (default.sample_config) : Can't find the node (.Foobar). 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 180 main : Test Value 1: 1 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 181 main : Test Value 2: 2 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 182 main : Foo Retrieval was: false 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 189 main : Retrieved Position Data (x,y,z): 1, 1, 2 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 195 main : TestArray retrieval returned: true 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 1 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 2 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 223 main : Retrieving CoolFilesInfo returned: true 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 0: |Tiger Eats Man In One Bite| - Tiger Attack at 55 (9) 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 1: |Tiny Car Jumps Bridge Over River| - Crazy Car Jump at 40 (5) 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 2: |Nevrax Presents Cool Open Source Contributors Awards| - Nevrax Gives Awards at 1 (1) 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 258 main : Bool Backet 1: true, Bool Bracket 2: false 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 267 main : Retrieved .CoolFilesInfo[2].Ranking using bracket and dot notation: 1 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 268 main : Retrieved .CoolFilesInfo[1].ShortName using bracket and dot notation: Crazy Car Jump 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 286 main : Updated WriteVal, it already existed in the form. 2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 293 main : Saved sample config file. 2012/12/08 11:20:25 INF 1320 nl_sample_georges.exe main.cpp 310 main : Begin loading packed sheets. 2012/12/08 11:20:26 WRN 1320 nl_sample_georges.exe file.cpp 265 NLMISC::CIFile::open : Failed to open file 'sample_configs.packed_sheets', error 2 : No such file or directory 2012/12/08 11:20:26 INF 1320 nl_sample_georges.exe load_form.h 878 loadForm : loadForm(): Loading packed file 'sample_configs.packed_sheets' 2012/12/08 11:20:26 INF 1320 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: Read error in file 'sample_configs.packed_sheets' (End of file?) 2012/12/08 11:20:26 INF 1320 nl_sample_georges.exe load_form.h 943 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (Read error in file 'sample_configs.packed_sheets' (End of file?)) 2012/12/08 11:20:26 INF 1320 nl_sample_georges.exe main.cpp 312 main : Number of sheets loaded: 0 2012/12/08 11:22:18 INF 1320 nl_sample_georges.exe main.cpp 315 main : Load packed sheets using CSheetId and the sheet_id.bin 2012/12/08 11:23:26 INF 1320 nl_sample_georges.exe sheet_id.cpp 195 NLMISC::CSheetId::loadSheetId : SHEETID: Removed 2 files on 2 from CSheetId because these files don't exist 2012/12/08 11:23:26 DBG 1320 nl_sample_georges.exe sheet_id.cpp 274 NLMISC::CSheetId::loadSheetId : Finished loading sheet_id.bin: 0 entries read 2012/12/08 11:23:31 INF 1320 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: In Stream: sample_configs_sheets.packed_sheets: Invalid data format Log Starting [2012/12/08 13:32:04] 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe path.cpp 936 NLMISC::CFileContainer::addSearchPath : PATH: CPath::addSearchPath("../share/nel/nl_sample_georges/", not recursive, not alternative): '"../share/nel/nl_sample_georges/"' is not a directory, I'll call addSearchFile() 2012/12/08 13:32:04 WRN 1028 nl_sample_georges.exe path.cpp 1077 NLMISC::CFileContainer::addSearchFile : PATH: CPath::addSearchFile("../share/nel/nl_sample_georges/", 0, ''): '"../share/nel/nl_sample_georges/"' is not found, skip it (current dir is 'D:/ext/server-0/trunk/server/code/nel/samples/georges' 2012/12/08 13:32:04 WRN 1028 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElm::getInternalNodeByName) on node (.) in form (default.sample_config) : Getting the node (.Foobar) : Struct does not contain element named (Foobar). 2012/12/08 13:32:04 WRN 1028 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElmStruct::getValueByName) on node () in form (default.sample_config) : Can't find the node (.Foobar). 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 180 main : Test Value 1: 1 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 181 main : Test Value 2: 2 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 182 main : Foo Retrieval was: false 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 189 main : Retrieved Position Data (x,y,z): 1, 1, 2 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 195 main : TestArray retrieval returned: true 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 1 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 2 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 223 main : Retrieving CoolFilesInfo returned: true 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 0: |Tiger Eats Man In One Bite| - Tiger Attack at 55 (9) 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 1: |Tiny Car Jumps Bridge Over River| - Crazy Car Jump at 40 (5) 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 2: |Nevrax Presents Cool Open Source Contributors Awards| - Nevrax Gives Awards at 1 (1) 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 258 main : Bool Backet 1: true, Bool Bracket 2: false 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 267 main : Retrieved .CoolFilesInfo[2].Ranking using bracket and dot notation: 1 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 268 main : Retrieved .CoolFilesInfo[1].ShortName using bracket and dot notation: Crazy Car Jump 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 286 main : Updated WriteVal, it already existed in the form. 2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 293 main : Saved sample config file. 2012/12/08 13:32:06 INF 1028 nl_sample_georges.exe main.cpp 310 main : Begin loading packed sheets. 2012/12/08 13:32:06 INF 1028 nl_sample_georges.exe load_form.h 878 loadForm : loadForm(): Loading packed file 'sample_configs.packed_sheets' 2012/12/08 13:32:06 INF 1028 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: Read error in file 'sample_configs.packed_sheets' (End of file?) 2012/12/08 13:32:06 INF 1028 nl_sample_georges.exe load_form.h 943 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (Read error in file 'sample_configs.packed_sheets' (End of file?)) 2012/12/08 13:32:06 DBG 1028 nl_sample_georges.exe load_form.h 968 loadForm : Can't find dependent file ! 2012/12/08 13:32:06 DBG 1028 nl_sample_georges.exe load_form.h 968 loadForm : Can't find dependent file yp ! 2012/12/08 13:32:06 DBG 1028 nl_sample_georges.exe load_form.h 968 loadForm : Can't find dependent file ! 2012/12/08 13:32:06 DBG 1028 nl_sample_georges.exe load_form.h 968 loadForm : Can't find dependent file ! 2012/12/08 13:32:06 DBG 1028 nl_sample_georges.exe load_form.h 968 loadForm : Can't find dependent file ! 2012/12/08 13:32:06 DBG 1028 nl_sample_georges.exe load_form.h 968 loadForm : Can't find dependent file ! 2012/12/08 13:32:07 INF 1028 nl_sample_georges.exe main.cpp 312 main : Number of sheets loaded: 0 2012/12/08 13:33:13 INF 1028 nl_sample_georges.exe main.cpp 315 main : Load packed sheets using CSheetId and the sheet_id.bin 2012/12/08 13:33:13 INF 1028 nl_sample_georges.exe sheet_id.cpp 195 NLMISC::CSheetId::loadSheetId : SHEETID: Removed 2 files on 2 from CSheetId because these files don't exist 2012/12/08 13:33:13 DBG 1028 nl_sample_georges.exe sheet_id.cpp 274 NLMISC::CSheetId::loadSheetId : Finished loading sheet_id.bin: 0 entries read 2012/12/08 13:33:13 WRN 1028 nl_sample_georges.exe file.cpp 265 NLMISC::CIFile::open : Failed to open file 'sample_configs_sheets.packed_sheets', error 2 : No such file or directory 2012/12/08 13:33:13 INF 1028 nl_sample_georges.exe common.cpp 573 NLMISC::Exception::Exception : Exception will be launched: can't open PackedSheet sample_configs_sheets.packed_sheets 2012/12/08 13:33:13 INF 1028 nl_sample_georges.exe load_form.h 219 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (can't open PackedSheet sample_configs_sheets.packed_sheets) 2012/12/08 13:33:14 INF 1028 nl_sample_georges.exe main.cpp 317 main : Number of sheets loaded with CSheetId's: 0 Log Starting [2012/12/08 13:33:32] 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe path.cpp 936 NLMISC::CFileContainer::addSearchPath : PATH: CPath::addSearchPath("../share/nel/nl_sample_georges/", not recursive, not alternative): '"../share/nel/nl_sample_georges/"' is not a directory, I'll call addSearchFile() 2012/12/08 13:33:32 WRN 74 nl_sample_georges.exe path.cpp 1077 NLMISC::CFileContainer::addSearchFile : PATH: CPath::addSearchFile("../share/nel/nl_sample_georges/", 0, ''): '"../share/nel/nl_sample_georges/"' is not found, skip it (current dir is 'D:/ext/server-0/trunk/server/code/nel/samples/georges' 2012/12/08 13:33:32 WRN 74 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElm::getInternalNodeByName) on node (.) in form (default.sample_config) : Getting the node (.Foobar) : Struct does not contain element named (Foobar). 2012/12/08 13:33:32 WRN 74 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElmStruct::getValueByName) on node () in form (default.sample_config) : Can't find the node (.Foobar). 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 180 main : Test Value 1: 1 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 181 main : Test Value 2: 2 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 182 main : Foo Retrieval was: false 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 189 main : Retrieved Position Data (x,y,z): 1, 1, 2 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 195 main : TestArray retrieval returned: true 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 1 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 2 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 223 main : Retrieving CoolFilesInfo returned: true 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 0: |Tiger Eats Man In One Bite| - Tiger Attack at 55 (9) 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 1: |Tiny Car Jumps Bridge Over River| - Crazy Car Jump at 40 (5) 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 2: |Nevrax Presents Cool Open Source Contributors Awards| - Nevrax Gives Awards at 1 (1) 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 258 main : Bool Backet 1: true, Bool Bracket 2: false 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 267 main : Retrieved .CoolFilesInfo[2].Ranking using bracket and dot notation: 1 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 268 main : Retrieved .CoolFilesInfo[1].ShortName using bracket and dot notation: Crazy Car Jump 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 286 main : Updated WriteVal, it already existed in the form. 2012/12/08 13:33:32 INF 74 nl_sample_georges.exe main.cpp 293 main : Saved sample config file. 2012/12/08 13:33:33 INF 74 nl_sample_georges.exe main.cpp 310 main : Begin loading packed sheets. 2012/12/08 13:33:33 WRN 74 nl_sample_georges.exe file.cpp 265 NLMISC::CIFile::open : Failed to open file 'sample_configs.packed_sheets', error 2 : No such file or directory 2012/12/08 13:33:33 INF 74 nl_sample_georges.exe load_form.h 878 loadForm : loadForm(): Loading packed file 'sample_configs.packed_sheets' 2012/12/08 13:33:33 INF 74 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: Read error in file 'sample_configs.packed_sheets' (End of file?) 2012/12/08 13:33:33 INF 74 nl_sample_georges.exe load_form.h 943 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (Read error in file 'sample_configs.packed_sheets' (End of file?)) 2012/12/08 13:33:33 INF 74 nl_sample_georges.exe main.cpp 312 main : Number of sheets loaded: 0 2012/12/08 13:33:35 INF 74 nl_sample_georges.exe main.cpp 315 main : Load packed sheets using CSheetId and the sheet_id.bin 2012/12/08 13:33:36 INF 74 nl_sample_georges.exe sheet_id.cpp 195 NLMISC::CSheetId::loadSheetId : SHEETID: Removed 2 files on 2 from CSheetId because these files don't exist 2012/12/08 13:33:36 DBG 74 nl_sample_georges.exe sheet_id.cpp 274 NLMISC::CSheetId::loadSheetId : Finished loading sheet_id.bin: 0 entries read 2012/12/08 13:33:36 INF 74 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: stream does not contain at least 256 bytes for check 2012/12/08 13:33:36 INF 74 nl_sample_georges.exe load_form.h 219 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (stream does not contain at least 256 bytes for check) 2012/12/08 13:33:36 DBG 74 nl_sample_georges.exe load_form.h 244 loadForm : Can't find dependent file ! 2012/12/08 13:33:36 DBG 74 nl_sample_georges.exe load_form.h 244 loadForm : Can't find dependent file yp ! 2012/12/08 13:33:36 DBG 74 nl_sample_georges.exe load_form.h 244 loadForm : Can't find dependent file ! 2012/12/08 13:33:36 DBG 74 nl_sample_georges.exe load_form.h 244 loadForm : Can't find dependent file ! 2012/12/08 13:33:36 DBG 74 nl_sample_georges.exe load_form.h 244 loadForm : Can't find dependent file ! 2012/12/08 13:33:36 DBG 74 nl_sample_georges.exe load_form.h 244 loadForm : Can't find dependent file ! 2012/12/08 13:33:36 INF 74 nl_sample_georges.exe main.cpp 317 main : Number of sheets loaded with CSheetId's: 0 Log Starting [2012/12/08 13:34:04] 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe path.cpp 936 NLMISC::CFileContainer::addSearchPath : PATH: CPath::addSearchPath("../share/nel/nl_sample_georges/", not recursive, not alternative): '"../share/nel/nl_sample_georges/"' is not a directory, I'll call addSearchFile() 2012/12/08 13:34:04 WRN c18 nl_sample_georges.exe path.cpp 1077 NLMISC::CFileContainer::addSearchFile : PATH: CPath::addSearchFile("../share/nel/nl_sample_georges/", 0, ''): '"../share/nel/nl_sample_georges/"' is not found, skip it (current dir is 'D:/ext/server-0/trunk/server/code/nel/samples/georges' 2012/12/08 13:34:04 WRN c18 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElm::getInternalNodeByName) on node (.) in form (default.sample_config) : Getting the node (.Foobar) : Struct does not contain element named (Foobar). 2012/12/08 13:34:04 WRN c18 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElmStruct::getValueByName) on node () in form (default.sample_config) : Can't find the node (.Foobar). 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 180 main : Test Value 1: 1 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 181 main : Test Value 2: 2 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 182 main : Foo Retrieval was: false 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 189 main : Retrieved Position Data (x,y,z): 1, 1, 2 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 195 main : TestArray retrieval returned: true 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 1 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 2 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 223 main : Retrieving CoolFilesInfo returned: true 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 0: |Tiger Eats Man In One Bite| - Tiger Attack at 55 (9) 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 1: |Tiny Car Jumps Bridge Over River| - Crazy Car Jump at 40 (5) 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 2: |Nevrax Presents Cool Open Source Contributors Awards| - Nevrax Gives Awards at 1 (1) 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 258 main : Bool Backet 1: true, Bool Bracket 2: false 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 267 main : Retrieved .CoolFilesInfo[2].Ranking using bracket and dot notation: 1 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 268 main : Retrieved .CoolFilesInfo[1].ShortName using bracket and dot notation: Crazy Car Jump 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 286 main : Updated WriteVal, it already existed in the form. 2012/12/08 13:34:04 INF c18 nl_sample_georges.exe main.cpp 293 main : Saved sample config file. 2012/12/08 13:34:05 INF c18 nl_sample_georges.exe main.cpp 310 main : Begin loading packed sheets. 2012/12/08 13:34:05 WRN c18 nl_sample_georges.exe file.cpp 265 NLMISC::CIFile::open : Failed to open file 'sample_configs.packed_sheets', error 2 : No such file or directory 2012/12/08 13:34:05 INF c18 nl_sample_georges.exe load_form.h 878 loadForm : loadForm(): Loading packed file 'sample_configs.packed_sheets' 2012/12/08 13:34:05 INF c18 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: Read error in file 'sample_configs.packed_sheets' (End of file?) 2012/12/08 13:34:05 INF c18 nl_sample_georges.exe load_form.h 943 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (Read error in file 'sample_configs.packed_sheets' (End of file?)) 2012/12/08 13:34:06 INF c18 nl_sample_georges.exe main.cpp 312 main : Number of sheets loaded: 0 2012/12/08 13:34:06 INF c18 nl_sample_georges.exe main.cpp 315 main : Load packed sheets using CSheetId and the sheet_id.bin 2012/12/08 13:34:27 INF c18 nl_sample_georges.exe sheet_id.cpp 195 NLMISC::CSheetId::loadSheetId : SHEETID: Removed 2 files on 2 from CSheetId because these files don't exist 2012/12/08 13:34:27 DBG c18 nl_sample_georges.exe sheet_id.cpp 274 NLMISC::CSheetId::loadSheetId : Finished loading sheet_id.bin: 0 entries read 2012/12/08 13:35:05 INF c18 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: stream does not contain at least 256 bytes for check ================================================ FILE: code/nel/samples/georges/main.cpp ================================================ /** * \file main.cpp * \date October 2004 * \author Matt Raykowski * * This sample shows how to load a Georges form and read parts from it. */ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // // System Includes // #include // // NeL Includes // #include "nel/misc/debug.h" #include "nel/georges/u_form_loader.h" #include "nel/georges/u_form.h" #include "nel/georges/u_form_elm.h" #include "nel/georges/load_form.h" #ifndef GF_DIR # define GF_DIR "." #endif struct TPositionData { uint X, Y, Z; /// This class must be serializable for the form to be packed. void serial(NLMISC::IStream &f) { f.serial(X); f.serial(Y); f.serial(Z); } }; struct TSampleConfig { /// Load a form, if necessary, and store its data in the members of this class. void readGeorges (const NLMISC::CSmartPtr &form, const NLMISC::CSheetId &sheetId) { readForm(form); } void readGeorges (const NLMISC::CSmartPtr &form, const std::string &sheetId) { readForm(form); } void readForm(const NLMISC::CSmartPtr &form) { nlinfo("Loading a sample config object."); // The system has already loaded the form and parsed it using a loader. So get the root node: NLGEORGES::UFormElm &root = form->getRootNode(); // And start loading the form values into the object. root.getValueByName(TestVal1, ".TestVal1"); root.getValueByName(TestVal2, ".TestVal2"); root.getValueByName(PosData.X,"PositionData.x"); root.getValueByName(PosData.Y,"PositionData.y"); root.getValueByName(PosData.Z,"PositionData.z"); // Get the array called "TestArray" NLGEORGES::UFormElm *testArray; root.getNodeByName(&testArray, ".TestArray"); if(testArray != NULL) { // Get the size of the array. uint size; testArray->getArraySize(size); // Cycle through the atoms in the array for(uint idx=0 ; idxgetArrayValue(arrayValue, idx); // And insert it into our container. TestArray.push_back(arrayValue); } } // And so on. We'll skip the rest of the sheet, you get the idea. // ... } /// This class must be serializable for the form to be packed. void serial(NLMISC::IStream &f) { f.serial(TestVal1); f.serial(TestVal2); f.serial(PosData); f.serialCont(TestArray); } /// This is called whenever the loader needs to remove an old sheet. void removed() { } /// This is used to make sure that changes in form/loader versions are correctly handled. This must be > 0. static uint getVersion() { return 1; } uint32 TestVal1; uint32 TestVal2; TPositionData PosData; std::vector TestArray; }; /// This contains the TSampleConfig sheets. std::map MySampleConfigsSheets; std::map MySampleConfigs; int main(void) { new NLMISC::CApplicationContext; // get a pointer ready for the form loader. NLGEORGES::UFormLoader *formLoader = NULL; NLMISC::CPath::addSearchPath(GF_DIR, false, false); try { // set the name of the form you're going to load. std::string sampleConfigFile = NLMISC::CPath::lookup("default.sample_config", false); // check to see if CPath found the config. if (!sampleConfigFile.empty()) { // we'll use this to test retrieving vars. bool res; // get a form loader. formLoader = NLGEORGES::UFormLoader::createLoader(); // this will hold the form we load - it must be contained in a smart pointer. NLMISC::CSmartPtr form; // load the form. form = formLoader->loadForm(sampleConfigFile.c_str()); // get the root of the form. NLGEORGES::UFormElm &root = form->getRootNode(); // retrieve the two test values uint32 testVal1, testVal2, badVar1; root.getValueByName(testVal1, ".TestVal1"); root.getValueByName(testVal2, ".TestVal2"); // try and get a var that doesn't exist. res=root.getValueByName(badVar1, ".Foobar"); if(res) { nlinfo("This should never have matched."); exit(1); } // and output them nlinfo("Test Value 1: %d",testVal1); nlinfo("Test Value 2: %d",testVal2); nlinfo("Foo Retrieval was: %s", res ? "true" : "false"); // Retrieve data from a root-level named struct uint xTest, yTest, zTest; root.getValueByName(xTest,"PositionData.x"); root.getValueByName(yTest,"PositionData.y"); root.getValueByName(zTest,"PositionData.z"); nlinfo("Retrieved Position Data (x,y,z): %d, %d, %d",xTest,yTest,zTest); // get a reference to the TestArray array... NLGEORGES::UFormElm *testArray; res=root.getNodeByName(&testArray, ".TestArray"); nlinfo("TestArray retrieval returned: %s", res ? "true" : "false"); // make sure it was there. if(testArray != NULL) { // get the size of the array. uint size; testArray->getArraySize(size); // cycle through the atoms in the array for(uint idx=0 ; idxgetArrayValue(arrayValue, idx); nlinfo("Found TestArray atom: %s",arrayValue.c_str()); } } else { if(res==true) nlinfo("TestArray wasn't configured properly but was found, double check the form."); else nlinfo("Something's wrong, the TestArray is missing from the form."); } // Next grab a set of structures from an array. NLGEORGES::UFormElm *coolFiles; res=root.getNodeByName(&coolFiles, ".CoolFilesInfo"); nlinfo("Retrieving CoolFilesInfo returned: %s", res ? "true" : "false"); if(coolFiles != NULL) { uint size; coolFiles->getArraySize(size); // cycle through the structs in the array. for(uint idx=0 ; idxgetArrayNode(&files, idx); // we can now access this struct in the array as a root. files->getValueByName(rank, ".Ranking"); files->getValueByName(toptenrank, ".TopTenRanking"); files->getValueByName(name, ".Name"); files->getValueByName(shortname, ".ShortName"); nlinfo("Retrieved struct %d: |%s| - %s at %d (%d)", idx, name.c_str(), shortname.c_str(), rank, toptenrank); } } else { if(res==true) nlinfo("CoolFilesInfo was found, but might have been entered incorrectly, double check the form."); else nlinfo("CoolFilesInfo wasn't found or there was a syntax error loading your form."); } // we can also access elements of an array by their backet identifier. std::string bbool1, bbool2; root.getValueByName(bbool1, ".TestByBracket[0]"); root.getValueByName(bbool2, ".TestByBracket[1]"); nlinfo("Bool Backet 1: %s, Bool Bracket 2: %s",bbool1.c_str(), bbool2.c_str()); // likewise you can access structures by index and dot notation. take the CoolFilesInfo. // the following should return 1, the ranking for the Nevrax Presents element. // and the 2nd one should return 'Crazy Car Jump' from that element. uint rankTest; std::string nameTest; root.getValueByName(rankTest, ".CoolFilesInfo[2].Ranking"); root.getValueByName(nameTest, ".CoolFilesInfo[1].ShortName"); nlinfo("Retrieved .CoolFilesInfo[2].Ranking using bracket and dot notation: %d", rankTest); nlinfo("Retrieved .CoolFilesInfo[1].ShortName using bracket and dot notation: %s", nameTest.c_str()); // if you set a value to a node name that doesn't exist, it's created. after running this you will see it listed in the form: uint writeValue; // first lets see if we can find it: res=root.getValueByName(writeValue,".WriteVal"); if(res) // if it existed, save the value and increment it. writeValue++; else writeValue=3; // now set the value. created tells us if the value was creaed or just updated. bool created; root.setValueByName(writeValue,".WriteVal",&created); if(created) { nlinfo("WriteVal wasn't found and was created."); } else { nlinfo("Updated WriteVal, it already existed in the form."); } // and finally save the form out in case we made changes. // if you're accessing a form read-only (not using set*) you can skip this. NLMISC::COFile saveSample(sampleConfigFile); form->write(saveSample, false); nlinfo("Saved sample config file."); } else { // CPath didn't find the file, just print an error and exit. nlinfo("Couldn't find the config file."); exit(1); } // finished, unload the form loader. NLGEORGES::UFormLoader::releaseLoader(formLoader); } catch(...) { // something went wrong, unload the form loader. nlinfo("Caught an exception, quitting."); NLGEORGES::UFormLoader::releaseLoader(formLoader); } // Now demonstrate the packed sheet system. nlinfo("Begin loading packed sheets."); ::loadForm( "sample_config", "sample_configs.packed_sheets", MySampleConfigs, true, false); nlinfo("Number of sheets loaded: %d", MySampleConfigs.size()); // Now demonstrate the packed sheet system using CSheetId's and the sheet_id.bin file. nlinfo("Load packed sheets using CSheetId and the sheet_id.bin"); ::loadForm( "sample_config", "sample_configs_sheets.packed_sheets", MySampleConfigsSheets, true, false); nlinfo("Number of sheets loaded with CSheetId's: %d", MySampleConfigsSheets.size()); } ================================================ FILE: code/nel/samples/georges/positiondata.dfn ================================================ ================================================ FILE: code/nel/samples/georges/sample_config.dfn ================================================ ================================================ FILE: code/nel/samples/georges/string.typ ================================================ Converted from old format Fri May 17 15:24:33 2002 (corvazier) File converted from old format ================================================ FILE: code/nel/samples/misc/CMakeLists.txt ================================================ ADD_SUBDIRECTORY(command) ADD_SUBDIRECTORY(configfile) ADD_SUBDIRECTORY(debug) ADD_SUBDIRECTORY(i18n) ADD_SUBDIRECTORY(log) ADD_SUBDIRECTORY(strings) ================================================ FILE: code/nel/samples/misc/command/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp) ADD_EXECUTABLE(nl_sample_command ${SRC}) TARGET_LINK_LIBRARIES(nl_sample_command nelmisc) NL_DEFAULT_PROPS(nl_sample_command "NeL, Samples, Misc: Commands") NL_ADD_RUNTIME_FLAGS(nl_sample_command) INSTALL(TARGETS nl_sample_command RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc) ================================================ FILE: code/nel/samples/misc/command/main.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include #include #include "nel/misc/types_nl.h" #include "nel/misc/debug.h" #include "nel/misc/log.h" #include "nel/misc/displayer.h" // include the command system #include "nel/misc/command.h" #include "nel/misc/variable.h" // // Commands // // with this macro, you can execute a specific command in real time. // this is an example of a command, the first param is the name of the command // (note that it is *not* a string). the second param is the help string that will // be displayed when the user calls the help command. the third param is the // usage of the command. it can the an empty string when the command doesn't // need any parameters. // when the program is launched, you can type the name of the command with // parameters if needed and it will be executed. NLMISC_COMMAND(square,"display the square of the parameter","") { // this code will be executed when the user will call this command. // you have access to some variables: // - args is a vector of strings. they are the user parameters, you have to // check if enough parameters are present and if they are in a good // format. // - log is a CLog object that is used to display the result of the command, // if any. see the log example to know how to use CLog. // this function must return true if the command successfully executed // or false is something wrong happens. for example, if there are not enough // parameters, return false. // check args, if there is not the right number of parameters, return bad status. if (args.size() != 1) return false; uint32 val; NLMISC::fromString(args[0], val); // display the result. log.displayNL("The square of %d is %d", val, val*val); // return ok status. return true; } // // Dummy variables // bool MyVar1; uint8 MyVar2; sint8 MyVar3; uint16 MyVar4; sint16 MyVar5; uint32 MyVar6; sint32 MyVar7; uint64 MyVar8; sint64 MyVar9; std::string MyVar10; ucchar MyVar13; float MyVar14; double MyVar15; // // Create commands on all variables // // with this macro, you can get or set the variable in real time. // this is the easiest way to set or get a variable in real time. you have a direct // access to the variable so you can use this macro. // first param is the type of the variable. second one is the variable name, // and the third one is an help string that describes what the variable does. // when the program is executed, you can type the variable name with no parameter // to see the value of the variable or type the variable name with one parameter // (the value you want to set) to change the variable contents. NLMISC_VARIABLE(bool, MyVar1, "a dummy variable"); NLMISC_VARIABLE(uint8, MyVar2, "a dummy variable"); NLMISC_VARIABLE(sint8, MyVar3, "a dummy variable"); NLMISC_VARIABLE(uint16, MyVar4, "a dummy variable"); NLMISC_VARIABLE(sint16, MyVar5, "a dummy variable"); NLMISC_VARIABLE(uint32, MyVar6, "a dummy variable"); NLMISC_VARIABLE(sint32, MyVar7, "a dummy variable"); NLMISC_VARIABLE(uint64, MyVar8, "a dummy variable"); NLMISC_VARIABLE(sint64, MyVar9, "a dummy variable"); NLMISC_VARIABLE(std::string, MyVar10, "a dummy variable"); NLMISC_VARIABLE(ucchar, MyVar13, "a dummy variable"); NLMISC_VARIABLE(float, MyVar14, "a dummy variable"); NLMISC_VARIABLE(double, MyVar15, "a dummy variable"); // // DynVariable // class CDynVar { private: int _PrivateVar; public: int get() { return _PrivateVar; } void set(int val) { _PrivateVar = val; } }; CDynVar dv; // with this macro, you can get or set the variable in real time. // this is an example of dynamic variable. the goal of this macro is to provide an // easy way to get or set a variable when you don't have a direct access on this variable. // first param is the type of the variable. second one is the name of the variable. // the third one is the help string about this variable (what this variable does). // when the program is executed, you can type the variable name with no parameter // to see the value of the variable or type the variable name with one parameter // (the value you want to set) to change the variable contents. NLMISC_DYNVARIABLE(int,PrivVar,"dummy variable") { // this code will be executed to get or set the variable. // you have to provide a way to do that. // the 'get' boolean says if you have to get or set the variable. // the 'pointer' is a pointer on the variable you have to read or write. // if 'get' is true, you have to set '*pointer' with the value of your variable. // if 'get' is false, you have to set your variable with the value of *pointer if (get) *pointer = dv.get(); else dv.set(*pointer); } // // Main // // look at the log sample NLMISC::CLog mylog; // look at the log sample NLMISC::CStdDisplayer mysd; int main (int argc, char **argv) { // look at the debug sample NLMISC::createDebug(); // look at the log sample mylog.addDisplayer(&mysd); printf("Type a command, 'help' or 'quit'\n"); while (true) { // display prompt std::cout << "> "; fflush(stdout); // get command line std::string commandLine; std::getline(std::cin, commandLine, '\n'); if (commandLine == "quit") break; // execute the command line. it will try to find the command or the // variable and call the associated code NLMISC::ICommand::execute(commandLine, mylog); } return EXIT_SUCCESS; } ================================================ FILE: code/nel/samples/misc/configfile/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp) ADD_EXECUTABLE(nl_sample_configfile ${SRC}) ADD_DEFINITIONS(-DNL_SAMPLE_CFG="\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_configfile/\\"") TARGET_LINK_LIBRARIES(nl_sample_configfile nelmisc) NL_DEFAULT_PROPS(nl_sample_configfile "NeL, Samples, Misc: Config Files") NL_ADD_RUNTIME_FLAGS(nl_sample_configfile) INSTALL(TARGETS nl_sample_configfile RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc) INSTALL(FILES simpletest.txt DESTINATION ${NL_SHARE_PREFIX}/nl_sample_configfile COMPONENT samplesmisc) ================================================ FILE: code/nel/samples/misc/configfile/main.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include #include #include #include // look at the debug example #include "nel/misc/debug.h" // contains the config class #include "nel/misc/config_file.h" // contains the cpath class #include "nel/misc/path.h" #ifndef NL_SAMPLE_CFG #define NL_SAMPLE_CFG "." #endif // NL_SAMPLE_CFG using namespace std; using namespace NLMISC; // this function will be called when the configfile will be modified by // an external program void mainCallback () { nlinfo ("The file was modified by external program!"); } // this function will be called when the variable var12 will be modified by // an external program void var12Callback (CConfigFile::CVar &var) { stringstream str; for (uint i = 0; i < var.size (); i++) str << var.asInt (i) << " "; nlinfo("%s modified, new value: %s\n", var.Name.c_str (), str.str().c_str()); } // the configfile CConfigFile cf; int main (int /* argc */, char ** /* argv */) { // look at the debug example createDebug(); // Add the data directory to the search path. CPath::addSearchPath(NL_SAMPLE_CFG); // load and parse the configfile cf.load (CPath::lookup("simpletest.txt")); // CConfigFile checks if the config file has been modified by an external program. // in this case, the configfile automatically reloads and reparses the file. // you can connect a callback function that will be called in this case if // you want, for example, reset variables // link a callback with this configfile. cf.setCallback (mainCallback); // link a callback with the var12. If and only if the var12 changed, this // callback will be called cf.setCallback ("var12", var12Callback); // display all variables cf.display(InfoLog); // get the value of var1 as int int var1 = cf.getVar ("var1").asInt(); nlinfo("var1 (int) = %d", var1); // get the value of var1 as double, in this case, a conversion from int // to double will be done double var2 = cf.getVar ("var1").asDouble(); nlinfo("var1 (double) = %lf", var2); // get the value of var2 as int, in this case, a conversion from string // to int will be done int var3 = cf.getVar ("var2").asInt(); nlinfo("var2 = %d", var3); // if the variable is an array of values, you can access them putting the // index of the variable you want. Example, get and print all value of var12: for (uint i = 0; i < cf.getVar ("var12").size(); i++) { int val = cf.getVar ("var12").asInt(i); nlinfo("%d -> %d", i, val); } // if you try to access an unknown variable or if something goes wrong, an // exception will be called, you can catch them individually or all together in a try/catch block try { // try to access an unknown variable int val = cf.getVar ("unknown_variable").asInt(); nlinfo("unknown_variable = %d", val); } catch (const EConfigFile &e) { nlinfo("something goes wrong with configfile: %s", e.what()); } cf.getVar ("var13").asInt (0); cf.getVar ("var13").asInt (1); cf.getVar ("var13").asInt (2); nlinfo("Try to modify the var12 in the configfile or any other variable.\n\nPress CTRL-C to exit\n"); while(true) { CConfigFile::checkConfigFiles(); } return EXIT_SUCCESS; } ================================================ FILE: code/nel/samples/misc/configfile/simpletest.txt ================================================ // one line comment /* big comment on more than one line */ var1 = 123; // var1 type:int, value:123 var2 = "456.25"; // var2 type:string, value:"456.25" var3 = 123.123; // var3 type:real, value:123.123 // the resulting type is type of the first left value var4 = 123.123 + 2; // var4 type:real, value:125.123 var5 = 123 + 2.1; // var5 type:int, value:125 var6 = (-112+1) * 3 - 14; // var6 type:int, value:-347 var7 = var1 + 1; // var7 type:int, value:124 var8 = var2 + 10; // var8 type:string, value:456.2510 (convert 10 into a string and concat it) var9 = 10.15 + var2; // var9 type:real, value:466.40 (convert var2 into a real and add it) var10 = { 10.0, 51.1 }; // var10 type:realarray, values:{10.0,51.1} var11 = { "str1", "str2", "str3" }; // var11 type:stringarray, values:{"str1", "str2", "str3"} var12 = { 133, -1 }; // var12 type:intarray, values:{133,-1} var13 = { 1, 0.5, -1 }; ================================================ FILE: code/nel/samples/misc/debug/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp) ADD_EXECUTABLE(nl_sample_debug ${SRC}) TARGET_LINK_LIBRARIES(nl_sample_debug nelmisc) NL_DEFAULT_PROPS(nl_sample_debug "NeL, Samples, Misc: Debugging") NL_ADD_RUNTIME_FLAGS(nl_sample_debug) INSTALL(TARGETS nl_sample_debug RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc) ================================================ FILE: code/nel/samples/misc/debug/main.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include #include // contains all debug features #include "nel/misc/debug.h" using namespace NLMISC; int main (int /* argc */, char ** /* argv */) { // all debug functions have different behaviors in debug and in release mode. // in general, in debug mode, all debug functions are active, they display // what happens and some break the program to debug it. In release mode, they often // do nothing to increase the execution speed. // this function initializes debug functions. it adds displayers into the debug // logger. // in debug mode, all debug functions display on the std output. // in release mode, this function does nothing by default. you have to add a displayer // manually, or put true in the parameter to say to the function that you want it to // add the default displayers createDebug (); // display debug information, that will be skipped in release mode. nldebug ("nldebug() %d", 1); // display the string nlinfo ("nlinfo() %d", 2); // when something not normal, but that the program can manage, occurs, call nlwarning() nlwarning ("nlwarning() %d", 3); // nlassert() is like assert but do more powerful things. in release mode, the test is // not executed and nothing will happen. (Press F5 in Visual C++ to continue the execution) nlassert (true == false); // in a switch case or when you want that the program never executes a part of code, use stop. // in release, nlstop does nothing. in debug mode, // if the code reaches the nlstop, a breakpoint will be set. (In Visual C++ press F5 to continue) nlstop; // when the program failed, call nlerror(), it displays the message and throws a EFatalError to // exit the program. don't forget to put a try/catch block everywhere an nlerror could // occurs. (In Visual C++ press F5 to continue) try { nlerror ("nlerror() %d", 4); } catch(const EFatalError &) { // just continue... nlinfo ("nlerror() generated an EFatalError exception, just ignore it"); } printf("\nPress to exit\n"); getchar (); return EXIT_SUCCESS; } ================================================ FILE: code/nel/samples/misc/i18n/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp) ADD_EXECUTABLE(nl_sample_i18n ${SRC}) ADD_DEFINITIONS(-DNL_LANG_DATA="\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_i18n/\\"") TARGET_LINK_LIBRARIES(nl_sample_i18n nelmisc) NL_DEFAULT_PROPS(nl_sample_i18n "NeL, Samples, Misc: I18N") NL_ADD_RUNTIME_FLAGS(nl_sample_i18n) INSTALL(TARGETS nl_sample_i18n RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc) INSTALL(FILES de.uxt en.uxt fr.uxt DESTINATION ${NL_SHARE_PREFIX}/nl_sample_i18n COMPONENT samplesmisc) ================================================ FILE: code/nel/samples/misc/i18n/de.uxt ================================================ // This is the name of this language. LanguageName [Deutsch] Hi [Hallo] PresentI18N [%s prämtiert das NeL Internationalisierungs-System] ExitStr [DrüEingabetaste> zum Beenden] ================================================ FILE: code/nel/samples/misc/i18n/en.uxt ================================================ // This is the name of this language. LanguageName [English] Hi [Hello] PresentI18N [%s is proud to present you NeL Internationalisation system] ExitStr [Press to exit] ================================================ FILE: code/nel/samples/misc/i18n/fr.uxt ================================================ // This is the name of the language. LanguageName [Franais] Hi [Bonjour] PresentI18N [%s est fire de vous prsenter le systme d'internationalisation de NeL] ExitStr [Appuyez sur pour quitter] ================================================ FILE: code/nel/samples/misc/i18n/main.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include #include // contains all i18n features #include "nel/misc/i18n.h" // contains the path features #include "nel/misc/path.h" #ifndef NL_LANG_DATA #define NL_LANG_DATA "." #endif // NL_LANG_DATA using namespace NLMISC; int main (int argc, char **argv) { createDebug(); // Add the language data path to the search path. CPath::addSearchPath(NL_LANG_DATA); InfoLog->displayRawNL("Please, choose 'en', 'fr' or 'de' and press "); std::string langName; std::getline(std::cin, langName); // load the language CI18N::load(langName); InfoLog->displayRawNL(CI18N::get("Hi").toString().c_str()); InfoLog->displayRawNL(CI18N::get("PresentI18N").toString().c_str(), "Nevrax"); InfoLog->displayRawNL(CI18N::get("ExitStr").toString().c_str()); getchar(); return EXIT_SUCCESS; } ================================================ FILE: code/nel/samples/misc/log/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp) ADD_EXECUTABLE(nl_sample_log ${SRC}) TARGET_LINK_LIBRARIES(nl_sample_log nelmisc) NL_DEFAULT_PROPS(nl_sample_log "NeL, Samples, Misc: Logging") NL_ADD_RUNTIME_FLAGS(nl_sample_log) INSTALL(TARGETS nl_sample_log RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc) ================================================ FILE: code/nel/samples/misc/log/main.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include #include // contains the logger #include "nel/misc/log.h" #include "nel/misc/string_common.h" // contains standard displayers #include "nel/misc/displayer.h" using namespace NLMISC; // create a displayer that displays on stdout and, on Windows, if the // application is in debug mode and launched with the debugger (F5), it displays // on the output windows of Visual C++. CStdDisplayer sd; // create a displayer that displays in a file. The first parameter is the filename // and the second one says that we want to clear the file before logging. // If you put false (default value), then, new logs are append to the file. CFileDisplayer fd("main.log",true); // create a displayer that displays in a message box. It actually works only on // Windows, it does nothing on other systems. CMsgBoxDisplayer mbd; int main (int /* argc */, char ** /* argv */) { // create a logger; it's an information logger. CLog logger (CLog::LOG_INFO); // the process name is used when we have more than one process logging stuffs // in the same displayer (for example for centralized displayer) logger.setProcessName ("my_process_name"); // add displayers for the logger logger.addDisplayer (&sd); logger.addDisplayer (&fd); logger.addDisplayer (&mbd); // so, now, if we send something on the logger, it will be displayed on the 3 displayers // (stdout, file and message box) // display the string with decoration. // The decoration is the text that displayers add before the string. // They could add the date, the process name and so on. // Before each display/displayNL, you have to set the position of where the display // occurs. If you don't do that, the position will not be displayed on the displayers. logger.setPosition (__LINE__, __FILE__); logger.display ("display using display() %d\n", 1); // display the string with decoration and a new line at the end of the string. logger.setPosition (__LINE__, __FILE__); logger.displayNL ("display using displayNL() %d", 2); // display the string without decoration. logger.displayRaw ("display using displayRaw() %d\n", 3); // display the string without decoration and with a new line at the end of the string. logger.displayRawNL ("display using displayRawNL() %d", 4); printf("\nPress to exit\n"); getchar(); return EXIT_SUCCESS; } ================================================ FILE: code/nel/samples/misc/strings/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp) ADD_EXECUTABLE(nl_sample_strings ${SRC}) TARGET_LINK_LIBRARIES(nl_sample_strings nelmisc) NL_DEFAULT_PROPS(nl_sample_strings "NeL, Samples, Misc: Strings") NL_ADD_RUNTIME_FLAGS(nl_sample_strings) INSTALL(TARGETS nl_sample_strings RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc) ================================================ FILE: code/nel/samples/misc/strings/main.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "nel/misc/types_nl.h" #include #include "nel/misc/string_common.h" using namespace std; using namespace NLMISC; int main (int argc, char **argv) { { uint8 val; val = 0; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); val = -1; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); val = 1; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); val = 255; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); } { sint8 val; val = 0; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); val = -128; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); val = 1; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); val = 127; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); } { uint16 val; val = -12158; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); val = 12557; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); } { sint16 val; val = -12158; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); val = 12557; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); } { uint32 val; val = -121556418; printf("'%u' should be equal to '%s' \n", val, toString(val).c_str()); val = 125848847; printf("'%u' should be equal to '%s' \n", val, toString(val).c_str()); } { sint32 val; val = -120547158; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); val = 12555857; printf("'%d' should be equal to '%s' \n", val, toString(val).c_str()); } string str; str += "This is an example of the use of toString(). It's a number " + toString(156); str += " and now a float " + toString(15.55f); printf("%s\n", str.c_str()); printf ("\nPress to exit\n"); getchar (); return EXIT_SUCCESS; } ================================================ FILE: code/nel/samples/misc/types_check/CMakeLists.txt ================================================ FILE(GLOB SRC *.cpp) ADD_EXECUTABLE(nl_sample_types_check ${SRC}) TARGET_LINK_LIBRARIES(nl_sample_types_check nelmisc) NL_DEFAULT_PROPS(nl_sample_types_check "Samples, MISC: Types check sample") NL_ADD_RUNTIME_FLAGS(nl_sample_types_check) INSTALL(TARGETS nl_sample_types_check RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc) ================================================ FILE: code/nel/samples/misc/types_check/main.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include #include #include #include #include #include using namespace std; #include "nel/misc/types_nl.h" #include "nel/misc/string_stream.h" #include "nel/misc/common.h" #include "nel/misc/debug.h" using namespace NLMISC; template bool check (T value) { T result; CMemStream msgout; msgout.serial (value); CMemStream msgin (true); msgin.fill (msgout.buffer(), msgout.size()); msgin.serial (result); if (value != result) { nlwarning ("CHECK FAILED: %s != %s", toString (value).c_str(), toString (result).c_str()); } if (toString(value) != toString(result)) { nlwarning ("toString() CHECK FAILED: %s != %s", toString (value).c_str(), toString (result).c_str()); } return value == result; } #define checkInt(__type, __start, __end, __step) \ { \ __type t = (__type)(__start); \ nlinfo ("checking "#__type" first %s", toString (t).c_str()); \ for (; t < (__type)(__end); t += (__type)(__step)) \ check ((__type)(t)); \ nlinfo ("checking "#__type" last %s", toString (t).c_str()); \ check ((__type)(t)); \ } void checkInts () { checkInt (uint8, 0, 255, 1); checkInt (sint8, -128, 127, 1); checkInt (uint16, 0, 65535, 1); checkInt (sint16, -32768, 32767, 1); checkInt (uint32, 0, 65535, 1); checkInt (uint32, 4294967295-65535, 4294967295, 1); checkInt (sint32, -2147483648, -2147483648+65535, 1); checkInt (sint32, 2147483647-65535, 2147483647, 1); checkInt (uint32, 0, 4294967295, 65535); checkInt (sint32, -2147483648, 2147483647, 65535); uint64 start, end; end=0; end--; start=end-65535; checkInt (uint64, 0, 65535, 1); checkInt (uint64, start, end, 1); checkInt (sint64, -9223372036854775808, -9223372036854775808+65535, 1); checkInt (sint64, 9223372036854775807-65535, 9223372036854775807, 1); } int main (int argc, char **argv) { if (sizeof (uint) != sizeof (void*)) nlwarning ("sizeof (uint) != sizeof (void*) : %d != %d", sizeof (uint), sizeof (void*)); if (sizeof (uint8) != 1) nlwarning ("sizeof (uint8) != 1 : %d != %d", sizeof (uint8), 1); if (sizeof (sint8) != 1) nlwarning ("sizeof (sint8) != 1 : %d != %d", sizeof (sint8), 1); if (sizeof (uint16) != 2) nlwarning ("sizeof (uint16) != 2 : %d != %d", sizeof (uint16), 2); if (sizeof (sint16) != 2) nlwarning ("sizeof (sint16) != 2 : %d != %d", sizeof (sint16), 2); if (sizeof (uint32) != 4) nlwarning ("sizeof (uint32) != 4 : %d != %d", sizeof (uint32), 4); if (sizeof (sint32) != 4) nlwarning ("sizeof (sint32) != 4 : %d != %d", sizeof (sint32), 4); if (sizeof (uint64) != 8) nlwarning ("sizeof (uint64) != 8 : %d != %d", sizeof (uint64), 8); if (sizeof (sint64) != 8) nlwarning ("sizeof (sint64) != 8 : %d != %d", sizeof (sint64), 8); checkInts (); printf ("\nPress to exit\n"); getchar (); return EXIT_SUCCESS; } ================================================ FILE: code/nel/samples/net/CMakeLists.txt ================================================ ADD_SUBDIRECTORY(chat) ADD_SUBDIRECTORY(udp) ADD_SUBDIRECTORY(login_system) ADD_SUBDIRECTORY(class_transport) #multi_shards #net_layer3 #net_layer4 #net_layer5 #service #udp_ping ================================================ FILE: code/nel/samples/net/chat/CMakeLists.txt ================================================ ADD_EXECUTABLE(nl_sample_chatclient client.cpp kbhit.cpp kbhit.h) ADD_EXECUTABLE(nl_sample_chatserver WIN32 server.cpp) ADD_DEFINITIONS(-DCHAT_DIR="\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_chat/\\"") TARGET_LINK_LIBRARIES(nl_sample_chatclient nelmisc nelnet) NL_DEFAULT_PROPS(nl_sample_chatclient "NeL, Samples, Net, Chat: Chat Client") NL_ADD_RUNTIME_FLAGS(nl_sample_chatclient) TARGET_LINK_LIBRARIES(nl_sample_chatserver nelmisc nelnet) NL_DEFAULT_PROPS(nl_sample_chatserver "NeL, Samples, Net, Chat: Chat Server") NL_ADD_RUNTIME_FLAGS(nl_sample_chatserver) INSTALL(TARGETS nl_sample_chatclient nl_sample_chatserver RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesnet) INSTALL(FILES chat_service.cfg client.cfg DESTINATION ${NL_SHARE_PREFIX}/nl_sample_chat COMPONENT samplesnet) ================================================ FILE: code/nel/samples/net/chat/chat_service.cfg ================================================ //NSHost = "localhost"; DontUseNS = 1; DontUseAES = 1; ================================================ FILE: code/nel/samples/net/chat/client.cfg ================================================ LSHost = "localhost"; ================================================ FILE: code/nel/samples/net/chat/client.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Login system example, client. * * This client connects to a front-end server using login system. * * Before running this client, the front end service sample must run, * and also the NeL naming_service, time_service, login_service, welcome_service. * */ // // Includes // #include #include "nel/misc/types_nl.h" #include "nel/misc/debug.h" #include "nel/misc/config_file.h" #include "nel/misc/bit_mem_stream.h" #include "nel/misc/path.h" #include "nel/net/callback_client.h" #ifdef NL_OS_WINDOWS #include #else #include "kbhit.h" #endif using namespace std; using namespace NLMISC; using namespace NLNET; // Really simple chat // Do not display what you are typing #ifdef NL_OS_WINDOWS #define KEY_ESC 27 #define KEY_ENTER 13 #else #define KEY_ESC 27 #define KEY_ENTER 10 #endif #ifndef CHAT_DIR # define CHAT_DIR "." #endif string CurrentEditString; // *************************************************************************** void serverSentChat (CMessage &msgin, TSockId from, CCallbackNetBase &netbase) { // Called when the server sent a CHAT message string text; msgin.serial(text); printf("%s\n", text.c_str()); } // *************************************************************************** // All messages handled by this server #define NB_CB 1 TCallbackItem CallbackArray[NB_CB] = { { "CHAT", serverSentChat } }; /* * main */ int main (int argc, char **argv) { NLMISC::CApplicationContext applicationContext; CCallbackClient *Client; NLMISC::CPath::addSearchPath(CHAT_DIR); // Read the host where to connect in the client.cfg file CConfigFile ConfigFile; ConfigFile.load (NLMISC::CPath::lookup("client.cfg")); string LSHost(ConfigFile.getVar("LSHost").asString()); // Init and Connect the client to the server located on port 3333 Client = new CCallbackClient(); Client->addCallbackArray (CallbackArray, NB_CB); printf("Please wait connecting...\n"); try { CInetAddress addr(LSHost+":3333"); Client->connect(addr); } catch(const ESocket &e) { printf("%s\n", e.what()); return 0; } if (!Client->connected()) { printf("Connection Error\n"); return 0; } printf("Connected.\n"); #ifdef NL_OS_UNIX init_keyboard(); #endif // The main loop do { int c; if (kbhit()) { c = getch(); if (c == KEY_ESC) { break; // FINSIH } else if (c == KEY_ENTER) { CMessage msg; msg.setType("CHAT"); msg.serial (CurrentEditString); Client->send(msg); CurrentEditString = ""; } else { CurrentEditString += c; } } Client->update(); } while (Client->connected()); #ifdef NL_OS_UNIX close_keyboard(); #endif // Finishing delete Client; } ================================================ FILE: code/nel/samples/net/chat/kbhit.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifdef __GNUC__ #include "kbhit.h" #include #include // for read() #include static struct termios initial_settings, new_settings; static int peek_character = -1; void init_keyboard() { tcgetattr(STDIN_FILENO,&initial_settings); new_settings = initial_settings; new_settings.c_lflag &= ~ICANON; new_settings.c_lflag &= ~ECHO; new_settings.c_lflag &= ~ISIG; new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; tcsetattr(STDIN_FILENO, TCSANOW, &new_settings); } void close_keyboard() { tcsetattr(STDIN_FILENO, TCSANOW, &initial_settings); } int kbhit() { unsigned char ch; int nread; if (peek_character != -1) return 1; new_settings.c_cc[VMIN]=0; tcsetattr(STDIN_FILENO, TCSANOW, &new_settings); nread = read(STDIN_FILENO,&ch,1); new_settings.c_cc[VMIN]=1; tcsetattr(STDIN_FILENO, TCSANOW, &new_settings); if(nread == 1) { peek_character = ch; return 1; } return 0; } int getch() { char ch; if(peek_character != -1) { ch = peek_character; peek_character = -1; return ch; } if (read(STDIN_FILENO,&ch,1) != 1) return ' '; return ch; } #endif // __GNUC__ ================================================ FILE: code/nel/samples/net/chat/kbhit.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef NL_KBHIT_H #define NL_KBHIT_H void init_keyboard(void); void close_keyboard(void); int kbhit(void); int getch(void); #endif // NL_KBHIT_H ================================================ FILE: code/nel/samples/net/chat/server.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include #include "nel/misc/common.h" #include "nel/misc/path.h" // contains the service base class #include "nel/net/service.h" #include "nel/net/callback_server.h" #ifdef NL_OS_WINDOWS # define NOMINMAX # include #endif // NL_OS_WINDOWS using namespace std; using namespace NLMISC; using namespace NLNET; #ifndef CHAT_DIR # define CHAT_DIR "" #endif // THE SERVER // Must be a pointer to control when to start listening socket and when stop it CCallbackServer *Server; vector Clients; // MESSAGES // *************************************************************************** void clientWantsToConnect ( TSockId from, void *arg ) { // Called when a client wants to connect Clients.push_back (from); } // *************************************************************************** void clientWantsToDisconnect ( TSockId from, void *arg ) { // Called when a client wants to disconnect for (uint i = 0; i < Clients.size(); ++i) if (Clients[i] == from) { Clients.erase(Clients.begin()+i); return; } } // *************************************************************************** void clientSentChat (CMessage &msgin, TSockId from, CCallbackNetBase &netbase) { // Called when a client sent a CHAT message string text; msgin.serial(text); CMessage msgout; msgout.setType("CHAT"); msgout.serial(text); for (uint i = 0; i < Clients.size(); ++i) Server->send(msgout, Clients[i]); } // *************************************************************************** // All messages handled by this server #define NB_CB 1 TCallbackItem CallbackArray[NB_CB] = { { "CHAT", clientSentChat } }; // SERVICE // *************************************************************************** class CChatService : public IService { public: void init () { // Init the server on port 3333 Server = new CCallbackServer(); Server->init (3333); Server->setConnectionCallback (clientWantsToConnect, NULL); Server->setDisconnectionCallback (clientWantsToDisconnect, NULL); Server->addCallbackArray (CallbackArray, NB_CB); } bool update () { // this function is called every "loop". you return true if you want // to continue or return false if you want to exit the service. // the loop is called evenly (by default, at least one time per second). Server->update(); return true; } void release () { // Must delete the server here delete Server; } }; // this macro is the "main". the first param is the class name inherited from IService. // the second one is the name of the service used to register and find the service // using the naming service. the third one is the port where the listen socket will // be created. If you put 0, the system automatically finds a port. NLNET_SERVICE_MAIN (CChatService, "CS", "chat_service", 0, EmptyCallbackArray, CHAT_DIR, ""); ================================================ FILE: code/nel/samples/net/class_transport/CMakeLists.txt ================================================ ADD_EXECUTABLE(nl_sample_ct_ai_service WIN32 ai_service.cpp) ADD_EXECUTABLE(nl_sample_ct_gd_service WIN32 gd_service.cpp) ADD_DEFINITIONS(-DNL_CT_CFG="\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_class_transport/\\"") TARGET_LINK_LIBRARIES(nl_sample_ct_ai_service nelmisc nelnet) NL_DEFAULT_PROPS(nl_sample_ct_ai_service "NeL, Samples, Net, Class Transport: AI Service") NL_ADD_RUNTIME_FLAGS(nl_sample_ct_ai_service) TARGET_LINK_LIBRARIES(nl_sample_ct_gd_service nelmisc nelnet) NL_DEFAULT_PROPS(nl_sample_ct_gd_service "NeL, Samples, Net, Class Transport: GD Service") NL_ADD_RUNTIME_FLAGS(nl_sample_ct_gd_service) INSTALL(TARGETS nl_sample_ct_ai_service nl_sample_ct_gd_service RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesnet) INSTALL(FILES ai_service.cfg gd_service.cfg DESTINATION ${NL_SHARE_PREFIX}/nl_sample_class_transport COMPONENT samplesnet) ================================================ FILE: code/nel/samples/net/class_transport/ai_service.cfg ================================================ NSHost = "localhost"; WindowStyle = "WIN"; ================================================ FILE: code/nel/samples/net/class_transport/ai_service.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Transport class example, gd server. * * This service have a class (CSharedClass) that send to other service when online. * * To run this program, ensure there is a file "ai_service.cfg" * containing the location of the naming service (NSHost, NSPort) * in the working directory. The naming service must be running. */ // // Includes // // We're using the NeL Service framework, and layer 5 #include "nel/net/service.h" #include "nel/misc/time_nl.h" #include "nel/misc/displayer.h" #include "nel/net/transport_class.h" #ifdef NL_OS_WINDOWS # define NOMINMAX # include #endif // NL_OS_WINDOWS #ifndef NL_CT_CFG #define NL_CT_CFG "" #endif // NL_CT_CFG // // Namespace // using namespace std; using namespace NLNET; using namespace NLMISC; // // Shared Class // struct CSharedClass : public CTransportClass { uint32 i1; uint16 i2; float f1, f2; vector vi1; string str; CEntityId eid; CSharedClass () : i1(20), i2(20), f1(20), str("str20"), eid (5, 1515664512) { } virtual void description () { className ("SharedClass"); property ("i1", PropUInt32, (uint32)21, i1); property ("f1", PropFloat, 2.5f, f1); property ("i2", PropUInt16, (uint16)22, i2); propertyCont ("vi1", PropUInt16, vi1); property ("str", PropString, (string)"str22", str); // property ("eid", PropEntityId, CEntityId::Unknown, eid); property ("f2", PropFloat, 2.5f, f2); } virtual void callback (const string &name, uint8 sid) { nlinfo ("Yes! I receive a Shared class from '%s' %d", name.c_str(), sid); } }; // // Variables // // // Functions // static void cbUpService (const std::string &serviceName, uint16 sid, void *arg) { // When a service comes, send the new class CSharedClass foo; foo.send((TServiceId)sid); } // // Main class // struct CAIService : public IService { void init() { // callback when a new service comes CUnifiedNetwork::getInstance()->setServiceUpCallback("*", (TUnifiedNetCallback)cbUpService, NULL); // init the class transport system CTransportClass::init (); // register the shared class TRANSPORT_CLASS_REGISTER (CSharedClass); } void release () { // release all the class transport system CTransportClass::release (); } }; /* * Declare a service with the class IService, the names "AIS" (short) and "ai_service" (long). * The port is automatically allocated (0) and the main callback array is empty. */ NLNET_SERVICE_MAIN( CAIService, "AIS", "ai_service", 0, EmptyCallbackArray, NL_CT_CFG, "" ) ================================================ FILE: code/nel/samples/net/class_transport/gd_service.cfg ================================================ NSHost = "localhost"; WindowStyle = "WIN"; ================================================ FILE: code/nel/samples/net/class_transport/gd_service.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Transport class example, gd server. * * This service have a class (CSharedClass) that send to other service when online. * * To run this program, ensure there is a file "gd_service.cfg" * containing the location of the naming service (NSHost, NSPort) * in the working directory. The naming service must be running. */ // // Includes // // We're using the NeL Service framework, and layer 5 #include "nel/net/service.h" #include "nel/misc/time_nl.h" #include "nel/misc/displayer.h" #include "nel/net/transport_class.h" #ifdef NL_OS_WINDOWS # define NOMINMAX # include #endif // NL_OS_WINDOWS #ifndef NL_CT_CFG #define NL_CT_CFG "" #endif // NL_CT_CFG // // Namespace // using namespace std; using namespace NLNET; using namespace NLMISC; // // Shared Class // struct CSharedClass : public CTransportClass { uint32 i1, i2, i3; float f1; vector vi1; string str; CEntityId eid; CSharedClass () : i1(10), i2(10), i3(10), f1(10), str("str10") { vi1.push_back(111); vi1.push_back(222); vi1.push_back(255); } virtual void description () { className ("SharedClass"); property ("i1", PropUInt32, (uint32)11, i1); property ("f1", PropFloat, 1.5f, f1); // property ("i2", PropUInt32, (uint32)12, i2); property ("i3", PropUInt32, (uint32)13, i3); propertyCont ("vi1", PropUInt32, vi1); property ("str", PropString, (string)"str12", str); // property ("eid", PropEntityId, CEntityId::Unknown, eid); } virtual void callback (const string &name, uint8 sid) { nlinfo ("Yes! I receive a Shared class from '%s' %d", name.c_str(), sid); } }; // // Variables // static CSharedClass SharedClass; // // Functions // static void cbUpService (const std::string &serviceName, uint16 sid, void *arg) { // When a service comes, send the new class CSharedClass foo; foo.send((TServiceId)sid); } // // Service class // struct CGDService : public IService { void init() { // callback when a new service comes CUnifiedNetwork::getInstance()->setServiceUpCallback("*", (TUnifiedNetCallback)cbUpService, NULL); // init the class transport system CTransportClass::init (); // register the shared class TRANSPORT_CLASS_REGISTER (CSharedClass); } void release () { // release all the class transport system CTransportClass::release (); } }; /* * Declare a service with the class IService, the names "GDS" (short) and "gd_service" (long). * The port is automatically allocated (0) and the main callback array is empty. */ NLNET_SERVICE_MAIN( CGDService, "GDS", "gd_service", 0, EmptyCallbackArray, NL_CT_CFG, "" ) ================================================ FILE: code/nel/samples/net/login_system/CMakeLists.txt ================================================ ADD_EXECUTABLE(nl_sample_ls_client client.cpp) ADD_EXECUTABLE(nl_sample_ls_fes WIN32 frontend_service.cpp) ADD_DEFINITIONS(-DNL_LS_CFG="\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_login_system/\\"") TARGET_LINK_LIBRARIES(nl_sample_ls_client nelmisc nelnet) NL_DEFAULT_PROPS(nl_sample_ls_client "NeL, Samples, Net, Login Service: LS Client") NL_ADD_RUNTIME_FLAGS(nl_sample_ls_client) TARGET_LINK_LIBRARIES(nl_sample_ls_fes nelmisc nelnet) NL_DEFAULT_PROPS(nl_sample_ls_fes "NeL, Samples, Net, Login Service: LS Frontend") NL_ADD_RUNTIME_FLAGS(nl_sample_ls_fes) INSTALL(TARGETS nl_sample_ls_client nl_sample_ls_fes RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesnet) INSTALL(FILES frontend_service.cfg client.cfg DESTINATION ${NL_SHARE_PREFIX}/nl_sample_login_system COMPONENT samplesnet) ================================================ FILE: code/nel/samples/net/login_system/client.cfg ================================================ LSHost = "localhost"; Login = "nel"; Password = "rox"; ClientApplication = "sample"; ShardId = 300; ================================================ FILE: code/nel/samples/net/login_system/client.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Login system example, client. * * This client connects to a front-end server using login system. * * Before running this client, the front end service sample must run, * and also the NeL naming_service, time_service, login_service, welcome_service. * */ // // Includes // #include #include "nel/misc/types_nl.h" #include "nel/misc/debug.h" #include "nel/misc/config_file.h" #include "nel/misc/bit_mem_stream.h" #include "nel/misc/md5.h" #include "nel/net/login_client.h" #include "nel/net/login_cookie.h" // The UDP mode wasn't tested, you should leave USE_UDP undef //#define USE_UDP #undef USE_UDP #ifdef USE_UDP # include "nel/net/udp_sock.h" #endif #ifndef NL_LS_CFG #define NL_LS_CFG "." #endif // NL_LS_CFG // // Namespaces // using namespace std; using namespace NLMISC; using namespace NLNET; // // Functions // int main (int argc, char **argv) { string result; CApplicationContext myApplicationContext; CPath::addSearchPath(NL_LS_CFG); CConfigFile ConfigFile; ConfigFile.load ("client.cfg"); string LSHost(ConfigFile.getVar("LSHost").asString()); ucstring Login = ConfigFile.getVar("Login").asString(); if(Login.empty()) { char buf[256]; printf("Login: "); Login = fgets(buf, 256, stdin); } ucstring Password = ConfigFile.getVar("Password").asString(); if(Password.empty()) { char buf[256]; printf("Password: "); Password = fgets(buf, 256, stdin); } // crypt with md5 the password CHashKeyMD5 hk = getMD5((uint8*)Password.c_str(), (uint32)Password.size()); string CPassword = hk.toString(); nlinfo("The crypted password is %s", CPassword.c_str()); string Application = ConfigFile.getVar("ClientApplication").asString(); /* Try to connect to the login service and check the login, password of the client. * return an empty string if all go well */ result = CLoginClient::authenticate(LSHost, Login, CPassword, Application); if(!result.empty()) nlerror ("*** Authenticate failed '%s' ***", result.c_str()); nlinfo("%d Shards are available:", CLoginClient::ShardList.size()); for (uint i = 0; i < CLoginClient::ShardList.size (); i++) { nlinfo (" ShardId %3d: %s (%d online players)", CLoginClient::ShardList[i].Id, CLoginClient::ShardList[i].Name.toUtf8().c_str (), CLoginClient::ShardList[i].NbPlayers); } sint32 sid = ConfigFile.getVar("ShardId").asInt(); if(sid == 0) { printf("Enter the ShardId you want to connect to: "); if (scanf("%d", &sid) != 1) { nlwarning("Can't parse ShardId"); } } /* Try to connect to the shard number 0 in the list. * return an empty string if all go well */ string ip, cookie; result = CLoginClient::wantToConnectToShard (sid, ip, cookie); if(!result.empty()) nlerror ("*** Connection to the shard failed '%s' ***", result.c_str()); #ifndef USE_UDP CCallbackClient *cnx = new CCallbackClient(); CLoginCookie lc; lc.setFromString(cookie); result = CLoginClient::connectToShard (lc, ip, *cnx); if(!result.empty()) nlerror ("*** Connection to the shard failed '%s' ***", result.c_str()); nlinfo ("*** Connection granted! You are connected on the frond end ***"); while (cnx->connected ()) { cnx->update (); nlSleep(10); } if( cnx->connected ()) cnx->disconnect (); #else // USE_UDP CUdpSock *cnx = new CUdpSock(); CLoginCookie lc; result = CLoginClient::connectToShard (0, *cnx, lc); if(!result.empty()) nlerror ("*** Connection to the shard failed '%s' ***", result.c_str()); // we have to talk with the FES to send the cookie CBitMemStream msgout; msgout.serial (lc); while (true) { // send the cookie uint32 len = msgout.length (); cnx->send (msgout.buffer (), len); uint8 buf[64000]; if (cnx->dataAvailable ()) { // manage answer len = 64000; cnx->receive (buf, len); CBitMemStream msgin (true); msgin.clear (); memcpy (msgin.bufferToFill (len), &buf[0], len); msgin.serial (result); break; } // sleep nlSleep (1000); } if(!result.empty()) nlerror ("*** Connection to the shard failed '%s' ***", result.c_str()); nlinfo ("*** Connection granted! You are connected on the frond end ***"); while (cnx->connected ()) { // do want you want! nlSleep(10); } #endif // USE_UDP delete cnx; return 0; } ================================================ FILE: code/nel/samples/net/login_system/frontend_service.cfg ================================================ NSHost = "localhost"; FSPort = 37373; WindowStyle = "WIN"; DontUseAES = 1; ================================================ FILE: code/nel/samples/net/login_system/frontend_service.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Layer 4 and Service example, front-end server. * * To run this program, ensure there is a file "frontend_service.cfg" * containing the location of the naming service (NSHost, NSPort) * in the working directory. * The NeL naming_service, time_service, login_service, welcome_service must be running. */ // We're using the NeL Service framework and layer 5. #include "nel/misc/config_file.h" #include "nel/misc/bit_mem_stream.h" #include "nel/net/callback_server.h" #include "nel/net/service.h" #include "nel/net/login_server.h" #ifdef NL_OS_WINDOWS # define NOMINMAX # include #endif // NL_OS_WINDOWS using namespace std; using namespace NLNET; using namespace NLMISC; #ifndef NL_LS_CFG #define NL_LS_CFG "" #endif // NL_LS_CFG //#define USE_UDP #undef USE_UDP #ifndef USE_UDP // // TCP server mode // /* * Connection callback for a client */ void onConnectionClient (TSockId from, const CLoginCookie &cookie) { nlinfo ("The client with uniq Id %d is connected", cookie.getUserId ()); // store the user id in appId from->setAppId (cookie.getUserId ()); } /* * Disconnection callback for a client */ void onDisconnectClient (TSockId from, void *arg) { nlinfo ("A client with uniq Id %d has disconnected", from->appId ()); // tell the login system that this client is disconnected CLoginServer::clientDisconnected ((uint32) from->appId ()); } /* * CFrontEndService, based on IService */ class CFrontEndService : public IService { private: /// The server on which the clients connect CCallbackServer _FServer; public: /* * Initialization */ void init() { // connect the front end login system uint16 fsPort = 37373; try { fsPort = IService::ConfigFile.getVar("FSPort").asInt(); } catch (const EUnknownVar&) { } _FServer.init(fsPort); CLoginServer::init (_FServer, onConnectionClient); // _FServer.setDisconnectionCallback(onDisconnectClient, NULL); } bool update() { _FServer.update(); return true; } }; #else // USE_UDP // // UDP server mode // #include "nel/net/udp_sock.h" /* * CFrontEndService, based on IService */ class CFrontEndService : public IService { private: /// The server on which the clients connect CUdpSock *_FServer; public: /* * Initialization */ void init() { // connect the front end login system uint16 fesPort = 37373; try { fesPort = IService5::ConfigFile.getVar("FESPort").asInt(); } catch (const EUnknownVar&) { } // Socket _FServer = new CUdpSock( false ); nlassert( _FServer ); // Test of multihomed host vector addrlist; addrlist = CInetAddress::localAddresses(); vector::iterator ivi; for ( ivi=addrlist.begin(); ivi!=addrlist.end(); ++ivi ) { nlinfo( "%s", (*ivi).asIPString().c_str() ); } addrlist[0].setPort( fesPort ); _FServer->bind( addrlist[0] ); CLoginServer::init (*_FServer, NULL); } bool update() { uint8 buf[64000]; uint len; CInetAddress addr; while (_FServer->dataAvailable ()) { len = 64000; _FServer->receivedFrom (buf, len, addr); CBitMemStream msgin (true); msgin.clear (); memcpy (msgin.bufferToFill (len), &buf[0], len); CLoginCookie lc; msgin.serial (lc); nlinfo ("Receive the cookie %s from %s", lc.toString ().c_str(), addr.asString ().c_str()); string res = CLoginServer::isValidCookie (lc); // send the result CBitMemStream msgout; msgout.serial (res); uint32 l = msgout.length (); _FServer->sendTo (msgout.buffer (), l, addr); } return true; } }; #endif // USE_UDP /* * Declare a service with the class CFrontEndService, the names "FS" (short) and "frontend_service" (long). * The port is dynamically find and there's no callback array. */ NLNET_SERVICE_MAIN (CFrontEndService, "FS", "frontend_service", 0, EmptyCallbackArray, NL_LS_CFG, "") ================================================ FILE: code/nel/samples/net/multi_shards/client.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Login system example, client. * * This client connects to a front-end server using login system. * * Before running this client, the front end service sample must run, * and also the NeL naming_service, time_service, login_service, welcome_service. * */ // We're using std #include // We're using NeL #include "nel/misc/types_nl.h" #include "nel/misc/debug.h" #include "nel/misc/config_file.h" #include "nel/misc/bit_mem_stream.h" // We're using the login client #include "nel/net/login_client.h" #include "nel/net/login_cookie.h" #include "nel/net/udp_sock.h" using namespace std; using namespace NLMISC; using namespace NLNET; /* * main */ void main (int argc, char **argv) { string result; CConfigFile ConfigFile; ConfigFile.load ("client.cfg"); string LSHost(ConfigFile.getVar("LSHost").asString()); char buf[256]; printf("Login: "); fgets(buf, 256, stdin); string Login(buf); printf("Password: "); fgets(buf, 256, stdin); string Password(buf); if (Login.empty ()) { Login = ConfigFile.getVar("Login").asString(); } if (Password.empty ()) { Password = ConfigFile.getVar("Password").asString(); } /* Try to connect to the login service and check the login, password and version of the client. * return an empty string if all go well */ result = CLoginClient::authenticate(LSHost+":49999", Login, Password, "sample"); if(!result.empty()) nlerror ("*** Authenticate failed '%s' ***", result.c_str()); // CLoginClient::ShardList contains all available shards for (uint i = 0; i < CLoginClient::ShardList.size (); i++) { nlinfo("*** shard %d is: %s (%d) ***", i, CLoginClient::ShardList[i].Name.c_str (), CLoginClient::ShardList[i].Id); } /* Try to connect to the last shard number in the list. * return an empty string if all go well */ string fs_ip, login_cookie; result = CLoginClient::wantToConnectToShard(CLoginClient::ShardList[CLoginClient::ShardList.size() - 1].Id, fs_ip, login_cookie); if (!result.empty()) nlerror("*** Select shard failed '%s' ***", result.c_str()); CLoginCookie cookie; cookie.setFromString(login_cookie); // who's idea was it to send the cookie as a string... CCallbackClient *cnx = new CCallbackClient(); result = CLoginClient::connectToShard(cookie, fs_ip, *cnx); if (!result.empty()) nlerror("*** Connection to the shard failed '%s' ***", result.c_str()); nlinfo ("*** Connection granted! You are connected on the frond end ***"); while (cnx->connected ()) { cnx->update (); nlSleep(10); } if( cnx->connected ()) cnx->disconnect (); delete cnx; } ================================================ FILE: code/nel/samples/net/multi_shards/frontend_service.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * multi shard example, front-end server. * * The goal of the example is to enable you to run 2 differents shards * on the same computer with a login system. * * The naming service, admin executor service, login service, welcome service must be running. */ // We're using the NeL Service framework and layer 5. #include "nel/misc/config_file.h" #include "nel/net/callback_server.h" #include "nel/net/service.h" #include "nel/net/login_server.h" using namespace std; using namespace NLNET; using namespace NLMISC; /* * Connection callback for a client */ void onConnectionClient (TSockId from, const CLoginCookie &cookie) { nlinfo ("The client with uniq Id %d is connected", cookie.getUserId ()); // store the user id in appId from->setAppId (cookie.getUserId ()); } /* * Disonnection callback for a client */ void onDisconnectClient (TSockId from, void *arg) { nlinfo ("A client with uniq Id %d has disconnected", from->appId ()); // tell the login system that this client is disconnected CLoginServer::clientDisconnected ((uint32) from->appId ()); } /* * CFrontEndService, based on IService */ class CFrontEndService : public IService { private: /// The server on which the clients connect CCallbackServer _FEServer; public: /* * Initialization */ void init() { // create a special connection for client (using TCP on port 37373) uint16 fesPort = 37373; try { fesPort = IService::ConfigFile.getVar("FESPort").asInt(); } catch ( EUnknownVar& ) { } _FEServer.init(fesPort); // connect and identify this front end to the login system CLoginServer::init (_FEServer, onConnectionClient); // _FEServer.setDisconnectionCallback(onDisconnectClient, NULL); } bool update() { _FEServer.update(); return true; } }; /* * Declare a service with the class CFrontEndService, the names "FS" (short) and "frontend_service" (long). * The port is dynamicaly find and there s no callback array. */ NLNET_SERVICE_MAIN (CFrontEndService, "FS", "frontend_service", 0, EmptyCallbackArray, "", "") ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/admin_executor_service.cfg ================================================ Services = { "NS", "LS", "WS" }; NS = { "r:\code\nelns\naming_service", "r:\code\nelns\naming_service\debug\naming_service.exe" }; LS = { "r:\code\nelns\login_service", "r:\code\nelns\login_service\debug\login_service.exe" }; WS = { "r:\code\nelns\welcome_service", "r:\code\nelns\welcome_service\debug\welcome_service.exe" }; WindowStyle = "WIN"; ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/client.cfg ================================================ LSHost = "localhost"; Login = "nevrax"; Password = "nevrax"; ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/login_service.cfg ================================================ WindowStyle = "WIN"; Port = 49999; // port for the client connection (default is 49999) WSPort = 49998; // port for the welcome connection (default is 49998) ServerVersion = 1; // version of shard (must match with the client version) AcceptNewUser = 1; // 1 if you want to add new player, 0 if you want to eject new player AcceptExternalShard = 1; // 1 is you accept external shard (not referenced in the config file), 0 if you want to eject unknown shards CryptPassword = 1; // 1 is you want to store password in crypted format, 0 for plain text Beep = 1; // 1 if you want to beep when a new client comes ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/login_service_database.cfg ================================================ Users = { "test1","test","1","", "test2","test","2",":priv1:", "test3","test","3",":priv2:", "test4","test","4",":priv1:priv2:", }; Shards = { "127.0.0.1", "local shard 1", "127.0.0.1", "local shard 2", "127.0.0.1", "local shard 3", }; ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/shard1_config/frontend_service.cfg ================================================ NSHost = "localhost"; NSPort = 50000; WindowStyle = "WIN"; ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/shard1_config/naming_service.cfg ================================================ WindowStyle = "WIN"; ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/shard1_config/welcome_service.cfg ================================================ // address of the naming service NSHost = "localhost"; NSPort = 50000; // address of the login service LSHost = "localhost:49998"; // short name of the frontend service FrontendServiceName = "FS"; WindowStyle = "WIN"; //FrontEndAddress = "195.68.21.196"; ShardName = ""; ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/shard2_config/frontend_service.cfg ================================================ NSHost = "localhost"; NSPort = 40000; WindowStyle = "WIN"; FESPort = 37374; ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/shard2_config/naming_service.cfg ================================================ WindowStyle = "WIN"; Port = 40000; BasePort = 41000; ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/shard2_config/welcome_service.cfg ================================================ // address of the naming service NSHost = "localhost"; NSPort = 40000; // address of the login service LSHost = "localhost:49998"; // short name of the frontend service FrontendServiceName = "FS"; WindowStyle = "WIN"; //FrontEndAddress = "195.68.21.196"; ShardName = ":priv1:"; ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/shard3_config/frontend_service.cfg ================================================ NSHost = "localhost"; NSPort = 30000; WindowStyle = "WIN"; FESPort = 37375; ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/shard3_config/naming_service.cfg ================================================ WindowStyle = "WIN"; Port = 30000; BasePort = 31000; ================================================ FILE: code/nel/samples/net/multi_shards/shard_config/shard3_config/welcome_service.cfg ================================================ // address of the naming service NSHost = "localhost"; NSPort = 30000; // address of the login service LSHost = "localhost:49998"; // short name of the frontend service FrontendServiceName = "FS"; WindowStyle = "WIN"; //FrontEndAddress = "195.68.21.196"; ShardName = ":priv2:"; ================================================ FILE: code/nel/samples/net/net_layer3/client.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Layer 3 example, client. * * This client connects to a front-end server at localhost:37000. * It sends pings and expects pongs (ping replies). */ // We're using NeL #include "nel/misc/types_nl.h" #include "nel/misc/debug.h" using namespace NLMISC; // We're using CInetAddress, CMessage and CCallbackClient (because we're building a client) #include "nel/net/inet_address.h" #include "nel/net/message.h" #include "nel/net/callback_client.h" using namespace NLNET; /* * Callback function called when receiving a "PONG" message * * Arguments: * - msgin: the incoming message * - from: the "sockid" of the sender (usually useless for a CCallbackClient) * - client: the CCallbackNetBase object (which really is a CCallbackClient object, for a client) * * Input (expected message): PONG * - uint32: ping counter * * Output (sent message): PING * - uint32: new ping counter */ void cbPong( CMessage& msgin, TSockId from, CCallbackNetBase& client ) { uint32 counter; // Input msgin.serial( counter ); nlinfo( "Received PONG number %u", counter ); counter++; // Output CMessage msgout ( "PING" ); msgout.serial( counter ); client.send( msgout ); nlinfo( "Sent PING number %u", counter ); } /* * Callback array */ TCallbackItem CallbackArray[] = { { "PONG", cbPong } // when receiving a "PONG" message, call cbPong() }; /* * main */ void main( int argc, char **argv ) { try { // Initialize and connect to the front-end server at localhost:37000 CCallbackClient client; client.addCallbackArray( CallbackArray, sizeof(CallbackArray)/sizeof(CallbackArray[0]) ); client.connect( CInetAddress( "localhost" , 37000 ) ); // Send a PING message uint32 counter = 0; CMessage msg( "PING" ); // create the message msg.serial( counter ); // serialize the counter into the message client.send( msg ); // put into the send queue nlinfo( "Sent PING number %u", counter ); // Main loop while ( client.connected() ) { // Perform sends and receives, call callbacks client.update(); } nlinfo( "Disconnected" ); } catch ( Exception &e ) { nlerror( "Error: %s", e.what() ); } } ================================================ FILE: code/nel/samples/net/net_layer3/frontend_service.cfg ================================================ NSHost = "localhost"; WindowStyle = "WIN"; ================================================ FILE: code/nel/samples/net/net_layer3/frontend_service.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Layer 3 and Service example, front-end server. * * This front-end server expects pings, and forward them to * the real ping server. When the ping server sends a pong back, * the front-end server forwards it to the client. * * To run this program, ensure there is a file "frontend_service.cfg" * containing the location of the naming service (NSHost, NSPort) * in the working directory. The naming service must be running. */ // We're building a server, using the NeL Service framework. // We need the naming service to know where the ping service is, so we're using CNamingClient. // We're using CCallbackClient when we talk to the naming service. // We're using CCallbackServer when we talk to our clients. #include "nel/net/service.h" #include "nel/net/naming_client.h" #include "nel/net/callback_client.h" #include "nel/net/callback_server.h" using namespace NLNET; #include using namespace std; // The front-end server is also a client of the ping service CCallbackClient *ToPingService; // Temp storage (a queue because the connection to the ping service is reliable, the order is preserved) deque ClientIds; /* * Callback function called when receiving a "PING" message * * Arguments: * - msgin: the incoming message (coming from a client) * - from: the "sockid" of the sender client * - frontendserver: the CCallbackNetBase object (which really is a CCallbackServer object, for a server) * * Input (expected message from a client): PING * - uint32: ping counter * * Output (sent message to the ping server): PONG * - uint32: ping counter */ void cbPing( CMessage& msgin, TSockId from, CCallbackNetBase& frontendserver ) { uint32 counter; // Input msgin.serial( counter ); ClientIds.push_back( from ); // store client sockid // Output CMessage msgout( "PING" ); msgout.serial( counter ); vector vect( 400000 ); msgout.serialCont( vect ); ToPingService->send( msgout ); nlinfo( "Received PING number %u from %s", counter, frontendserver.hostAddress(from).asString().c_str() ); } /* * Disconnection callback, called when a client disconnects */ void discCallback( TSockId from, void *p ) { // Remove all occurences of from in the queue deque::iterator iq; for ( iq=ClientIds.begin(); iq!=ClientIds.end(); ) { if ( *iq == from ) { iq = ClientIds.erase( iq ); } else { iq++; } } } /* * Callback function called when receiving a "PONG" message * * Arguments: * - msgin: the incoming message (coming from the ping server) * - from: the "sockid" of the sender (usually useless for a CCallbackClient) * - clientofthepingserver: the CCallbackNetBase object (which really is a CCallbackClient object) * * Input (expected message from the ping server): PONG * - uint32: ping counter * - TSockId: "sock id" of the client who sent the ping * * Output (sent message to a client): PONG * - uint32: ping counter */ void cbPong( CMessage& msgin, TSockId from, CCallbackNetBase& clientofthepingserver ) { uint32 counter; TSockId clientfrom; // Input: process the reply of the ping service msgin.serial( counter ); clientfrom = ClientIds.front(); // retrieve client sockid ClientIds.pop_front(); // Output: send the reply to the client CCallbackServer *server = IService::getInstance()->getServer(); CMessage msgout( "PONG" ); msgout.serial( counter ); server->send( msgout, clientfrom ); nlinfo( "Sent PONG number %u to %s", counter, clientfrom->asString().c_str() ); } /* * Callback array for messages received from a client */ TCallbackItem CallbackArray[] = { { "PING", cbPing } // when receiving a "PING" message, call cbPing() }; /* * Callback array for message received from the ping service */ TCallbackItem PingServiceCallbackArray[] = { { "PONG", cbPong } // when receiving a "PONG" message, call cbPong() }; /* * CFrontEndService, based on IService */ class CFrontEndService : public IService { public: /* * Initialization */ void init() { // Connect to the ping service ToPingService = new CCallbackClient( IService::getRecordingState(), "PS.nmr" ); ToPingService->addCallbackArray( PingServiceCallbackArray, sizeof(PingServiceCallbackArray)/sizeof(PingServiceCallbackArray[0]) ); if ( ! CNamingClient::lookupAndConnect( "PS", *ToPingService ) ) { nlerror( "Ping Service not available" ); } // Disconnection callback for the clients IService::getServer()->setDisconnectionCallback( discCallback, NULL ); } /* * Update */ bool update() { ToPingService->update( 20 ); // 20 ms max return ToPingService->connected(); // true continues, false stops the service } /* * Finalization */ void release() { delete ToPingService; } }; /* * Declare a service with the class CFrontEndService, the names "FS" (short) and "frontend_service" (long). * The port is set to 37000 and the main callback array is CallbackArray. */ NLNET_OLD_SERVICE_MAIN( CFrontEndService, "FS", "frontend_service", 37000, CallbackArray, "", "" ) ================================================ FILE: code/nel/samples/net/net_layer3/ping_service.cfg ================================================ NSHost = "localhost"; WindowStyle = "WIN"; ================================================ FILE: code/nel/samples/net/net_layer3/ping_service.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Layer 3 and Service example, ping server. * * This ping service expects pings, sends pongs back. * * To run this program, ensure there is a file "ping_service.cfg" * containing the location of the naming service (NSHost, NSPort) * in the working directory. The naming service must be running. */ // We're building a server, using the NeL Service framework #include "nel/net/service.h" using namespace NLNET; /* * Callback function called when receiving a "PING" message * * Arguments: * - msgin: the incoming message (coming from a client) * - from: the "sockid" of the sender client * - server: the CCallbackNetBase object (which really is a CCallbackServer object, for a server) * * Input (expected message from a client): PING * - uint32: ping counter * * Output (sent message to the ping server): PONG * - uint32: ping counter */ void cbPing( CMessage& msgin, TSockId from, CCallbackNetBase& server ) { uint32 counter; // Input msgin.serial( counter ); // Output CMessage msgout( "PONG" ); msgout.serial( counter ); server.send( msgout, from ); nlinfo( "PING -> PONG" ); } /* * Callback array for messages received from a client */ TCallbackItem CallbackArray[] = { { "PING", cbPing } }; // We use IService directly, no need to inherit from it /* * Declare a service with the class IService, the names "PS" (short) and "ping_service" (long). * The port is automatically allocated (0) and the main callback array is CallbackArray. */ NLNET_OLD_SERVICE_MAIN( IService, "PS", "ping_service", 0, CallbackArray, "", "" ) ================================================ FILE: code/nel/samples/net/net_layer4/client.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Layer 4 example, client. * * This client connects to a front-end server at localhost:37000. * It sends pings and expects pongs (ping replies). */ // We're using NeL #include "nel/misc/types_nl.h" #include "nel/misc/debug.h" using namespace NLMISC; // We're using the layer 4 #include "nel/net/net_manager.h" using namespace NLNET; // Name of the front-end service const char SVC [3] = "FS"; /* * Callback function called when receiving a "PONG" message * * Arguments: * - msgin: the incoming message * - from: the "sockid" of the sender (usually useless for a CCallbackClient) * - client: the CCallbackNetBase object (which really is a CCallbackClient object, for a client) * * Input (expected message): PONG * - uint32: ping counter * * Output (sent message): PING * - uint32: new ping counter */ void cbPong( CMessage& msgin, TSockId from, CCallbackNetBase& client ) { uint32 counter; // Input msgin.serial( counter ); nlinfo( "Received PONG number %u", counter ); counter++; // Output CMessage msgout ( "PING" ); msgout.serial( counter ); CNetManager::send( SVC, msgout ); nlinfo( "Sent PING number %u", counter ); } /* * Callback array */ TCallbackItem CallbackArray[] = { { "PONG", cbPong } // when receiving a "PONG" message, call cbPong() }; /* * main */ void main( int argc, char **argv ) { try { // Initialize (we don't call CNetManager::init() because we don't use the naming service) // Connect to the front-end server at localhost:37000 CNetManager::addClient( SVC, "localhost:37000" ); CNetManager::addCallbackArray( SVC, CallbackArray, sizeof(CallbackArray)/sizeof(CallbackArray[0]) ); // Send a PING message uint32 counter = 0; CMessage msg( "PING" ); // create the message msg.serial( counter ); // serialize the counter into the message CNetManager::send( SVC, msg ); // put into the send queue nlinfo( "Sent PING number %u", counter ); // Main loop while ( CNetManager::getNetBase( SVC )->connected() ) { // Perform sends and receives, call callbacks CNetManager::update(); } nlinfo( "Disconnected" ); // We don't call CNetManager::release() because we didn't call CNetManager::init() } catch ( Exception &e ) { nlerror( "Error: %s", e.what() ); } } ================================================ FILE: code/nel/samples/net/net_layer4/frontend_service.cfg ================================================ NSHost = "localhost"; WindowStyle = "WIN"; ================================================ FILE: code/nel/samples/net/net_layer4/frontend_service.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Layer 4 and Service example, front-end server. * * This front-end server expects pings, and forward them to * the real ping server. When the ping server sends a pong back, * the front-end server forwards it to the client. * * Even if the connection to the ping server is broken, our * front-end server will keep storing the ping messages and * will forward them when the connection is restored. * * To run this program, ensure there is a file "frontend_service.cfg" * containing the location of the naming service (NSHost, NSPort) * in the working directory. The naming service must be running. * * DEPRECATED: You should use layer5 (take a look in the layer5 sample directory) * */ // We're using the NeL Service framework and layer 4. #include "nel/net/service.h" #include "nel/net/net_manager.h" using namespace NLNET; #include using namespace std; // Storage (a queue because the connection to the ping service is reliable, the order is preserved) deque< pair > ClientIds; /* * Callback function called when receiving a "PING" message * * Arguments: * - msgin: the incoming message (coming from a client) * - from: the "sockid" of the sender client * - frontendserver: the CCallbackNetBase object (which really is a CCallbackServer object, for a server) * * Input (expected message from a client): PING * - uint32: ping counter * * Output (sent message to the ping server): PONG * - uint32: ping counter */ void cbPing( CMessage& msgin, TSockId from, CCallbackNetBase& frontendserver ) { uint32 counter; // Input msgin.serial( counter ); ClientIds.push_back( make_pair( from, counter ) ); // store client sockid // Output CMessage msgout( "PING" ); msgout.serial( counter ); CNetManager::send( "PS", msgout ); // does not send if not connected nlinfo( "Received PING number %u from %s", counter, frontendserver.hostAddress(from).asString().c_str() ); } /* * Callback function called when receiving a "PONG" message * * Arguments: * - msgin: the incoming message (coming from the ping server) * - from: the "sockid" of the sender (usually useless for a CCallbackClient) * - clientofthepingserver: the CCallbackNetBase object (which really is a CCallbackClient object) * * Input (expected message from the ping server): PONG * - uint32: ping counter * - TSockId: "sock id" of the client who sent the ping * * Output (sent message to a client): PONG * - uint32: ping counter */ void cbPong( CMessage& msgin, TSockId from, CCallbackNetBase& clientofthepingserver ) { uint32 counter; TSockId clientfrom; // Input: process the reply of the ping service msgin.serial( counter ); // Do not send in case of double ping service reply (see onDisconnectPS()) // (does not work if two clients send the same counter at the same time) if ( ( !ClientIds.empty() ) && (ClientIds.front().second == counter) ) { clientfrom = ClientIds.front().first; // retrieve client sockid ClientIds.pop_front(); // Output: send the reply to the client CMessage msgout( "PONG" ); msgout.serial( counter ); CNetManager::send( "FS", msgout, clientfrom ); nlinfo( "Sent PONG number %u to %s", counter, clientfrom->asString().c_str() ); } } /* * Disonnection callback for the ping service */ void onDisconnectPS( const std::string &serviceName, TSockId from, void *arg ) { /* Note: the pings already forwarded should get no reply, but it may occur * (e.g. if the server reconnects before the forwarding of a PING and * the reconnection callbacks is called after that). Then onReconnectPS() * may send PINGs that have already been sent and the front-end may get * the same PONG twice. This is partially handled in cbPong. */ nlinfo( "Ping Service disconnecting: pongs will be delayed until reconnection" ); } /* * Connection callback for the ping service */ void onReconnectPS( const std::string &serviceName, TSockId from, void *arg ) { uint32 i; uint32 counter; // Output: forward all stored pings to the reconnected ping service for ( i=0; i!=ClientIds.size(); i++ ) { CMessage msgout( "PING" ); counter = ClientIds[i].second; msgout.serial( counter ); CNetManager::send( "PS", msgout ); } nlinfo( "Ping Service reconnected: %d pings forwarded", ClientIds.size() ); } /* * Disonnection callback for a client */ void onDisconnectClient( const std::string &serviceName, TSockId from, void *arg ) { // Erase all associated elements in the queue deque< pair >::iterator iq = ClientIds.begin(); while ( iq!=ClientIds.end() ) { if ( (*iq).first == from ) { iq = ClientIds.erase( iq ); } else { iq++; } } nlinfo( "A client has disconnected" ); } /* * Callback array for messages received from a client */ TCallbackItem CallbackArray[] = { { "PING", cbPing } // when receiving a "PING" message, call cbPing() }; /* * Callback array for message received from the ping service */ TCallbackItem PingServiceCallbackArray[] = { { "PONG", cbPong } // when receiving a "PONG" message, call cbPong() }; /* * CFrontEndService, based on IService */ class CFrontEndService : public IService { public: /* * Initialization */ void init() { // Connect to the ping service CNetManager::addClient( "PS" ); CNetManager::addCallbackArray( "PS", PingServiceCallbackArray, sizeof(PingServiceCallbackArray)/sizeof(PingServiceCallbackArray[0]) ); CNetManager::setConnectionCallback( "PS", onReconnectPS, NULL ); CNetManager::setDisconnectionCallback( "PS", onDisconnectPS, NULL ); CNetManager::setDisconnectionCallback( "FS", onDisconnectClient, NULL ); } }; /* * Declare a service with the class CFrontEndService, the names "FS" (short) and "frontend_service" (long). * The port is set to 37000 and the main callback array is CallbackArray. */ NLNET_OLD_SERVICE_MAIN( CFrontEndService, "FS", "frontend_service", 37000, CallbackArray, "", "" ) ================================================ FILE: code/nel/samples/net/net_layer4/ping_service.cfg ================================================ NSHost = "localhost"; WindowStyle = "WIN"; ================================================ FILE: code/nel/samples/net/net_layer4/ping_service.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Layer 4 and Service example, ping server. * * This ping service expects pings, sends pongs back. * * To run this program, ensure there is a file "ping_service.cfg" * containing the location of the naming service (NSHost, NSPort) * in the working directory. The naming service must be running. * * DEPRECATED: You should use layer5 (take a look in the layer5 sample directory) * */ // We're using the NeL Service framework, and layer 4 #include "nel/net/service.h" using namespace NLNET; /* * Callback function called when receiving a "PING" message * * Arguments: * - msgin: the incoming message (coming from a client) * - from: the "sockid" of the sender client * - server: the CCallbackNetBase object (which really is a CCallbackServer object, for a server) * * Input (expected message from a client): PING * - uint32: ping counter * * Output (sent message to the ping server): PONG * - uint32: ping counter */ void cbPing( CMessage& msgin, TSockId from, CCallbackNetBase& server ) { uint32 counter; // Input msgin.serial( counter ); // Output (uses layer 4 but this is not really necessary, see server.cpp in layer 3 example) CMessage msgout( "PONG" ); msgout.serial( counter ); CNetManager::send( "PS", msgout, from ); nlinfo( "PING -> PONG %u", counter ); } /* * Callback array for messages received from a client */ TCallbackItem CallbackArray[] = { { "PING", cbPing } }; // We use IService directly, no need to inherit from it /* * Declare a service with the class IService, the names "PS" (short) and "ping_service" (long). * The port is automatically allocated (0) and the main callback array is CallbackArray. */ NLNET_OLD_SERVICE_MAIN( IService, "PS", "ping_service", 0, CallbackArray, "", "" ) ================================================ FILE: code/nel/samples/net/net_layer5/flood_service.cfg ================================================ NSHost = "localhost"; WindowStyle = "WIN"; ================================================ FILE: code/nel/samples/net/net_layer5/flood_service.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Layer 4 and Service example, ping server. * * This ping service expects pings, sends pongs back. * * To run this program, ensure there is a file "ping_service.cfg" * containing the location of the naming service (NSHost, NSPort) * in the working directory. The naming service must be running. */ // We're using the NeL Service framework, and layer 5 #include "nel/net/service.h" #include "nel/misc/time_nl.h" #include "nel/misc/thread.h" using namespace std; using namespace NLNET; using namespace NLMISC; // const uint NumThreads = 10; volatile TTime PingDates[NumThreads]; volatile bool ServiceReady = false; void cbPong(CMessage &msgin, const std::string &serviceName, TServiceId sid) { uint32 counter; msgin.serial( counter ); TTime pingTime = CTime::getLocalTime()-PingDates[counter]; PingDates[counter] = 0; nlinfo("Received PONG %u (%u ms)", counter, pingTime); CMessage msgout("ACK_POS"); CUnifiedNetwork::getInstance()->send("PLS", msgout); } void sendPing(uint i) { PingDates[i] = CTime::getLocalTime(); uint32 counter = i; CMessage msgout("PING"); msgout.serial( counter ); nlinfo( "Send PING %d", counter); CUnifiedNetwork::getInstance()->send("PS", msgout); nlinfo( "PING %d sent", counter); } class CPinger : public IRunnable { private: static volatile uint _PingerCount; uint _PingerId; public: CPinger() { _PingerId = _PingerCount++; } void run() { uint i; uint totalPing = 0; while (!ServiceReady) { nlSleep(10); } while (totalPing < 200) { i = rand()*200/RAND_MAX+200; nlSleep(i); if (PingDates[_PingerId] == 0) { sendPing(_PingerId); ++totalPing; } } } }; volatile uint CPinger::_PingerCount = 0; // void cbPos(CMessage &msgin, const std::string &serviceName, TServiceId sid) { CMessage msgout("POS"); CUnifiedNetwork::getInstance()->send("GPMS", msgout); nlinfo( "Received POS from %s, send POS to GPMS", serviceName.c_str()); } void cbAckPos(CMessage &msgin, const std::string &serviceName, TServiceId sid) { nlinfo( "Received ACK_POS from %s", serviceName.c_str()); } // void cbUpPS(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("Ping Service connecting"); } void cbDownPS(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("Ping Service disconnecting"); } // void cbUpService(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("Service %s %d is up", serviceName.c_str(), sid.get()); } void cbDownService(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("Service %s %d is down", serviceName.c_str(), sid.get()); } /* * Callback array for messages received from a client */ TUnifiedCallbackItem CallbackArray[] = { { "PONG", cbPong }, { "POS", cbPos }, { "ACK_POS", cbAckPos } }; // class CFloodService : public IService { public: bool update() { ServiceReady = true; return true; } /* * Initialization */ void init() { // Connect to the ping service CUnifiedNetwork *instance = CUnifiedNetwork::getInstance(); instance->setServiceUpCallback("PS", cbUpPS, NULL); instance->setServiceDownCallback("PS", cbDownPS, NULL); instance->setServiceUpCallback("*", cbUpService, NULL); instance->setServiceDownCallback("*", cbDownService, NULL); uint i; for (i=0; istart(); } } }; /* * Declare a service with the class IService, the names "PS" (short) and "ping_service" (long). * The port is automatically allocated (0) and the main callback array is CallbackArray. */ NLNET_SERVICE_MAIN( CFloodService, "FLS", "flood_service", 0, CallbackArray, "", "" ) ================================================ FILE: code/nel/samples/net/net_layer5/frontend_service.cfg ================================================ NSHost = "localhost"; WindowStyle = "WIN"; //Networks = { "192.168.0.0", "192.168.1.0", }; //DefaultNetworks = { }; ================================================ FILE: code/nel/samples/net/net_layer5/frontend_service.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Layer 5 and Service example, front-end server. * * This front-end server expects pings, and forward them to * the real ping server. When the ping server sends a pong back, * the front-end server forwards it to the client. * * Even if the connection to the ping server is broken, our * front-end server will keep storing the ping messages and * will forward them when the connection is restored. * * To run this program, ensure there is a file "frontend_service.cfg" * containing the location of the naming service (NSHost, NSPort) * in the working directory. The naming service must be running. */ // We're using the NeL Service framework and layer 5. #include "nel/net/service.h" #include "nel/misc/time_nl.h" #include "nel/misc/displayer.h" #include "nel/misc/command.h" #include "nel/misc/hierarchical_timer.h" #include "nel/misc/bit_mem_stream.h" #include using namespace std; using namespace NLNET; using namespace NLMISC; // TTime pingDate; /* * Callback function called when receiving a "PONG" message * * Arguments: * - msgin: the incoming message (coming from the ping server) * - from: the "sockid" of the sender (usually useless for a CCallbackClient) * - clientofthepingserver: the CCallbackNetBase object (which really is a CCallbackClient object) * * Input (expected message from the ping server): PONG * - uint32: ping counter * - TSockId: "sock id" of the client who sent the ping * * Output (sent message to a client): PONG * - uint32: ping counter */ void cbPong(CMessage &msgin, const std::string &serviceName, TServiceId sid) { uint32 counter; msgin.serial( counter ); TTime pingTime = CTime::getLocalTime()-pingDate; nlinfo("Received PONG %u (%u ms)", counter, pingTime); } void sendPing() { pingDate = CTime::getLocalTime(); uint32 counter = 0; CMessage msgout("PING"); msgout.serial( counter ); nlinfo( "Send PING 0"); CUnifiedNetwork::getInstance()->send("PS", msgout); } // void cbPos(CMessage &msgin, const std::string &serviceName, TServiceId sid) { // decode the message TCPUCycle v1 = CTime::getPerformanceTime (); uint32 nbid; msgin.serial (nbid); for (uint i = 0; i < nbid; i++) { uint64 id; msgin.serial (id); } TCPUCycle v2 = CTime::getPerformanceTime (); nlinfo("Received POS from %s (serial: %.2fs)", serviceName.c_str(), CTime::ticksToSecond(v2-v1)); } TTime t = 0; void sendRequestVision () { // nlSleep (1000); CMessage msgout("ASK_VISION"); CUnifiedNetwork::getInstance()->send("GPMS", msgout); nlinfo ("ask a new vision"); t = CTime::getLocalTime (); } void cbVision(CMessage &msgin, const std::string &serviceName, TServiceId sid) { uint32 NbValue; uint32 Value; t = CTime::getLocalTime() - t; //H_BEFORE (Vision); TCPUCycle v1 = CTime::getPerformanceTime (); //H_BEFORE (serial); msgin.serial (NbValue); //H_AFTER (serial); //H_BEFORE (serials); for (uint i = 0; i < NbValue; i++) msgin.serial( Value ); //H_AFTER (serials); TCPUCycle v2 = CTime::getPerformanceTime (); nlinfo("%dms of lag, Received Vision with %d values in %.2fms", (uint32) t, NbValue, CTime::ticksToSecond (v2-v1)*1000.0f); // sendRequestVision(); //H_AFTER (Vision); } void sendPos() { nlinfo("Simulate receive pos from client, send POS to GPMS"); CMessage msgout("POS"); CUnifiedNetwork::getInstance()->send("GPMS", msgout); } // void cbUpGPMS(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo( "GPMS connecting."); sendRequestVision (); } // void cbUpPS(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo( "Ping Service connecting."); sendPing(); } void cbDownPS(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo( "Ping Service disconnecting." ); } // void cbUpService(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("Service %s %d is up", serviceName.c_str(), sid.get()); } void cbDownService(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("Service %s %d is down", serviceName.c_str(), sid.get()); } /* * Callback array for message received from the ping service */ NLNET::TUnifiedCallbackItem CallbackArray[] = { { "POS", cbPos }, { "PONG", cbPong }, { "VISION", cbVision } }; /* * CFrontEndService, based on IService */ class CFrontEndService : public NLNET::IService { public: bool update() { static TTime lastPing = CTime::getLocalTime(); static TTime lastGetPos = CTime::getLocalTime(); TTime ctime = CTime::getLocalTime(); // check vision every 2 seconds if (ctime - lastPing> 2000) { sendRequestVision(); lastPing = ctime; } /* // check ping every 15 seconds if (ctime - lastPing> 15000) { sendPing(); lastPing = ctime; } // do as if receive a position every second if (ctime - lastGetPos > 1000) { sendPos(); lastGetPos = ctime; } */ return true; } /* * Initialization */ void init() { /* uint32 u = 0xFFFFFFFF; uint32 z = 0; uint32 res = 0; CBitMemStream bms2; bms2.serial (u, 1); bms2.serial (z, 18); bms2.serial (u, 4); bms2.serial (z, 3); nlinfo ("len %d", bms2.length()); bms2.invert (); nlinfo ("len %d", bms2.length()); bms2.invert (); nlinfo ("len %d", bms2.length()); */ /* CBitMemStream bms; nlinfo ("len %d", bms.length()); bms.serial (u, 1); bms.serial (z, 18); bms.serial (u, 4); bms.serial (z, 3); bms.serial (u, 30); nlinfo ("len %d", bms.length()); bms.clear (); nlinfo ("len %d", bms.length()); bms.serial (z, 1); bms.serial (u, 18); bms.serial (z, 4); bms.serial (u, 3); bms.serial (z, 30); nlinfo ("len %d", bms.length()); vector cont; for(uint i=0;i<32;i++) cont.push_back(i); bms.serialCont (cont); nlinfo ("len %d", bms.length()); bms.invert (); nlinfo ("len %d", bms.length()); while (bms.getPosInBit() != 30+3+4+18+1) { nlinfo ("%d", bms.getPosInBit()); bms.serial (res, 1); nlinfo ((res==0)?"0":"1"); } nlinfo ("%d", bms.getPosInBit()); vector cont2; bms.serialCont (cont2); nlinfo ("%d", bms.getPosInBit()); for(uint j=0;jsetServiceUpCallback("PS", cbUpPS, NULL); instance->setServiceDownCallback("PS", cbDownPS, NULL); instance->setServiceUpCallback("GPMS", cbUpGPMS, NULL); instance->setServiceUpCallback("*", cbUpService, NULL); instance->setServiceDownCallback("*", cbDownService, NULL); } }; /* * Declare a service with the class CFrontEndService, the names "FS" (short) and "frontend_service" (long). * The port is set to 37000 and the main callback array is CallbackArray. */ NLNET_SERVICE_MAIN( CFrontEndService, "FS", "frontend_service", 37000, CallbackArray, "", "" ) ================================================ FILE: code/nel/samples/net/net_layer5/gpm_service.cfg ================================================ NSHost = "localhost"; WindowStyle = "WIN"; NbId = 200000; IWinParam = 0; //Networks = { "192.168.1.0", "192.168.0.0" }; //DefaultNetworks = { "FS1" }; ================================================ FILE: code/nel/samples/net/net_layer5/gpm_service.cpp ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* * Layer 4 and Service example, ping server. * * This ping service expects pings, sends pongs back. * * To run this program, ensure there is a file "ping_service.cfg" * containing the location of the naming service (NSHost, NSPort) * in the working directory. The naming service must be running. */ // We're using the NeL Service framework, and layer 5 #include "nel/net/service.h" #include "nel/misc/time_nl.h" #include "nel/misc/displayer.h" #include "nel/misc/command.h" #include "nel/misc/hierarchical_timer.h" using namespace std; using namespace NLNET; using namespace NLMISC; uint32 NbId = 0; // TTime pingDate; void cbPong(CMessage &msgin, const std::string &serviceName, TServiceId sid) { uint32 counter; msgin.serial( counter ); TTime pingTime = CTime::getLocalTime()-pingDate; nlinfo("Received PONG %u (%u ms)", counter, pingTime); } void sendPing() { pingDate = CTime::getLocalTime(); uint32 counter = 0; CMessage msgout("PING"); msgout.serial( counter ); nlinfo( "Send PING 0"); CUnifiedNetwork::getInstance()->send("PS", msgout); } // void cbPos(CMessage &msgin, const std::string &serviceName, TServiceId sid) { CMessage msgout("ACK_POS"); CUnifiedNetwork::getInstance()->send("PLS", msgout); TCPUCycle v1 = CTime::getPerformanceTime (); CMessage msgoutfe("POS", false, CMessage::UseDefault, NbId*8); uint64 id = rand(); msgoutfe.serial (NbId); for (uint i = 0; i < NbId; i++) { msgoutfe.serial (id); id++; } TCPUCycle v2 = CTime::getPerformanceTime (); CUnifiedNetwork::getInstance()->send("FS", msgoutfe); TCPUCycle v3 = CTime::getPerformanceTime (); nlinfo( "Received POS, Sending POS to FS (serial %.2fs, send %.2fs)", CTime::ticksToSecond (v2-v1), CTime::ticksToSecond (v3-v2)); } void cbAskVision(CMessage &msgin, const std::string &serviceName, TServiceId sid) { uint32 Value = '0ACE'; // H_BEFORE (Vision); TCPUCycle v1 = CTime::getPerformanceTime (); // H_BEFORE (CMessage); CMessage msgout("VISION", false, CMessage::UseDefault, 10000000); // H_AFTER (CMessage); // H_BEFORE (serial); msgout.serial(NbId); // H_AFTER (serial); // H_BEFORE (serials); for (uint i = 0; i < NbId; i++) msgout.serial( Value ); // H_AFTER(serials); // H_BEFORE (send); CUnifiedNetwork::getInstance()->send("FS", msgout); // H_AFTER (send); /* CMessage msgout("VISION"); uint32 Nb = 10; for (uint j = 0; j < 1000; j++) { msgout.clear(); msgout.setType("VISION"); msgout.serial(Nb); for (uint i = 0; i < Nb; i++) msgout.serial( Value ); CUnifiedNetwork::getInstance()->send("FS", msgout); } */ TCPUCycle v2 = CTime::getPerformanceTime (); // H_AFTER (Vision); // ca prend bcp de cpu un info... nlinfo("Sent Vision with %d values in %.2fms", NbId, CTime::ticksToSecond (v2-v1)*1000.0f); } // void cbUpPS(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("Ping Service connecting"); sendPing(); } void cbDownPS(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("Ping Service disconnecting"); } // void cbUpFS(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("F Service connecting"); sendPing(); } void cbDownFS(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("F Service disconnecting"); } // void cbUpService(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("Service %s %d is up", serviceName.c_str(), sid.get()); CMessage msgout("TOTO"); uint32 i = 10; msgout.serial(i); CUnifiedNetwork::getInstance()->send(sid, msgout); } void cbDownService(const std::string &serviceName, TServiceId sid, void *arg) { nlinfo("Service %s %d is down", serviceName.c_str(), sid.get()); } /* * Callback array for messages received from a client */ TUnifiedCallbackItem CallbackArray[] = { { "PONG", cbPong }, { "POS", cbPos }, { "ASK_VISION", cbAskVision } }; void cbVar (CConfigFile::CVar &var) { if (var.Name == "NbId") NbId = var.asInt (); else nlstop; } // class CGPMService : public IService { public: bool update() { static TTime lastPing = CTime::getLocalTime(); TTime ctime = CTime::getLocalTime(); /* // check ping every 15 seconds if (ctime - lastPing > 15000) { sendPing(); lastPing = ctime; } */ return true; } /* * Initialization */ void init() { // nlerror ("oups"); /* //nlassert(false); char *p=0; p[0]=0; printf(p); */ ConfigFile.setCallback ("NbId", cbVar); cbVar (ConfigFile.getVar ("NbId")); // Connect to the ping service CUnifiedNetwork *instance = CUnifiedNetwork::getInstance(); instance->setServiceUpCallback("PS", cbUpPS, NULL); instance->setServiceDownCallback("PS", cbDownPS, NULL); instance->setServiceUpCallback("FS", cbUpFS, NULL); instance->setServiceDownCallback("FS", cbDownFS, NULL); instance->setServiceUpCallback("*", cbUpService, NULL); instance->setServiceDownCallback("*", cbDownService, NULL); } }; /* * Declare a service with the class IService, the names "PS" (short) and "ping_service" (long). * The port is automatically allocated (0) and the main callback array is CallbackArray. */ NLNET_SERVICE_MAIN( CGPMService, "GPMS", "gpm_service", 0, CallbackArray, "", "" ) NLMISC_COMMAND (wait, "", "

NeLTest Unit Tests Results

Designed by CppTest

Summary

Tests Errors Success Time (s)
66 1 98% 35.265000

Test suites

Name Tests Errors Success Time (s)
CUTMiscCoTask 2 0 100% 0.000000
CUTMiscCommand 5 0 100% 0.015000
CUTMiscConfigFile 6 0 100% 0.032000
CUTMiscDebug 2 0 100% 0.000000
CUTMiscDynLibLoad 1 0 100% 0.000000
CUTMiscFile 4 0 100% 0.859000
CUTMiscPackFile 11 0 100% 0.016000
CUTMiscSingleton 2 0 100% 0.000000
CUTMiscSString 1 0 100% 0.000000
CUTMiscStream 4 0 100% 0.000000
CUTMiscVariable 1 0 100% 0.000000
CUTMiscTypes 1 1 0% 0.000000
CUTNetLayer3 1 0 100% 2.312000
CUTNetMessage 3 0 100% 0.000000
CUTNetModule 21 0 100% 32.031000
CUTLigoPrimitive 1 0 100% 0.000000

Suite: CUTMiscCoTask

Name Errors Success Time (s)
runTasks 0 true 0.000000
tasksAndThreads 0 true 0.000000

Back to top

Suite: CUTMiscCommand

Name Errors Success Time (s)
createOneInstance 0 true 0.015000
createAnotherInstance 0 true 0.000000
deleteOneInstance 0 true 0.000000
derivedClass 0 true 0.000000
derivedClassAndBaseCall 0 true 0.000000

Back to top

Suite: CUTMiscConfigFile

Name Errors Success Time (s)
configWithInclude 0 true 0.016000
configWithOptional 0 true 0.000000
configWithDefine 0 true 0.000000
configWithBadTest 0 true 0.000000
configIncludeAndOptional 0 true 0.000000
reportErrorInSubFiles 0 true 0.016000

Back to top

Suite: CUTMiscDebug

Name Errors Success Time (s)
testInstanceCounter 0 true 0.000000
testInstanceCounterOutput 0 true 0.000000

Back to top

Suite: CUTMiscDynLibLoad

Name Errors Success Time (s)
libraryNameDecoration 0 true 0.000000

Back to top

Suite: CUTMiscFile

Name Errors Success Time (s)
copyOneBigFile 0 true 0.187000
copyDifferentFileSize 0 true 0.203000
moveOneBigFile 0 true 0.203000
moveDifferentFileSize 0 true 0.266000

Back to top

Suite: CUTMiscPackFile

Name Errors Success Time (s)
addBnp 0 true 0.000000
loadFromBnp 0 true 0.000000
addXmlpack 0 true 0.016000
loadFromXmlpack 0 true 0.000000
compressMemory 0 true 0.000000
loadFromBnpCompressed 0 true 0.000000
loadFromXmlpackCompressed 0 true 0.000000
decompressMemory 0 true 0.000000
loadFromBnpUncompressed 0 true 0.000000
loadFromXmlpackUncompressed 0 true 0.000000
loadXmlpackWithSameName 0 true 0.000000

Back to top

Suite: CUTMiscSingleton

Name Errors Success Time (s)
createSingleton 0 true 0.000000
accessSingleton 0 true 0.000000

Back to top

Suite: CUTMiscSString

Name Errors Success Time (s)
testStrtok 0 true 0.000000

Back to top

Suite: CUTMiscStream

Name Errors Success Time (s)
constAndStream 0 true 0.000000
memStreamSwap 0 true 0.000000
copyOnWrite 0 true 0.000000
preallocatedBitStream 0 true 0.000000

Back to top

Suite: CUTMiscVariable

Name Errors Success Time (s)
declareVar 0 true 0.000000

Back to top

Suite: CUTMiscTypes

Name Errors Success Time (s)
basicTypes 1 false 0.000000

Back to top

Suite: CUTNetLayer3

Name Errors Success Time (s)
sendReceiveUpdate 0 true 2.312000

Back to top

Suite: CUTNetMessage

Name Errors Success Time (s)
messageSwap 0 true 0.000000
lockSubMEssage 0 true 0.000000
lockSubMEssageWithLongName 0 true 0.000000

Back to top

Suite: CUTNetModule

Name Errors Success Time (s)
testModuleInitInfoParsing 0 true 0.000000
testModuleInitInfoQuering 0 true 0.000000
testModuleInitInfoBadParsing 0 true 0.000000
localModuleFactory 0 true 0.016000
failedInit 0 true 0.000000
createLocalGateway 0 true 0.000000
plugLocalGateway 0 true 0.000000
gatewayTransportManagement 0 true 1.219000
connectGateways 0 true 0.828000
moduleDisclosure 0 true 1.328000
moduleMessaging 0 true 1.625000
localMessageQueing 0 true 0.609000
uniqueNameGenerator 0 true 0.000000
gwPlugUnplug 0 true 0.000000
peerInvisible 0 true 3.453000
firewalling 0 true 3.438000
distanceAndConnectionLoop 0 true 6.109000
securityPlugin 0 true 5.094000
synchronousMessaging 0 true 1.031000
layer3Autoconnect 0 true 6.672000
interceptorTest 0 true 0.609000

Back to top

Suite: CUTLigoPrimitive

Name Errors Success Time (s)
testAliasGenerator 0 true 0.000000

Back to top


Test results

CUTMiscTypes::basicTypes

Test CUTMiscTypes::basicTypes
File d:\ryzom\nel\tools\nel_unit_test\ut_misc_types.h:31
Message sizeof(time_t) == sizeof(uint32)

Back to CUTMiscTypes


Valid XHTML 1.0 Strict

================================================ FILE: code/nel/tools/nel_unit_test/run_test.bat ================================================ nel_unit_test.exe --html start result.html ================================================ FILE: code/nel/tools/nel_unit_test/ut_ligo.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_LIGO #define UT_LIGO #include #include "ut_ligo_primitive.h" // Add a line here when adding a new test CLASS struct CUTLigo : public Test::Suite { CUTLigo() { add(auto_ptr(new CUTLigoPrimitive)); // Add a line here when adding a new test CLASS } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_ligo_primitive.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_LIGO_PRIMITIVE #define UT_LIGO_PRIMITIVE #include #include class CUTLigoPrimitive : public Test::Suite { public: CUTLigoPrimitive() { TEST_ADD(CUTLigoPrimitive::testAliasGenerator) } private: string _RestorePath; string _WorkingPath; string _RefPrimFileName; void setup() { _RestorePath = NLMISC::CPath::getCurrentPath(); NLMISC::CPath::setCurrentPath(_WorkingPath.c_str()); _RefPrimFileName = "__test_prim.primitive"; // register ligo class factory NLLIGO::Register(); // create a primitive config file nlinfo("Building a default ligo class file"); const char *CLASS_FILE_NAME = "__ligo_class.xml"; string classfile; classfile = string() + "\n" + "\n" + " \n" + " \n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n" + " \n" + " \n" + " \n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""; FILE *fp = fopen(CLASS_FILE_NAME, "wt"); nlassert(fp != NULL); size_t s = fwrite(classfile.data(), 1, classfile.size(), fp); nlassert(s == classfile.size()); fclose(fp); // init ligo NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig = &_LigoConfig; _LigoConfig.readPrimitiveClass(CLASS_FILE_NAME, false); // create a reference primitive if (NLMISC::CFile::isExists(_RefPrimFileName)) { NLMISC::CFile::deleteFile(_RefPrimFileName); } NLLIGO::CPrimitives primDoc; nlassert(primDoc.RootNode != NULL); NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = &primDoc; NLLIGO::IPrimitive *p = dynamic_cast (NLMISC::CClassRegistry::create ("CPrimNode")); p->addPropertyByName("class", new NLLIGO::CPropertyString("test")); p->addPropertyByName("name", new NLLIGO::CPropertyString("test_root")); primDoc.RootNode->insertChild(p); NLLIGO::CPrimAlias *pa = dynamic_cast (NLMISC::CClassRegistry::create ("CPrimAlias")); pa->addPropertyByName("class", new NLLIGO::CPropertyString("alias")); pa->addPropertyByName("name", new NLLIGO::CPropertyString("alias")); p->insertChild(pa); NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; // save the file saveXmlPrimitiveFile(primDoc, _RefPrimFileName); } void tear_down() { NLMISC::CPath::setCurrentPath(_RestorePath.c_str()); } void testAliasGenerator() { //Known bug : is we load/save a primitive and replacing a primitive node with itself (conserving the alias), the // 'last generated alias' counter is incremented. uint32 lastGeneratedAlias; // First, load then save the doc { NLLIGO::CPrimitives primDoc; NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = &primDoc; loadXmlPrimitiveFile(primDoc, _RefPrimFileName, _LigoConfig); NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; lastGeneratedAlias = primDoc.getLastGeneratedAlias(); // get a copy of the primitive NLLIGO::IPrimitive *prim = NULL; NLLIGO::IPrimitive *primCopy = NULL; TEST_ASSERT(primDoc.RootNode->getChild(prim, 0)); if (prim) { primCopy = prim->copy(); TEST_ASSERT(primCopy != NULL); if (primCopy) { // remove the primitive primDoc.RootNode->removeChild(prim); // insert the copy NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = &primDoc; primDoc.RootNode->insertChild(primCopy); NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; } } // save the file saveXmlPrimitiveFile(primDoc, _RefPrimFileName); } // second, reload the file and check the last generated alias { NLLIGO::CPrimitives primDoc; NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = &primDoc; loadXmlPrimitiveFile(primDoc, _RefPrimFileName, _LigoConfig); NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; TEST_ASSERT(lastGeneratedAlias == primDoc.getLastGeneratedAlias()); } } NLLIGO::CLigoConfig _LigoConfig; }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC #define UT_MISC #include "ut_misc_co_task.h" #include "ut_misc_command.h" #include "ut_misc_config_file.h" #include "ut_misc_debug.h" #include "ut_misc_dynlibload.h" #include "ut_misc_file.h" #include "ut_misc_pack_file.h" #include "ut_misc_singleton.h" #include "ut_misc_sstring.h" #include "ut_misc_stream.h" #include "ut_misc_variable.h" #include "ut_misc_types.h" #include "ut_misc_string_common.h" // Add a line here when adding a new test CLASS struct CUTMisc : public Test::Suite { CUTMisc() { add(auto_ptr(new CUTMiscCoTask)); add(auto_ptr(new CUTMiscCommand)); add(auto_ptr(new CUTMiscConfigFile)); add(auto_ptr(new CUTMiscDebug)); add(auto_ptr(new CUTMiscDynLibLoad)); add(auto_ptr(new CUTMiscFile)); add(auto_ptr(new CUTMiscPackFile)); add(auto_ptr(new CUTMiscSingleton)); add(auto_ptr(new CUTMiscSString)); add(auto_ptr(new CUTMiscStream)); add(auto_ptr(new CUTMiscVariable)); add(auto_ptr(new CUTMiscTypes)); add(auto_ptr(new CUTMiscStringCommon)); // Add a line here when adding a new test CLASS } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_co_task.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_CO_TASK #define UT_MISC_CO_TASK #include #include const char *referenceResult[] = { "Task1 : 0", "Task2 : 0", "Main : 0", "Task1 : 1", "Task2 : 1", "Main : 1", "Task1 : 2", "Task2 : 2", "Task1 : 3", "Task2 : 3", "Task1 : 4", "Task2 : 4", "Task2 : 5", "Task2 : 6", }; const char *referenceResultThread1[] = { "Task1 : 0", "Thread : 0", "Task1 : 1", "Thread : 1", "Task1 : 2", "Thread : 2", "Task1 : 3", "Thread : 3", "Task1 : 4", "Thread : 4", }; const char *referenceResultThread2[] = { "Task2 : 0", "Main : 0", "Task2 : 1", "Main : 1", "Task2 : 2", "Task2 : 3", "Task2 : 4", }; vector result; vector result2; // a simple task class CTask1 : public NLMISC::CCoTask { vector &Output; public: CTask1(vector &output = result) : Output(output) {} void run() { for (uint i=0; i<5; ++i) { string s = NLMISC::toString("Task1 : %u", i); Output.push_back(s); yield(); } } }; // another simple task class CTask2 : public NLMISC::CCoTask { vector &Output; public: CTask2(vector &output = result) : Output(output) {} void run() { for (uint i=0; i<7; ++i) { string s = NLMISC::toString("Task2 : %u", i); Output.push_back(s); yield(); } } }; // a thread runnable class class CTaskThread : public NLMISC::IRunnable { void run() { CTask1 t1(result2); for (uint i=0; i<5; ++i) { t1.resume(); string s = NLMISC::toString("Thread : %u", i); result2.push_back(s); NLMISC::nlSleep(0); } } }; // Test suite for coroutine task class CUTMiscCoTask: public Test::Suite { public: CUTMiscCoTask() { TEST_ADD(CUTMiscCoTask::runTasks); TEST_ADD(CUTMiscCoTask::tasksAndThreads); } void tasksAndThreads() { // test running task in two separate thread (this stress the // multithreading support of task). CoTask API ;ake use of // thread local storage API to store by thread current task info. result.clear(); result2.clear(); CTaskThread tt; NLMISC::IThread *th = NLMISC::IThread::create(&tt); CTask2 t2; // start the thread th->start(); for (uint i=0; i<2; ++i) { t2.resume(); string s = NLMISC::toString("Main : %u", i); result.push_back(s); NLMISC::nlSleep(0); } // wait task completion t2.wait(); // wait thread completion th->wait(); delete th; // test result for (uint i=0; i // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_COMMAND #define UT_MISC_COMMAND #include vector callList; class TTest : public NLMISC::ICommandsHandler { protected: std::string _Name; public: const std::string &getCommandHandlerName() const { return _Name; } void setName(const std::string &name) { nlassert(_Name.empty()); _Name = name; registerCommandsHandler(); } NLMISC_COMMAND_HANDLER_TABLE_BEGIN(TTest) NLMISC_COMMAND_HANDLER_ADD(TTest, theCommand1, "help", "args") NLMISC_COMMAND_HANDLER_ADD(TTest, theCommand2, "other help", "other args") NLMISC_COMMAND_HANDLER_TABLE_END NLMISC_CLASS_COMMAND_DECL(theCommand1) { callList.push_back(_Name+".theCommand1"); return true; } NLMISC_CLASS_COMMAND_DECL(theCommand2) { callList.push_back(_Name+".theCommand2"); return true; } }; class TTestDerived : public TTest { public: NLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(TTestDerived, TTest) NLMISC_COMMAND_HANDLER_ADD(TTestDerived, derivedCommand, "help", "args") NLMISC_COMMAND_HANDLER_ADD(TTestDerived, commandToOverride, "help", "args") NLMISC_COMMAND_HANDLER_TABLE_END NLMISC_CLASS_COMMAND_DECL(derivedCommand) { callList.push_back(_Name+".derivedCommand"); return true; } NLMISC_CLASS_COMMAND_DECL(commandToOverride) { callList.push_back(_Name+".commandToOverride"); return true; } }; class TTestDerived2 : public TTestDerived { public: NLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(TTestDerived2, TTestDerived) NLMISC_COMMAND_HANDLER_ADD(TTestDerived2, derivedCommand2, "help", "args") NLMISC_COMMAND_HANDLER_ADD(TTestDerived2, commandToOverride, "help", "args") NLMISC_COMMAND_HANDLER_TABLE_END NLMISC_CLASS_COMMAND_DECL(derivedCommand2) { callList.push_back(_Name+".derivedCommand2"); return true; } NLMISC_CLASS_COMMAND_DECL(commandToOverride) { callList.push_back(_Name+".command Overidden"); return true; } }; class TTestDerived3 : public TTestDerived2 { // empty class }; class TTestDerived4 : public TTestDerived3 { public: NLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(TTestDerived4, TTestDerived3) NLMISC_COMMAND_HANDLER_ADD(TTestDerived4, derivedCommand4, "help", "args") NLMISC_COMMAND_HANDLER_ADD(TTestDerived4, theCommand1, "help", "args") NLMISC_COMMAND_HANDLER_TABLE_END NLMISC_CLASS_COMMAND_DECL(derivedCommand4) { callList.push_back(_Name+".derivedCommand4"); return true; } NLMISC_CLASS_COMMAND_DECL(theCommand1) { callList.push_back(_Name+".recallBase"); NLMISC_CLASS_COMMAND_CALL_BASE(TTestDerived3, theCommand1); return true; } }; class CUTMiscCommand : public Test::Suite { TTest *t1; TTest *t2; public: CUTMiscCommand() { TEST_ADD(CUTMiscCommand::createOneInstance); TEST_ADD(CUTMiscCommand::createAnotherInstance); TEST_ADD(CUTMiscCommand::deleteOneInstance); TEST_ADD(CUTMiscCommand::derivedClass); TEST_ADD(CUTMiscCommand::derivedClassAndBaseCall); } void derivedClassAndBaseCall() { TTestDerived4 t4; t4.setName("T4"); callList.clear(); NLMISC::ICommand::execute("T4.derivedCommand4", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 1); TEST_ASSERT(callList[0] == "T4.derivedCommand4"); NLMISC::ICommand::execute("T4.theCommand1", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 3); TEST_ASSERT(callList[1] == "T4.recallBase"); TEST_ASSERT(callList[2] == "T4.theCommand1"); } void derivedClass() { TTestDerived t1; t1.setName("T1"); TTestDerived2 t2; t2.setName("T2"); callList.clear(); NLMISC::ICommand::execute("T1.theCommand1", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 1); TEST_ASSERT(callList[0] == "T1.theCommand1"); NLMISC::ICommand::execute("T1.derivedCommand", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 2); TEST_ASSERT(callList[1] == "T1.derivedCommand"); NLMISC::ICommand::execute("T1.commandToOverride", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 3); TEST_ASSERT(callList[2] == "T1.commandToOverride"); NLMISC::ICommand::execute("T2.theCommand1", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 4); TEST_ASSERT(callList[3] == "T2.theCommand1"); NLMISC::ICommand::execute("T2.derivedCommand", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 5); TEST_ASSERT(callList[4] == "T2.derivedCommand"); NLMISC::ICommand::execute("T2.commandToOverride", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 6); TEST_ASSERT(callList[5] == "T2.command Overidden"); } void createOneInstance() { t1 = new TTest; t1->setName("inst1"); TEST_ASSERT(callList.empty()); NLMISC::ICommand::execute("inst1.theCommand1", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 1); TEST_ASSERT(callList[0] == "inst1.theCommand1"); NLMISC::ICommand::execute("inst1.theCommand2", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 2); TEST_ASSERT(callList[0] == "inst1.theCommand1"); TEST_ASSERT(callList[1] == "inst1.theCommand2"); } void createAnotherInstance() { t2 = new TTest; t2->setName("inst2"); TEST_ASSERT(callList.size() == 2); NLMISC::ICommand::execute("inst2.theCommand1", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 3); TEST_ASSERT(callList[0] == "inst1.theCommand1"); TEST_ASSERT(callList[1] == "inst1.theCommand2"); TEST_ASSERT(callList[2] == "inst2.theCommand1"); NLMISC::ICommand::execute("inst2.theCommand2", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 4); TEST_ASSERT(callList[0] == "inst1.theCommand1"); TEST_ASSERT(callList[1] == "inst1.theCommand2"); TEST_ASSERT(callList[2] == "inst2.theCommand1"); TEST_ASSERT(callList[3] == "inst2.theCommand2"); } void deleteOneInstance() { delete t1; NLMISC::ICommand::execute("inst1.theCommand2", *NLMISC::InfoLog); TEST_ASSERT(callList.size() == 4); TEST_ASSERT(callList[0] == "inst1.theCommand1"); TEST_ASSERT(callList[1] == "inst1.theCommand2"); TEST_ASSERT(callList[2] == "inst2.theCommand1"); TEST_ASSERT(callList[3] == "inst2.theCommand2"); } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_config_file.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_CONFIG_FILE #define UT_MISC_CONFIG_FILE #include #ifndef NEL_UNIT_BASE #define NEL_UNIT_BASE "" #endif // NEL_UNIT_BASE // Test suite for CConfigFile class class CUTMiscConfigFile : public Test::Suite { string _WorkingPath; string _OldPath; public: CUTMiscConfigFile () { TEST_ADD(CUTMiscConfigFile::configWithInclude); TEST_ADD(CUTMiscConfigFile::configWithOptional); TEST_ADD(CUTMiscConfigFile::configWithDefine); TEST_ADD(CUTMiscConfigFile::configWithBadTest); TEST_ADD(CUTMiscConfigFile::configIncludeAndOptional); TEST_ADD(CUTMiscConfigFile::reportErrorInSubFiles); } void setup() { _OldPath = NLMISC::CPath::getCurrentPath(); NLMISC::CPath::setCurrentPath(_WorkingPath.c_str()); } void tear_down() { NLMISC::CPath::setCurrentPath(_OldPath.c_str()); } void configWithInclude() { NLMISC::CConfigFile configFile; TEST_THROWS_NOTHING(configFile.load(NEL_UNIT_BASE "ut_misc_files/cfg_with_include.cfg")); TEST_ASSERT(configFile.loaded()); TEST_ASSERT(configFile.getVarPtr("CfgWithInclude") != NULL); TEST_ASSERT(configFile.getVar("CfgWithInclude").asString(0) == "ok"); TEST_ASSERT(configFile.getVarPtr("IncludedCfg") != NULL); TEST_ASSERT(configFile.getVar("IncludedCfg").asString(0) == "ok"); } void configWithOptional() { NLMISC::CConfigFile configFile; TEST_THROWS_NOTHING(configFile.load(NEL_UNIT_BASE "ut_misc_files/cfg_with_optional.cfg")); TEST_ASSERT(configFile.loaded()); TEST_ASSERT(configFile.getVarPtr("CfgWithInclude") != NULL); TEST_ASSERT(configFile.getVar("CfgWithInclude").asString(0) == "ok"); TEST_ASSERT(configFile.getVarPtr("IncludedCfg") != NULL); TEST_ASSERT(configFile.getVar("IncludedCfg").asString(0) == "ok"); } void configWithDefine() { NLMISC::CConfigFile configFile; TEST_THROWS_NOTHING(configFile.load(NEL_UNIT_BASE "ut_misc_files/cfg_with_define.cfg")); TEST_ASSERT(configFile.loaded()); TEST_ASSERT(configFile.getVarPtr("CfgReadableVar") != NULL); TEST_ASSERT(configFile.getVarPtr("CfgNotToBeFound") == NULL); TEST_ASSERT(configFile.getVarPtr("CfgInvisible") == NULL); TEST_ASSERT(configFile.getVarPtr("CfgMustExist") != NULL); } class CMyDisplayer : public NLMISC::IDisplayer { public: vector Lines; virtual void doDisplay( const NLMISC::CLog::TDisplayInfo& args, const char *message) { Lines.push_back(message); } }; void configWithBadTest() { // override the warning channel to get the error on unclosed if CMyDisplayer warnings; NLMISC::CLog logger; logger.addDisplayer(&warnings); NLMISC::CNLWarningOverride override(&logger); NLMISC::CConfigFile configFile; string fullName = NLMISC::CPath::getFullPath(NEL_UNIT_BASE "ut_misc_files/cfg_with_bad_test.cfg", false); TEST_THROWS_NOTHING(configFile.load(NEL_UNIT_BASE "ut_misc_files/cfg_with_bad_test.cfg")); TEST_ASSERT(configFile.getVarPtr("ASimpleVar") != NULL); // check that we have the warnings TEST_ASSERT(warnings.Lines.size() == 13); TEST_ASSERT(warnings.Lines[0].find(string("Preprocess: In file ")+fullName+"(6) : Error unrecognized preprocessor command") != string::npos); TEST_ASSERT(warnings.Lines[1].find(string("Preprocess: In file ")+fullName+"(9) : Error found '#endif' without matching #if") != string::npos); // skip the I18N warning from parseMarkedString TEST_ASSERT(warnings.Lines[3].find(string("Preprocess: In file ")+fullName+"(12) : Error parsing include file command") != string::npos); // skip the I18N warning from parseMarkedString TEST_ASSERT(warnings.Lines[5].find(string("Preprocess: In file ")+fullName+"(13) : Error parsing include file command") != string::npos); // skip the I18N warning from parseMarkedString TEST_ASSERT(warnings.Lines[7].find(string("Preprocess: In file ")+fullName+"(14) : Error parsing optional file command") != string::npos); // skip the I18N warning from parseMarkedString TEST_ASSERT(warnings.Lines[9].find(string("Preprocess: In file ")+fullName+"(15) : Error parsing optional file command") != string::npos); TEST_ASSERT(warnings.Lines[10].find(string("Preprocess: In file ")+fullName+"(16) : Error parsing #define command") != string::npos); TEST_ASSERT(warnings.Lines[11].find(string("Preprocess: In file ")+fullName+"(17) : Error parsing #ifdef command") != string::npos); TEST_ASSERT(warnings.Lines[12].find("Preprocess: Missing 1 closing #endif after parsing") != string::npos); } void configIncludeAndOptional() { CMyDisplayer warnings; NLMISC::CLog logger; logger.addDisplayer(&warnings); NLMISC::CNLWarningOverride override(&logger); NLMISC::CConfigFile configFile; string fullName = NLMISC::CPath::getFullPath(NEL_UNIT_BASE "ut_misc_files/cfg_with_include_and_optional.cfg", false); TEST_THROWS_NOTHING(configFile.load(NEL_UNIT_BASE "ut_misc_files/cfg_with_include_and_optional.cfg")); // check that we have the warnings only for the 'include' command TEST_ASSERT(warnings.Lines.size() == 1); TEST_ASSERT(warnings.Lines[0].find(string("Preprocess: In file ")+fullName+"(2) : Cannot include file 'a_missing_file.cfg'") != string::npos); } void reportErrorInSubFiles() { CMyDisplayer warnings; NLMISC::CLog logger; logger.addDisplayer(&warnings); NLMISC::CNLWarningOverride override(&logger); NLMISC::CConfigFile configFile; string fullName = NLMISC::CPath::getFullPath(NEL_UNIT_BASE "ut_misc_files/cfg_with_error_main.cfg", false); string subfullName = NLMISC::CPath::getFullPath(NEL_UNIT_BASE "ut_misc_files/cfg_with_error.cfg", false); TEST_THROWS(configFile.load(NEL_UNIT_BASE "ut_misc_files/cfg_with_error_main.cfg"), NLMISC::EParseError); // check that we have error report with correct filename and line number TEST_ASSERT(warnings.Lines.size() == 1); // the first error is in the subfile TEST_ASSERT(warnings.Lines[0].find(string("CF: Parsing error in file ")+subfullName+" line 18") != string::npos); } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_debug.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_DEBUG #define UT_MISC_DEBUG #include #include class CMiscUnitTestNelLibrary : public NLMISC::INelLibrary { void onLibraryLoaded(bool firstTime) { } void onLibraryUnloaded(bool lastTime) { } }; NLMISC_DECL_PURE_LIB(CMiscUnitTestNelLibrary); // Test suite for CInstanceCounter class CFoo1 { public: NL_INSTANCE_COUNTER_DECL(CFoo1); }; NL_INSTANCE_COUNTER_IMPL(CFoo1); class CFoo2 { public: NL_INSTANCE_COUNTER_DECL(CFoo2); }; NL_INSTANCE_COUNTER_IMPL(CFoo2); class CFoo3 : public CFoo2 { public: NL_INSTANCE_COUNTER_DECL(CFoo3); }; NL_INSTANCE_COUNTER_IMPL(CFoo3); class CUTMiscDebug : public Test::Suite { public: CUTMiscDebug() { TEST_ADD(CUTMiscDebug::testInstanceCounter) TEST_ADD(CUTMiscDebug::testInstanceCounterOutput) } private: void testInstanceCounter() { sint32 n; { CFoo1 foo1; sint32 n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 1); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == 1); NLMISC::CInstanceCounterManager::getInstance().resetDeltaCounter(); n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 1); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == 0); } n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 0); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == -1); { CFoo1 foo1; CFoo1 other(foo1); sint32 n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 2); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == 1); NLMISC::CInstanceCounterManager::getInstance().resetDeltaCounter(); n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 2); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == 0); } n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 0); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == -2); { CFoo1 foo1; CFoo1 other; foo1 = other; sint32 n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 2); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == 0); NLMISC::CInstanceCounterManager::getInstance().resetDeltaCounter(); n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 2); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == 0); } n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 0); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == -2); CFoo1 *foo1s[10]; CFoo2 *foo2s[10]; CFoo3 *foo3s[10]; for (uint i=0; i<10; ++i) { foo1s[i] = new CFoo1; foo2s[i] = new CFoo2; foo3s[i] = new CFoo3; } n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 10); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == 8); n = NL_GET_INSTANCE_COUNTER(CFoo2); TEST_ASSERT(n == 20); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo2); TEST_ASSERT(n == 20); n = NL_GET_INSTANCE_COUNTER(CFoo3); TEST_ASSERT(n == 10); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo3); TEST_ASSERT(n == 10); NLMISC::CInstanceCounterManager::getInstance().resetDeltaCounter(); n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 10); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == 0); n = NL_GET_INSTANCE_COUNTER(CFoo2); TEST_ASSERT(n == 20); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo2); TEST_ASSERT(n == 0); n = NL_GET_INSTANCE_COUNTER(CFoo3); TEST_ASSERT(n == 10); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo3); TEST_ASSERT(n == 0); for (uint i=0; i<5; ++i) { delete foo1s[i]; delete foo2s[i]; delete foo3s[i]; } n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 5); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == -5); n = NL_GET_INSTANCE_COUNTER(CFoo2); TEST_ASSERT(n == 10); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo2); TEST_ASSERT(n == -10); n = NL_GET_INSTANCE_COUNTER(CFoo3); TEST_ASSERT(n == 5); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo3); TEST_ASSERT(n == -5); for (uint i=5; i<10; ++i) { delete foo1s[i]; delete foo2s[i]; delete foo3s[i]; } n = NL_GET_INSTANCE_COUNTER(CFoo1); TEST_ASSERT(n == 0); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1); TEST_ASSERT(n == -10); n = NL_GET_INSTANCE_COUNTER(CFoo2); TEST_ASSERT(n == 0); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo2); TEST_ASSERT(n == -20); n = NL_GET_INSTANCE_COUNTER(CFoo3); TEST_ASSERT(n == 0); n = NL_GET_INSTANCE_COUNTER_DELTA(CFoo3); TEST_ASSERT(n == -10); } void testInstanceCounterOutput() { NLMISC::CInstanceCounterManager::getInstance().resetDeltaCounter(); CFoo1 *foo1s[10]; CFoo2 *foo2s[10]; CFoo3 *foo3s[10]; for (uint i=0; i<10; ++i) { foo1s[i] = new CFoo1; foo2s[i] = new CFoo2; foo3s[i] = new CFoo3; } string ref = "Listing 3 Instance counters :\n" " Class 'CFoo1 ', \t 10 instances, \t 10 delta\n" " Class 'CFoo2 ', \t 20 instances, \t 20 delta\n" " Class 'CFoo3 ', \t 10 instances, \t 10 delta\n"; string ret = NLMISC::CInstanceCounterManager::getInstance().displayCounters(); nlinfo("%s", ref.c_str()); nlinfo("%s", ret.c_str()); TEST_ASSERT(ref == ret); } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_dynlibload.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_DYNLIBLOAD #define UT_MISC_DYNLIBLOAD #include class CUTMiscDynLibLoad : public Test::Suite { public: CUTMiscDynLibLoad () { TEST_ADD(CUTMiscDynLibLoad ::libraryNameDecoration) } void libraryNameDecoration() { string libName = "libmylib_with_dll_so_some_very_bad_rd_df_tag_inside_df"; string fileName = "some/path/to/add/difficulties/"+NLMISC::CLibrary::makeLibName(libName); string cleanedName = NLMISC::CLibrary::cleanLibName(fileName); TEST_ASSERT(cleanedName == libName); } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_file.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_FILE #define UT_MISC_FILE #include #include // Test suite for NLMISC::CFile behavior struct CUTMiscFile : public Test::Suite { CUTMiscFile() { TEST_ADD(CUTMiscFile::copyOneBigFile); TEST_ADD(CUTMiscFile::copyDifferentFileSize); TEST_ADD(CUTMiscFile::moveOneBigFile); TEST_ADD(CUTMiscFile::moveDifferentFileSize); // Add a line here when adding a new test METHOD } private: string _SrcFile; string _DstFile; void setup() { _SrcFile = "__copy_file_src.foo"; _DstFile = "__copy_file_dst.foo"; } void tear_down() { } void copyFileSize(uint fileSize) { // create a source file (using standard c code) FILE *fp = fopen(_SrcFile.c_str(), "wb"); nlverify(fp != NULL); for (uint i=0; i The content of the first file Another content but for the second file The content of the first fileAnother content but for the second file ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_1/samename/.xml_pack_index ================================================ file1_in_sub_1.xml file2_in_sub_1.xml ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_1/samename/file1_in_sub_1.xml ================================================ ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_1/samename/file2_in_sub_1.xml ================================================ ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_1/samename/samename.xml_pack ================================================ ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_2/samename/.xml_pack_index ================================================ file1_in_sub_2.xml file2_in_sub_2.xml ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_2/samename/file1_in_sub_2.xml ================================================ ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_2/samename/file2_in_sub_2.xml ================================================ ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_2/samename/samename.xml_pack ================================================ ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/included_cfg.cfg ================================================ IncludedCfg = "ok"; ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/xml_files/file1_in_xml_pack.xml ================================================ ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/xml_files/file2_in_xml_pack.xml ================================================ ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/xml_files/same_subfolder_1/samename/samename.xml_pack ================================================ ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/xml_files/same_subfolder_2/samename/samename.xml_pack ================================================ ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_files/xml_files/xml_files.xml_pack ================================================ ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_pack_file.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_PACK_FILE #define UT_MISC_PACK_FILE // Commenting out the ifdef since the files are authored on Windows // and therefore always have a Windows-style newline. //#ifdef NL_OS_WINDOWS const string NewLine("\r\n"); //#elif defined(NL_OS_UNIX) //const string NewLine("\n"); //#else //#error "Specify the new line format for text file"; //#endif #ifndef NEL_UNIT_BASE #define NEL_UNIT_BASE "" #endif // NEL_UNIT_BASE // Test suite for bnp and xml pack files class CUTMiscPackFile : public Test::Suite { string _WorkingPath; string _OldPath; public: CUTMiscPackFile () { TEST_ADD(CUTMiscPackFile::addBnp); TEST_ADD(CUTMiscPackFile::loadFromBnp); TEST_ADD(CUTMiscPackFile::addXmlpack); TEST_ADD(CUTMiscPackFile::loadFromXmlpack); TEST_ADD(CUTMiscPackFile::compressMemory); TEST_ADD(CUTMiscPackFile::loadFromBnpCompressed); TEST_ADD(CUTMiscPackFile::loadFromXmlpackCompressed); TEST_ADD(CUTMiscPackFile::decompressMemory); TEST_ADD(CUTMiscPackFile::loadFromBnpUncompressed); TEST_ADD(CUTMiscPackFile::loadFromXmlpackUncompressed); TEST_ADD(CUTMiscPackFile::loadXmlpackWithSameName); } void setup() { _OldPath = NLMISC::CPath::getCurrentPath(); NLMISC::CPath::setCurrentPath(_WorkingPath.c_str()); string pathAfter = NLMISC::CPath::getCurrentPath(); } void tear_down() { NLMISC::CPath::setCurrentPath(_OldPath.c_str()); } void addBnp() { // add bnp file in the path and access to file inside NLMISC::CPath::addSearchBigFile(NEL_UNIT_BASE "ut_misc_files/files.bnp", false, false); } void loadFromBnp() { // lookup for the file string filename = NLMISC::CPath::lookup("file1_in_bnp.txt", true, true, false); TEST_ASSERT(filename == "files.bnp@file1_in_bnp.txt"); // read the first file content { NLMISC::CIFile file1(filename); string content1; content1.resize(file1.getFileSize()); file1.serialBuffer((uint8*)content1.data(), file1.getFileSize()); // check the file content TEST_ASSERT(content1 == "The content of the first file"); } // lookup for the 2nd file filename = NLMISC::CPath::lookup("file2_in_bnp.txt", true, true, false); TEST_ASSERT(filename == "files.bnp@file2_in_bnp.txt"); { // read the second file content NLMISC::CIFile file2(filename); string content2; content2.resize(file2.getFileSize()); file2.serialBuffer((uint8*)content2.data(), file2.getFileSize()); // check the file content TEST_ASSERT(content2 == "Another content but for the second file"); } } void addXmlpack() { // add xml_pack file in the path and access to file inside NLMISC::CPath::addSearchXmlpackFile(NEL_UNIT_BASE "ut_misc_files/xml_files/xml_files.xml_pack", false, false); } void loadFromXmlpack() { // lookup for the file string filename = NLMISC::CPath::lookup("file1_in_xml_pack.xml", true, true, false); TEST_ASSERT(filename == NEL_UNIT_BASE "ut_misc_files/xml_files/xml_files.xml_pack@@file1_in_xml_pack.xml"); // read the first file content { NLMISC::CIFile file1(filename); string content1; content1.resize(file1.getFileSize()); file1.serialBuffer((uint8*)content1.data(), file1.getFileSize()); // check the file content string refText = ""+NewLine; TEST_ASSERT(content1 == refText); } // lookup for the 2nd file filename = NLMISC::CPath::lookup("file2_in_xml_pack.xml", true, true, false); TEST_ASSERT(filename == NEL_UNIT_BASE "ut_misc_files/xml_files/xml_files.xml_pack@@file2_in_xml_pack.xml"); { // read the second file content NLMISC::CIFile file2(filename); string content2; content2.resize(file2.getFileSize()); file2.serialBuffer((uint8*)content2.data(), file2.getFileSize()); // check the file content string refText=""+NewLine; TEST_ASSERT(content2 == refText); } } void compressMemory() { //#ifdef WIN32 //_CrtCheckMemory(); //#endif NLMISC::CPath::memoryCompress(); //#ifdef WIN32 //_CrtCheckMemory(); //#endif } void loadFromBnpCompressed() { // simply recall loadFromBnp loadFromBnp(); } void loadFromXmlpackCompressed() { // simply recall loadFromXmlpack loadFromXmlpack(); } void decompressMemory() { NLMISC::CPath::memoryUncompress(); } void loadFromBnpUncompressed() { // simply recall loadFromBnp loadFromBnp(); } void loadFromXmlpackUncompressed() { // simply recall loadFromXmlpack loadFromXmlpack(); } void loadXmlpackWithSameName() { // we support xml_pack file in subfolder that have the same name // but the 'addSearchPath' or add xml pack must be done // at a higher discriminant directory // NLMISC::CPath::addSearchXmlpackFile(NEL_UNIT_BASE "ut_misc_files/xml_files/same_subfolder_1/samename/samename.xml_pack", true, false, NULL); // NLMISC::CPath::addSearchXmlpackFile(NEL_UNIT_BASE "ut_misc_files/xml_files/same_subfolder_2/samename/samename.xml_pack", true, false, NULL); NLMISC::CPath::addSearchPath(NEL_UNIT_BASE "ut_misc_files/xml_files", true, false); // lookup for the files in first subdirectory string filename = NLMISC::CPath::lookup("file1_in_sub_1.xml", true, true, false); TEST_ASSERT(filename == NEL_UNIT_BASE "ut_misc_files/xml_files/same_subfolder_1/samename/samename.xml_pack@@file1_in_sub_1.xml"); filename = NLMISC::CPath::lookup("file2_in_sub_1.xml", true, true, false); TEST_ASSERT(filename == NEL_UNIT_BASE "ut_misc_files/xml_files/same_subfolder_1/samename/samename.xml_pack@@file2_in_sub_1.xml"); // lookup for the files in the second subdirectory filename = NLMISC::CPath::lookup("file1_in_sub_2.xml", true, true, false); TEST_ASSERT(filename == NEL_UNIT_BASE "ut_misc_files/xml_files/same_subfolder_2/samename/samename.xml_pack@@file1_in_sub_2.xml"); filename = NLMISC::CPath::lookup("file2_in_sub_2.xml", true, true, false); TEST_ASSERT(filename == NEL_UNIT_BASE "ut_misc_files/xml_files/same_subfolder_2/samename/samename.xml_pack@@file2_in_sub_2.xml"); // read the file content of the first file in first pack filename = NLMISC::CPath::lookup("file1_in_sub_1.xml", true, true, false); // check that we can read the file modif date uint32 d = NLMISC::CFile::getFileModificationDate(filename); TEST_ASSERT(d != 0); { NLMISC::CIFile file1(filename); string content1; content1.resize(file1.getFileSize()); file1.serialBuffer((uint8*)content1.data(), file1.getFileSize()); // check the file content string refText = ""+NewLine; TEST_ASSERT(content1 == refText); } // read the file content of the second file in the second pack filename = NLMISC::CPath::lookup("file2_in_sub_2.xml", true, true, false); { // read the second file content NLMISC::CIFile file2(filename); string content2; content2.resize(file2.getFileSize()); file2.serialBuffer((uint8*)content2.data(), file2.getFileSize()); // check the file content string refText=""+NewLine; TEST_ASSERT(content2 == refText); } } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_singleton.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_SINGLETON #define UT_MISC_SINGLETON #include class CSafeSingleton { NL_INSTANCE_COUNTER_DECL(CSafeSingleton); NLMISC_SAFE_SINGLETON_DECL(CSafeSingleton); CSafeSingleton() {} }; NL_INSTANCE_COUNTER_IMPL(CSafeSingleton); NLMISC_SAFE_SINGLETON_IMPL(CSafeSingleton); class CUnsafeSingleton { NL_INSTANCE_COUNTER_DECL(CUnsafeSingleton); static CUnsafeSingleton *_Instance; CUnsafeSingleton() {} CUnsafeSingleton(const CUnsafeSingleton &other) {} public: static CUnsafeSingleton &getInstance() { if (_Instance == NULL) _Instance = new CUnsafeSingleton; return *_Instance; } }; NL_INSTANCE_COUNTER_IMPL(CUnsafeSingleton); CUnsafeSingleton *CUnsafeSingleton::_Instance = NULL; // Test suite for Singleton behavior class CUTMiscSingleton : public Test::Suite { std::string WorkingPath; std::string OldPath; public: CUTMiscSingleton() { TEST_ADD(CUTMiscSingleton::createSingleton); TEST_ADD(CUTMiscSingleton::accessSingleton); //TEST_ADD(CUTMiscSingleton::multiDllSingleton); } void setup() { OldPath = NLMISC::CPath::getCurrentPath(); NLMISC::CPath::setCurrentPath(WorkingPath.c_str()); } void tear_down() { NLMISC::CPath::setCurrentPath(OldPath.c_str()); } void createSingleton() { TEST_ASSERT(NLMISC::CInstanceCounterManager::getInstance().getInstanceCounter("CSafeSingleton") == 0); CSafeSingleton &ss = CSafeSingleton::getInstance(); TEST_ASSERT(NL_GET_INSTANCE_COUNTER(CSafeSingleton) == 1); TEST_ASSERT(NL_GET_INSTANCE_COUNTER(CUnsafeSingleton) == 0); CUnsafeSingleton &us = CUnsafeSingleton::getInstance(); TEST_ASSERT(NL_GET_INSTANCE_COUNTER(CUnsafeSingleton) == 1); } void accessSingleton() { TEST_ASSERT(NL_GET_INSTANCE_COUNTER(CSafeSingleton) == 1); CSafeSingleton &ss = CSafeSingleton::getInstance(); TEST_ASSERT(NL_GET_INSTANCE_COUNTER(CSafeSingleton) == 1); TEST_ASSERT(NL_GET_INSTANCE_COUNTER(CUnsafeSingleton) == 1); CUnsafeSingleton &us = CUnsafeSingleton::getInstance(); TEST_ASSERT(NL_GET_INSTANCE_COUNTER(CUnsafeSingleton) == 1); } /*void multiDllSingleton() { TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().exists("aDynLibCommand") == false); CLibrary lib; if (lib.loadLibrary("dyn_lib_test", true, true, true) != true) { TEST_ASSERT_MSG(false, "failed to reload the dll for testing singletons across dlls"); return; } TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().isCommand("aDynLibCommand") == true); IDynLibTest *libTest = dynamic_cast(lib.getNelLibraryInterface()); TEST_ASSERT(libTest != NULL); libTest->testSingleton(this); }*/ void assertmentWrapper(Test::Source src) { assertment(src); } bool continue_after_failureWrapper() { return continue_after_failure(); } friend class CDynLibTest; }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_sstring.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_SSTRING #define UT_MISC_SSTRING #include struct CUTMiscSString : public Test::Suite { CUTMiscSString() { TEST_ADD(CUTMiscSString::testStrtok); // Add a line here when adding a new test METHOD } void testStrtok() { NLMISC::CSString testLine(" a=b c (a=e b=c) \t\t c(a=e b=c) toto(bimbo(foo(bar(a=b))))"); NLMISC::CSString part; part = testLine.strtok(" \t", true, false); TEST_ASSERT(part == "a=b"); part = testLine.strtok(" \t", true, false); TEST_ASSERT(part == "c"); part = testLine.strtok(" \t", true, false); TEST_ASSERT(part == "(a=e b=c)"); part = testLine.strtok(" \t", true, false); TEST_ASSERT(part == "c"); part = testLine.strtok(" \t=", true, false); TEST_ASSERT(part == "(a=e b=c)"); part = testLine.strtok(" \t=", true, false); TEST_ASSERT(part == "toto"); part = testLine.strtok(" \t=", true, false); TEST_ASSERT(part == "(bimbo(foo(bar(a=b))))"); part = part.stripBlockDelimiters(); NLMISC::CSString part2 = part.strtok(" \t=", true, false); TEST_ASSERT(part2 == "bimbo"); part2 = part.strtok(" \t=", true, false); TEST_ASSERT(part2 == "(foo(bar(a=b)))"); } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_stream.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_STREAM #define UT_MISC_STREAM #include #include // The following line is known to crash in a Ryzom service NLMISC::CBitMemStream globalBms( false, 2048 ); // global to avoid reallocation // Test suite for stream based classes // ! not complete at all at time of writing ! class CUTMiscStream: public Test::Suite { public: CUTMiscStream () { TEST_ADD(CUTMiscStream::constAndStream); TEST_ADD(CUTMiscStream::memStreamSwap); TEST_ADD(CUTMiscStream::copyOnWrite); TEST_ADD(CUTMiscStream::preallocatedBitStream); } void preallocatedBitStream() { NLMISC::CBitMemStream localBms( false, 2048 ); // global to avoid reallocation } void copyOnWrite() { // test the copy on write strategy in the mem stream (and derived) class. // The point is to be able to copy a mem stream (e.g a NLNET::CMessage) // but to do not copy the stream buffer. // If more than one stream use the same buffer, any attempt to // modifye the buffer content while lead to a buffer duplication NLMISC::CMemStream s1; NLMISC::CMemStream s2; NLMISC::CMemStream s3; uint32 i = 1; s1.serial(i); s2 = s1; s3 = s2; TEST_ASSERT(s1.buffer() == s2.buffer()); TEST_ASSERT(s1.buffer() == s3.buffer()); // change s1 s1.serial(i); TEST_ASSERT(s1.buffer() != s2.buffer()); TEST_ASSERT(s2.buffer() == s3.buffer()); s2.invert(); s3 = s2; TEST_ASSERT(s2.buffer() == s3.buffer()); s2.serial(i); TEST_ASSERT(s2.buffer() == s3.buffer()); } enum TEnum { e_a, e_b, e_c, e_d }; void constAndStream() { // check that we can serialize with const stream or const object NLMISC::CMemStream s1; NLMISC::IStream &is1 = s1; const string str("toto"); const uint32 i(1234546); const TEnum e(e_a); string str2("titi"); uint32 i2(123456); TEnum e2(e_b); // no need for const cast any more nlWriteSerial(s1, str); nlWriteSerial(s1, i); nlWrite(s1, serialEnum, e); nlWriteSerial(is1, str); nlWriteSerial(is1, i); nlWrite(is1, serialEnum, i); // this work as well s1.serial(str2); s1.serial(i2); s1.serialEnum(e2); is1.serial(str2); is1.serial(i2); is1.serialEnum(e2); const NLMISC::CMemStream &s2 = s1; const NLMISC::IStream &is2 = s2; string str3; uint32 i3; TEnum e3(e_c); // cant write in a const stream TEST_THROWS(nlReadSerial(s2, str3), NLMISC::ENotInputStream); TEST_THROWS(nlReadSerial(s2, i3), NLMISC::ENotInputStream); TEST_THROWS(nlRead(s2, serialEnum, e3), NLMISC::ENotInputStream); TEST_THROWS(nlReadSerial(is2, str3), NLMISC::ENotInputStream); TEST_THROWS(nlReadSerial(is2, i3), NLMISC::ENotInputStream); TEST_THROWS(nlRead(is2, serialEnum, e3), NLMISC::ENotInputStream); s1.invert(); nlReadSerial(s2, str3); nlReadSerial(s2, i3); nlRead(s2, serialEnum, e3); nlReadSerial(is2, str3); nlReadSerial(is2, i3); nlRead(is2, serialEnum, e3); // cant read a const value TEST_THROWS(nlWriteSerial(s1, str), NLMISC::ENotOutputStream); TEST_THROWS(nlWriteSerial(s1, i), NLMISC::ENotOutputStream); TEST_THROWS(nlWrite(s1, serialEnum, e), NLMISC::ENotOutputStream); TEST_THROWS(nlWriteSerial(is1, str), NLMISC::ENotOutputStream); TEST_THROWS(nlWriteSerial(is1, i), NLMISC::ENotOutputStream); TEST_THROWS(nlWrite(is1, serialEnum, e), NLMISC::ENotOutputStream); } void memStreamSwap() { NLMISC::CMemStream ms2; string s; { NLMISC::CMemStream ms1; s = "foo1"; ms1.serial(s); s = "foo2"; ms1.serial(s); s = ""; ms2.swap(ms1); // check that ms1 is empty now TEST_ASSERT(ms1.length() == 0); } TEST_ASSERT(!ms2.isReading()); ms2.invert(); ms2.serial(s); TEST_ASSERT(s == "foo1"); ms2.serial(s); TEST_ASSERT(s == "foo2"); } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_string_common.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_STRING_COMMON #define UT_MISC_STRING_COMMON #include struct CUTMiscStringCommon : public Test::Suite { CUTMiscStringCommon() { TEST_ADD(CUTMiscStringCommon::fromStringSint8); TEST_ADD(CUTMiscStringCommon::fromStringUint8); TEST_ADD(CUTMiscStringCommon::fromStringSint16); TEST_ADD(CUTMiscStringCommon::fromStringUint16); TEST_ADD(CUTMiscStringCommon::fromStringSint32); TEST_ADD(CUTMiscStringCommon::fromStringUint32); // Add a line here when adding a new test METHOD } void fromStringSint8() { bool ret; // tests for sint8 sint8 val; // positive value ret = NLMISC::fromString("1", val); TEST_ASSERT(ret && val == 1); // negative value ret = NLMISC::fromString("-1", val); TEST_ASSERT(ret && val == -1); // bad character ret = NLMISC::fromString("a", val); TEST_ASSERT(!ret && val == 0); // right character and bad character ret = NLMISC::fromString("1a", val); TEST_ASSERT(ret && val == 1); // min limit ret = NLMISC::fromString("-128", val); TEST_ASSERT(ret && val == -128); // max limit ret = NLMISC::fromString("127", val); TEST_ASSERT(ret && val == 127); // min limit -1 ret = NLMISC::fromString("-129", val); TEST_ASSERT(!ret && val == 0); // max limit +1 ret = NLMISC::fromString("128", val); TEST_ASSERT(!ret && val == 0); // with period ret = NLMISC::fromString("1.2", val); TEST_ASSERT(ret && val == 1); // with coma ret = NLMISC::fromString("1,2", val); TEST_ASSERT(ret && val == 1); // with spaces before ret = NLMISC::fromString(" 10", val); TEST_ASSERT(ret && val == 10); // with spaces after ret = NLMISC::fromString("10 ", val); TEST_ASSERT(ret && val == 10); // with 0s before ret = NLMISC::fromString("001", val); TEST_ASSERT(ret && val == 1); // with + before ret = NLMISC::fromString("+1", val); TEST_ASSERT(ret && val == 1); } void fromStringUint8() { bool ret; // tests for uint8 uint8 val; // positive value ret = NLMISC::fromString("1", val); TEST_ASSERT(ret && val == 1); // bad character ret = NLMISC::fromString("a", val); TEST_ASSERT(!ret && val == 0); // right character and bad character ret = NLMISC::fromString("1a", val); TEST_ASSERT(ret && val == 1); // min limit ret = NLMISC::fromString("0", val); TEST_ASSERT(ret && val == 0); // max limit ret = NLMISC::fromString("255", val); TEST_ASSERT(ret && val == 255); // min limit -1 ret = NLMISC::fromString("-1", val); TEST_ASSERT(!ret && val == 0); // max limit +1 ret = NLMISC::fromString("256", val); TEST_ASSERT(!ret && val == 0); // with period ret = NLMISC::fromString("1.2", val); TEST_ASSERT(ret && val == 1); // with coma ret = NLMISC::fromString("1,2", val); TEST_ASSERT(ret && val == 1); // with spaces before ret = NLMISC::fromString(" 10", val); TEST_ASSERT(ret && val == 10); // with spaces after ret = NLMISC::fromString("10 ", val); TEST_ASSERT(ret && val == 10); // with 0s before ret = NLMISC::fromString("001", val); TEST_ASSERT(ret && val == 1); // with + before ret = NLMISC::fromString("+1", val); TEST_ASSERT(ret && val == 1); } void fromStringSint16() { bool ret; // tests for sint16 sint16 val; // positive value ret = NLMISC::fromString("1", val); TEST_ASSERT(ret && val == 1); // negative value ret = NLMISC::fromString("-1", val); TEST_ASSERT(ret && val == -1); // bad character ret = NLMISC::fromString("a", val); TEST_ASSERT(!ret && val == 0); // right character and bad character ret = NLMISC::fromString("1a", val); TEST_ASSERT(ret && val == 1); // min limit ret = NLMISC::fromString("-32768", val); TEST_ASSERT(ret && val == -32768); // max limit ret = NLMISC::fromString("32767", val); TEST_ASSERT(ret && val == 32767); // min limit -1 ret = NLMISC::fromString("-32769", val); TEST_ASSERT(!ret && val == 0); // max limit +1 ret = NLMISC::fromString("32768", val); TEST_ASSERT(!ret && val == 0); // with period ret = NLMISC::fromString("1.2", val); TEST_ASSERT(ret && val == 1); // with coma ret = NLMISC::fromString("1,2", val); TEST_ASSERT(ret && val == 1); // with spaces before ret = NLMISC::fromString(" 10", val); TEST_ASSERT(ret && val == 10); // with spaces after ret = NLMISC::fromString("10 ", val); TEST_ASSERT(ret && val == 10); // with 0s before ret = NLMISC::fromString("001", val); TEST_ASSERT(ret && val == 1); // with + before ret = NLMISC::fromString("+1", val); TEST_ASSERT(ret && val == 1); } void fromStringUint16() { bool ret; // tests for uint16 uint16 val; // positive value ret = NLMISC::fromString("1", val); TEST_ASSERT(ret && val == 1); // bad character ret = NLMISC::fromString("a", val); TEST_ASSERT(!ret && val == 0); // right character and bad character ret = NLMISC::fromString("1a", val); TEST_ASSERT(ret && val == 1); // min limit ret = NLMISC::fromString("0", val); TEST_ASSERT(ret && val == 0); // max limit ret = NLMISC::fromString("65535", val); TEST_ASSERT(ret && val == 65535); // min limit -1 ret = NLMISC::fromString("-1", val); TEST_ASSERT(!ret && val == 0); // max limit +1 ret = NLMISC::fromString("65536", val); TEST_ASSERT(!ret && val == 0); // with period ret = NLMISC::fromString("1.2", val); TEST_ASSERT(ret && val == 1); // with coma ret = NLMISC::fromString("1,2", val); TEST_ASSERT(ret && val == 1); // with spaces before ret = NLMISC::fromString(" 10", val); TEST_ASSERT(ret && val == 10); // with spaces after ret = NLMISC::fromString("10 ", val); TEST_ASSERT(ret && val == 10); // with 0s before ret = NLMISC::fromString("001", val); TEST_ASSERT(ret && val == 1); // with + before ret = NLMISC::fromString("+1", val); TEST_ASSERT(ret && val == 1); } void fromStringSint32() { bool ret; // tests for sint32 sint32 val; // positive value ret = NLMISC::fromString("1", val); TEST_ASSERT(ret && val == 1); // negative value ret = NLMISC::fromString("-1", val); TEST_ASSERT(ret && val == -1); // bad character ret = NLMISC::fromString("a", val); TEST_ASSERT(!ret && val == 0); // right character and bad character ret = NLMISC::fromString("1a", val); TEST_ASSERT(ret && val == 1); // min limit ret = NLMISC::fromString("-2147483648", val); TEST_ASSERT(ret && val == INT_MIN); // max limit ret = NLMISC::fromString("2147483647", val); TEST_ASSERT(ret && val == INT_MAX); // min limit -1 ret = NLMISC::fromString("-2147483649", val); TEST_ASSERT(!ret && val == 0); // max limit +1 ret = NLMISC::fromString("2147483648", val); TEST_ASSERT(!ret && val == 0); // with period ret = NLMISC::fromString("1.2", val); TEST_ASSERT(ret && val == 1); // with coma ret = NLMISC::fromString("1,2", val); TEST_ASSERT(ret && val == 1); // with spaces before ret = NLMISC::fromString(" 10", val); TEST_ASSERT(ret && val == 10); // with spaces after ret = NLMISC::fromString("10 ", val); TEST_ASSERT(ret && val == 10); // with 0s before ret = NLMISC::fromString("001", val); TEST_ASSERT(ret && val == 1); // with + before ret = NLMISC::fromString("+1", val); TEST_ASSERT(ret && val == 1); } void fromStringUint32() { bool ret; // tests for uint32 uint32 val; // positive value ret = NLMISC::fromString("1", val); TEST_ASSERT(ret && val == 1); // bad character ret = NLMISC::fromString("a", val); TEST_ASSERT(!ret && val == 0); // right character and bad character ret = NLMISC::fromString("1a", val); TEST_ASSERT(ret && val == 1); // min limit ret = NLMISC::fromString("0", val); TEST_ASSERT(ret && val == 0); // max limit ret = NLMISC::fromString("4294967295", val); TEST_ASSERT(ret && val == 4294967295); // min limit -1 ret = NLMISC::fromString("-1", val); TEST_ASSERT(!ret && val == 0); // max limit +1 ret = NLMISC::fromString("4294967296", val); TEST_ASSERT(!ret && val == 0); // with period ret = NLMISC::fromString("1.2", val); TEST_ASSERT(ret && val == 1); // with coma ret = NLMISC::fromString("1,2", val); TEST_ASSERT(ret && val == 1); // with spaces before ret = NLMISC::fromString(" 10", val); TEST_ASSERT(ret && val == 10); // with spaces after ret = NLMISC::fromString("10 ", val); TEST_ASSERT(ret && val == 10); // with 0s before ret = NLMISC::fromString("001", val); TEST_ASSERT(ret && val == 1); // with + before ret = NLMISC::fromString("+1", val); TEST_ASSERT(ret && val == 1); } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_types.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_TYPES #define UT_MISC_TYPES #include class CUTMiscTypes: public Test::Suite { public: CUTMiscTypes () { TEST_ADD(CUTMiscTypes::basicTypes) } void basicTypes() { // this doesn't work on 64bit architectures //Test_ASSERT(sizeof(uint) == sizeof(void*)); TEST_ASSERT(sizeof(sint8) == 1); TEST_ASSERT(sizeof(uint8) == 1); TEST_ASSERT(sizeof(sint16) == 2); TEST_ASSERT(sizeof(uint16) == 2); TEST_ASSERT(sizeof(sint32) == 4); TEST_ASSERT(sizeof(uint32) == 4); TEST_ASSERT(sizeof(sint64) == 8); TEST_ASSERT(sizeof(uint64) == 8); TEST_ASSERT(sizeof(sint) >= 4); TEST_ASSERT(sizeof(uint) >= 4); } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_misc_variable.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_MISC_VARIABLE #define UT_MISC_VARIABLE #include class CUTMiscVariable : public Test::Suite { public: CUTMiscVariable () { TEST_ADD(CUTMiscVariable ::declareVar) } void declareVar() { { NLMISC::CVariable myLocalVar("test", "myLocalVar", "no help", ""); TEST_ASSERT(myLocalVar.get() == string("")); TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute("myLocalVar foo", (*NLMISC::InfoLog))); TEST_ASSERT(myLocalVar.get() == string("foo")); } TEST_ASSERT(!NLMISC::CCommandRegistry::getInstance().execute("myLocalVar foo", (*NLMISC::InfoLog))); } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_net.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_NET #define UT_NET #include #include "ut_net_layer3.h" #include "ut_net_message.h" #include "ut_net_module.h" // Add a line here when adding a new test CLASS struct CUTNet : public Test::Suite { CUTNet() { add(auto_ptr(new CUTNetLayer3)); add(auto_ptr(new CUTNetMessage)); add(auto_ptr(new CUTNetModule)); // Add a line here when adding a new test CLASS } }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_net_layer3.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_NET_LAYER3 #define UT_NET_LAYER3 #include #include uint16 TestPort1 = 56000; uint NbTestReceived = 0; NLNET::CMessage msgoutExpectingAnswer0, msgoutSimple0, msgoutSimple50; // Data structure for messages struct TData { string PayloadString; bool ExpectingAnswer; // Constructor TData() : ExpectingAnswer(false) {} // Serial void serial( NLMISC::IStream& s ) { s.serial( PayloadString ); s.serial( ExpectingAnswer ); } }; // This callback must not take more than 10 ms void cbTest( NLNET::CMessage &msgin, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase ) { NLMISC::TTime before = NLMISC::CTime::getLocalTime(); // Read data from the message TData data; msgin.serial( data ); if ( data.PayloadString == "Payload" ) ++NbTestReceived; // Send the answer if required if ( data.ExpectingAnswer ) netbase.send( msgoutSimple0, from ); // Check that the duration is compatible with our timeout tests NLMISC::TTime maxDuration; if ( msgin.getName() == "TEST_50" ) { while ( NLMISC::CTime::getLocalTime() - before < 49 ); // wait maxDuration = 70; } else maxDuration = 10; NLMISC::TTime actualDuration = NLMISC::CTime::getLocalTime() - before; if ( actualDuration > maxDuration ) nlerror( "The callback cbTest takes too long (%u) for %s, please fix the test", (uint)actualDuration, msgin.getName().c_str() ); } static NLNET::TCallbackItem CallbackArray[] = { { "TEST_0", cbTest }, { "TEST_50", cbTest } }; // Test suite for layer 3 class CUTNetLayer3: public Test::Suite { public: // CUTNetLayer3 () { _Server = NULL; _Client = NULL; TEST_ADD(CUTNetLayer3::sendReceiveUpdate); } // ~CUTNetLayer3 () { if ( _Server ) delete _Server; _Server = NULL; if ( _Client ) delete _Client; _Client = NULL; } // void sendReceiveUpdate() { // Prepare messages for tests TData data; data.PayloadString = "Payload"; data.ExpectingAnswer = true; msgoutExpectingAnswer0.clear(); // optional msgoutExpectingAnswer0.setType( "TEST_0" ); // could be passed to the constructor msgoutExpectingAnswer0.serial( data ); data.ExpectingAnswer = false; msgoutSimple0.clear(); // optional msgoutSimple0.setType( "TEST_0" ); // could be passed to the constructor msgoutSimple0.serial( data ); msgoutSimple50.clear(); // optional msgoutSimple50.setType( "TEST_50" ); // could be passed to the constructor msgoutSimple50.serial( data ); // Init connections _Server = new NLNET::CCallbackServer(); _Server->init( TestPort1 ); _Server->addCallbackArray( CallbackArray, sizeof(CallbackArray)/sizeof(NLNET::TCallbackItem) ); _Client = new NLNET::CCallbackClient(); _Client->connect( NLNET::CInetAddress( "localhost", TestPort1 ) ); _Client->addCallbackArray( CallbackArray, sizeof(CallbackArray)/sizeof(NLNET::TCallbackItem) ); // TEST: Simple message transmission NbTestReceived = 0; _Client->send( msgoutExpectingAnswer0 ); for ( uint i=0; i!=10; ++i ) // give some time to receive { _Client->update(); _Server->update(); // legacy version NLMISC::nlSleep( 50 ); } TEST_ASSERT( NbTestReceived == 2 ); // answer and reply // TEST: ONE-SHOT update mode on the receiver NbTestReceived = 0; for ( uint i=0; i!=20; ++i ) // send 20 messages _Client->send( msgoutSimple0 ); while ( NbTestReceived < 20 ) { _Client->update2(); uint prevNbTestReceived = NbTestReceived; _Server->update2( 0 ); // shortest time-out = ONE-SHOT mode TEST_ASSERT( (NbTestReceived == prevNbTestReceived) || (NbTestReceived == prevNbTestReceived + 1) ); NLMISC::nlSleep( 10 ); } // TEST: GREEDY update mode on the receiver NbTestReceived = 0; for ( uint i=0; i!=20; ++i ) // send 20 messages _Client->send( msgoutSimple0 ); for ( uint i=0; i!=10; ++i ) // make sure all messages are flushed { _Client->update2(); NLMISC::nlSleep( 10 ); } _Server->update2( -1 ); // receive all TEST_ASSERT( NbTestReceived == 20 ); // TEST: CONSTRAINED update mode on the receiver NbTestReceived = 0; for ( uint i=0; i!=20; ++i ) // send 20 messages that will trigger a time-consuming callback _Client->send( msgoutSimple50 ); for ( uint i=0; i!=10; ++i ) // make sure all messages are flushed { _Client->update2(); NLMISC::nlSleep( 10 ); } while ( NbTestReceived < 20 ) { uint prevNbTestReceived = NbTestReceived; _Server->update2( 80 ); // no more time than two callback executions TEST_ASSERT( NbTestReceived <= prevNbTestReceived + 2 ); } // TEST: CONSTRAINED with minTime update mode on the receiver NbTestReceived = 0; while ( NbTestReceived < 20 ) { _Client->send( msgoutSimple0 ); _Client->send( msgoutSimple0 ); // send 2 messages at a time _Client->update2(); NLMISC::TTime before = NLMISC::CTime::getLocalTime(); _Server->update2( -1, 30 ); NLMISC::TTime duration = NLMISC::CTime::getLocalTime() - before; TEST_ASSERT( duration >= 30 ); } } private: NLNET::CCallbackServer *_Server; NLNET::CCallbackClient *_Client; }; #endif ================================================ FILE: code/nel/tools/nel_unit_test/ut_net_message.h ================================================ // NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_NET_MESSAGE #define UT_NET_MESSAGE class CUTNetMessage: public Test::Suite { public: CUTNetMessage () { TEST_ADD(CUTNetMessage::messageSwap); TEST_ADD(CUTNetMessage::lockSubMEssage); TEST_ADD(CUTNetMessage::lockSubMEssageWithLongName); } void lockSubMEssageWithLongName() { NLNET::CMessage master("BIG"); // serial some stuff for (uint8 i=0; i<10; ++i) { master.serial(i); } uint32 sizes[4]; // serial 4 sub messages for (uint i=0; i<4; ++i) { NLNET::CMessage sub(NLMISC::toString("A_VERY_LONG_SUB_MESSAGE_NAME_%u", i)); for (uint8 j=0; j // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef UT_NET_MODULE #define UT_NET_MODULE #include #include #include #include #include #include #include #include #include #include class CModuleType0 : public NLNET::CModuleBase { public: uint PingCount; uint ResponseReceived; set ModuleType0; uint32 ModuleUpCalled; uint32 ModuleDownCalled; uint32 ProcessMessageCalled; uint32 SecurityUpdateCalled; CModuleType0() : PingCount(0), ResponseReceived(0) { ModuleUpCalled = 0; ModuleDownCalled = 0; ProcessMessageCalled = 0; SecurityUpdateCalled = 0; } std::string buildModuleManifest() const { return "CModuleType0"; } bool initModule(const NLNET::TParsedCommandLine ¶m) { bool ret = CModuleBase::initModule(param); if (param.getParam("FAIL") != NULL) return false; return ret; } void onServiceUp(const std::string &serviceName, NLNET::TServiceId serviceId) { } /// A nel layer 5 service has stopped. void onServiceDown(const std::string &serviceName, NLNET::TServiceId serviceId) { } void onModuleUpdate() { } /** The service main loop is terminating it job', all module will be * disconnected and removed after this callback. */ void onApplicationExit() { } void onModuleUp(NLNET::IModuleProxy *moduleProxy) { ModuleUpCalled++; if (moduleProxy->getModuleClassName() == getModuleClassName()) ModuleType0.insert(moduleProxy); } /** Called by a socket to inform this module that another * module has been deleted OR has been no more accessible (due to * some gateway disconnection). */ void onModuleDown(NLNET::IModuleProxy *moduleProxy) { ModuleDownCalled++; if (moduleProxy->getModuleClassName() == getModuleClassName()) ModuleType0.erase(moduleProxy); } bool onProcessModuleMessage(NLNET::IModuleProxy *senderModuleProxy, const NLNET::CMessage &message) { ProcessMessageCalled++; if (message.getName() == "DEBUG_MOD_PING") { PingCount++; return true; } else if (message.getName() == "HELLO") { NLNET::CMessage ping("DEBUG_MOD_PING"); senderModuleProxy->sendModuleMessage(this, NLNET::CMessage(ping)); senderModuleProxy->sendModuleMessage(this, NLNET::CMessage(ping)); { NLNET::CMessage resp; resp.setType("HELLO_RESP", NLNET::CMessage::Response); senderModuleProxy->sendModuleMessage(this, resp); } senderModuleProxy->sendModuleMessage(this, NLNET::CMessage(ping)); senderModuleProxy->sendModuleMessage(this, NLNET::CMessage(ping)); return true; } else if (message.getName() == "HELLO2") { // the response for the life, the universe and all other things... throw 42; return true; } return false; } void onModuleSecurityChange(NLNET::IModuleProxy *moduleProxy) { SecurityUpdateCalled++; } void onModuleSocketEvent(NLNET::IModuleSocket *moduleSocket, IModule::TModuleSocketEvent eventType) { } void startTaskA() { // start a task on module NLNET_START_MODULE_TASK(CModuleType0, taskA); } // test task A void taskA() { // use the first like me in the list nlassert(!ModuleType0.empty()); NLNET::TModuleProxyPtr proxy = *ModuleType0.begin(); NLNET::CMessage msg; msg.setType("HELLO", NLNET::CMessage::Request); NLNET::CMessage resp; invokeModuleOperation(proxy, msg, resp); nlassert(resp.getName() == "HELLO_RESP"); ResponseReceived++; } void startTaskB() { // start a task on module NLNET_START_MODULE_TASK(CModuleType0, taskB); } // test task B void taskB() { // use the first like me in the list nlassert(!ModuleType0.empty()); NLNET::TModuleProxyPtr proxy = *ModuleType0.begin(); NLNET::CMessage msg; msg.setType("HELLO2", NLNET::CMessage::Request); NLNET::CMessage resp; try { invokeModuleOperation(proxy, msg, resp); } catch(const IModule::EInvokeFailed &) { ResponseReceived++; } } }; NLNET_REGISTER_MODULE_FACTORY(CModuleType0, "ModuleType0"); // A module that doesn't support immediate dispatching class CModuleAsync : public CModuleType0 { public: bool isImmediateDispatchingSupported() const { return false; } }; NLNET_REGISTER_MODULE_FACTORY(CModuleAsync, "ModuleAsync"); enum TTestSecurityTypes { tst_type1, tst_type2, tst_type3, tst_type4, }; // security type 1 data : contains host gateway name struct TSecurityType1 : public NLNET::TSecurityData { string SecurityGatewayName; TSecurityType1(const TCtorParam ¶m) : NLNET::TSecurityData(param) { } void serial(NLMISC::CMemStream &s) { s.serial(SecurityGatewayName); } }; NLMISC_REGISTER_OBJECT(NLNET::TSecurityData, TSecurityType1, uint8, tst_type1); // security type 2 data : contains host gateway name and a predefined integer value struct TSecurityType2 : public NLNET::TSecurityData { string SecurityGatewayName; uint32 IntegerValue; TSecurityType2(const TCtorParam ¶m) : NLNET::TSecurityData(param) { IntegerValue = 0x12345678; } void serial(NLMISC::CMemStream &s) { s.serial(SecurityGatewayName); s.serial(IntegerValue); } }; NLMISC_REGISTER_OBJECT(NLNET::TSecurityData, TSecurityType2, uint8, tst_type2); // security type 3 data, same as type 1 struct TSecurityType3 : public NLNET::TSecurityData { string SecurityGatewayName; TSecurityType3(const TCtorParam ¶m) : NLNET::TSecurityData(param) { } void serial(NLMISC::CMemStream &s) { s.serial(SecurityGatewayName); } }; NLMISC_REGISTER_OBJECT(NLNET::TSecurityData, TSecurityType3, uint8, tst_type3); // security type 4 data, same as type 1 but not registered struct TSecurityType4 : public NLNET::TSecurityData { string SecurityGatewayName; TSecurityType4(const TCtorParam ¶m) : NLNET::TSecurityData(param) { } void serial(NLMISC::CMemStream &s) { s.serial(SecurityGatewayName); } }; /** a sample security plug-in that add type 1 security data to local modules, * type 2 security to foreign module, * and that remove received type 1 security from foreign module */ class CTestSecurity1 : public NLNET::CGatewaySecurity { public: CTestSecurity1(const TCtorParam ¶ms) : NLNET::CGatewaySecurity(params) {} virtual void onNewProxy(NLNET::IModuleProxy *proxy) { if (proxy->getGatewayRoute() == NULL) { // add a type 1 security TSecurityType1 *st1 = new TSecurityType1(NLNET::TSecurityData::TCtorParam(tst_type1)); st1->SecurityGatewayName = _Gateway->getFullyQualifiedGatewayName(); setSecurityData(proxy, st1); } else { // remove any type 1 data and set a type 2 data removeSecurityData(proxy, tst_type1); TSecurityType2 *st2 = new TSecurityType2(NLNET::TSecurityData::TCtorParam(tst_type2)); st2->SecurityGatewayName = _Gateway->getFullyQualifiedGatewayName(); setSecurityData(proxy, st2); } forceSecurityUpdate(proxy); } void onNewSecurityData(NLNET::CGatewayRoute *from, NLNET::IModuleProxy *proxy, NLNET::TSecurityData *firstSecurityData) { // replace the complete security set replaceAllSecurityDatas(proxy, firstSecurityData); // remove any type 1 data and set a type 2 data removeSecurityData(proxy, tst_type1); TSecurityType2 *st2 = new TSecurityType2(NLNET::TSecurityData::TCtorParam(tst_type2)); st2->SecurityGatewayName = _Gateway->getFullyQualifiedGatewayName(); setSecurityData(proxy, st2); // we don't need to update in this case (update is always done by gateway) } virtual void onDelete() { vector proxies; _Gateway->getModuleProxyList(proxies); // remove any security data managed by this plug-in for (uint i=0; igetFirstSecurityData() != NULL) { bool update = false; update |= removeSecurityData(proxy, tst_type1); update |= removeSecurityData(proxy, tst_type2); if (update) forceSecurityUpdate(proxy); } } } }; NLMISC_REGISTER_OBJECT(NLNET::CGatewaySecurity, CTestSecurity1, std::string, "TestSecurity1"); /** a sample security plug-in that add type 3 and type 4 security data to local modules, */ class CTestSecurity2 : public NLNET::CGatewaySecurity { public: CTestSecurity2(const TCtorParam ¶ms) : NLNET::CGatewaySecurity(params) {} virtual void onNewProxy(NLNET::IModuleProxy *proxy) { if (proxy->getGatewayRoute() == NULL) { // add a type 3 security TSecurityType3 *st3 = new TSecurityType3(NLNET::TSecurityData::TCtorParam(tst_type3)); st3->SecurityGatewayName = _Gateway->getFullyQualifiedGatewayName(); setSecurityData(proxy, st3); // add a type 4 security TSecurityType4 *st4 = new TSecurityType4(NLNET::TSecurityData::TCtorParam(tst_type4)); st4->SecurityGatewayName = _Gateway->getFullyQualifiedGatewayName(); setSecurityData(proxy, st4); forceSecurityUpdate(proxy); } } void onNewSecurityData(NLNET::CGatewayRoute *from, NLNET::IModuleProxy *proxy, NLNET::TSecurityData *firstSecurityData) { // replace the complete security set replaceAllSecurityDatas(proxy, firstSecurityData); } virtual void onDelete() { vector proxies; _Gateway->getModuleProxyList(proxies); // remove any security data managed by this plug-in for (uint i=0; igetGatewayRoute() == NULL) { removeSecurityData(proxy, tst_type3); removeSecurityData(proxy, tst_type4); forceSecurityUpdate(proxy); } } } }; NLMISC_REGISTER_OBJECT(NLNET::CGatewaySecurity, CTestSecurity2, std::string, "TestSecurity2"); // A module interceptor class CInterceptor : public NLNET::IModuleInterceptable { public: string Name; uint32 ModuleUpCalled; uint32 ModuleDownCalled; uint32 ProcessMessageCalled; uint32 SecurityUpdateCalled; CInterceptor(NLNET::IInterceptorRegistrar *registrar, const string &name) : Name(name) { NLNET::IModuleInterceptable::registerInterceptor(registrar), ModuleUpCalled = 0; ModuleDownCalled = 0; ProcessMessageCalled = 0; SecurityUpdateCalled = 0; } virtual std::string buildModuleManifest() const { return Name; } virtual void onModuleUp(NLNET::IModuleProxy *moduleProxy) { ModuleUpCalled++; } virtual void onModuleDown(NLNET::IModuleProxy *moduleProxy) { ModuleDownCalled++; } virtual bool onProcessModuleMessage(NLNET::IModuleProxy *senderModuleProxy, const NLNET::CMessage &message) { ProcessMessageCalled++; return false; } virtual void onModuleSecurityChange(NLNET::IModuleProxy *moduleProxy) { SecurityUpdateCalled++; } }; // Test suite for Modules class class CUTNetModule : public Test::Suite { string _WorkingPath; string _RestorePath; public: // utility to look for a specified proxy in a vector of proxy // return true if the proxy if found bool lookForModuleProxy(const vector proxList, const std::string &modName) { for (uint i=0; igetModuleName().find(modName) == (proxList[i]->getModuleName().size() - modName.size())) return true; } return false; } NLNET::IModuleProxy *retrieveModuleProxy(NLNET::IModuleGateway *gw, const std::string &modName) { vector proxList; gw->getModuleProxyList(proxList); for (uint i=0; igetModuleName().find(modName) == (proxList[i]->getModuleName().size() - modName.size())) return proxList[i]; } return NULL; } void setup() { _RestorePath = NLMISC::CPath::getCurrentPath(); NLMISC::CPath::setCurrentPath(_WorkingPath.c_str()); } void tear_down() { NLMISC::CPath::setCurrentPath(_RestorePath.c_str()); } CUTNetModule () { TEST_ADD(CUTNetModule::testModuleInitInfoParsing); TEST_ADD(CUTNetModule::testModuleInitInfoQuering); TEST_ADD(CUTNetModule::testModuleInitInfoBadParsing); TEST_ADD(CUTNetModule::localModuleFactory); //TEST_ADD(CUTNetModule::loadModuleLib); //TEST_ADD(CUTNetModule::createModule); //TEST_ADD(CUTNetModule::deleteModule); TEST_ADD(CUTNetModule::failedInit); //TEST_ADD(CUTNetModule::unloadModuleLib); TEST_ADD(CUTNetModule::createLocalGateway); TEST_ADD(CUTNetModule::plugLocalGateway); //TEST_ADD(CUTNetModule::moduleManagerCommands); TEST_ADD(CUTNetModule::gatewayTransportManagement); TEST_ADD(CUTNetModule::connectGateways); TEST_ADD(CUTNetModule::moduleDisclosure); TEST_ADD(CUTNetModule::moduleMessaging); TEST_ADD(CUTNetModule::localMessageQueing); TEST_ADD(CUTNetModule::uniqueNameGenerator); TEST_ADD(CUTNetModule::gwPlugUnplug); TEST_ADD(CUTNetModule::peerInvisible); TEST_ADD(CUTNetModule::firewalling); TEST_ADD(CUTNetModule::distanceAndConnectionLoop); TEST_ADD(CUTNetModule::securityPlugin); TEST_ADD(CUTNetModule::synchronousMessaging); TEST_ADD(CUTNetModule::layer3Autoconnect); TEST_ADD(CUTNetModule::interceptorTest); } void interceptorTest() { // Check that the interceptor system. // TODO : right now, there is no test of the security update call NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance(); // create the modules NLNET::IModule *gw = mm.createModule("StandardGateway", "gw", ""); NLNET::IModule *mod = mm.createModule("ModuleType0", "mod", ""); NLNET::IModuleGateway *gGw = dynamic_cast(gw); CModuleType0 *mod0 = dynamic_cast(mod); TEST_ASSERT(gGw != NULL); TEST_ASSERT(mod0 != NULL); // create the interceptors and attach it to the mod0 CInterceptor *inter0 = new CInterceptor(mod, "Inter0"); CInterceptor *inter1 = new CInterceptor(mod, "Inter1"); // plug the modules cr.execute("gw.plug gw", NLMISC::InfoLog()); cr.execute("mod.plug gw", NLMISC::InfoLog()); // update the network for (uint i=0; i<5; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } // send a message to the module fro; the gateway NLNET::CMessage msg("foo"); NLNET::IModuleProxy *modProx = retrieveModuleProxy(gGw, "mod"); TEST_ASSERT(modProx != NULL); modProx->sendModuleMessage(gw, msg); // update the network for (uint i=0; i<5; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } // check the module manifest TEST_ASSERT(modProx->getModuleManifest() == "CModuleType0 Inter0 Inter1"); // unplug the modules cr.execute("gw.unplug gw", NLMISC::InfoLog()); cr.execute("mod.unplug gw", NLMISC::InfoLog()); // update the network for (uint i=0; i<5; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } // now check that all methods have been called in that // module and in the two interceptors, // also check the manifest string content. TEST_ASSERT(mod0->ModuleUpCalled == 1); TEST_ASSERT(mod0->ModuleDownCalled == 1); TEST_ASSERT(mod0->ProcessMessageCalled == 1); // TEST_ASSERT(mod0->SecurityUpdateCalled); TEST_ASSERT(inter0->ModuleUpCalled == 1); TEST_ASSERT(inter0->ModuleDownCalled == 1); TEST_ASSERT(inter0->ProcessMessageCalled == 1); // TEST_ASSERT(inter0->SecurityUpdateCalled); TEST_ASSERT(inter1->ModuleUpCalled == 1); TEST_ASSERT(inter1->ModuleDownCalled == 1); TEST_ASSERT(inter1->ProcessMessageCalled == 1); // TEST_ASSERT(inter1->SecurityUpdateCalled); // delete the modules mm.deleteModule(gw); mm.deleteModule(mod); // delete the interceptors delete inter0; delete inter1; } void layer3Autoconnect() { // Check that layer 3 client can automatically reconnect in case of server // down/up // // We create two gateway, gw1 and gw2, plugged in themselves, then we create // a layer 3 client on gw1, update the network, then we create the layer 3 server // on gw2, update the network then check that module are connected. // // Then we close the L3 server on gw2, update the network, check that module // are diconnected and reopen the L3 server and recheck that module are connected. // // NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance(); // create the modules NLNET::IModule *gw1 = mm.createModule("StandardGateway", "gw1", ""); NLNET::IModule *gw2 = mm.createModule("StandardGateway", "gw2", ""); NLNET::IModuleGateway *gGw1 = dynamic_cast(gw1); NLNET::IModuleGateway *gGw2 = dynamic_cast(gw2); // plug gateway in themselves cr.execute("gw1.plug gw1", NLMISC::InfoLog()); cr.execute("gw2.plug gw2", NLMISC::InfoLog()); // create the client transport cr.execute("gw1.transportAdd L3Client l3c", NLMISC::InfoLog()); cr.execute("gw1.transportCmd l3c(retryInterval=1)", NLMISC::InfoLog()); cr.execute("gw1.transportCmd l3c(connect addr=localhost:8062)", NLMISC::InfoLog()); // update the network for (uint i=0; i<5; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } TEST_ASSERT(retrieveModuleProxy(gGw1, "gw2") == NULL); TEST_ASSERT(retrieveModuleProxy(gGw1, "gw2") == NULL); // open the server cr.execute("gw2.transportAdd L3Server l3s", NLMISC::InfoLog()); cr.execute("gw2.transportCmd l3s(open port=8062)", NLMISC::InfoLog()); // update the network (give more time because we must cover the Layer3 client reconnection timer) for (uint i=0; i<40; ++i) { mm.updateModules(); NLMISC::nlSleep(50); } // check module connectivity TEST_ASSERT(retrieveModuleProxy(gGw1, "gw2") != NULL); TEST_ASSERT(retrieveModuleProxy(gGw1, "gw2") != NULL); // exchange some message cr.execute("gw1.sendPing "+gw2->getModuleFullyQualifiedName(), NLMISC::InfoLog()); cr.execute("gw2.sendPing "+gw1->getModuleFullyQualifiedName(), NLMISC::InfoLog()); // update the network for (uint i=0; i<5; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } // check the ping counter TEST_ASSERT(gGw1->getReceivedPingCount() == 1); TEST_ASSERT(gGw2->getReceivedPingCount() == 1); // flood a little with ping for (uint i=0; i<100; ++i) cr.execute("gw1.sendPing "+gw2->getModuleFullyQualifiedName(), NLMISC::InfoLog()); // close the server cr.execute("gw2.transportCmd l3s(close)", NLMISC::InfoLog()); // update the network for (uint i=0; i<5; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } // test no connectivity TEST_ASSERT(retrieveModuleProxy(gGw1, "gw2") == NULL); TEST_ASSERT(retrieveModuleProxy(gGw2, "gw1") == NULL); // re-open the server cr.execute("gw2.transportCmd l3s(open port=8062)", NLMISC::InfoLog()); // update the network (give more time because we must cover the Layer3 client reconnection timer) for (uint i=0; i<40; ++i) { mm.updateModules(); NLMISC::nlSleep(50); } // check module connectivity TEST_ASSERT(retrieveModuleProxy(gGw1, "gw2") != NULL); TEST_ASSERT(retrieveModuleProxy(gGw2, "gw1") != NULL); // exchange some message cr.execute("gw1.sendPing "+gw2->getModuleFullyQualifiedName(), NLMISC::InfoLog()); cr.execute("gw2.sendPing "+gw1->getModuleFullyQualifiedName(), NLMISC::InfoLog()); // update the network for (uint i=0; i<5; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } // check the ping counter TEST_ASSERT(gGw1->getReceivedPingCount() == 2); TEST_ASSERT(gGw2->getReceivedPingCount() == 2); // cleanup modules mm.deleteModule(gw1); mm.deleteModule(gw2); } void synchronousMessaging() { // check that the synchronous messaging is working // by using module task NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance(); // create the modules NLNET::IModule *gw = mm.createModule("StandardGateway", "gw", ""); NLNET::IModule *m1 = mm.createModule("ModuleType0", "m1", ""); NLNET::IModule *m2 = mm.createModule("ModuleType0", "m2", ""); // plug the two modules in the gateway cr.execute("m1.plug gw", NLMISC::InfoLog()); cr.execute("m2.plug gw", NLMISC::InfoLog()); // update the network for (uint i=0; i<15; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } CModuleType0 *mod1 = dynamic_cast(m1); // start a task on module 1 mod1->startTaskA(); // update the network for (uint i=0; i<5; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } TEST_ASSERT(mod1->PingCount == 4); TEST_ASSERT(mod1->ResponseReceived == 1); // start a task on module 1 mod1->startTaskB(); // update the network for (uint i=0; i<5; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } TEST_ASSERT(mod1->PingCount == 4); TEST_ASSERT(mod1->ResponseReceived == 2); mm.deleteModule(m1); mm.deleteModule(m2); mm.deleteModule(gw); } void securityPlugin() { // Check that security plug-in work well. // // We connect three gateway in series with the central gateway // using a security module that adds security data to // proxies : // For local proxies, it adds type 1 security data // For foreign proxies, it adds type 2 security data // for foreign proxies, it removes any type 1 security data found // // gw1 (l3c) -------- (l3s) gw2 (l3c) ------ (l3s) gw3 // ^ ^ // | | // SecurityPlugin2 SecurityPlugin1 // // After connecting and plugging-in each gateway into themselves, // we check the presence and content of the security datas. // then we remove the securityPlugin1 and check that all // security data have been removed, // Then, we re create the securityPlugin1 and recheck // then one again, we remove it and recheck. // // For the second part of the check, we create a security // plug-in 2 on gw1 that add 'type3' security data on // local plug-in. // We also plug the security plug-in 1 and then we check that // we have the correct security data NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance(); NLNET::IModule *gw1, *gw2, *gw3; // create the modules gw1 = mm.createModule("StandardGateway", "gw1", ""); gw2 = mm.createModule("StandardGateway", "gw2", ""); gw3 = mm.createModule("StandardGateway", "gw3", ""); TEST_ASSERT(gw1 != NULL); TEST_ASSERT(gw2 != NULL); TEST_ASSERT(gw3 != NULL); // plug gateway in themselves NLNET::IModuleSocket *sGw1, *sGw2, *sGw3; sGw1 = mm.getModuleSocket("gw1"); sGw2 = mm.getModuleSocket("gw2"); sGw3 = mm.getModuleSocket("gw3"); TEST_ASSERT(sGw1 != NULL); TEST_ASSERT(sGw2 != NULL); TEST_ASSERT(sGw3 != NULL); gw1->plugModule(sGw1); gw2->plugModule(sGw2); gw3->plugModule(sGw3); string cmd; // create security plug-in cmd = "gw2.securityCreate TestSecurity1"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // create the transports cmd = "gw1.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw2.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw2.transportAdd L3Server l3s"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw3.transportAdd L3Server l3s"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // connect transport cmd = "gw2.transportCmd l3s(open port=8062)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw3.transportCmd l3s(open port=8063)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw1.transportCmd l3c(connect addr=localhost:8062)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw2.transportCmd l3c(connect addr=localhost:8063)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); for (uint retry = 0; retry < 2; ++retry) { if (retry > 0) { // recreate the security plug-in cmd = "gw2.securityCreate TestSecurity1"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); } // update the network for (uint i=0; i<15; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } NLNET::IModuleGateway *gGw1, *gGw2, *gGw3; gGw1 = dynamic_cast(gw1); TEST_ASSERT(gGw1 != NULL); gGw2 = dynamic_cast(gw2); TEST_ASSERT(gGw2 != NULL); gGw3 = dynamic_cast(gw3); TEST_ASSERT(gGw3 != NULL); // check security data NLNET::IModuleProxy *proxGw1_1, *proxGw2_1, *proxGw3_1; NLNET::IModuleProxy *proxGw1_2, *proxGw2_2, *proxGw3_2; NLNET::IModuleProxy *proxGw1_3, *proxGw2_3, *proxGw3_3; proxGw1_1 = retrieveModuleProxy(gGw1, "gw1"); proxGw2_1 = retrieveModuleProxy(gGw1, "gw2"); proxGw3_1 = retrieveModuleProxy(gGw1, "gw3"); proxGw1_2 = retrieveModuleProxy(gGw2, "gw1"); proxGw2_2 = retrieveModuleProxy(gGw2, "gw2"); proxGw3_2 = retrieveModuleProxy(gGw2, "gw3"); proxGw1_3 = retrieveModuleProxy(gGw3, "gw1"); proxGw2_3 = retrieveModuleProxy(gGw3, "gw2"); proxGw3_3 = retrieveModuleProxy(gGw3, "gw3"); TEST_ASSERT(proxGw1_1 != NULL); TEST_ASSERT(proxGw2_1 != NULL); TEST_ASSERT(proxGw3_1 != NULL); TEST_ASSERT(proxGw1_2 != NULL); TEST_ASSERT(proxGw2_2 != NULL); TEST_ASSERT(proxGw3_2 != NULL); TEST_ASSERT(proxGw1_3 != NULL); TEST_ASSERT(proxGw2_3 != NULL); TEST_ASSERT(proxGw3_3 != NULL); const NLNET::TSecurityData *ms; const TSecurityType1 *st1; const TSecurityType2 *st2; ms = proxGw1_1->getFirstSecurityData(); TEST_ASSERT(ms == NULL); ms = proxGw1_2->getFirstSecurityData(); TEST_ASSERT(ms != NULL); TEST_ASSERT(ms->DataTag == tst_type2); st2 = dynamic_cast(ms); TEST_ASSERT(st2 != NULL); TEST_ASSERT(st2->SecurityGatewayName == gw2->getModuleFullyQualifiedName()); TEST_ASSERT(st2->IntegerValue == 0x12345678); TEST_ASSERT(st2->NextItem == NULL); ms = proxGw1_3->getFirstSecurityData(); TEST_ASSERT(ms != NULL); TEST_ASSERT(ms->DataTag == tst_type2); st2 = dynamic_cast(ms); TEST_ASSERT(st2 != NULL); TEST_ASSERT(st2->SecurityGatewayName == gw2->getModuleFullyQualifiedName()); TEST_ASSERT(st2->IntegerValue == 0x12345678); TEST_ASSERT(st2->NextItem == NULL); ms = proxGw2_1->getFirstSecurityData(); TEST_ASSERT(ms != NULL); TEST_ASSERT(ms->DataTag == tst_type1); st1 = dynamic_cast(ms); TEST_ASSERT(st1 != NULL); TEST_ASSERT(st1->SecurityGatewayName == gw2->getModuleFullyQualifiedName()); TEST_ASSERT(st1->NextItem == NULL); ms = proxGw2_2->getFirstSecurityData(); TEST_ASSERT(ms != NULL); TEST_ASSERT(ms->DataTag == tst_type1); st1 = dynamic_cast(ms); TEST_ASSERT(st1 != NULL); TEST_ASSERT(st1->SecurityGatewayName == gw2->getModuleFullyQualifiedName()); TEST_ASSERT(st1->NextItem == NULL); ms = proxGw2_3->getFirstSecurityData(); TEST_ASSERT(ms != NULL); TEST_ASSERT(ms->DataTag == tst_type1); st1 = dynamic_cast(ms); TEST_ASSERT(st1 != NULL); TEST_ASSERT(st1->SecurityGatewayName == gw2->getModuleFullyQualifiedName()); TEST_ASSERT(st1->NextItem == NULL); ms = proxGw3_1->getFirstSecurityData(); TEST_ASSERT(ms != NULL); TEST_ASSERT(ms->DataTag == tst_type2); st2 = dynamic_cast(ms); TEST_ASSERT(st2 != NULL); TEST_ASSERT(st2->SecurityGatewayName == gw2->getModuleFullyQualifiedName()); TEST_ASSERT(st2->IntegerValue == 0x12345678); TEST_ASSERT(st2->NextItem == NULL); ms = proxGw3_2->getFirstSecurityData(); TEST_ASSERT(ms != NULL); TEST_ASSERT(ms->DataTag == tst_type2); st2 = dynamic_cast(ms); TEST_ASSERT(st2 != NULL); TEST_ASSERT(st2->SecurityGatewayName == gw2->getModuleFullyQualifiedName()); TEST_ASSERT(st2->IntegerValue == 0x12345678); TEST_ASSERT(st2->NextItem == NULL); ms = proxGw3_3->getFirstSecurityData(); TEST_ASSERT(ms == NULL); // remove the security plug-in // create security plug-in cmd = "gw2.securityRemove"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // update the network for (uint i=0; i<15; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } ms = proxGw1_1->getFirstSecurityData(); TEST_ASSERT(ms == NULL); ms = proxGw1_2->getFirstSecurityData(); TEST_ASSERT(ms == NULL); ms = proxGw1_3->getFirstSecurityData(); TEST_ASSERT(ms == NULL); ms = proxGw2_1->getFirstSecurityData(); TEST_ASSERT(ms == NULL); ms = proxGw2_2->getFirstSecurityData(); TEST_ASSERT(ms == NULL); ms = proxGw2_3->getFirstSecurityData(); TEST_ASSERT(ms == NULL); ms = proxGw3_1->getFirstSecurityData(); TEST_ASSERT(ms == NULL); ms = proxGw3_2->getFirstSecurityData(); TEST_ASSERT(ms == NULL); ms = proxGw3_3->getFirstSecurityData(); TEST_ASSERT(ms == NULL); } // part 2 // create the security plug-in cmd = "gw2.securityCreate TestSecurity1"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw1.securityCreate TestSecurity2"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // update the network for (uint i=0; i<15; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } NLNET::IModuleGateway *gGw1, *gGw2, *gGw3; gGw1 = dynamic_cast(gw1); TEST_ASSERT(gGw1 != NULL); gGw2 = dynamic_cast(gw2); TEST_ASSERT(gGw2 != NULL); gGw3 = dynamic_cast(gw3); TEST_ASSERT(gGw3 != NULL); // check security data NLNET::IModuleProxy *proxGw1_1, *proxGw2_1, *proxGw3_1; NLNET::IModuleProxy *proxGw1_2, *proxGw2_2, *proxGw3_2; NLNET::IModuleProxy *proxGw1_3, *proxGw2_3, *proxGw3_3; proxGw1_1 = retrieveModuleProxy(gGw1, "gw1"); proxGw2_1 = retrieveModuleProxy(gGw1, "gw2"); proxGw3_1 = retrieveModuleProxy(gGw1, "gw3"); proxGw1_2 = retrieveModuleProxy(gGw2, "gw1"); proxGw2_2 = retrieveModuleProxy(gGw2, "gw2"); proxGw3_2 = retrieveModuleProxy(gGw2, "gw3"); proxGw1_3 = retrieveModuleProxy(gGw3, "gw1"); proxGw2_3 = retrieveModuleProxy(gGw3, "gw2"); proxGw3_3 = retrieveModuleProxy(gGw3, "gw3"); TEST_ASSERT(proxGw1_1 != NULL); TEST_ASSERT(proxGw2_1 != NULL); TEST_ASSERT(proxGw3_1 != NULL); TEST_ASSERT(proxGw1_2 != NULL); TEST_ASSERT(proxGw2_2 != NULL); TEST_ASSERT(proxGw3_2 != NULL); TEST_ASSERT(proxGw1_3 != NULL); TEST_ASSERT(proxGw2_3 != NULL); TEST_ASSERT(proxGw3_3 != NULL); const NLNET::TSecurityData *ms; // const TSecurityType1 *st1; // const TSecurityType2 *st2; ms = proxGw1_1->findSecurityData(tst_type1); TEST_ASSERT(ms == NULL); ms = proxGw1_1->findSecurityData(tst_type2); TEST_ASSERT(ms == NULL); ms = proxGw1_1->findSecurityData(tst_type3); TEST_ASSERT(ms != NULL); ms = proxGw1_1->findSecurityData(tst_type4); TEST_ASSERT(ms != NULL); TEST_ASSERT(dynamic_cast(ms) != NULL); ms = proxGw1_2->findSecurityData(tst_type1); TEST_ASSERT(ms == NULL); ms = proxGw1_2->findSecurityData(tst_type2); TEST_ASSERT(ms != NULL); ms = proxGw1_2->findSecurityData(tst_type3); TEST_ASSERT(ms != NULL); ms = proxGw1_2->findSecurityData(0xff); TEST_ASSERT(ms != NULL); TEST_ASSERT(dynamic_cast(ms) != NULL); ms = proxGw1_3->findSecurityData(tst_type1); TEST_ASSERT(ms == NULL); ms = proxGw1_3->findSecurityData(tst_type2); TEST_ASSERT(ms != NULL); ms = proxGw1_3->findSecurityData(tst_type3); TEST_ASSERT(ms != NULL); ms = proxGw1_3->findSecurityData(0xff); TEST_ASSERT(ms != NULL); TEST_ASSERT(dynamic_cast(ms) != NULL); ms = proxGw2_1->findSecurityData(tst_type1); TEST_ASSERT(ms != NULL); ms = proxGw2_1->findSecurityData(tst_type2); TEST_ASSERT(ms == NULL); ms = proxGw2_1->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw2_1->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw2_2->findSecurityData(tst_type1); TEST_ASSERT(ms != NULL); ms = proxGw2_2->findSecurityData(tst_type2); TEST_ASSERT(ms == NULL); ms = proxGw2_2->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw2_2->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw2_3->findSecurityData(tst_type1); TEST_ASSERT(ms != NULL); ms = proxGw2_3->findSecurityData(tst_type2); TEST_ASSERT(ms == NULL); ms = proxGw2_3->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw2_3->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw3_1->findSecurityData(tst_type1); TEST_ASSERT(ms == NULL); ms = proxGw3_1->findSecurityData(tst_type2); TEST_ASSERT(ms != NULL); ms = proxGw3_1->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw3_1->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw3_2->findSecurityData(tst_type1); TEST_ASSERT(ms == NULL); ms = proxGw3_2->findSecurityData(tst_type2); TEST_ASSERT(ms != NULL); ms = proxGw3_2->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw3_2->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw3_3->findSecurityData(tst_type1); TEST_ASSERT(ms == NULL); ms = proxGw3_3->findSecurityData(tst_type2); TEST_ASSERT(ms == NULL); ms = proxGw3_3->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw3_3->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); // remove the security plug-in // create security plug-in cmd = "gw1.securityRemove"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // update the network for (uint i=0; i<15; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } ms = proxGw1_1->findSecurityData(tst_type1); TEST_ASSERT(ms == NULL); ms = proxGw1_1->findSecurityData(tst_type2); TEST_ASSERT(ms == NULL); ms = proxGw1_1->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw1_1->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw1_2->findSecurityData(tst_type1); TEST_ASSERT(ms == NULL); ms = proxGw1_2->findSecurityData(tst_type2); TEST_ASSERT(ms != NULL); ms = proxGw1_2->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw1_2->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw1_3->findSecurityData(tst_type1); TEST_ASSERT(ms == NULL); ms = proxGw1_3->findSecurityData(tst_type2); TEST_ASSERT(ms != NULL); ms = proxGw1_3->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw1_3->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw2_1->findSecurityData(tst_type1); TEST_ASSERT(ms != NULL); ms = proxGw2_1->findSecurityData(tst_type2); TEST_ASSERT(ms == NULL); ms = proxGw2_1->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw2_1->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw2_2->findSecurityData(tst_type1); TEST_ASSERT(ms != NULL); ms = proxGw2_2->findSecurityData(tst_type2); TEST_ASSERT(ms == NULL); ms = proxGw2_2->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw2_2->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw2_3->findSecurityData(tst_type1); TEST_ASSERT(ms != NULL); ms = proxGw2_3->findSecurityData(tst_type2); TEST_ASSERT(ms == NULL); ms = proxGw2_3->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw2_3->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw3_1->findSecurityData(tst_type1); TEST_ASSERT(ms == NULL); ms = proxGw3_1->findSecurityData(tst_type2); TEST_ASSERT(ms != NULL); ms = proxGw3_1->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw3_1->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw3_2->findSecurityData(tst_type1); TEST_ASSERT(ms == NULL); ms = proxGw3_2->findSecurityData(tst_type2); TEST_ASSERT(ms != NULL); ms = proxGw3_2->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw3_2->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); ms = proxGw3_3->findSecurityData(tst_type1); TEST_ASSERT(ms == NULL); ms = proxGw3_3->findSecurityData(tst_type2); TEST_ASSERT(ms == NULL); ms = proxGw3_3->findSecurityData(tst_type3); TEST_ASSERT(ms == NULL); ms = proxGw3_3->findSecurityData(tst_type4); TEST_ASSERT(ms == NULL); // cleanup mm.deleteModule(gw1); mm.deleteModule(gw2); mm.deleteModule(gw3); } void distanceAndConnectionLoop() { // Check that we support a closed loop or multi connection // of gateway and that the gateway chooses the best // route to reach a module when more than one is possible // and that the distance is updated // // For this test, we use the following context: // three gateway (gw1, gw2, gw3), each having a layer 3 // server and client transport. // one gateway (gw4) having just a layer3 server // gw1 connects on gw2, gw2 connects on gw3, gw3 connects on gw4. // we check the module list and distance, then gw3 connects to gw1, closing // the loop. // we recheck module list and distance. // We then disconnect gw3 from gw1 and recheck module list and distance. // // Finally, we create a second connection from gw1 to gw2 and // recheck module list and distances // // /------\ // (l3s) gw1 (l3c) (l3s) gw2 (l3c) ------ (l3s) gw3 (l3c) ------ (l3s) gw4 // | \----------------/ | // | | // | | // \-----------------------------------------------------/ // NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance(); NLNET::IModule *gw1, *gw2, *gw3, *gw4; // create the modules gw1 = mm.createModule("StandardGateway", "gw1", ""); gw2 = mm.createModule("StandardGateway", "gw2", ""); gw3 = mm.createModule("StandardGateway", "gw3", ""); gw4 = mm.createModule("StandardGateway", "gw4", ""); TEST_ASSERT(gw1 != NULL); TEST_ASSERT(gw2 != NULL); TEST_ASSERT(gw3 != NULL); TEST_ASSERT(gw4 != NULL); // plug gateway into themselves NLNET::IModuleSocket *sGw1, *sGw2, *sGw3, *sGw4; sGw1 = mm.getModuleSocket("gw1"); sGw2 = mm.getModuleSocket("gw2"); sGw3 = mm.getModuleSocket("gw3"); sGw4 = mm.getModuleSocket("gw4"); TEST_ASSERT(sGw1 != NULL); TEST_ASSERT(sGw2 != NULL); TEST_ASSERT(sGw3 != NULL); TEST_ASSERT(sGw4 != NULL); gw1->plugModule(sGw1); gw2->plugModule(sGw2); gw3->plugModule(sGw3); gw4->plugModule(sGw4); string cmd; // create the transports cmd = "gw1.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw1.transportAdd L3Server l3s"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw2.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw2.transportAdd L3Server l3s"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw3.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw3.transportAdd L3Server l3s"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw4.transportAdd L3Server l3s"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // connect transport cmd = "gw1.transportCmd l3s(open port=8061)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw2.transportCmd l3s(open port=8062)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw3.transportCmd l3s(open port=8063)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw4.transportCmd l3s(open port=8064)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw1.transportCmd l3c(connect addr=localhost:8062)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw2.transportCmd l3c(connect addr=localhost:8063)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gw3.transportCmd l3c(connect addr=localhost:8064)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // update the network for (uint i=0; i<15; ++i) { mm.updateModules(); NLMISC::nlSleep(40); } // check the modules list // ok, now, check that each gateways know the gateway it must know NLNET::IModuleGateway *gGw1, *gGw2, *gGw3, *gGw4; gGw1 = dynamic_cast(gw1); TEST_ASSERT(gGw1 != NULL); gGw2 = dynamic_cast(gw2); TEST_ASSERT(gGw2 != NULL); gGw3 = dynamic_cast(gw3); TEST_ASSERT(gGw3 != NULL); gGw4 = dynamic_cast(gw4); TEST_ASSERT(gGw4 != NULL); vector proxList; gGw1->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); proxList.clear(); gGw2->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); proxList.clear(); gGw3->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); proxList.clear(); gGw4->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); // check the distance NLNET::IModuleProxy *gw1_1Prox, *gw1_2Prox, *gw1_3Prox, *gw1_4Prox; NLNET::IModuleProxy *gw2_1Prox, *gw2_2Prox, *gw2_3Prox, *gw2_4Prox; NLNET::IModuleProxy *gw3_1Prox, *gw3_2Prox, *gw3_3Prox, *gw3_4Prox; NLNET::IModuleProxy *gw4_1Prox, *gw4_2Prox, *gw4_3Prox, *gw4_4Prox; gw1_1Prox = retrieveModuleProxy(gGw1, "gw1"); TEST_ASSERT(gw1_1Prox != NULL); TEST_ASSERT(gw1_1Prox->getModuleDistance() == 0); gw1_2Prox = retrieveModuleProxy(gGw2, "gw1"); TEST_ASSERT(gw1_2Prox != NULL); TEST_ASSERT(gw1_2Prox->getModuleDistance() == 1); gw1_3Prox = retrieveModuleProxy(gGw3, "gw1"); TEST_ASSERT(gw1_3Prox != NULL); TEST_ASSERT(gw1_3Prox->getModuleDistance() == 2); gw1_4Prox = retrieveModuleProxy(gGw4, "gw1"); TEST_ASSERT(gw1_4Prox != NULL); TEST_ASSERT(gw1_4Prox->getModuleDistance() == 3); gw2_1Prox = retrieveModuleProxy(gGw1, "gw2"); TEST_ASSERT(gw2_1Prox != NULL); TEST_ASSERT(gw2_1Prox->getModuleDistance() == 1); gw2_2Prox = retrieveModuleProxy(gGw2, "gw2"); TEST_ASSERT(gw2_2Prox != NULL); TEST_ASSERT(gw2_2Prox->getModuleDistance() == 0); gw2_3Prox = retrieveModuleProxy(gGw3, "gw2"); TEST_ASSERT(gw2_3Prox != NULL); TEST_ASSERT(gw2_3Prox->getModuleDistance() == 1); gw2_4Prox = retrieveModuleProxy(gGw4, "gw2"); TEST_ASSERT(gw2_4Prox != NULL); TEST_ASSERT(gw2_4Prox->getModuleDistance() == 2); gw3_1Prox = retrieveModuleProxy(gGw1, "gw3"); TEST_ASSERT(gw3_1Prox != NULL); TEST_ASSERT(gw3_1Prox->getModuleDistance() == 2); gw3_2Prox = retrieveModuleProxy(gGw2, "gw3"); TEST_ASSERT(gw3_2Prox != NULL); TEST_ASSERT(gw3_2Prox->getModuleDistance() == 1); gw3_3Prox = retrieveModuleProxy(gGw3, "gw3"); TEST_ASSERT(gw3_3Prox != NULL); TEST_ASSERT(gw3_3Prox->getModuleDistance() == 0); gw3_4Prox = retrieveModuleProxy(gGw4, "gw3"); TEST_ASSERT(gw3_4Prox != NULL); TEST_ASSERT(gw3_4Prox->getModuleDistance() == 1); gw4_1Prox = retrieveModuleProxy(gGw1, "gw4"); TEST_ASSERT(gw4_1Prox != NULL); TEST_ASSERT(gw4_1Prox->getModuleDistance() == 3); gw4_2Prox = retrieveModuleProxy(gGw2, "gw4"); TEST_ASSERT(gw4_2Prox != NULL); TEST_ASSERT(gw4_2Prox->getModuleDistance() == 2); gw4_3Prox = retrieveModuleProxy(gGw3, "gw4"); TEST_ASSERT(gw4_3Prox != NULL); TEST_ASSERT(gw4_3Prox->getModuleDistance() == 1); gw4_4Prox = retrieveModuleProxy(gGw4, "gw4"); TEST_ASSERT(gw4_4Prox != NULL); TEST_ASSERT(gw4_4Prox->getModuleDistance() == 0); // now, connect gw3 to gw1 cmd = "gw3.transportCmd l3c(connect addr=localhost:8061)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // update the network for (uint i=0; i<7; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // check module list proxList.clear(); gGw1->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); proxList.clear(); gGw2->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); proxList.clear(); gGw3->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); proxList.clear(); gGw4->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); // check the distances gw1_1Prox = retrieveModuleProxy(gGw1, "gw1"); TEST_ASSERT(gw1_1Prox != NULL); TEST_ASSERT(gw1_1Prox->getModuleDistance() == 0); gw1_2Prox = retrieveModuleProxy(gGw2, "gw1"); TEST_ASSERT(gw1_2Prox != NULL); TEST_ASSERT(gw1_2Prox->getModuleDistance() == 1); gw1_3Prox = retrieveModuleProxy(gGw3, "gw1"); TEST_ASSERT(gw1_3Prox != NULL); TEST_ASSERT(gw1_3Prox->getModuleDistance() == 1); gw1_4Prox = retrieveModuleProxy(gGw4, "gw1"); TEST_ASSERT(gw1_4Prox != NULL); TEST_ASSERT(gw1_4Prox->getModuleDistance() == 2); gw2_1Prox = retrieveModuleProxy(gGw1, "gw2"); TEST_ASSERT(gw2_1Prox != NULL); TEST_ASSERT(gw2_1Prox->getModuleDistance() == 1); gw2_2Prox = retrieveModuleProxy(gGw2, "gw2"); TEST_ASSERT(gw2_2Prox != NULL); TEST_ASSERT(gw2_2Prox->getModuleDistance() == 0); gw2_3Prox = retrieveModuleProxy(gGw3, "gw2"); TEST_ASSERT(gw2_3Prox != NULL); TEST_ASSERT(gw2_3Prox->getModuleDistance() == 1); gw2_4Prox = retrieveModuleProxy(gGw4, "gw2"); TEST_ASSERT(gw2_4Prox != NULL); TEST_ASSERT(gw2_4Prox->getModuleDistance() == 2); gw3_1Prox = retrieveModuleProxy(gGw1, "gw3"); TEST_ASSERT(gw3_1Prox != NULL); TEST_ASSERT(gw3_1Prox->getModuleDistance() == 1); gw3_2Prox = retrieveModuleProxy(gGw2, "gw3"); TEST_ASSERT(gw3_2Prox != NULL); TEST_ASSERT(gw3_2Prox->getModuleDistance() == 1); gw3_3Prox = retrieveModuleProxy(gGw3, "gw3"); TEST_ASSERT(gw3_3Prox != NULL); TEST_ASSERT(gw3_3Prox->getModuleDistance() == 0); gw3_4Prox = retrieveModuleProxy(gGw4, "gw3"); TEST_ASSERT(gw3_4Prox != NULL); TEST_ASSERT(gw3_4Prox->getModuleDistance() == 1); gw4_1Prox = retrieveModuleProxy(gGw1, "gw4"); TEST_ASSERT(gw4_1Prox != NULL); TEST_ASSERT(gw4_1Prox->getModuleDistance() == 2); gw4_2Prox = retrieveModuleProxy(gGw2, "gw4"); TEST_ASSERT(gw4_2Prox != NULL); TEST_ASSERT(gw4_2Prox->getModuleDistance() == 2); gw4_3Prox = retrieveModuleProxy(gGw3, "gw4"); TEST_ASSERT(gw4_3Prox != NULL); TEST_ASSERT(gw4_3Prox->getModuleDistance() == 1); gw4_4Prox = retrieveModuleProxy(gGw4, "gw4"); TEST_ASSERT(gw4_4Prox != NULL); TEST_ASSERT(gw4_4Prox->getModuleDistance() == 0); // close gw3 to gw1 cmd = "gw3.transportCmd l3c(close connId=1)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // update the network for (uint i=0; i<7; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // check module list proxList.clear(); gGw1->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); proxList.clear(); gGw2->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); proxList.clear(); gGw3->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); proxList.clear(); gGw4->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); // check the distances gw1_1Prox = retrieveModuleProxy(gGw1, "gw1"); TEST_ASSERT(gw1_1Prox != NULL); TEST_ASSERT(gw1_1Prox->getModuleDistance() == 0); gw1_2Prox = retrieveModuleProxy(gGw2, "gw1"); TEST_ASSERT(gw1_2Prox != NULL); TEST_ASSERT(gw1_2Prox->getModuleDistance() == 1); gw1_3Prox = retrieveModuleProxy(gGw3, "gw1"); TEST_ASSERT(gw1_3Prox != NULL); TEST_ASSERT(gw1_3Prox->getModuleDistance() == 2); gw1_4Prox = retrieveModuleProxy(gGw4, "gw1"); TEST_ASSERT(gw1_4Prox != NULL); TEST_ASSERT(gw1_4Prox->getModuleDistance() == 3); gw2_1Prox = retrieveModuleProxy(gGw1, "gw2"); TEST_ASSERT(gw2_1Prox != NULL); TEST_ASSERT(gw2_1Prox->getModuleDistance() == 1); gw2_2Prox = retrieveModuleProxy(gGw2, "gw2"); TEST_ASSERT(gw2_2Prox != NULL); TEST_ASSERT(gw2_2Prox->getModuleDistance() == 0); gw2_3Prox = retrieveModuleProxy(gGw3, "gw2"); TEST_ASSERT(gw2_3Prox != NULL); TEST_ASSERT(gw2_3Prox->getModuleDistance() == 1); gw2_4Prox = retrieveModuleProxy(gGw4, "gw2"); TEST_ASSERT(gw2_4Prox != NULL); TEST_ASSERT(gw2_4Prox->getModuleDistance() == 2); gw3_1Prox = retrieveModuleProxy(gGw1, "gw3"); TEST_ASSERT(gw3_1Prox != NULL); TEST_ASSERT(gw3_1Prox->getModuleDistance() == 2); gw3_2Prox = retrieveModuleProxy(gGw2, "gw3"); TEST_ASSERT(gw3_2Prox != NULL); TEST_ASSERT(gw3_2Prox->getModuleDistance() == 1); gw3_3Prox = retrieveModuleProxy(gGw3, "gw3"); TEST_ASSERT(gw3_3Prox != NULL); TEST_ASSERT(gw3_3Prox->getModuleDistance() == 0); gw3_4Prox = retrieveModuleProxy(gGw4, "gw3"); TEST_ASSERT(gw3_4Prox != NULL); TEST_ASSERT(gw3_4Prox->getModuleDistance() == 1); gw4_1Prox = retrieveModuleProxy(gGw1, "gw4"); TEST_ASSERT(gw4_1Prox != NULL); TEST_ASSERT(gw4_1Prox->getModuleDistance() == 3); gw4_2Prox = retrieveModuleProxy(gGw2, "gw4"); TEST_ASSERT(gw4_2Prox != NULL); TEST_ASSERT(gw4_2Prox->getModuleDistance() == 2); gw4_3Prox = retrieveModuleProxy(gGw3, "gw4"); TEST_ASSERT(gw4_3Prox != NULL); TEST_ASSERT(gw4_3Prox->getModuleDistance() == 1); gw4_4Prox = retrieveModuleProxy(gGw4, "gw4"); TEST_ASSERT(gw4_4Prox != NULL); TEST_ASSERT(gw4_4Prox->getModuleDistance() == 0); // make a double connection from gw1 to gw2 cmd = "gw1.transportCmd l3c(connect addr=localhost:8062)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // update the network for (uint i=0; i<7; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // check module list proxList.clear(); gGw1->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); proxList.clear(); gGw2->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); proxList.clear(); gGw3->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); proxList.clear(); gGw4->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); // check the distances gw1_1Prox = retrieveModuleProxy(gGw1, "gw1"); TEST_ASSERT(gw1_1Prox != NULL); TEST_ASSERT(gw1_1Prox->getModuleDistance() == 0); gw1_2Prox = retrieveModuleProxy(gGw2, "gw1"); TEST_ASSERT(gw1_2Prox != NULL); TEST_ASSERT(gw1_2Prox->getModuleDistance() == 1); gw1_3Prox = retrieveModuleProxy(gGw3, "gw1"); TEST_ASSERT(gw1_3Prox != NULL); TEST_ASSERT(gw1_3Prox->getModuleDistance() == 2); gw1_4Prox = retrieveModuleProxy(gGw4, "gw1"); TEST_ASSERT(gw1_4Prox != NULL); TEST_ASSERT(gw1_4Prox->getModuleDistance() == 3); gw2_1Prox = retrieveModuleProxy(gGw1, "gw2"); TEST_ASSERT(gw2_1Prox != NULL); TEST_ASSERT(gw2_1Prox->getModuleDistance() == 1); gw2_2Prox = retrieveModuleProxy(gGw2, "gw2"); TEST_ASSERT(gw2_2Prox != NULL); TEST_ASSERT(gw2_2Prox->getModuleDistance() == 0); gw2_3Prox = retrieveModuleProxy(gGw3, "gw2"); TEST_ASSERT(gw2_3Prox != NULL); TEST_ASSERT(gw2_3Prox->getModuleDistance() == 1); gw2_4Prox = retrieveModuleProxy(gGw4, "gw2"); TEST_ASSERT(gw2_4Prox != NULL); TEST_ASSERT(gw2_4Prox->getModuleDistance() == 2); gw3_1Prox = retrieveModuleProxy(gGw1, "gw3"); TEST_ASSERT(gw3_1Prox != NULL); TEST_ASSERT(gw3_1Prox->getModuleDistance() == 2); gw3_2Prox = retrieveModuleProxy(gGw2, "gw3"); TEST_ASSERT(gw3_2Prox != NULL); TEST_ASSERT(gw3_2Prox->getModuleDistance() == 1); gw3_3Prox = retrieveModuleProxy(gGw3, "gw3"); TEST_ASSERT(gw3_3Prox != NULL); TEST_ASSERT(gw3_3Prox->getModuleDistance() == 0); gw3_4Prox = retrieveModuleProxy(gGw4, "gw3"); TEST_ASSERT(gw3_4Prox != NULL); TEST_ASSERT(gw3_4Prox->getModuleDistance() == 1); gw4_1Prox = retrieveModuleProxy(gGw1, "gw4"); TEST_ASSERT(gw4_1Prox != NULL); TEST_ASSERT(gw4_1Prox->getModuleDistance() == 3); gw4_2Prox = retrieveModuleProxy(gGw2, "gw4"); TEST_ASSERT(gw4_2Prox != NULL); TEST_ASSERT(gw4_2Prox->getModuleDistance() == 2); gw4_3Prox = retrieveModuleProxy(gGw3, "gw4"); TEST_ASSERT(gw4_3Prox != NULL); TEST_ASSERT(gw4_3Prox->getModuleDistance() == 1); gw4_4Prox = retrieveModuleProxy(gGw4, "gw4"); TEST_ASSERT(gw4_4Prox != NULL); TEST_ASSERT(gw4_4Prox->getModuleDistance() == 0); // release modules mm.deleteModule(gw1); mm.deleteModule(gw2); mm.deleteModule(gw3); mm.deleteModule(gw4); } void firewalling() { // check that, with firewall mode enabled, unsafe root can only see protected // modules if they initiate the dialog first (i.e only a protected module can send // a message to an unsafe module). // // for this test, we have the following context : // 'master' : a gateway that accesses connection on two transports, one 'firewalled', the other one normal // 'peer1' : gateway connected to gateway 'master' on a firewalled transport // 'peer2' : gateway connected to gateway 'master' on a firewalled transport // 'other' : gateway connected to gateway 'master' on a classic transport // // peer1 (l3c)-----\ // >-|<- (l3s1/Firewalled) master (l3s2) ----- (l3c) other // peer2 (l3c)-----/ // // 'peer1' and 'peer2' must not see any module except modules that try to communicate with them // 'master' and 'other' must see 'peer1', 'peer2', 'master' and 'other' // // Switching OFF the firewall should disclose all modules, // switching ON then must throw an exception NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance(); NLNET::IModule *peer1, *peer2, *master, *other; // create the modules peer1 = mm.createModule("StandardGateway", "peer1", ""); peer2 = mm.createModule("StandardGateway", "peer2", ""); master = mm.createModule("StandardGateway", "master", ""); other = mm.createModule("StandardGateway", "other", ""); TEST_ASSERT(peer1 != NULL); TEST_ASSERT(peer2 != NULL); TEST_ASSERT(master != NULL); TEST_ASSERT(other != NULL); // plug gateway in themselves NLNET::IModuleSocket *sPeer1, *sPeer2, *sMaster, *sOther; sPeer1 = mm.getModuleSocket("peer1"); sPeer2 = mm.getModuleSocket("peer2"); sMaster = mm.getModuleSocket("master"); sOther = mm.getModuleSocket("other"); TEST_ASSERT(sPeer1 != NULL); TEST_ASSERT(sPeer2 != NULL); TEST_ASSERT(sMaster != NULL); TEST_ASSERT(sOther != NULL); peer1->plugModule(sPeer1); peer2->plugModule(sPeer2); master->plugModule(sMaster); other->plugModule(sOther); string cmd; // create the transports cmd = "peer1.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "peer2.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "master.transportAdd L3Server l3s1"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "master.transportAdd L3Server l3s2"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "other.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // Set option and connect transport cmd = "master.transportOptions l3s1(Firewalled)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "master.transportCmd l3s1(open port=8060)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "master.transportCmd l3s2(open port=8061)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "peer1.transportCmd l3c(connect addr=localhost:8060)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "peer2.transportCmd l3c(connect addr=localhost:8060)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "other.transportCmd l3c(connect addr=localhost:8061)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // d'ho ! all done, now let's run some loop of update for (uint i=0; i<7; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // ok, now, check that each gateway only knows the gateway it must know NLNET::IModuleGateway *gPeer1, *gPeer2, *gMaster, *gOther; gPeer1 = dynamic_cast(peer1); TEST_ASSERT(gPeer1 != NULL); gPeer2 = dynamic_cast(peer2); TEST_ASSERT(gPeer2 != NULL); gMaster = dynamic_cast(master); TEST_ASSERT(gMaster != NULL); gOther = dynamic_cast(other); TEST_ASSERT(gOther != NULL); vector proxList; gPeer1->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 1); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); proxList.clear(); gPeer2->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 1); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); proxList.clear(); gMaster->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); proxList.clear(); gOther->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "other")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); // now send the debug 'PING' message from 'other' to 'peer1', and a message from 'master' to 'peer2' { NLNET::CMessage ping("DEBUG_MOD_PING"); // retrieve peer1 proxy from other NLNET::IModuleProxy *peer1Prox = retrieveModuleProxy(gMaster, "peer1"); TEST_ASSERT(peer1Prox != NULL); peer1Prox->sendModuleMessage(master, ping); } { NLNET::CMessage ping("DEBUG_MOD_PING"); // retrieve peer1 proxy from other NLNET::IModuleProxy *peer2Prox = retrieveModuleProxy(gOther, "peer2"); TEST_ASSERT(peer2Prox != NULL); peer2Prox->sendModuleMessage(other, ping); } // update the network for (uint i=0; i<7; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // check new proxy table and ping counter TEST_ASSERT(gPeer1->getReceivedPingCount() == 1); proxList.clear(); gPeer1->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 2); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(gPeer2->getReceivedPingCount() == 1); proxList.clear(); gPeer2->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 2); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); proxList.clear(); gMaster->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); proxList.clear(); gOther->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "other")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); // now, remove firewall mode cmd = "master.transportOptions l3s1()"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // update the network for (uint i=0; i<7; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // check new proxy table and ping counter proxList.clear(); gPeer1->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); TEST_ASSERT(gPeer2->getReceivedPingCount() == 1); proxList.clear(); gPeer2->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); proxList.clear(); gMaster->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); proxList.clear(); gOther->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "other")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); // no try reactivate firewall mode with active route cmd = "master.transportOptions l3s1(Firewalled)"; TEST_THROWS(cr.execute(cmd, NLMISC::InfoLog()), NLNET::IModuleGateway::EGatewayFirewallBreak); // cleanup mm.deleteModule(peer1); mm.deleteModule(peer2); mm.deleteModule(master); mm.deleteModule(other); } void peerInvisible() { // check that, with peer invisible enable, the peer modules are effectively invisible, // and, also, check that other modules, on other route are visible. // for this test, we have the following context : // 'master' : a gateway that acces connection on to transport, on 'peer invisible', the other normal // 'peer1' : gateway connected to gateway 'master' on a peer invisible transport // 'peer2' : gateway connected to gateway 'master' on a peer invisible transport // 'other' : gateway connected to gateway 'master' on a classic transport // // peer1 (l3c)-----\ // >-- (l3s1/PeerInvisible) master (l3s2) ----- (l3c) other // peer2 (l3c)-----/ // // 'peer1' must see 'master' and 'other' // 'peer2' must see 'master' and 'other' // 'master' must see 'peer1', 'peer2' and 'other' // 'other' must see 'peer1', 'peer2' and 'master' // // When switching the PeerInvisible option to OFF, peer1 and peer2 must see each other NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance(); NLNET::IModule *peer1, *peer2, *master, *other; // create the modules peer1 = mm.createModule("StandardGateway", "peer1", ""); peer2 = mm.createModule("StandardGateway", "peer2", ""); master = mm.createModule("StandardGateway", "master", ""); other = mm.createModule("StandardGateway", "other", ""); TEST_ASSERT(peer1 != NULL); TEST_ASSERT(peer2 != NULL); TEST_ASSERT(master != NULL); TEST_ASSERT(other != NULL); // plug gateway in themselves NLNET::IModuleSocket *sPeer1, *sPeer2, *sMaster, *sOther; sPeer1 = mm.getModuleSocket("peer1"); sPeer2 = mm.getModuleSocket("peer2"); sMaster = mm.getModuleSocket("master"); sOther = mm.getModuleSocket("other"); TEST_ASSERT(sPeer1 != NULL); TEST_ASSERT(sPeer2 != NULL); TEST_ASSERT(sMaster != NULL); TEST_ASSERT(sOther != NULL); peer1->plugModule(sPeer1); peer2->plugModule(sPeer2); master->plugModule(sMaster); other->plugModule(sOther); string cmd; // create the transports cmd = "peer1.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "peer2.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "master.transportAdd L3Server l3s1"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "master.transportAdd L3Server l3s2"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "other.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // Set option and connect transport cmd = "master.transportOptions l3s1(PeerInvisible)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "master.transportCmd l3s1(open port=8060)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "master.transportCmd l3s2(open port=8061)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "peer1.transportCmd l3c(connect addr=localhost:8060)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "peer2.transportCmd l3c(connect addr=localhost:8060)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "other.transportCmd l3c(connect addr=localhost:8061)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // d'ho ! all done, now let's run some loop of update for (uint i=0; i<7; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // ok, now, check that each gateway only knows the gateway it must know NLNET::IModuleGateway *gPeer1, *gPeer2, *gMaster, *gOther; gPeer1 = dynamic_cast(peer1); TEST_ASSERT(gPeer1 != NULL); gPeer2 = dynamic_cast(peer2); TEST_ASSERT(gPeer2 != NULL); gMaster = dynamic_cast(master); TEST_ASSERT(gMaster != NULL); gOther = dynamic_cast(other); TEST_ASSERT(gOther != NULL); vector proxList; gPeer1->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 3); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); proxList.clear(); gPeer2->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 3); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); proxList.clear(); gMaster->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); proxList.clear(); gOther->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "other")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); // now, remove the 'PeerInvisible' options cmd = "master.transportOptions l3s1()"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // update the network for (uint i=0; i<7; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // check new proxy table proxList.clear(); gPeer1->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); proxList.clear(); gPeer2->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); proxList.clear(); gMaster->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); proxList.clear(); gOther->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "other")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); // now, re set the 'PeerInvisible' options cmd = "master.transportOptions l3s1(PeerInvisible)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // update the network for (uint i=0; i<7; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // check new proxy table proxList.clear(); gPeer1->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 3); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); proxList.clear(); gPeer2->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 3); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); proxList.clear(); gMaster->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); TEST_ASSERT(lookForModuleProxy(proxList, "other")); proxList.clear(); gOther->getModuleProxyList(proxList); TEST_ASSERT(proxList.size() == 4); TEST_ASSERT(lookForModuleProxy(proxList, "other")); TEST_ASSERT(lookForModuleProxy(proxList, "master")); TEST_ASSERT(lookForModuleProxy(proxList, "peer1")); TEST_ASSERT(lookForModuleProxy(proxList, "peer2")); // cleanup mm.deleteModule(peer1); mm.deleteModule(peer2); mm.deleteModule(master); mm.deleteModule(other); } void gwPlugUnplug() { // check that multiple plug/unplug operations work well NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance(); NLNET::IModule *mod = mm.createModule("StandardGateway", "gw", ""); TEST_ASSERT(mod != NULL); NLNET::IModuleSocket *socket = mm.getModuleSocket("gw"); TEST_ASSERT(socket != NULL); mod->plugModule(socket); mod->unplugModule(socket); mod->plugModule(socket); mod->unplugModule(socket); mod->plugModule(socket); std::vector result; socket->getModuleList(result); TEST_ASSERT(result.size() == 1); mod->unplugModule(socket); mm.deleteModule(mod); } void uniqueNameGenerator() { NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance(); mm.setUniqueNameRoot("foo"); // create a simple module NLNET::IModule *mod = mm.createModule("ModuleType0", "mod", ""); TEST_ASSERT(mod != NULL); TEST_ASSERT(mod->getModuleFullyQualifiedName() == "foo:mod"); mm.deleteModule(mod); // reset the unique name to normal value mm.setUniqueNameRoot(string()); mod = mm.createModule("ModuleType0", "mod", ""); TEST_ASSERT(mod != NULL); TEST_ASSERT(mod->getModuleFullyQualifiedName() != "foo:mod"); mm.deleteModule(mod); } void localMessageQueing() { NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance(); NLNET::IModule *mods = mm.createModule("StandardGateway", "gws", ""); TEST_ASSERT(mods != NULL); NLNET::IModuleGateway *gws = dynamic_cast(mods); TEST_ASSERT(gws != NULL); // get the socket interface of the gateway NLNET::IModuleSocket *socketGws = mm.getModuleSocket("gws"); TEST_ASSERT(socketGws != NULL); // create two modules that will communicate localy NLNET::IModule *m1= mm.createModule("ModuleType0", "m1", ""); TEST_ASSERT(m1!= NULL); NLNET::IModule *m2= mm.createModule("ModuleAsync", "m2", ""); TEST_ASSERT(m2!= NULL); m1->plugModule(socketGws); m2->plugModule(socketGws); // update the networks for (uint i=0; i<4; ++i) { mm.updateModules(); NLMISC::nlSleep(50); } // retrieve module proxy and send one ping to each other vector proxiesC; gws->getModuleProxyList(proxiesC); TEST_ASSERT(proxiesC.size() == 2); TEST_ASSERT(lookForModuleProxy(proxiesC, "m2")); NLNET::IModuleProxy *pm2 = retrieveModuleProxy(gws, "m2"); TEST_ASSERT(pm2 != NULL); NLNET::CMessage aMessage("DEBUG_MOD_PING"); pm2->sendModuleMessage(m1, aMessage); proxiesC.clear(); gws->getModuleProxyList(proxiesC); TEST_ASSERT(proxiesC.size() == 2); TEST_ASSERT(lookForModuleProxy(proxiesC, "m1")); NLNET::IModuleProxy *pm1 = retrieveModuleProxy(gws, "m1"); TEST_ASSERT(pm1 != NULL); aMessage = NLNET::CMessage("DEBUG_MOD_PING"); pm1->sendModuleMessage(m2, aMessage); // check received ping count CModuleType0 *mod1 = dynamic_cast(m1); TEST_ASSERT(mod1 != NULL); TEST_ASSERT(mod1->PingCount == 1); CModuleType0 *mod2 = dynamic_cast(m2); TEST_ASSERT(mod2 != NULL); TEST_ASSERT(mod2->PingCount == 0); // update the networks for (uint i=0; i<4; ++i) { mm.updateModules(); NLMISC::nlSleep(50); } // check received ping count TEST_ASSERT(mod1->PingCount == 1); TEST_ASSERT(mod2->PingCount == 1); // update the networks for (uint i=0; i<4; ++i) { mm.updateModules(); NLMISC::nlSleep(50); } // check received ping count TEST_ASSERT(mod1->PingCount == 1); TEST_ASSERT(mod2->PingCount == 1); // cleanup mm.deleteModule(m1); mm.deleteModule(m2); mm.deleteModule(mods); } void moduleMessaging() { NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance(); // create two gateway an connect them, plug the gateway on themselves and send a message NLNET::IModule *mods = mm.createModule("StandardGateway", "gws", ""); TEST_ASSERT(mods != NULL); NLNET::IModuleGateway *gws = dynamic_cast(mods); TEST_ASSERT(gws != NULL); // plug the module in itself before opening connection NLNET::IModuleSocket *socketGws = mm.getModuleSocket("gws"); TEST_ASSERT(socketGws != NULL); mods->plugModule(socketGws); // add transport for server mode string cmd = "gws.transportAdd L3Server l3s"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gws.transportCmd l3s(open port=6185)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); NLNET::IModule *modc = mm.createModule("StandardGateway", "gwc", ""); TEST_ASSERT(modc != NULL); NLNET::IModuleGateway *gwc = dynamic_cast(modc); TEST_ASSERT(gwc != NULL); // add transport for client mode cmd = "gwc.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gwc.transportCmd l3c(connect addr=localhost:6185)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // plug the module in itself before opening connection NLNET::IModuleSocket *socketGwc = mm.getModuleSocket("gwc"); TEST_ASSERT(socketGwc != NULL); modc->plugModule(socketGwc); // update the gateways... for (uint i=0; i<4; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // send a message from gws to gwc using the proxy // First, get the proxy for the client (must be the second one) vector proxiesS; gws->getModuleProxyList(proxiesS); TEST_ASSERT(proxiesS.size() == 2); TEST_ASSERT(lookForModuleProxy(proxiesS, "gwc")); NLNET::CMessage aMessage("DEBUG_MOD_PING"); proxiesS[1]->sendModuleMessage(mods, aMessage); // update the gateways... for (uint i=0; i<4; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // check that the ping has been received TEST_ASSERT(gwc->getReceivedPingCount() == 1); // send two crossing messages simultaneously vector proxiesC; gwc->getModuleProxyList(proxiesC); TEST_ASSERT(proxiesC.size() == 2); TEST_ASSERT(lookForModuleProxy(proxiesC, "gws")); proxiesS[1]->sendModuleMessage(mods, aMessage); proxiesC[1]->sendModuleMessage(modc, aMessage); // update the gateways... for (uint i=0; i<4; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // check that the ping has been received TEST_ASSERT(gwc->getReceivedPingCount() == 2); TEST_ASSERT(gws->getReceivedPingCount() == 1); // send with ISocket socketGws->sendModuleMessage(mods, proxiesS[1]->getModuleProxyId(), aMessage); // update the gateways... for (uint i=0; i<4; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // check that the ping has been received TEST_ASSERT(gwc->getReceivedPingCount() == 3); TEST_ASSERT(gws->getReceivedPingCount() == 1); // cleanup modules mm.deleteModule(mods); TEST_ASSERT(mm.getLocalModule("gws") == NULL); mm.deleteModule(modc); TEST_ASSERT(mm.getLocalModule("gwc") == NULL); } void moduleDisclosure() { NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance(); NLNET::IModule *mods = mm.createModule("StandardGateway", "gws", ""); TEST_ASSERT(mods != NULL); NLNET::IModuleGateway *gws = dynamic_cast(mods); TEST_ASSERT(gws != NULL); TEST_ASSERT(gws->getProxyCount() == 0); // plug the module in itself before opening connection NLNET::IModuleSocket *socketGws = mm.getModuleSocket("gws"); TEST_ASSERT(socketGws != NULL); mods->plugModule(socketGws); // now, there must be one proxy in the gateway TEST_ASSERT(gws->getProxyCount() == 1); vector proxies; gws->getModuleProxyList(proxies); TEST_ASSERT(proxies.size() == 1); TEST_ASSERT(proxies[0]->getGatewayRoute() == NULL); TEST_ASSERT(proxies[0]->getForeignModuleId() == mods->getModuleId()); // add transport for server mode string cmd = "gws.transportAdd L3Server l3s"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gws.transportCmd l3s(open port=6185)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); NLNET::IModule *modc = mm.createModule("StandardGateway", "gwc", ""); TEST_ASSERT(modc != NULL); NLNET::IModuleGateway *gwc = dynamic_cast(modc); TEST_ASSERT(gwc != NULL); // add transport for client mode cmd = "gwc.transportAdd L3Client l3c"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gwc.transportCmd l3c(connect addr=localhost:6185)"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); for (uint i=0; i<5; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // The server must have not changed TEST_ASSERT(gws->getProxyCount() == 1); // The client must have one proxy TEST_ASSERT(gwc->getProxyCount() == 1); proxies.clear(); gwc->getModuleProxyList(proxies); TEST_ASSERT(proxies.size() == 1); TEST_ASSERT(proxies[0]->getGatewayRoute() != NULL); TEST_ASSERT(proxies[0]->getModuleName().find("gws") == proxies[0]->getModuleName().size() - 3); // plug the client module in itself after opening connection NLNET::IModuleSocket *socketGwc = mm.getModuleSocket("gwc"); TEST_ASSERT(socketGwc != NULL); modc->plugModule(socketGwc); for (uint i=0; i<4; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } // The server must have now the two modules TEST_ASSERT(gws->getProxyCount() == 2); proxies.clear(); gws->getModuleProxyList(proxies); TEST_ASSERT(proxies.size() == 2); TEST_ASSERT(proxies[0]->getGatewayRoute() == NULL); TEST_ASSERT(proxies[0]->getForeignModuleId() == mods->getModuleId()); TEST_ASSERT(proxies[1]->getGatewayRoute() != NULL); TEST_ASSERT(proxies[1]->getModuleName().find("gwc") == proxies[1]->getModuleName().size() - 3); // The client must have two module also TEST_ASSERT(gwc->getProxyCount() == 2); proxies.clear(); gwc->getModuleProxyList(proxies); TEST_ASSERT(proxies.size() == 2); TEST_ASSERT(proxies[0]->getGatewayRoute() != NULL); TEST_ASSERT(proxies[0]->getModuleName().find("gws") == proxies[1]->getModuleName().size() - 3); TEST_ASSERT(proxies[1]->getGatewayRoute() == NULL); TEST_ASSERT(proxies[1]->getForeignModuleId() == modc->getModuleId()); // unplug the client module in itself after opening connection mods->unplugModule(socketGws); for (uint i=0; i<4; ++i) { NLMISC::nlSleep(100); mm.updateModules(); } // The server must have one module left TEST_ASSERT(gws->getProxyCount() == 1); proxies.clear(); gws->getModuleProxyList(proxies); TEST_ASSERT(proxies.size() == 1); TEST_ASSERT(proxies[0]->getGatewayRoute() != NULL); TEST_ASSERT(proxies[0]->getModuleName().find("gwc") == proxies[0]->getModuleName().size() - 3); // The client must have one module left TEST_ASSERT(gwc->getProxyCount() == 1); proxies.clear(); gwc->getModuleProxyList(proxies); TEST_ASSERT(proxies.size() == 1); TEST_ASSERT(proxies[0]->getGatewayRoute() == NULL); TEST_ASSERT(proxies[0]->getForeignModuleId() == modc->getModuleId()); // Dump the module state cmd = "gws.dump"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); cmd = "gwc.dump"; TEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog())); // cleanup modules mm.deleteModule(mods); TEST_ASSERT(mm.getLocalModule("gws") == NULL); mm.deleteModule(modc); TEST_ASSERT(mm.getLocalModule("gwc") == NULL); } void connectGateways() { NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLNET::IModule *mods = mm.createModule("StandardGateway", "gws", ""); TEST_ASSERT(mods != NULL); NLNET::IModuleGateway *gws = dynamic_cast(mods); TEST_ASSERT(gws != NULL); // add transport for server mode string cmd = "gws.transportAdd L3Server l3s"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); cmd = "gws.transportCmd l3s(open port=6185)"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); NLNET::IModule *modc1 = mm.createModule("StandardGateway", "gwc1", ""); TEST_ASSERT(modc1 != NULL); NLNET::IModuleGateway *gwc1 = dynamic_cast(modc1); TEST_ASSERT(gwc1 != NULL); // add transport for client mode cmd = "gwc1.transportAdd L3Client l3c"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); cmd = "gwc1.transportCmd l3c(connect addr=localhost:6185)"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); for (uint i=0; i<4; ++i) { mm.updateModules(); NLMISC::nlSleep(100); } TEST_ASSERT(gws->getRouteCount() == 1); TEST_ASSERT(gwc1->getRouteCount() == 1); // do a second connect to the server for stress // add transport for client mode cmd = "gwc1.transportCmd l3c(connect addr=localhost:6185)"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); // create third gateway NLNET::IModule *modc2 = mm.createModule("StandardGateway", "gwc2", ""); TEST_ASSERT(modc2 != NULL); NLNET::IModuleGateway *gwc2 = dynamic_cast(modc2); TEST_ASSERT(gwc2 != NULL); // add transport for client mode cmd = "gwc2.transportAdd L3Client l3c"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); cmd = "gwc2.transportCmd l3c(connect addr=localhost:6185)"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); // update the module to update the network callback client and server for (uint i=0; i<4; ++i) { // give some time to the listen and receiver thread to do there jobs NLMISC::nlSleep(100); mm.updateModules(); } TEST_ASSERT(gws->getRouteCount() == 3); TEST_ASSERT(gwc1->getRouteCount() == 2); TEST_ASSERT(gwc2->getRouteCount() == 1); // dump the gateways state cmd = "gws.dump"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); cmd = "gwc1.dump"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); cmd = "gwc2.dump"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); // cleanup the modules mm.deleteModule(mods); TEST_ASSERT(mm.getLocalModule("gws") == NULL); mm.deleteModule(modc1); TEST_ASSERT(mm.getLocalModule("gwc1") == NULL); mm.deleteModule(modc2); TEST_ASSERT(mm.getLocalModule("gwc2") == NULL); } void gatewayTransportManagement() { NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); // create a gateway module NLNET::IModule *mod = mm.createModule("StandardGateway", "gw", ""); TEST_ASSERT(mod != NULL); NLNET::IModuleGateway *gw = dynamic_cast(mod); TEST_ASSERT(gw != NULL); // Create a layer 3 server transport // send a transport creation command string cmd = "gw.transportAdd L3Server l3s"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); NLNET::IGatewayTransport *transportL3s = gw->getGatewayTransport("l3s"); TEST_ASSERT(transportL3s != NULL); // send a transport command cmd = "gw.transportCmd l3s(open port=6185)"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); // Create a layer 3 client transport // send a transport creation command cmd = "gw.transportAdd L3Client l3c"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); NLNET::IGatewayTransport *transportL3c = gw->getGatewayTransport("l3c"); TEST_ASSERT(transportL3c != NULL); // send a transport command cmd = "gw.transportCmd l3c(connect addr=localhost:6185)"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); // update the module to update the network callback client and server for (uint i=0; i<4; ++i) { // give some time to the listen and receiver thread to do there jobs mm.updateModules(); NLMISC::nlSleep(100); } TEST_ASSERT(transportL3s->getRouteCount() == 1); TEST_ASSERT(transportL3c->getRouteCount() == 1); TEST_ASSERT(gw->getRouteCount() == 2); // dump the gateways state cmd = "gw.dump"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); // close all connections cmd = "gw.transportCmd l3s(close)"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); cmd = "gw.transportCmd l3c(close connId=0)"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); // update the module to update the network callback client and server for (uint i=0; i<4; ++i) { // give some time to the listen and receiver thread to do there jobs mm.updateModules(); NLMISC::nlSleep(100); } TEST_ASSERT(transportL3s->getRouteCount() == 0); TEST_ASSERT(transportL3c->getRouteCount() == 0); TEST_ASSERT(gw->getRouteCount() == 0); // Remove transports cmd = "gw.transportRemove l3s"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); cmd = "gw.transportRemove l3c"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); TEST_ASSERT(gw->getGatewayTransport("l3c") == NULL); TEST_ASSERT(gw->getGatewayTransport("l3s") == NULL); TEST_ASSERT(gw->getTransportCount() == 0); // update the module to update the network callback client and server for (uint i=0; i<4; ++i) { // give some time to the listen and receiver thread to do there jobs mm.updateModules(); NLMISC::nlSleep(100); } // cleanup the modules mm.deleteModule(mod); TEST_ASSERT(mm.getLocalModule("gw") == NULL); } /* void moduleManagerCommands() { string cmd; // load a library cmd = "moduleManager.loadLibrary net_module_lib_test/net_module_lib_test"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); // dump the module state cmd = "moduleManager.dump"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); // create a module cmd = "moduleManager.createModule ModuleType1 AModuleName"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); // dump the module state cmd = "moduleManager.dump"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); // delete the module cmd = "moduleManager.deleteModule AModuleName"; TEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog())); }*/ void plugLocalGateway() { NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLNET::IModule *gateway1 = mm.createModule("LocalGateway", "g1", ""); TEST_ASSERT(gateway1 != NULL); NLNET::IModule *gateway2 = mm.createModule("LocalGateway", "g2", ""); TEST_ASSERT(gateway2 != NULL); NLNET::IModuleSocket *socket1 = mm.getModuleSocket("g1"); TEST_ASSERT(socket1 != NULL); NLNET::IModuleSocket *socket2 = mm.getModuleSocket("g2"); TEST_ASSERT(socket2 != NULL); gateway1->plugModule(socket1); gateway1->plugModule(socket2); gateway2->plugModule(socket1); gateway2->plugModule(socket2); mm.deleteModule(gateway1); TEST_ASSERT(mm.getLocalModule("g1") == NULL); mm.deleteModule(gateway2); TEST_ASSERT(mm.getLocalModule("g2") == NULL); } void createLocalGateway() { NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLNET::IModule *gateway = mm.createModule("LocalGateway", "localGateway", ""); TEST_ASSERT(gateway != NULL); NLNET::IModule *mod1 = mm.createModule("ModuleType0", "plugged1", ""); TEST_ASSERT(mod1 != NULL); NLNET::IModule *mod2 = mm.createModule("ModuleType0", "plugged2", ""); TEST_ASSERT(mod2 != NULL); NLNET::IModuleSocket *socket = mm.getModuleSocket("localGateway"); TEST_ASSERT(socket != NULL); mod1->plugModule(socket); mod2->plugModule(socket); mm.deleteModule(mod1); TEST_ASSERT(mm.getLocalModule("plugged1") == NULL); mm.deleteModule(mod2); TEST_ASSERT(mm.getLocalModule("plugged2") == NULL); mm.deleteModule(gateway); TEST_ASSERT(mm.getLocalModule("localGateway") == NULL); } /* void unloadModuleLib() { IModuleManager &mm = IModuleManager::getInstance(); CRefPtr module1 = mm.createModule("ModuleType1", "TheModule2", "the args"); TEST_ASSERT(module1 != NULL); TEST_ASSERT(mm.unloadModuleLibrary("net_module_lib_test")); // the module must have been deleted TEST_ASSERT(module1 == NULL); TModulePtr module2 = mm.createModule("ModuleType1", "TheModuleThatCantBeCreated", "the args"); TEST_ASSERT(module2 == NULL); }*/ void failedInit() { NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); NLNET::IModule *module = mm.createModule("ModuleType0", "FailingInit", "FAIL"); TEST_ASSERT(module == NULL); } /* void deleteModule() { IModuleManager &mm = IModuleManager::getInstance(); IModule *module = mm.createModule("ModuleType1", "TheModuleToDelete", "the args"); TEST_ASSERT(module != NULL); CRefPtr checkPtr(module); mm.deleteModule(module); TEST_ASSERT(checkPtr == NULL); }*/ /* void createModule() { IModuleManager &mm = IModuleManager::getInstance(); TModulePtr module = mm.createModule("ModuleType1", "TheModule", "the args"); TEST_ASSERT(module != NULL); TEST_ASSERT(module->getModuleClassName() == "ModuleType1"); TEST_ASSERT(module->getModuleName() == "TheModule"); string lh; if (IService::isServiceInitialized()) lh = IService::getInstance()->getHostName(); else lh = ::NLNET::CInetAddress::localHost().hostName(); string fqmn = lh+":"+toString(getpid())+":TheModule"; TEST_ASSERT(module->getModuleFullyQualifiedName() == fqmn); }*/ /* void loadModuleLib() { string moduleLibName = "net_module_lib_test/net_module_lib_test"; IModuleManager &mm = IModuleManager::getInstance(); TEST_ASSERT(mm.loadModuleLibrary(moduleLibName)); vector moduleList; mm.getAvailableModuleClassList(moduleList); TEST_ASSERT(moduleList.size() == 6); TEST_ASSERT(moduleList[0] == "LocalGateway"); TEST_ASSERT(moduleList[1] == "ModuleAsync"); TEST_ASSERT(moduleList[2] == "ModuleType0"); TEST_ASSERT(moduleList[3] == "ModuleType1"); TEST_ASSERT(moduleList[4] == "ModuleType2"); TEST_ASSERT(moduleList[5] == "StandardGateway"); }*/ void localModuleFactory() { NLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance(); vector moduleList; mm.getAvailableModuleClassList(moduleList); TEST_ASSERT(moduleList.size() == 4); TEST_ASSERT(moduleList[0] == "LocalGateway"); TEST_ASSERT(moduleList[1] == "ModuleAsync"); TEST_ASSERT(moduleList[2] == "ModuleType0"); TEST_ASSERT(moduleList[3] == "StandardGateway"); } void testModuleInitInfoBadParsing() { NLNET::TParsedCommandLine mif; string paramString = " a=1 b=2 ( b=1) "; TEST_ASSERT(!mif.parseParamList(paramString)); paramString = " lswkd ,fpqoj(( cruq fzemfwijf ujr wmozejifp_zujf woijpc_u ' "; TEST_ASSERT(!mif.parseParamList(paramString)); paramString = "a ( b=2"; TEST_ASSERT(!mif.parseParamList(paramString)); paramString = "a b=2)"; TEST_ASSERT(!mif.parseParamList(paramString)); paramString = "a b=2\"toto\""; TEST_ASSERT(!mif.parseParamList(paramString)); paramString = "=a"; TEST_ASSERT(!mif.parseParamList(paramString)); paramString = "a(=b)"; TEST_ASSERT(!mif.parseParamList(paramString)); } void testModuleInitInfoQuering() { NLNET::TParsedCommandLine mif; string paramString = " a=1 b=2 sub ( y=22 zzzz=12 subsub (g=\"bean in box\" z=2) ) "; TEST_ASSERT(mif.parseParamList(paramString)); TEST_ASSERT(mif.getParam("a") != NULL); TEST_ASSERT(mif.getParam("a") == mif.SubParams[0]); TEST_ASSERT(mif.getParam("sub") != NULL); TEST_ASSERT(mif.getParam("sub") == mif.SubParams[2]); TEST_ASSERT(mif.getParam("foo") == NULL); TEST_ASSERT(mif.getParam("sub.subsub.g") != NULL); TEST_ASSERT(mif.getParam("sub.subsub.g") == mif.SubParams[2]->SubParams[2]->SubParams[0]); } void testModuleInitInfoParsing() { NLNET::TParsedCommandLine mif; string paramString = "a"; TEST_ASSERT(mif.parseParamList(paramString)); paramString = "a=1"; TEST_ASSERT(mif.parseParamList(paramString)); paramString = "a(b=1)"; TEST_ASSERT(mif.parseParamList(paramString)); paramString = "a a a a"; TEST_ASSERT(mif.parseParamList(paramString)); TEST_ASSERT(mif.SubParams.size() == 4); paramString = " a ( b=1 )"; TEST_ASSERT(mif.parseParamList(paramString)); paramString = " a=1 b=2 sub ( y=22 zzzz=12 subsub (g=\"bean in box\" z=2) ) "; TEST_ASSERT(mif.parseParamList(paramString)); TEST_ASSERT(mif.SubParams.size() == 3); TEST_ASSERT(mif.SubParams[0]->SubParams.size() == 0); TEST_ASSERT(mif.SubParams[0]->ParamName == "a"); TEST_ASSERT(mif.SubParams[0]->ParamValue == "1"); TEST_ASSERT(mif.SubParams[1]->SubParams.size() == 0); TEST_ASSERT(mif.SubParams[1]->ParamName == "b"); TEST_ASSERT(mif.SubParams[1]->ParamValue == "2"); TEST_ASSERT(mif.SubParams[2]->SubParams.size() == 3); TEST_ASSERT(mif.SubParams[2]->ParamName == "sub"); TEST_ASSERT(mif.SubParams[2]->ParamValue.empty()); TEST_ASSERT(mif.SubParams[2]->SubParams[0]->SubParams.size() == 0); TEST_ASSERT(mif.SubParams[2]->SubParams[0]->ParamName == "y"); TEST_ASSERT(mif.SubParams[2]->SubParams[0]->ParamValue == "22"); TEST_ASSERT(mif.SubParams[2]->SubParams[1]->SubParams.size() == 0); TEST_ASSERT(mif.SubParams[2]->SubParams[1]->ParamName == "zzzz"); TEST_ASSERT(mif.SubParams[2]->SubParams[1]->ParamValue == "12"); TEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams.size() == 2); TEST_ASSERT(mif.SubParams[2]->SubParams[2]->ParamName == "subsub"); TEST_ASSERT(mif.SubParams[2]->SubParams[2]->ParamValue.empty()); TEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams[0]->SubParams.size() == 0); TEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams[0]->ParamName == "g"); TEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams[0]->ParamValue == "bean in box"); TEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams[1]->SubParams.size() == 0); TEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams[1]->ParamName == "z"); TEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams[1]->ParamValue == "2"); } }; #endif ================================================ FILE: code/nelDashBuild.cmd ================================================ @echo off # Default the source directory to the current directory. set NEL_DIR=%CD% set BUILDTYPE=Experimental # Load the development environment. If you run MSVC2008 you may need to change this to VS90COMNTOOLS. call "%VS80COMNTOOLS%vsvars32.bat" if "%1" == "" ( rem No arguments were specified. Print out usage information. echo Usage: %0 [c:\path\to\source] exit /b ) set BUILDTYPE=%1 if not "%2" == "" ( set NEL_DIR=%2 ) # Execute the build. If you run an Express version of MSVC you may need to change devenv to vcexpress. devenv "%NEL_DIR%\build\NeL.sln" /build Debug /project %1% ================================================ FILE: code/nelDashBuild.sh ================================================ #!/bin/sh # # Usage: ./nelDashBuild.sh [/path/to/source] # # # Default the source directory to where this is run from. NEL_DIR=`pwd` BUILDTYPE="Continuous" # Check to make sure we have at least one argument. Output usage. if [ $# -lt 1 ]; then echo "Usage: $0 [/path/to/source]" exit; else # Save the build type. BUILDTYPE=$1 fi # If we have more than one argument assume the 2nd argument is the source dir. if [ $# -gt 1 ]; then NEL_DIR=$2 fi # Change to the NeL source dir for this build. if [ -e $NEL_DIR/build ]; then cd $NEL_DIR/build else echo "$0: Failed to change to build dir: $NEL_DIR/build" exit; fi #this is due to a bug, the process extracts information from the svn output which needs to be in english #export LC_MESSAGES=en_GB # Start the build make -j -l 2.0 $1 ================================================ FILE: code/revision.h.in ================================================ #ifndef REVISION_H #define REVISION_H #cmakedefine REVISION "${REVISION}" #cmakedefine BUILD_DATE "${BUILD_DATE}" #endif ================================================ FILE: tools/protobuf/JS/README.md ================================================ 1,安装 nodejs 命令行下 2,安装淘宝cnpm 国外有很多库被墙,淘宝自己弄个了国内同步的 npm install -g cnpm --registry=https://registry.npm.taobao.org 3,cnpm install protobufjs@6.8.4 -g 4,cnpm install @egret/protobuf -g 5,使用 protobuf_gen_js.bat 生成 ================================================ FILE: tools/protobuf/JS/protobuf/protofile/hold ================================================ ================================================ FILE: tools/protobuf/JS/protobuf_gen_js.bat ================================================ del .\protobuf\protofile\*.proto /f /a /q copy ..\*.proto .\protobuf\protofile\ call pb-egret generate del .\protobuf\protofile\*.proto /f /a /q pause ================================================ FILE: tools/protobuf/define_attrib.proto ================================================ syntax = "proto2"; package PB; enum TAttribType { INVALID_ATTRIB = 0; ID = 2001001 ; LEVEL_UP_EXP_INT = 2001002 ; NAME_STRING = 2001003 ; LIFE_INT = 2001004 ; LIFE_CURR_INT = 2001005 ; }; ================================================ FILE: tools/protobuf/define_pro.proto ================================================ syntax = "proto2"; package PB; enum TEvent { EventInvalid = 0; // 无效事件 EventPlayerUp = 2; // 玩家升级 EventCostMoney = 40; // 消费金钱 EventLogin = 46; // 玩家登录 }; /// 标识占据第几位 0-63 enum TPlayerFlagBit { PLAYER_FLAG_TEST_0 = 0; // 玩家第一次做xx事的标识位 PLAYER_FLAG_FIRST_CARD_ONE = 1; // PLAYER_FLAG_FIRST_CARD_TEN = 2; // }; enum TErrorType { INVALID_TYPE = 0; ACCOUNT_LOGGED = 1; SERVER_FULL = 2; SERVER_NOT_OPEN = 3; TEXT_SUCESS = 4; TEXT_FAIL = 5; PWD_ERROR = 6; PLAYER_ONLINE_TO_FES = 7; PLAYER_EXISTS = 8; PLAYER_RELOAD = 9; SUCESS = 23; NO_AUTH_TYPE = 24; CONFIG_NOT_FOUND = 33; // 配置未找到 NOT_ENOUGH_MONEY = 37; // 金币不足 PLAYER_BASE_ERROR = 128; // 玩家基本数据不正确 }; enum TGender { MALE = 0; // 男性 FEMALE = 1; // 女性 }; // 房间付费方式 enum TGameConsumePay { TGC_GOLD = 0; TGC_SILVER = 1; } //房间付费机制 enum TPaymentMechanism { ROOM_OWNER_OPTION = 0; // 房主; AA_SYSTEM_OPTION = 1; // AA制; BIG_OWNER_OPTION = 2; // 大赢家; VIP_TISSUE_OPTION = 3; // 消耗高级牌友圈房卡; } enum TRoomCmdRecord { RC_ACTION_NULL = 0; // 用户过牌; RC_ACTION_START_GAME = 1; // 游戏开始; ( MsgRecordNodeList 中的 card_value[0] 为 会儿皮 ) RC_ACTION_OPERATE_RESULT = 2; // 用户选择权限结果; RC_ACTION_SEND_CARD = 3; // 用户发牌; RC_ACTION_OUT_CARD = 4; // 用户出牌; RC_ACTION_SHOWDOWN_DIANPAO = 5; // 用户点炮胡牌; 有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card ) RC_ACTION_SHOWDOWN_ZIMO = 6; // 用户自摸胡牌; 有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card ) RC_ACTION_SHOWDOWN_QIANGGANGHU = 7; // 用户抢杠胡牌; 有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card ) RC_ACTION_SHOWDOWN_LIUJU = 8; // 用户流局胡牌; 有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card ) RC_ACTION_SHOWDOWN = 9; // 进入结算 RC_ACTION_CONTRACT = 10; // 户承包关系; ( MsgRecordNodeList 中的 TarGetID 为承包id 、 ActionID为被承包id ) RC_ACTION_SEND_FLOWER_CARD = 11; // 用户抓牌花牌; ( MsgRecordNodeList 中的 card_index 为 flower_num ) RC_ACTION_START_FLOWER_CARD = 12; // 用户手牌补花; ( MsgRecordNodeList 中的 card_index 为 flower_num ) RC_ACTION_OPERATE_CHOICE = 13; // 用户选择权限; RC_ACTION_MINGLOU = 14; // 用户明楼; RC_ACTION_SEND_HAND_CARD = 15; // 用户发送手牌; RC_ACTION_CATHECTIC = 16; // 用户下注; RC_ACTION_HUNYOU = 17; // 用户混悠; RC_ACTION_TRUST_STATE = 18; // 用户托管状态; } enum TShowDownEvent { EVENT_XIAOHU = 1; // 小胡; EVENT_MEIHUI = 2; // 没会; EVENT_HUIGUIWEI = 3; // 会归位; EVENT_GANGKAIHUA = 4; // 杠开花; EVENT_TIANHU = 5; // 天胡; EVENT_DIHU = 6; // 地胡; EVENT_SIGEHUI = 7; // 四个会; EVENT_QIDUI = 8; // 七对; EVENT_QINGQIDUI = 9; // 清七对; EVENT_HAOHUAQIDUI = 10; // 豪华七对; EVENT_CHAOHUAQIDUI = 11; // 超豪华七对; EVENT_CHAOCHAOHAOHUAQIDUI = 12; // 超超豪华七对; EVENT_ZHUANGJIA = 13; // 庄家; EVENT_MINGGANG = 14; // 明杠; EVENT_ANGANG = 15; // 暗杠; EVENT_SIXIFENG = 16; // 四喜风; EVENT_SANZHIJIAN = 17; // 三支箭; EVENT_HUIMINGGANG = 18; // 会明杠; EVENT_HUIANGANG = 19; // 会暗杠; EVENT_MENG = 20; // 梦; EVENT_GENZHUANG = 21; // 跟庄(罚款); EVENT_SHISANYAO = 22; // 十三幺; EVENT_LONG = 23; // 一条龙; EVENT_QINGYISE = 24; // 清一色; EVENT_HUNYISE = 25; // 混一色; EVENT_PENGPENGHU = 26; // 碰碰胡; EVENT_JIANGYISE = 27; // 将一色; EVENT_HAIDILAOYUE = 28; // 海底捞月; EVENT_HUGANGFANG = 29; // 胡杠放; EVENT_WUHUAGUO = 30; // 无花果; EVENT_TING = 31; // 听牌; EVENT_PFFLOWER = 32; // 碰风花; EVENT_KOU_PAI = 33; // 扣牌; EVENT_THREE_ZUAN = 34; // 三钻; EVENT_FOUR_ZUAN = 35; // 四钻; EVENT_DIAOWUWAN = 36; // 吊五万; EVENT_ZHUOWUKUI = 37; // 捉五魁; EVENT_ZHI_GANG = 38; // 直杠; EVENT_DIANPAO = 39; // 点炮; EVENT_ZIMO = 40; // 自摸; EVENT_QIANGGANGHU = 41; // 抢杠胡; EVENT_BASESCORE = 42; // 底分; EVENT_JIAPINGHU = 43; // 夹平胡; EVENT_SHISANBUKAO = 44; // 十三不靠; EVENT_PAOPEIPINGHU = 45; // 跑配平胡; EVENT_PAOPEIQIDUI = 46; // 跑配七对; EVENT_KANHUI = 47; // 砍会 EVENT_MINGLOU = 48; // 明楼 EVENT_XIAOGANGKAIHUA = 49; // 小杠开花; EVENT_HUANGZHUANG = 50; // 荒庄; EVENT_HAOHUAQQIDUI = 51; // 豪华清七对; EVENT_CHAOHUAQQIDUI = 52; // 超豪华清七对; EVENT_CHAOCHAOHAOHUAQQIDUI = 53; // 超超豪华清七对; EVENT_PIAOCAI = 54; // 飘财; EVENT_BAOTOU = 55; // 爆头; EVENT_LAOZHUANG = 56; // 老庄; EVENT_DASANYUAN = 57; // 大三元 EVENT_DIAOYU = 58; // 钓鱼 EVENT_SUIJIYISE = 59; // 随机清一色 EVENT_LANPAI = 60; // 烂牌 EVENT_QIXINGLANPAI = 61; // 七星烂牌 EVENT_SANCAISHEN = 62; // 三财神 EVENT_QIFENGDAO = 63; // 七风倒 EVENT_QIFENGBAIDA = 64; // 七风百搭 EVENT_SHISANBAIDA = 65; // 十三白搭 EVENT_QUANFENGZI = 66; // 全风子 EVENT_DANDIAO = 67; // 单吊 EVENT_WUCAI = 68; // 无财 EVENT_QUANFENGZIPENGPENGHU = 69; // 全风子大碰胡 EVENT_QUANFENGZIQIDUI = 70; // 全风子七对子 EVENT_DIANPAOFEN = 71; // 点炮分 EVENT_QIANGGANGHUFEN = 72; // 抢杠胡分 EVENT_ZIMOFEN = 73; // 自摸分 EVENT_DUIDUIHU = 74; // 对对胡 EVENT_MEIBAIDA = 75; // 没百搭 EVENT_SANBAIDA = 76; // 三百搭 EVENT_DADIAOCHE = 77; // 大吊车 EVENT_SHUANGPIAO = 78; // 双飘财 EVENT_SANPIAO = 79; // 三飘财 EVENT_LANBAIDA = 80; // 烂百搭 EVENT_FENGZIBAIDA = 81; // 风字百搭 EVENT_SIHUA = 82; // 四花牌 EVENT_CHUNHUA = 83; // 纯花 EVENT_PENGFENGHUA = 84; // 碰风花 EVENT_GANGHUA = 85; // 杠花 EVENT_HUNPENG = 86; // 混碰 EVENT_QINGPENG = 87; // 清碰 EVENT_HUNQIDUI = 88; // 混七对 EVENT_HUAPAI = 89; // 花牌 EVENT_GUODAN = 90; // 过蛋儿 EVENT_MENQING = 91; // 闭门(门前清) EVENT_SANJIABIMEN = 92; // 三家闭门 EVENT_SHOWBAYI = 93; // 手把一 EVENT_SIGUIYI = 94; // 四归一 EVENT_XUANFENGGANG = 95; // 旋风杠 EVENT_JIEGANG = 96; // 借杠 EVENT_ZIYISE = 97; // 随机字一色 EVENT_TESHUYISE = 98; // 特殊清一色 EVENT_19LAOTOUBAIDA = 99; // 19老头百搭 EVENT_QIANGANGXIAOHU = 100; // 强杠小胡 EVENT_BUQIUREN = 101; // 不求人清一色 EVENT_CONTRACT = 102; // 承包 EVENT_ZHAMA = 103; // 扎码 EVENT_HUNBAZHANG = 104; // 胡八张 EVENT_QUEYIMEN = 105; // 缺一门 EVENT_HUIDIAO = 106; // 会吊 EVENT_QINGHU = 107; // 清胡 EVENT_HUIDIAOHUI = 108; // 会吊会 EVENT_PIAOHU = 109; // 飘胡 EVENT_THREEBIAN = 110; // 三边 EVENT_FOURBIAN = 111; // 四边 EVENT_SUHU = 112; // 素胡 EVENT_HUNDIAOHUN = 113; // 会吊会 EVENT_DAIZHUANG = 114; // 带庄 EVENT_JIA1FEN = 115; // 加1分 EVENT_JIA2FEN = 116; // 加2分 EVENT_WUZI = 117; // 无字; EVENT_KANZHANG = 118; // 坎张; EVENT_BIANZHANG = 119; // 边张; EVENT_SBALUOHAN = 120; // 十八罗汉 EVENT_HONGZGBAO = 121; // 红中宝 EVENT_QUEYI = 122; // 缺一 EVENT_LUANYAO = 123; // 乱幺; EVENT_BAO3QIANGGANGHU = 124; // 包三抢杠胡 EVENT_ERWUBAJIANG = 125; // 258将 EVENT_GUJIANG = 126; // 孤将 EVENT_DUANYAOJIU = 127; // 断幺九 EVENT_YIBIANGAO = 128; // 一边高 EVENT_GULIANLIU = 129; // 孤连六 EVENT_DAXIAOWU = 130; // 大小五 EVENT_GOUSHAN = 131; // 够扇 EVENT_ZHONGFABAI = 132; // 中发白 EVENT_THREEZA = 133; // 三砸 EVENT_FOURZA = 134; // 四砸 EVENT_KAWUKUI = 135; // 卡五魁 EVENT_ANXIAO = 136; // 暗潇 EVENT_SANGEYI = 137; // 三个一 EVENT_SANGEJIU = 138; // 三个九 EVENT_SUQIDUI = 139; // 素七对 EVENT_HUIDIAOQIXIAODUI = 140; // 会吊七小对 EVENT_MANGUAN = 141; // 满贯 EVENT_HUIBENLONG = 142; // 本会儿龙 EVENT_DIAOWUKUI = 143; // 吊五魁 EVENT_LAZHUANG = 144; // 拉庄 EVENT_LIUGANG = 145; // 流杠 EVENT_SULONG = 146; // 素龙 EVENT_HUNLONG = 147; // 混龙 EVENT_HEIFENG = 148; // 黑风 EVENT_HONGFENG = 149; // 红风 EVENT_YIJIU = 150; // 一九 EVENT_ZMH_PH = 151; // 桥东自摸屁胡 EVENT_ZMH_MQ = 152; // 桥东自摸门清 EVENT_QGH_PH = 153; // 桥东抢杠胡屁胡 EVENT_QGH_MQ = 154; // 桥东抢杠胡门清 EVENT_DPH_PH = 155; // 桥东点炮胡屁胡 EVENT_DPH_MQ = 156; // 桥东点炮胡门清 EVENT_QYS_LONG = 157; // 清一色+一条龙 EVENT_LIANGXI = 158; // 亮喜 EVENT_BUXI = 159; // 补喜 EVENT_PENG = 160; // 碰 EVENT_DAJIANG = 161; // 大将 EVENT_FENGYISE = 162; // 风一色 EVENT_QIDUIHUIDIAO = 163; // 七对会调 EVENT_QIDUIHUIDIAOHUI = 164; // 七对会调会 EVENT_DASIXI = 165; // 大四喜 EVENT_XIAOSIXI = 166; // 小四喜 EVENT_XIAOSANYUAN = 167; // 小三元 EVENT_GANGGANGHU = 168; // 杠杠胡 EVENT_BUHUAHU = 169; // 花上 EVENT_LIANGTAIHUA = 170; // 两台花 EVENT_LIANGTAIHUAQUEYI = 171; // 两台花缺一 EVENT_HUAGANG = 172; // 花杠 EVENT_HUISCORE = 173; // 混儿加分 EVENT_HUWEI = 174; // 胡尾 EVENT_ANKAN = 175; // 暗坎 EVENT_HUNERDIAO = 176; // 混儿吊 EVENT_PINGHU = 177; // 平胡 EVENT_HUNERYOU = 178; // 混儿悠 EVENT_YITIAOZHENLONG = 179; // 一条真龙 EVENT_YITIAOJIALONG = 180; // 一条假龙 EVENT_HUANGJINGANG = 181; // 黄金杠 EVENT_ZMH_PH_PINGHU = 182; // 桥东自摸屁胡,平胡(上面是大胡) EVENT_ZMH_MQ_PINGHU = 183; // 桥东自摸门清,平胡 EVENT_QGH_PH_PINGHU = 184; // 桥东抢杠胡屁胡,平胡 EVENT_QGH_MQ_PINGHU = 185; // 桥东抢杠胡门清,平胡 EVENT_DPH_PH_PINGHU = 186; // 桥东点炮胡屁胡,平胡 EVENT_DPH_MQ_PINGHU = 187; // 桥东点炮胡门清,平胡 EVENT_PINGHU_MINGGANG = 188; // 平胡明杠(桥东用,相对于大胡) EVENT_PINGHU_ANGANG = 189; // 平胡暗杠(桥东) EVENT_DIANPAO_QIDUI = 190; // 点炮七对(桥东) EVENT_ZIMO_QIDUI = 191; // 自摸七对(桥东) EVENT_PINGHU_GENZHUANG = 192; // 平胡跟庄(罚款)(桥东用); EVENT_FAGANG = 193; // 满城罚杠; EVENT_ZIMOFENGKE = 194; // 自摸风刻(天台); EVENT_ZIMOFENGDIAO = 195; // 自摸风调(天台); EVENT_ZIMOKE = 196; // 自摸刻子(天台); EVENT_ZIMOJIA = 197; // 自摸夹子(天台); EVENT_ZIMODIAO = 198; // 自摸单调(天台); EVENT_DIANPAOKE = 199; // 点炮刻字(天台); EVENT_DIANPAODIAO = 200; // 点炮单调(天台); EVENT_DIANPAOJIA = 201; // 点炮夹子(天台); EVENT_FENGKEZI = 202; // 风刻子(天台); EVENT_NORMALKEZI = 203; // 正常刻子(天台); EVENT_ZIJIAHUA = 204; // 自家花(天台); EVENT_SIGEHUA = 205; // 四个花(天台); EVENT_BAGEHUA = 206; // 八个花(天台); EVENT_BIANKADIAOSANQI = 207; // 边卡吊三七; EVENT_ZIJIAPENG = 208; // 自家碰(天台); EVENT_ZIJIAKEZI = 209; // 自家刻(天台); EVENT_HONGZHONGPENG = 210; // 红中碰(天台); EVENT_HONGZHONGKEZI = 211; // 红中刻(天台); EVENT_FACAIPENG = 212; // 发财碰(天台); EVENT_FACAIKEZI = 213; // 发财刻(天台); EVENT_HUJUEZHANG = 214; // 胡绝张 EVENT_YIBANGAO = 215; // 一般高 EVENT_LIANLIU = 216; // 连六 EVENT_QUANLAOTOU = 217; // 全老头 EVENT_LUANLAOTOU = 218; // 乱老头 EVENT_SANBAIDAZUOKE = 219; // 三百搭作刻 EVENT_CHUBAIDA = 220; // 出百搭 EVENT_CHAOQIANGGANGHU = 221; // 超抢杠胡(东台); EVENT_DUISHANGGANG = 222; // 对上杠(东台); EVENT_DUITIANTING = 223; // 对天听(东台); EVENT_DUIDANDIAO = 224; // 对单钓(东台); EVENT_SHANGGANG = 225; // 上杠(东台); EVENT_TIANTING = 226; // 天听(东台); EVENT_GANGSHANGDIANPAO = 227; // 杠上点炮(东台); EVENT_BAIDADUIZUOTOU = 228; // 百搭对作头(嘉善硬自摸) EVENT_SHUANGGANKAN = 229; // 双干坎(嘉善硬自摸) EVENT_GANGKAIHUIDIAOHUI = 230; // 杠开会吊会儿 EVENT_HUIDIAOLONG = 231; // 会吊龙 EVENT_HUIDIAOBENHUILONG = 232; // 会吊本会龙 EVENT_ZHANGMAO = 233; // 长毛 EVENT_ZIJIAGANG = 234; // 自家杠(天台); EVENT_HONGZHONGGANG = 235; // 红中杠(天台); EVENT_FACAIGANG = 236; // 发财杠(天台); EVENT_ZIJIADUI = 237; // 自家对子(天台); EVENT_FACAIDUI = 238; // 发财对子(天台); EVENT_HONGZHONGDUI = 239; // 红中对子(天台); EVENT_YIJIUCARD = 240; // 1,9 组合(清河); EVENT_HUADUIZIJIA = 241; // 花墩子+ EVENT_HUADUIZIJIAN = 242; // 花墩子- EVENT_QYS_QIDUI = 243; // 清一色+七对 EVENT_ZHONGMA = 244; // 中马 (自由麻将) EVENT_PENGHOUGANG = 245; // 碰后杠(自由麻将) EVENT_QYS_HUIDIAO = 246; // 清一色混吊(易县麻将) EVENT_ZIMOWUHUN = 247; // 自摸无混(易县麻将) EVENT_HENGYIHENGJIU = 248; // 清河横一横九 ENENT_CAIFENG = 249; // 清河彩风组合 EVENT_DDZDIFEN = 250; // 斗地主底分 EVENT_ZHADAN = 251; // 斗地主炸弹翻倍 EVENT_CHUNTIAN = 252; // 斗地主春天翻倍 EVENT_MINGPAI = 253; // 斗地主明牌翻倍 EVENT_DIPAI = 254; // 斗地主底牌翻倍 EVENT_QIANGDIZHU = 255; // 斗地主抢地主翻倍 EVENT_JIABEI = 256; // 斗地主加倍翻倍 EVENT_JIAOFEN = 257; // 斗地主叫分翻倍 EVENT_XIAOWANG = 258; // 斗地主底牌小王翻倍 EVENT_DAWANG = 259; // 斗地主底牌大王翻倍 EVENT_DUIZI = 260; // 斗地主底牌对子翻倍 EVENT_TONGHUA = 261; // 斗地主底牌同花翻倍 EVENT_SHUNZI = 262; // 斗地主底牌顺子翻倍 EVENT_SANZHANG = 263; // 斗地主底牌三张翻倍 EVENT_TONGHUASHUN = 264; // 斗地主底牌同花顺翻倍 EVENT_DAIYIJIU = 265; // 带一九 EVENT_LONGQIDUI = 266; // 龙七对 EVENT_GEN = 267; // 根 EVENT_JINGOUHU = 268; // 金钩胡 EVENT_ZHONGZHANG = 269; // 中张 EVENT_GANGSHANGPAO = 270; // 杠上炮 EVENT_DIANPAOHU = 271; // 点炮胡 EVENT_BEIZIMO = 272; // 被自摸 EVENT_ZIMOHU = 273; // 自摸胡 EVENT_GUAFENG = 274; // 刮风 EVENT_BEIGUAFENG = 275; // 被刮风 EVENT_XIAYU = 276; // 下雨 EVENT_BEIXIAYU = 277; // 被下雨 EVENT_MIANXIAGANG = 278; // 面下杠(二次杠) EVENT_BEIMIANXIAGANG = 279; // 被面下杠(二次杠) EVENT_HUJIAOZHUANYI = 280; // 呼叫转移 EVENT_BEIHUJIAOZHUANYI = 281; // 被呼叫转移 EVENT_CHAHUAZHU = 282; // 查花猪 EVENT_CHAJIAO = 283; // 查叫 EVENT_BEICHAHUAZHU = 284; // 被查花猪 EVENT_BEICHAJIAO = 285; // 被查叫 } ================================================ FILE: tools/protobuf/lua/protobuf_gen_lua.bat ================================================ del *.proto /f /a /q del *.pb /f /a /q copy ..\*.proto . del ..\..\..\code\EVA\server\script\DataTable\*.proto /f /a /q copy ..\*.proto ..\..\..\code\EVA\server\script\DataTable\proto\ /y protoc-3.2.0rc2 --descriptor_set_out=./ProtoMsg.pb define_pro.proto define_attrib.proto msg_client.proto msg_service.proto msg_doudizhu.proto copy ProtoMsg.pb ..\..\..\code\EVA\server\script\DataTable\ /y del *.proto /f /a /q del *.pb /f /a /q pause ================================================ FILE: tools/protobuf/msg_client.proto ================================================ syntax = "proto2"; package PB; import "define_pro.proto"; message MsgLogin { optional string Version = 1; optional string Channel = 2; optional string AppName = 3; optional string User = 4; optional string NonceStr = 5; optional string Token = 6; optional uint64 Timestamp = 7; optional uint64 UID = 8; optional string RoomType = 9; } message MsgPlayerInfo { optional uint64 UID = 1; optional string Nickname = 2; optional uint32 Portrait = 3; optional uint64 Money = 4; optional uint64 RMB = 5; optional uint32 Main = 6; optional uint64 FlagBit = 7; } message MsgCreatePrivateRoom { optional uint32 consume_id = 1; optional TGameConsumePay consume_kind = 2; optional string room_type = 3; optional uint32 special_kind = 4; optional uint32 score = 5; optional uint32 game_versione = 6; optional TPaymentMechanism pay_ment = 7; optional uint32 player_number = 8; optional uint64 tissue_id = 9; } message MsgEnterPrivateRoom { optional uint64 room_id = 1; optional string room_type = 2; optional string app_name = 3; optional uint32 game_version = 4; } message MsgCard { optional uint32 card = 1; } message MsgCards { optional uint32 type = 1; repeated uint32 cards = 2; } message MsgInt { optional int64 value = 1; } message MsgBool { optional bool value = 1; } message MsgString { optional string str = 1; } message MsgError { optional uint32 errno = 1; optional uint64 value = 2; } //////////////////////////////// Record Start ////////////////////// message MsgRecordRoleInfo { optional uint64 id = 1; optional uint32 seat = 2; optional string usename = 3; optional int64 score = 4; repeated uint32 hand_card = 5; optional string nick_name = 6; optional uint32 game_state = 7; optional uint32 series = 8; optional int64 current_score = 9; } message MsgRecordRoomInfo { optional uint32 special_kind = 1; optional uint64 banker = 2; optional uint32 score = 3; optional uint32 game_count = 4; repeated uint32 bottom_cards = 5; } message MsgRecordEvent { optional uint32 event_id = 1; optional uint32 count = 2; repeated int32 score = 3; repeated uint32 score_count = 4; } message MsgRecordWeaveCard { optional uint32 card = 1; optional uint32 wik = 2; optional uint32 barkind = 3; repeated uint32 mix_card = 4; // 组合牌; } message MsgRecordShowDown { optional uint64 id = 1; optional int64 score = 2; optional int64 fixedscore = 3; optional int64 param1 = 4; optional int64 param2 = 5; optional uint32 hucard = 6; repeated MsgRecordEvent event = 7; optional int64 money = 8; optional int64 param3 = 9; optional int64 param4 = 10; optional int64 param5 = 11; optional int64 play_id = 12; repeated uint32 hand_card = 13; repeated MsgRecordWeaveCard weave_card = 14; repeated uint32 hucard_list = 15; } message MsgGDShowDownRole { optional uint64 role_id = 1; optional uint32 game_count = 2; optional uint32 series = 3; optional int32 score = 4; optional int32 current_score = 5; } message MsgGDRankInfo { repeated uint64 rank_list = 1; } message MsgRecordNodeList { optional uint32 cmd_id = 1; repeated uint32 card_value = 2; optional uint32 card_index = 3; optional uint64 action_id = 4; optional uint32 action_wik = 5; optional uint64 target_id = 6; optional uint32 node_size = 7; repeated MsgRecordRoleInfo role_data = 8; optional MsgRecordRoomInfo room_data = 9; repeated MsgRecordShowDown showdown_list = 10; repeated MsgRecordNodeList next_node = 11; repeated MsgGDShowDownRole win_role = 12; repeated MsgGDShowDownRole lost_role = 13; optional MsgGDRankInfo room_ranking = 14; } //////////////////////////////// Record End //////////////////////////// ================================================ FILE: tools/protobuf/msg_doudizhu.proto ================================================ syntax = "proto2"; package PB; import "msg_client.proto"; enum TDDZPlayerWik // 玩家权限 { ASK_DDZ_NULL = 1; // 空 ASK_DDZ_TISHI = 2; // 提示 ASK_DDZ_BUCHU = 3; // 不出 ASK_DDZ_CHUPAI = 4; // 出牌 ASK_DDZ_DIZHU_MINGPAI = 5; // 地主明牌 }; enum TDDZPlayerState // 玩家状态 { STATE_DDZ_READY = 1; // 准备 STATE_DDZ_GUOPAI = 2; // 过牌 STATE_DDZ_CHUNTIAN = 3; // 春天 STATE_DDZ_NEWROLE = 4; // 新玩家 STATE_DDZ_ROOM_OWNER = 5; // 房主 STATE_DDZ_RELIEVE = 6; // 解除房间状态; STATE_DDZ_LEAVE = 7; // 离开状态 STATE_DDZ_LIMIT = 8; // 限制状态 STATE_DDZ_OFFLINE = 9; // 脱机状态; STATE_DDZ_MINGPAI = 10; // 明牌 状态; STATE_DDZ_DIZHU = 11; // 地主状态; STATE_DDZ_NONGMING = 12; // 农民状态; STATE_DDZ_JIABEI = 13; // 加倍状态 STATE_DDZ_QIANGDIZHU = 14; // 抢地主状态 STATE_DDZ_SELECT_JIABEI = 15; // 选择加倍状态 STATE_DDZ_SELECT_MINGPAISTART = 16; // 选择明牌开始状态 STATE_DDZ_FENGDING = 17; // 封顶状态 STATE_DDZ_CONTINUE_GAME = 18; // 继续游戏状态 }; enum TDDZState // 游戏房间状态 { TDDZStateWait = 0; // 等待开始 TDDZStateCheckStartGame = 1; // 检查是否可以开始游戏 TDDZStateSelectMingCardStart = 2; // 选择明牌开始阶段 TDDZStateStartGame = 3; // 开始游戏 TDDZStateSendCard = 4; // 发送手牌 TDDZStateQiangDiZhu = 5; // 抢地主阶段 TDDZStateSelectAddTimes = 6; // 选择加倍阶段 TDDZStateAction = 7; // 玩家自由活动 TDDZStateOutCard = 8; // 出牌状态 TDDZStateShowDown = 9; // 游戏结算 TDDZStateRelieveRoom = 10; // 解散房间 }; enum TDDZCT // 牌型 { CT_DDZ_ERROR = 0; // 错误类型 CT_DDZ_SINGLE = 1; // 单牌类型 CT_DDZ_DOUBLE = 2; // 对子类型 CT_DDZ_THREE_TIAO = 3; // 三条类型 CT_DDZ_THREE_TIAO_WITH_ONE = 4; // 三带一单类型 CT_DDZ_THREE_TIAO_WITH_YIDUI = 5; // 三带一对类型 CT_DDZ_SHUN_ZI = 6; // 顺子类型 CT_DDZ_LIAN_DUI = 7; // 连对类型 CT_DDZ_FEIJI_WITH_NULL = 8; // 飞机不带类型 CT_DDZ_FEIJI_WITH_ONE = 9; // 飞机带单类型 CT_DDZ_FEIJI_WITH_YIDUI = 10; // 飞机带对类型 CT_DDZ_FOUR_WITHDOUBLE = 11; // 四带二类型 CT_DDZ_FOUR_LIANGDUI = 12; // 四带二对类型 CT_DDZ_ZHADAN_SIZHANG = 13; // 炸弹 CT_DDZ_HUOJIAN = 14; // 火箭 }; enum TDDZBottomType // 底牌牌型 { DDZ_BT_NULL = 0; // 无类型 DDZ_BT_XIAO_KING = 1; // 小王类型 DDZ_BT_DA_KING = 2; // 大王类型 DDZ_BT_DUIZI = 3; // 对子类型 DDZ_BT_TONGHUA = 4; // 同花类型 DDZ_BT_SHUNZI = 5; // 顺子类型 DDZ_BT_SANZHANG = 6; // 三张类型 DDZ_BT_TONGHUASHUN = 7; // 同花顺类型 }; enum TDDZQiangDiZhu // 抢地主权限 { DDZ_QDZ_JIAODIZHU = 1; // 叫地主 DDZ_QDZ_BUJIAO = 2; // 不叫 DDZ_QDZ_QIANGDIZHU = 3; // 抢地主 DDZ_QDZ_BUQIANG = 4; // 不抢 }; enum TDDZJiaoFen // 叫分权限 { DDZ_JF_BUJIAO = 1; // 不叫 DDZ_JF_JIAO_ONE = 2; // 叫一分 DDZ_JF_JIAO_TWO = 3; // 叫二分 DDZ_JF_JIAO_THREE = 4; // 叫三分 }; enum TDDZAddTimes // 加倍选择 { DDZ_AT_NULL = 0; DDZ_AT_BUJIABIE = 1; // 不加倍 DDZ_AT_JIABIE = 2; // 加倍 }; enum TDDZMingPaiType // 明牌选择 { DDZ_MP_NULL = 0; DDZ_MP_NORMALSTART = 1; // 普通开始 DDZ_MP_MINGPAISTART = 2; // 明牌开始 }; enum TGameSpecialKindDouDiZhu // 斗地主房间玩法 { TSK_DDZ_NULL = 0; TSK_DDZ_QDZ = 1; // 抢地主 TSK_DDZ_JF = 2; // 叫分 TSK_DDZ_BFD = 3; // 不封顶 TSK_DDZ_16 = 4; // 16封顶 TSK_DDZ_32 = 5; // 32封顶 TSK_DDZ_64 = 6; // 64封顶 TSK_DDZ_DIPAI = 7; // 底牌翻倍 TSK_DDZ_JIABEI = 8; // 加倍 TSK_DDZ_MINGPAI = 9; // 明牌 } message MsgQiangDiZhu // 抢地主信息(服务器发给客户端的) { optional uint64 playid = 1; // 玩家id optional uint64 qingdizhu_wiki = 2; // 玩家可操作的权限 } message MsgQiangDiZhuResult // 抢地主结果(客户端发给服务器的,服务器广播的) { optional uint64 playid = 1; // 玩家id optional uint64 result = 2; // 玩家选择的结果 optional uint64 state = 3; // 状态 repeated uint32 dizhu_cards = 4; // 刷新地主的手牌 optional uint64 cardcount = 5; // 手牌数量 optional uint64 multiple = 6; // 房间倍数 } message MsgBRQiangDiZhuResult // 抢地主最终结果(服务器广播的) { repeated MsgQiangDiZhuResult player_list = 1; optional uint64 multiple = 2; // 房间倍数 repeated MsgDiPaiMutiple dipai_multi_list = 3; // 底牌翻倍列表 } message MsgDiPaiMutiple // 底牌翻倍的类型事件 { optional uint32 event_id = 1; optional uint32 count = 2; } message MsgMingPaiResult // 选择明牌结果(客户端发给服务器的,服务器广播的) { optional uint64 playid = 1; // 玩家id optional uint64 result = 2; // 玩家选择的结果 optional uint64 state = 3; // 状态 repeated uint32 dizhu_cards = 4; // 地主明牌时刷新手牌 optional uint64 multiple = 5; // 房间倍数 } message MsgJiaBeiResult // 选择加倍结果(客户端发给服务器的,服务器广播的) { optional uint64 playid = 1; // 玩家id optional uint64 result = 2; // 玩家选择的结果 optional uint64 state = 3; // 状态 } message MsgDDZPlayer // 玩家信息 { optional MsgPlayerInfo player_base = 1; // 玩家信息(房间信息填充) optional uint32 state = 2; // 玩家状态 optional uint32 hand_count = 3; // 手牌数量 repeated uint32 card_list = 4; // 手牌列表(房间信息、showdown填充) optional uint32 seats = 5; // 座位(房间信息填充) optional int64 score = 6; // 玩家当前的积分 optional int64 show_down_score = 7; // 玩家该局游戏的加减分 optional uint32 qingdizhu_wiki = 8; // 玩家抢地主的权限 optional uint32 qingdizhu_value = 9; // 玩家抢地主的结果 optional uint32 multiple = 10; // 玩家倍数,(结算时使用) optional uint32 integral_num = 11; // 加券数 repeated uint32 out_cards = 12; // 上把玩家出的牌信息 optional uint32 out_type = 13; // 上把玩家的出牌种类 } message MsgDDZActon { optional uint64 new_actionid = 1; // 当前活动玩家 optional uint64 old_actionid = 2; // 上把的活动玩家 repeated uint32 last_out_cards = 3; // 上把玩家出的牌信息 optional uint32 last_out_type = 4; // 上把玩家的出牌种类 optional uint32 wik = 5; // 当前活动玩家的权限 TDDZPlayerWik repeated MsgDDZPlayer player_list = 6; // 玩家信息 } message MsgDDZUserOutCard { optional uint64 old_actionid = 1; // 旧玩家ID optional uint32 out_type = 2; // 出牌种类 optional uint32 hand_count = 3; // 玩家手牌数量 repeated uint32 out_cards = 4; // 出牌列表 optional uint64 multiple = 5; // 房间倍数 repeated uint32 hand_cards = 6; // 明牌玩家剩余的手牌,客户端刷新使用 } message MsgDDZRoom // 房间信息 { optional uint32 room_state = 1; // 房间当前状态 TDDZState optional uint32 state_time = 2; // 状态运行时间 repeated MsgDDZPlayer player_list = 3; // 玩家信息 optional uint64 action_id = 4; // 当前活动玩家 optional uint64 room_id = 5; // 房间ID optional uint32 game_count = 6; // 当前是该房间的第几局 optional MsgCreatePrivateRoom private_room = 7; // 私房信息; optional MsgDDZUserOutCard last_outcard = 8; // 房间上家牌的信息 optional uint32 wik = 9; // 当前活动玩家的权限 TDDZPlayerWik optional uint32 bottom_cards = 10; // 底牌列表 optional uint64 multiple = 11; // 房间倍数 repeated MsgDiPaiMutiple dipai_multi_list = 12; // 底牌翻倍列表 optional uint32 room_pay_type = 13; // 付费类型 } message MsgDDZRoomShowDown // 结算房间信息 { optional uint32 room_state = 1; // 房间当前状态 TDDZState optional uint32 state_time = 2; // 状态运行时间 repeated MsgDDZPlayer player_list = 3; // 玩家信息 optional uint64 room_id = 4; // 房间ID optional uint32 game_count = 5; // 当前是该房间的第几局 optional uint32 time = 6; // 时间 optional bool game_over = 8; // 是否结束 repeated MsgDDZShowDownEvent event_count = 9; // 结算事件; repeated MsgDDZIntegralCount integral_list = 10; // 积分卷; } // 积分卷 message MsgDDZIntegralCount { optional uint64 roleid = 1; optional uint32 count = 2; } message MsgDDZShowDownEvent // 结算事件; { optional uint32 event_id = 1; optional uint32 count = 2; } ================================================ FILE: tools/protobuf/msg_service.proto ================================================ syntax = "proto2"; package PB; message MsgGameType { optional string Type = 1; optional uint32 Max = 2; optional uint32 Curr = 3; } message MsgServiceInfo { repeated MsgGameType RoomList = 1; optional uint32 MaxPlayer = 2; optional uint32 CurrPlayer = 3; optional uint32 ServiceID = 4; optional string ServiceName = 5; } ================================================ FILE: tools/server/admin/common.php ================================================ assign('iPhone', $iPhone); $tpl->template_dir = NELTOOL_SYSTEMBASE .'/templates/default/'; $tpl->compile_dir = NELTOOL_SYSTEMBASE .'/templates/default_c/'; $tpl->config_dir = NELTOOL_SYSTEMBASE .'/templates/config/'; $tpl->cache_dir = NELTOOL_SYSTEMBASE .'/templates/cache/'; $tpl->caching = false; $tpl->clear_all_cache(); if (NELTOOL_DEBUG) $tpl->debugging = false; if (defined('NELTOOL_NO_USER_NEEDED')) { // this is used for cron jobs that don't need authentifications when running } else { nt_auth_start_session(); $NELTOOL = array( 'POST_VARS' => &$_POST, 'GET_VARS' => &$_GET, 'COOKIE_VARS' => &$_COOKIE, 'SESSION_VARS' => &$_SESSION, 'SERVER_VARS' => &$_SERVER, ); $nel_user = null; $nel_debug = array(); nt_common_add_debug(date("Y-m-d H:i:s",time())); nt_common_add_debug('-- Basic init complete, time to get some work done.'); // login and session process if (isset($NELTOOL['GET_VARS']['mode']) && ($NELTOOL['GET_VARS']['mode'] == 'logout')) { $nel_user = null; nt_auth_stop_session(); nt_common_redirect(''); exit(); } elseif (isset($NELTOOL['SESSION_VARS']['nelid']) && !empty($NELTOOL['SESSION_VARS']['nelid'])) { $nel_user = nt_auth_load_user($NELTOOL['SESSION_VARS']['nelid']); } elseif (isset($NELTOOL['POST_VARS']['nel_login']) && isset($NELTOOL['POST_VARS']['nel_passwd']) && ($NELTOOL['POST_VARS']['action'] == 'login')) { $nel_user = nt_auth_check_login($NELTOOL['POST_VARS']['nel_login'], $NELTOOL['POST_VARS']['nel_passwd']); if ($nel_user) { nt_auth_set_session_var('nelid',$nel_user['user_id']); nt_auth_set_logging_count($nel_user['user_id']); $nel_user['new_login'] = true; } } if (!$nel_user) { nt_auth_load_login(); exit(); } nt_common_add_debug('-- User authentification complete.'); // some site settings if (NELTOOL_DEBUG && ($nel_user['group_level'] == 10)) // need to use the array instead of the value being hardcoded { $tpl->assign('NELTOOL_DEBUG', true); //$nel_debug); } $tpl->assign('nel_script', $NELTOOL['SERVER_VARS']['SCRIPT_NAME']); $tpl->assign('nel_request_uri', basename($NELTOOL['SERVER_VARS']['REQUEST_URI'])); $tpl->assign('nel_tool_title', NELTOOL_SITETITLE); $tpl->assign('nel_web_base_uri', NELTOOL_SITEBASE); $tpl->assign('tool_title', "<unknown>"); $tpl->assign('user_info', $nel_user['user_name'] .' ('. $nel_user['group_name'] .')'); // load user & group applications/domains/shards $nel_user['access'] = array( 'applications' => tool_admin_applications_get_list(), 'user_applications' => tool_admin_users_applications_get_list($nel_user['user_id']), 'user_domains' => tool_admin_users_domains_get_list($nel_user['user_id']), 'user_shards' => tool_admin_users_shards_get_list($nel_user['user_id']), 'group_applications' => tool_admin_groups_applications_get_list($nel_user['user_group_id']), 'group_domains' => tool_admin_groups_domains_get_list($nel_user['user_group_id']), 'group_shards' => tool_admin_groups_shards_get_list($nel_user['user_group_id']), ); $nel_user['access']['domains'] = tool_admin_users_groups_domains_merge(); $nel_user['access']['shards'] = tool_admin_users_groups_shards_merge(); $nel_user['has_lock'] = false; //nt_common_add_debug($nel_user); // load the user application menu $tool_application_list = tool_admin_applications_build_menu_list($nel_user['access']); $tpl->assign('nel_menu', $tool_application_list); $tpl->assign('menu_style', $nel_user['user_menu_style']); $tpl->assign('unknown_menu', 'imgs/icon_unknown.png'); if (isset($nel_user['new_login'])) { $default_user_application_id = 0; if (isset( $nel_user['user_default_application_id']) &&($nel_user['user_default_application_id'] > 0)) { $default_user_application_id = $nel_user['user_default_application_id']; }elseif (isset( $nel_user['group_default_application_id']) &&($nel_user['group_default_application_id'] > 0)) { $default_user_application_id = $nel_user['group_default_application_id']; } if ($default_user_application_id > 0) { nt_common_add_debug("default application : user:". $nel_user['user_default_application_id'] ." group:". $nel_user['group_default_application_id']); $default_user_application_data = tool_admin_applications_get_default($tool_application_list, $default_user_application_id); nt_common_redirect($default_user_application_data['application_uri']); exit(); } } $nel_tool_extra_css = ''; if (BG_IMG !== null) { $nel_tool_extra_css .= "\n"; } $tpl->assign('nel_tool_extra_css', $nel_tool_extra_css); $tpl->assign('system_time', time()); nt_common_add_debug('-- Common init. complete.'); } ?> ================================================ FILE: tools/server/admin/config.php ================================================ 0, 'level_name' => 'Normal'), array( 'level_id' => 10, 'level_name' => 'Administrator'), ); $restart_notification_emails = array('li9chuan@qq.com'); ?> ================================================ FILE: tools/server/admin/crons/cron_harddisk.php ================================================ '. print_r($domain_data, true) .''; $adminService = new MyAdminService; if (@$adminService->connect($domain_data['domain_as_host'], $domain_data['domain_as_port'], $res) !== false) { $status = $adminService->getStates(); $domainServices = tool_main_parse_status($status); $aesList = tool_main_get_aes_from_status($domainServices); //echo '
'. print_r($aesList, true) .'
'; if (sizeof($aesList)) { reset($aesList); foreach($aesList as $service) { $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { // error } } $aes_df_result = $tpl->get_template_vars('tool_execute_result'); $tpl->clear_assign('tool_execute_result'); if (defined('NELTOOL_NO_USER_NEEDED') && defined('NELTOOL_CRON_DEBUG')) echo '
'. print_r($aes_df_result, true) .'
'; tool_main_update_hd_data_for_domain($domain_data['domain_id'], $aes_df_result); } unset($adminService); } } } } if (defined('NELTOOL_CRON_DEBUG')) echo "checked ". sizeof($aesList) ." servers!\n"; if (defined('NELTOOL_CRON_DEBUG')) { if ($fp = fopen("./logs/checkdisk_". date("YmdHis", time()) .".log", "w")) { fputs($fp, ob_get_contents()); fclose($fp); } } ob_end_clean(); ?> ================================================ FILE: tools/server/admin/crons/cron_harddisk.sh ================================================ #!/bin/sh cd /home/atrium-admin/public_html/crons /usr/bin/php4 cron_harddisk.php cd - ================================================ FILE: tools/server/admin/crons/index.html ================================================ ================================================ FILE: tools/server/admin/docs/shard_restart/Filelist.xml ================================================ ================================================ FILE: tools/server/admin/docs/shard_restart/H38.css ================================================ BODY {background:#FFFFFF} .menuItem { font-family:sans-serif; font-size:small; width:220;padding-left:20; background-color:menu; color:black } .highlightItem { font-family:sans-serif; font-size:small; width:220; padding-left:20; background-Color:highlight; color:white; } .navBar { background-Color:buttonface; } .oldNavBar { background-Color:black; } .pageView { background-Color:white; } .propViewer { background-Color:white; color: black; font-family: Verdana; font-style: italic; font-weight: bold; font-size: medium; text-align: center; } .propViewerTABLE { background-Color: black; font-weight: medium; border-width: 1pt; border-color: black; } .propViewerTHEAD { background-Color: rgb(230,230,230); color: black; font-family: Verdana; font-style: italic; font-weight: medium; font-size: small; } .propViewerHeaderSep { background-Color: black; height: 0pt; } .propViewerLines { background-Color: black; height: 2pt; } .propViewerTD { font-family: Verdana; color: black; font-size: x-small; font-style: normal; align: center; } .propViewerEvenRow { background-Color: rgb(253,254,238); } .propViewerOddRow { background-Color: rgb(254,254,247); } .clTab { cursor:hand; background:buttonface; font: 0.7em Arial; padding-left:3px; padding-right:3px; text-align:center; } .clBorder { background:windowframe; font:1pt; } .clScroll { font:8pt Courier New; color:threeddarkshadow; cursor:default; line-height:10pt; } .clScroll2 { font:10pt Arial; color:threeddarkshadow; cursor:default; line-height:11pt; } ================================================ FILE: tools/server/admin/docs/shard_restart/H70_2.htm ================================================ Restarting Ryzom Game Shards <body> <p>This page requires a browser that supports frames, your's doesn't.</p> </body> ================================================ FILE: tools/server/admin/docs/shard_restart/HOWTO_Restarting_Ryzom_Game_Shards.htm ================================================ ================================================ FILE: tools/server/admin/docs/shard_restart/Hd36.xml ================================================ Drawing1 1. Login to the Ryzom Admin tool. 3.346456692913386 11.318897637795276 Click the 'Main' button at the top right of the screen to get a view something like this: 3.346456692913386 10.925196850393698 3.444881889763779 8.471653543307085 2. Select the shard that you want to restart 3.346456692913386 11.318897637795274 3.343110236220473 8.865354330708659 0.590551181102362 9.566929133858269 3.809004357293814 9.571398391822701 3. Click the 'lock shard' button to take control of the shard that you've selected 4.227356009930337 11.111767279090113 3.343110236220473 8.865354330708659 The pink 'restart sequence' button will appear 3.354717958339129 6.200787401574803 3.349803149606298 3.747244094488188 1.722440944881890 9.999999999999998 4.330657900600900 10.004469257964431 2.283464566929134 4.881889763779529 4.645618530522161 4.886359021743961 4. Click on the 'restart sequence' button 3.346456692913385 11.515748031496063 3.343110236220473 9.055118110236219 You will be prompted to continue: 3.346456692913386 6.387357830271215 2.449803149606299 5.487795275590552 The restart sequence interface will appear below the shard services. It should have the following appearance: 5.216535433070866 4.429133858267717 3.349803149606297 1.961417322834646 2.283464566929134 10.196850393700787 4.645618530522159 10.201319651665219 3.661417322834646 0.866141732283465 6.545224829734759 0.791870832767583 5. Click on the 'Stop the Shard' button 3.346456692913385 11.391951006124234 3.343110236220473 9.055118110236219 You will be prompted to continue 3.344887613645888 6.397637795275591 1.950590551181103 5.487795275590552 WARNING: Pressing this button has a direct effect on the game. Don't press this button unless you are sure of what you're doing. 3.346456692913385 4.330708661417323 3.011811023622047 8.759842519685039 5.492075223435546 8.764311777649471 Pressing OK here will broadcast a message to all players who are logged in telling them that shard will be shut down and will prevent new players from logging in. 3.838582677165354 3.740157480314961 6.215551181102361 8.671259842519685 6.539640283161631 8.517154135620743 Clicking the ‘Cancel’ Button will close the ‘Restart Interface’ without any effect on the shard 8.169291338582674 8.169291338582676 During this time messages are broadcast to the players warning them that the game shard is going to be stopped and that they should log out 6.200787401574803 11.122047244094491 This sequence starts automatically when the 'Step 1' timer reaches zero. During this time persistent data is saved and the game services shut down cleanly 5.413385826771653 7.677165354330715 When the 'Step 2' timer reaches zero, the 'Running State' column should read 'stopped' for all services. 4.291338582677165 4.232283464566931 3.346456692913385 8.654330708661423 3.021653543307086 9.874803149606306 3.444881889763779 5.121456692913391 3.441535433070867 1.835236220472441 6. Wait for the shutdown sequence to begin 4.133858267716535 11.515748031496065 7. Wait for the shutdown sequence to go through. 6.003937007874015 8.169291338582683 If this is not the case then the developers should be contacted and you should click the ‘Give Up, Shard cannot be started’ button. 5.452755905511811 -0.688976377952756 3.349803149606298 -2.319291338582677 5.841535433070866 -2.834645669291338 6.559988609262317 -2.830176411326904 6.235236220472441 9.881889763779526 6.539640283161631 9.716890432038076 5.511760262805623 9.879272407570738 Clicking the ‘Cancel’ Button will abort the shutdown sequence and allow players to login to the shard 8.169291338582676 9.350393700787400 8. Start the start sequence by pressing the '1/4 - Start Low Level' button. 4.232283464566929 11.278433945756781 The services will start launching 4.232283464566929 7.972440944881889 3.349803149606299 9.688582677165352 9. Click on the shard name every few seconds or so to update the view until the 'ts', 'ms' and 'rns' services are all running. 7.244094488188976 2.854330708661416 3.343110236220473 5.518897637795275 2.175196850393701 9.389763779527558 4.684988609262318 9.394233037491990 1.279527559055118 4.694881889763780 4.104279947844995 4.886359021743958 1.269685039370079 3.799212598425196 4.104279947844995 3.803681856389628 1.269685039370079 4.330708661417321 4.104279947844995 4.335177919381754 The 'running state' and 'state' columns for these services should both read 'online' and the 'Report' column should read '01s' This step should only take a few seconds 6.240157480314960 2.362204724409448 If the states don't update correctly then the developers should be contacted and you should click the ‘Give Up, Shard cannot be started’ button. 6.240157480314960 1.870078740157480 3.349803149606299 0.239763779527558 5.841535433070867 -0.275590551181102 6.559988609262317 -0.271121293216669 10. Click on the '2/4 - Start Mid Level' button to continue the start sequence 4.133858267716535 11.278433945756781 3.349803149606299 9.688582677165353 The main game services will be started... they will take a minute or two to initialise so patience is required. 5.708661417322834 8.169291338582678 11. Click on the shard name every few seconds or so to update the view until the 'egs', 'ios' and 'gpms' services are all running. 7.677165354330708 7.578740157480314 2.155511811023622 9.251968503937007 4.675146089577279 9.256437761901440 The 'running state' and 'state' columns for these services should both read 'online' and the 'Report' column should read '01s' This step will generally take one or two minutes but may be a little longer. It should not exceed 5 minutes. 7.775590551181102 7.086614173228346 3.444881889763779 4.520472440944881 If the states don't update correctly then the developers should be contacted and you should click the ‘Give Up, Shard cannot be started’ button. 6.240157480314961 2.066929133858268 3.448228346456693 0.436614173228346 12. Click on the '3/4 - Start High Level' button to continue the start sequence 4.822834645669291 11.318897637795274 3.343110236220473 9.688582677165353 The AI services will be started... they will take a minute or so to initialise 4.960629921259843 7.972440944881889 13. Click on the shard name every few seconds or so to update the view until the 'ais' services are all running. 6.062992125984252 2.854330708661417 3.343110236220472 5.518897637795275 2.155511811023622 9.114173228346456 4.675146089577279 9.118642486310888 1.427165354330709 6.131889763779526 4.281158906272716 6.110971265772092 The 'running state' and 'state' columns for these services should both read 'online' and the 'Report' column should read '01s' This step should take roughly one minute. 6.496062992125983 2.362204724409448 If the states don't update correctly then the developers should be contacted and you should click the ‘Give Up, Shard cannot be started’ button. 6.240157480314960 1.870078740157481 3.448228346456692 0.239763779527558 14. Click on the '4/4 - Start Top Level' button to continue the start sequence 5.669291338582677 11.318897637795276 3.343110236220473 9.688582677165353 The Front end communication services will be started 4.232283464566929 7.972440944881889 15. Click on the shard name every few seconds or so to update the view until ALL services are running. 6.099628492123085 7.381889763779527 2.145669291338582 8.956692913385828 4.675146089577279 8.961162171350260 The 'running state' and 'state' columns for ALL services should both read 'online' and the 'Report' column should read '01s' NOTE: The RWS service state will read ‘open’ when the other services read ‘online’. This step should only take a few seconds. 5.416119539372975 6.786526684164478 If the states don't update correctly then the developers should be contacted and you should click the ‘Give Up, Shard cannot be started’ button. 6.240157480314961 1.476377952755906 3.448228346456693 -0.153937007874017 3.444881889763779 4.047047244094488 16. Click on the 'Hand Over to Customer Support' button to finish the start sequence 4.566929133858268 11.318897637795276 3.343110236220473 9.688582677165353 The shard is now open in restricted mode - the customer support team can log in and check that everything is ok before the shard opens The customer support volunteers can now open the shard to the players when they are ready 4.035433070866141 7.785870516185478 17. Click on the 'Done' button to exit the 'restart sequence' interface 4.232283464566930 6.988188976377953 3.349803149606299 4.591141732283464 2.942913385826772 8.818897637795274 5.472390184065468 8.823366895759707 6.240157480314961 3.011811023622048 6.564909869104838 3.016280281586480 18. Click on the 'Unlock Shard' button to finish 3.346456692913386 11.278433945756781 3.349803149606299 8.921850393700787 You should be back to a view that looks something like this: 3.346456692913386 6.397637795275590 3.349803149606299 4.000590551181102 1.771653543307087 10.019685039370080 4.379870499026097 10.004469257964434 ================================================ FILE: tools/server/admin/docs/shard_restart/Hf69.htm ================================================ Restarting Ryzom Game Shards ================================================ FILE: tools/server/admin/docs/shard_restart/Hg39_1.htm ================================================ Restarting Ryzom Game Shards
================================================ FILE: tools/server/admin/docs/shard_restart/Hg41_2.htm ================================================ Restarting Ryzom Game Shards
================================================ FILE: tools/server/admin/docs/shard_restart/Hg43_3.htm ================================================ Restarting Ryzom Game Shards
================================================ FILE: tools/server/admin/docs/shard_restart/Hg45_4.htm ================================================ Restarting Ryzom Game Shards
================================================ FILE: tools/server/admin/docs/shard_restart/Hg47_5.htm ================================================ Restarting Ryzom Game Shards
================================================ FILE: tools/server/admin/docs/shard_restart/Hg49_6.htm ================================================ Restarting Ryzom Game Shards
================================================ FILE: tools/server/admin/docs/shard_restart/Hg51_7.htm ================================================ Restarting Ryzom Game Shards
================================================ FILE: tools/server/admin/docs/shard_restart/Hg53_8.htm ================================================ Restarting Ryzom Game Shards
================================================ FILE: tools/server/admin/docs/shard_restart/Hg55_9.htm ================================================ Restarting Ryzom Game Shards
================================================ FILE: tools/server/admin/docs/shard_restart/Hg57_10.htm ================================================ Restarting Ryzom Game Shards
================================================ FILE: tools/server/admin/docs/shard_restart/Hg59_11.htm ================================================ Restarting Ryzom Game Shards
================================================ FILE: tools/server/admin/docs/shard_restart/Hg61_12.htm ================================================ Restarting Ryzom Game Shards
================================================ FILE: tools/server/admin/docs/shard_restart/Hn68.htm ================================================ ================================================ FILE: tools/server/admin/docs/shard_restart/Hu37.js ================================================ var g_theApp = parent.g_theApp; var layerRef=""; var layerStyleRef = ""; var styleSwitch = ""; var FILEProtocol = "file://"; var HTTPProtocol = "http://"; if (navigator.appName == "Netscape") { layerStyleRef="layer."; layerRef="document.layers"; styleSwitch=""; } else { layerStyleRef="layer.style."; layerRef="document.all"; styleSwitch=".style"; } function CImage(id) { this.id = id; if ( g_theApp.isIE ) this.image = eval('document.images.' + this.id); else this.image = eval('document.images["' + this.id + '"]'); this.put_Source = SetSource; this.get_Source = GetSource; this.put_Title = put_Title; this.get_Title = get_Title; } function SetSource(newsrc) { if ( this.image ) this.image.src = newsrc; } function GetSource() { if ( this.image ) return this.image.src; } function put_Title(txt) { if ( this.image && g_theApp.isIE ) this.image.title = txt; } function get_Title(txt) { if ( this.image && g_theApp.isIE ) return this.image.title; } function CDiv(id, doc) { this.id = id; this.layer = FindLayer(id, doc); this.Show = Show; this.Hide = Hide; this.IsHidden = IsHidden; this.put_innerHTML = put_innerHTML; } function Show() { if ( this.layer ) eval('this.' + layerStyleRef + 'visibility' + '= "visible"'); } function Hide() { if ( this.layer ) eval('this.' + layerStyleRef + 'visibility' + '= "hidden"'); } function IsHidden() { if ( this.layer && (-1 != eval('this.' + layerStyleRef + 'visibility').indexOf("hid")) ) return true; return false; } function put_innerHTML(txt) { if ( this.layer ) { if ( g_theApp.isIE ) this.layer.innerHTML = txt; else { this.layer.document.writeln(txt); this.layer.document.close(); } } } function SetZoomControl(f) { if ( !parent.g_NavBarLoaded ) return; var formZoom = FindForm("zoomForm", parent.frmZoomBox.document); if (formZoom != null) { s = formZoom.zoomFactor; if ( -1 != f ) f *= 100; for ( i = 0 ; i < s.options.length ; i++ ) { if ( s.options[i].value == f ) { s.selectedIndex = i; break; } } } } function zoom_onchange(val) { if ( g_theApp.ActiveViewMgr ) { if ( g_theApp.ActiveViewMgr.ZoomIsPresent == true) { g_theApp.ActiveViewMgr.put_Zoom(parseInt(val)); } } } function CViewMgr() { //Set all zoom functions to null assuming the addons related //to the data will provide their own functions. this.onResize = null; this.put_Zoom = null; this.get_Zoom = null; this.ApplyZoom = null; //General functions. this.onLoad = ViewMgrOnLoad; this.put_Location = ViewMgrDefaultFind; //MUST BE SET FOR FIND FEATURE this.ZoomIsPresent = false; } function ViewMgrOnLoad() { this.id = "ConvertedImage"; this.zoomFactor = -1; this.zoomLast = -1; this.origWH = 1; this.origWidth = 100; if ( g_theApp.isIE ) { p = document.all; this.s = document.all(this.id).style; if ( this.s ) { this.s.position = "absolute"; this.origWidth = this.s.pixelWidth; this.origWH = this.s.pixelWidth / this.s.pixelHeight; } } else { this.s = null; } SetZoomControl(this.zoomFactor); } function ViewMgrDefaultFind() { return; } function handleResize() { location.reload(); return false; } function IsFrame(frameName) { return window.name == frameName; } function UpdNavBar() { if (g_theApp.PageUpdateFunc != null) g_theApp.PageUpdateFunc (); if ( parent.g_NavBarLoaded ) //parent.frmZoomBox.UpdateNavBar(); parent.frmNavBar.UpdateNavBar(); } function UpdZoom() { if (g_theApp.ZoomResetFunc != null) g_theApp.ZoomResetFunc (); } function UpdCPViewer() { if (g_theApp.CPResetFunc != null) g_theApp.CPResetFunc (); } function UpdTitleBar() { if ( parent.g_TitleBarLoaded ) parent.frmTitleBar.UpdateTitleBar(); } function GetCurPageNum() { return g_theApp.CurrentPageIX; } function GetNumPages() { return g_theApp.FileList.length; } function GoToNextPage() { GoToPage(g_theApp.CurrentPageIX + 1); } function GoToPrevPage() { GoToPage(g_theApp.CurrentPageIX - 1); } function GoToFirstPage() { GoToPage(0); } function GoToLastPage() { GoToPage(gDocTable.length - 1) }; function GoToPage(ix) { var entry; if ( (g_theApp != null) && (ix != g_theApp.CurrentPageIX) && (null != (entry = g_theApp.FileList[ix])) ) { var newPage; if (SupportsPriOutputType ()) { newPage = entry.PriImage; if ( "" == newPage ) newPage = newPage = entry.SecImage; } else newPage = entry.SecImage; if (frames["frmPageView"] != null) { frames["frmPageView"].window.location = newPage; } else { parent.frmPageView.location = newPage; } PageUpdated (ix); } } function PageUpdated (ix) { g_theApp.CurrentPageIX = ix; NotifyPageSyncs(ix); } function GoToPageByName(pageName) { var pageIndex = PageIndexFromName (pageName); if (pageIndex >= 0) { GoToPage (pageIndex); } } function GoToPageByID(pageID) { var pageIndex = PageIndexFromID (pageID); if (pageIndex >= 0) { GoToPage (pageIndex); } } function PageIndexFromName (pageName) { if (g_theApp != null) { var entry; var count; var fileEntry; var bFoundEntry = false; for (count = 0; count < g_theApp.FileList.length && !bFoundEntry; count++) { fileEntry = g_theApp.FileList[count]; if (pageName == fileEntry.PageName) { return count; } } } return -1; } function PageIndexFromID (pageID) { if (g_theApp != null) { var entry; var count; var fileEntry; var bFoundEntry = false; for (count = 0; count < g_theApp.FileList.length && !bFoundEntry; count++) { fileEntry = g_theApp.FileList[count]; if (pageID == fileEntry.PageID) { return count; } } } return -1; } function ZoomAvailable() { if (SupportsPriOutputType () && g_theApp.FileList[0].PriImage != "") { return g_theApp.PriFormatSupportsZoom; } else { return (g_theApp.SecFormatSupportsZoom && g_theApp.FileList[0].SecImage != ""); } } function NotifyPageSyncs(ix) { UpdNavBar(); UpdTitleBar(); UpdZoom(); UpdCPViewer(); } function HasPrevSld() { return (GetCurPageNum() > 0); } function HasNextSld() { return ((GetCurPageNum() + 1) < GetNumPages()); } function CancelDrag() { window.event.cancelBubble=true; window.event.returnValue=false } function html_escape(txt) { var result = ""; for ( var i = 0 ; i < txt.length ; i++ ) { if ( txt.charAt(i) == '&' ) result += "&"; else if ( txt.charAt(i) == '<' ) result += "<"; else if ( txt.charAt(i) == '>' ) result += ">"; else result += txt.charAt(i); } return result; } function FindForm(form, doc) { if ( g_theApp.isIE ) return doc.forms[form]; else if ( null != doc ) { if ( null != doc.forms ) { for ( i = 0 ; i < doc.forms.length ; i++ ) { if ( form == doc.forms[i].name ) return doc.forms[i]; } } if ( null != doc.layers ) { for ( i = 0 ; i < doc.layers.length ; i++ ) { result = FindForm(form, doc.layers[i].document); if ( null != result ) return result; } } } return null; } function FindLayer(layer, doc) { var result = null; if ( g_theApp.isIE ) return doc.all(layer); else if ( (null != doc) && (null != doc.layers) ) { for ( i = 0 ; i < doc.layers.length ; i++ ) { result = doc.layers[i]; if ( layer == result.name ) return result; result = FindLayer(layer, result.document); if ( null != result ) return result; } } return null; } function Unquote (str) { var nStartIndex = 0; var nEndIndex = str.length; if (str.charAt (0) == '"') { nStartIndex = 1; } if (str.charAt (nEndIndex - 1) == '"') { nEndIndex -= 1; } return str.substring (nStartIndex, nEndIndex); } function ConvertXorYCoordinate(PosValue, OldMin, OldMax, NewMin, NewMax, MapBackwards) { //This is a simple conversion routine that changes from one system to another. var OldMid = (OldMax - OldMin) / 2; var NewMid = (NewMax - NewMin) / 2; var ConvertResult = 1 * PosValue; ConvertResult = ConvertResult - (OldMin + OldMid); ConvertResult = ConvertResult / OldMid; if(MapBackwards != 0) { ConvertResult = 0 - ConvertResult; } ConvertResult = ConvertResult * NewMid; ConvertResult = ConvertResult + (NewMin + NewMid); return ConvertResult; } function GoToURL (defURL) { if ((g_theApp == null) || !SupportsXML () || (g_theApp.objParser == null)) { if (defURL.indexOf ("javascript:") == 0) { // This is actually a function call, not a URL. eval (defURL); return; } parent.location = defURL; } } var el; function showMenu(pageID, shapeID) { if (SupportsXML ()) { var shapeXML = FindShapeXML (pageID, shapeID); if (shapeXML != null) { CreateHLMenu (shapeXML); //ContextElement=window.event.srcElement; parent.frmPageView.menu1.style.leftPos += 10; parent.frmPageView.menu1.style.posLeft = event.clientX; parent.frmPageView.menu1.style.posTop = event.clientY; parent.frmPageView.menu1.style.display = ""; var clientWidth = event.srcElement.document.body.clientWidth; var clientHeight = event.srcElement.document.body.clientHeight; var menuWidth = parseInt (parent.frmPageView.menu1.style.width); var margin = 10; // Figure out where to place the menu (X). var menuX = event.clientX; if (event.clientX + parent.frmPageView.menu1.clientWidth > clientWidth) { menuX = clientWidth - parent.frmPageView.menu1.clientWidth - margin; if (menuX < margin) { menuX = margin; } } // Figure out where to place the menu (Y). var menuY = event.clientY; if (event.clientY + parent.frmPageView.menu1.clientHeight > clientHeight) { menuY = clientHeight - parent.frmPageView.menu1.clientHeight - margin; if (menuY < margin) { menuY = margin; } } parent.frmPageView.menu1.style.posLeft = menuX; parent.frmPageView.menu1.style.posTop = menuY; parent.frmPageView.menu1.setCapture(); event.cancelBubble = true; } } } function toggleMenu() { el=event.srcElement; if (el.className=="menuItem") { el.className="highlightItem"; } else if (el.className=="highlightItem") { el.className="menuItem"; } } function clickMenu() { if (parent.frmPageView.menu1.style.display != "none") { parent.frmPageView.menu1.releaseCapture(); parent.frmPageView.menu1.style.display="none"; el=event.srcElement; if (el.doFunction != null) { eval(el.doFunction); } } } function CreateHLMenu (shapeNode) { // Create the HTML string. var strHLMenuHTML = ""; if (shapeNode != null) { // Look up all the Hyperlink nodes. var hlColl = shapeNode.selectNodes ("Scratch/B/SolutionXML/HLURL:Hyperlinks/HLURL:Hyperlink"); // Walk the list of Hyperlink nodes to generate the menu. var hlCount = hlColl.length; for (var count = 0; count < hlCount; count++) { var strDoFunction = ""; var strDesc = ""; var strAddress = ""; var hlAddress = hlColl.item(count).selectSingleNode("HLURL:Address/textnode()"); if (hlAddress != null && hlAddress.text.length > 0 && IsValidAddress (hlAddress.text)) { strDoFunction = "'parent.location.href="; // Get the absolute URL. var absoluteURL = hlColl.item(count).selectSingleNode("HLURL:AbsoluteURL/textnode()"); if (g_theApp.DocHasBaseHL && absoluteURL != null && absoluteURL.text.length > 0) { // Use the absolute URL for our hyperlink. strAddress = absoluteURL.text; } else { // Just use the address field. strAddress = hlAddress.text; } strDoFunction += '"' + EscapePath (strAddress) + '"' + ";'"; // Now try to get the description field. If empty, use the address as the description. hlDesc = hlColl.item(count).selectSingleNode("HLURL:Description/textnode()"); if (hlDesc != null && hlDesc.text.length > 0) { strDesc = hlDesc.text; } else { strDesc = strAddress; } } else // Address is not present, assume it's a link into a different page in this document. { hlAddress = hlColl.item(count).selectSingleNode("HLURL:SubAddress/textnode()"); if (hlAddress != null && hlAddress.text.length > 0) { strAddress = hlAddress.text; // Strip off the shape id (if present). var pageShapeSep = strAddress.lastIndexOf ('/'); if (pageShapeSep > 0) { strAddress = strAddress.substring (0, pageShapeSep); } strAddress = unescape(strAddress); var pageIndex = PageIndexFromName (strAddress); strDoFunction = "'GoToPage (" + pageIndex + ");'"; // Just set the description to the page name as well. strDesc = strAddress; } } if (strDoFunction.length > 0 && strDesc.length > 0) { strHLMenuHTML += ""; } } } parent.frmPageView.menu1.innerHTML = strHLMenuHTML; } function IsValidAddress (strAddress) { var ret = false; if (strAddress != null && strAddress.length > 0) { var strFullPath = g_theApp.VisDocPath + g_theApp.VisDocName; if (strAddress != strFullPath && strAddress != g_theApp.VisDocName) { // Points to something other than this file, go ahead // and consider it valid. ret = true; } } return ret; } function FindShapeXML (pageID, shapeID) { var shapeObj = null; if (g_theApp != null && g_theApp.objParser != null) { // Get the Pages collection. var pagesObj = g_theApp.objParser.selectSingleNode("VisioDocument/Pages"); if(!pagesObj) { return null; } // Get the correct page. var pageQuerryString = './/Page[@ID = "' + pageID + '"]'; var pageObj = pagesObj.selectSingleNode(pageQuerryString); if(!pageObj) { return null; } // Get the correct shape. var shapeQuerryString = './/Shape[@ID = "' + shapeID + '"]'; shapeObj = pageObj.selectSingleNode(shapeQuerryString); } return shapeObj; } function UpdateProps(pageID, shapeID) { // Check to see if we should ignore this event. if (window.event != null && window.event.ctrlKey) { // If the control key is down, do nothing! return; } if (SupportsXML ()) { var shape = FindShapeXML (pageID, shapeID); if (g_theApp.custPropEntryPoint != null) g_theApp.custPropEntryPoint (shape); } } function SupportsXML () { return (g_theApp != null && g_theApp.isIE && g_theApp.verIE >= 5.0); } function SupportsPriOutputType () { if (g_theApp.isIE) // IE { return ((g_theApp.verIE >= g_theApp.PriFormatMinIE) && (g_theApp.PriFormatMinIE > 0.0)); } else if (g_theApp.isNav) // Nav { return ((g_theApp.verNav >= g_theApp.PriFormatMinNav) && (g_theApp.PriFormatMinNav > 0.0)); } // Unsupported browser. return false; } function EscapePath (strPath) { var strResult = ""; for ( var i = 0 ; i < strPath.length ; i++ ) { if ( strPath.charAt(i) == '\\' ) { strResult += "\\\\"; } else { strResult += strPath.charAt(i); } } return strResult; } ================================================ FILE: tools/server/admin/docs/shard_restart/Hz63.htm ================================================ ================================================ FILE: tools/server/admin/functions_auth.php ================================================ sql_query($sql); } function nt_auth_load_user($nelid) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_USER_TABLE ." LEFT JOIN ". NELDB_GROUP_TABLE ." ON (user_group_id=group_id) WHERE user_id=". $nelid; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function nt_auth_get_group_name($group_id) { global $db; $sql = "SELECT user_name FROM ". NELDB_USER_TABLE ." WHERE user_id=". $group_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $row = $db->sql_fetchrow($result); return $row['user_name']; } } return null; } function nt_auth_check_login($user,$passwd) { global $db; $data = null; $user = trim($user); $passwd = md5(trim($passwd)); $sql = "SELECT * FROM ". NELDB_USER_TABLE ." LEFT JOIN ". NELDB_GROUP_TABLE ." ON (user_group_id=group_id) WHERE user_name='". $user ."' AND user_password='". $passwd ."' AND user_active=1 AND group_active=1"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function nt_auth_load_login() { global $tpl; $tpl->assign('tool_login_title','Login'); $tpl->display('index_login.tpl'); } function nt_auth_start_session() { session_name(NELTOOL_SESSIONID); session_cache_limiter('nocache'); session_start(); header("Expires: Mon, 01 May 2000 06:00:00 GMT"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); } function nt_auth_stop_session() { global $NELTOOL; foreach($NELTOOL['SESSION_VARS'] as $key => $val) { unset($NELTOOL['SESSION_VARS'][$key]); } } function nt_auth_set_session_var($name,$value) { global $NELTOOL; $NELTOOL['SESSION_VARS'][$name] = $value; } function nt_auth_get_session_var($name) { global $NELTOOL; if (isset($NELTOOL['SESSION_VARS'][$name])) return $NELTOOL['SESSION_VARS'][$name]; return null; } function nt_auth_unset_session_var($name) { global $NELTOOL; unset($NELTOOL['SESSION_VARS'][$name]); } ?> ================================================ FILE: tools/server/admin/functions_common.php ================================================ sql_query($sql); return true; } if (!function_exists('array_combine')) { function array_combine( $keys, $vals ) { $keys = array_values( (array) $keys ); $vals = array_values( (array) $vals ); $n = max( count( $keys ), count( $vals ) ); $r = array(); for( $i=0; $i<$n; $i++ ) { $r[ $keys[ $i ] ] = $vals[ $i ]; } return $r; } } if (!function_exists('array_chunk')) { function array_chunk($input,$size,$preserve_keys=false) { @reset($input); $i = $j = 0; while (@list($key,$value) = @each($input)) { if( !( isset( $chunks[$i] ) ) ) { $chunks[$i] = array(); } if( count( $chunks[$i] ) < $size ) { if( $preserve_keys ) { $chunks[$i][$key] = $value; $j++; } else { $chunks[$i][] = $value; } } else { $i++; if( $preserve_keys ) { $chunks[$i][$key] = $value; $j++; } else { $j = 0; $chunks[$i][$j] = $value; } } } return $chunks; } } function array_natsort_list($array) { // for all arguments without the first starting at end of list for ($i=func_num_args();$i>1;$i--) { // get column to sort by $sort_by = func_get_arg($i-1); // clear arrays $new_array = array(); $temporary_array = array(); // walk through original array foreach($array as $original_key => $original_value) { // and save only values $temporary_array[] = $original_value[$sort_by]; } // sort array on values natsort($temporary_array); // delete double values $temporary_array = array_unique($temporary_array); // walk through temporary array foreach($temporary_array as $temporary_value) { // walk through original array foreach($array as $original_key => $original_value) { // and search for entries having the right value if($temporary_value == $original_value[$sort_by]) { // save in new array $new_array[$original_key] = $original_value; } } } // update original array $array = $new_array; } return $array; } function nt_common_assert( $script, $line, $message ) { nt_common_add_debug('ASSERT ('. $script .':'. $line .') : '. ereg_replace( '^.*//\*', '', $message )); //exit; } function nt_log($data) { global $db; global $nel_user; $log_user_name = $nel_user['user_name']; $log_date = time(); $log_data = addslashes(trim($data)); $sql = "INSERT INTO ". NELDB_LOG_TABLE ." (`logs_user_name`,`logs_date`,`logs_data`) VALUES ('". $log_user_name ."','". $log_date ."','". $log_data ."')"; $db->sql_query($sql); } function nt_sleep($delay) { if ($delay > 0) { sleep($delay); } } function nt_email($subject,$message,$emails=null) { if ($message !== '' && $subject !== '') { if ($emails === null) { $emails = 'vl@ryzom.com'; } elseif (is_array($emails)) { $emails = implode(', ', $emails); } $headers = "From: vl@ryzom.com\r\nReply-To: vl@ryzom.com\r\nX-Mailer: Shard Admin Tool\r\n"; mail($emails, $subject, $message, $headers); } } ?> ================================================ FILE: tools/server/admin/functions_mysql.php ================================================ persistency = $persistency; $this->user = $sqluser; $this->password = $sqlpassword; $this->server = $sqlserver; $this->dbname = $database; if($this->persistency) { $this->db_connect_id = mysql_pconnect($this->server, $this->user, $this->password); } else { $this->db_connect_id = mysql_connect($this->server, $this->user, $this->password); } if($this->db_connect_id) { if($database != "") { $this->dbname = $database; $dbselect = mysql_select_db($this->dbname); if(!$dbselect) { mysql_close($this->db_connect_id); $this->db_connect_id = $dbselect; } } return $this->db_connect_id; } else { echo "Connection to mySQL failed!"; exit; } } // // Other base methods // function sql_close() { if($this->db_connect_id) { if($this->query_result) { @mysql_free_result($this->query_result); } $result = mysql_close($this->db_connect_id); return $result; } else { return false; } } // // Base query method // function sql_query($query = "", $transaction = FALSE) { // Remove any pre-existing queries unset($this->query_result); if($query != "") { nt_common_add_debug($query); $this->num_queries++; $this->query_result = mysql_query($query, $this->db_connect_id); } if($this->query_result) { unset($this->row[$this->query_result]); unset($this->rowset[$this->query_result]); return $this->query_result; } else { return ( $transaction == 'END_TRANSACTION' ) ? true : false; } } function sql_select_db($dbname) { if($this->db_connect_id) { $result = mysql_select_db($dbname, $this->db_connect_id); return $result; } return false; } function sql_reselect_db() { if($this->db_connect_id) { $result = mysql_select_db($this->dbname, $this->db_connect_id); return $result; } return false; } // // Other query methods // function sql_numrows($query_id = 0) { if(!$query_id) { $query_id = $this->query_result; } if($query_id) { $result = mysql_num_rows($query_id); return $result; } else { return false; } } function sql_affectedrows() { if($this->db_connect_id) { $result = mysql_affected_rows($this->db_connect_id); return $result; } else { return false; } } function sql_numfields($query_id = 0) { if(!$query_id) { $query_id = $this->query_result; } if($query_id) { $result = mysql_num_fields($query_id); return $result; } else { return false; } } function sql_fieldname($offset, $query_id = 0) { if(!$query_id) { $query_id = $this->query_result; } if($query_id) { $result = mysql_field_name($query_id, $offset); return $result; } else { return false; } } function sql_fieldtype($offset, $query_id = 0) { if(!$query_id) { $query_id = $this->query_result; } if($query_id) { $result = mysql_field_type($query_id, $offset); return $result; } else { return false; } } function sql_fetchrow($query_id = 0) { if(!$query_id) { $query_id = $this->query_result; } if($query_id) { $this->row[$query_id] = mysql_fetch_array($query_id); return $this->row[$query_id]; } else { return false; } } function sql_fetchrowset($query_id = 0) { if(!$query_id) { $query_id = $this->query_result; } if($query_id) { unset($this->rowset[$query_id]); unset($this->row[$query_id]); while($this->rowset[$query_id] = mysql_fetch_array($query_id)) { $result[] = $this->rowset[$query_id]; } return $result; } else { return false; } } function sql_fetchfield($field, $rownum = -1, $query_id = 0) { if(!$query_id) { $query_id = $this->query_result; } if($query_id) { if($rownum > -1) { $result = mysql_result($query_id, $rownum, $field); } else { if(empty($this->row[$query_id]) && empty($this->rowset[$query_id])) { if($this->sql_fetchrow()) { $result = $this->row[$query_id][$field]; } } else { if($this->rowset[$query_id]) { $result = $this->rowset[$query_id][$field]; } else if($this->row[$query_id]) { $result = $this->row[$query_id][$field]; } } } return $result; } else { return false; } } function sql_rowseek($rownum, $query_id = 0){ if(!$query_id) { $query_id = $this->query_result; } if($query_id) { $result = mysql_data_seek($query_id, $rownum); return $result; } else { return false; } } function sql_nextid(){ if($this->db_connect_id) { $result = mysql_insert_id($this->db_connect_id); return $result; } else { return false; } } function sql_freeresult($query_id = 0){ if(!$query_id) { $query_id = $this->query_result; } if ( $query_id ) { unset($this->row[$query_id]); unset($this->rowset[$query_id]); @mysql_free_result($query_id); return true; } else { return false; } } function sql_error($query_id = 0) { $result["message"] = mysql_error($this->db_connect_id); $result["code"] = mysql_errno($this->db_connect_id); return $result; } } // class sql_db class sql_db_string extends sql_db { // // Constructor ($connstring format : mysql://user:password@host/dbname) // function sql_db_string($connstring, $persistency = true) { $ret = false; if ($connstring != '') { if (ereg("^mysql\:\/\/([^\:]+)\:([^\@]+)\@([^\\]+)\/([^\/]+)[\/]?$", $connstring, $params)) { $sqlserver = $params[3]; $sqluser = $params[1]; $sqlpassword = $params[2]; $database = $params[4]; $ret = $this->sql_db($sqlserver, $sqluser, $sqlpassword, $database, $persistency); } } return $ret; } } // class sql_db_string } // if ... define ?> ================================================ FILE: tools/server/admin/functions_mysqli.php ================================================ persistency = $persistency; $this->user = $sqluser; $this->password = $sqlpassword; $this->server = $sqlserver; $this->dbname = $database; if($this->persistency) { $this->server = 'p:'.$this->server; } $this->db_connect_id = mysqli_connect($this->server, $this->user, $this->password); if($this->db_connect_id) { if($database != "") { $this->dbname = $database; $dbselect = mysqli_select_db($this->db_connect_id, $this->dbname); if(!$dbselect) { mysqli_close($this->db_connect_id); $this->db_connect_id = $dbselect; } } return $this->db_connect_id; } else { echo "Connection to mySQL failed!"; exit; } } // // Other base methods // function sql_close() { if($this->db_connect_id) { if($this->query_result) { @mysqli_free_result($this->query_result); } $result = mysqli_close($this->db_connect_id); return $result; } else { return false; } } // // Base query method // function sql_query($query = "", $transaction = FALSE) { // Remove any pre-existing queries unset($this->query_result); if($query != "") { nt_common_add_debug($query); $this->num_queries++; $this->query_result = mysqli_query($this->db_connect_id, $query); } if($this->query_result) { return $this->query_result; } else { return ( $transaction == 'END_TRANSACTION' ) ? true : false; } } function sql_select_db($dbname) { if($this->db_connect_id) { $result = mysqli_select_db($this->db_connect_id, $dbname); return $result; } return false; } function sql_reselect_db() { if($this->db_connect_id) { $result = mysqli_select_db($this->db_connect_id, $this->dbname); return $result; } return false; } // // Other query methods // function sql_numrows($query_id = 0) { if(!$query_id) { $query_id = $this->query_result; } if($query_id) { $result = mysqli_num_rows($query_id); return $result; } else { return false; } } function sql_affectedrows() { if($this->db_connect_id) { $result = mysqli_affected_rows($this->db_connect_id); return $result; } else { return false; } } function sql_numfields($query_id = 0) { if(!$query_id) { $query_id = $this->query_result; } if($query_id) { $result = mysqli_num_fields($query_id); return $result; } else { return false; } } // function sql_fieldname($query_id = 0){} // function sql_fieldtype($offset, $query_id = 0){} function sql_fetchrow($query_id = 0) { if(!$query_id) { $query_id = $this->query_result; } if($query_id) { return mysqli_fetch_array($query_id); } else { return false; } } function sql_fetchrowset($query_id = 0) { if(!$query_id) { $query_id = $this->query_result; } if($query_id) { while($row = mysqli_fetch_array($query_id)) { $result[] = $row; } return $result; } else { return false; } } // function sql_fetchfield($field, $rownum = -1, $query_id = 0){} // function sql_rowseek($rownum, $query_id = 0){} function sql_nextid(){ if($this->db_connect_id) { $result = mysqli_insert_id($this->db_connect_id); return $result; } else { return false; } } function sql_freeresult($query_id = 0){ if(!$query_id) { $query_id = $this->query_result; } if ( $query_id ) { @mysqli_free_result($query_id); return true; } else { return false; } } function sql_error($query_id = 0) { $result["message"] = mysqli_error($this->db_connect_id); $result["code"] = mysqli_errno($this->db_connect_id); return $result; } } // class sql_db class sql_db_string extends sql_db { // // Constructor ($connstring format : mysql://user:password@host/dbname) // function sql_db_string($connstring, $persistency = true) { $ret = false; if ($connstring != '') { if (preg_match("#^mysqli?://([^:]+)(?::([^@]*))?@([^\\/]+)/([^/]+)[/]?$#", $connstring, $params)) { $sqlserver = $params[3]; $sqluser = $params[1]; $sqlpassword = $params[2]; $database = $params[4]; $ret = $this->sql_db($sqlserver, $sqluser, $sqlpassword, $database, $persistency); } } return $ret; } } // class sql_db_string } // if ... define ================================================ FILE: tools/server/admin/functions_tool_administration.php ================================================ 'Main', 'key' => 'help', 'uri' => 'tool_administration.php?toolmode=help', 'tpl' => 'tool_administration.tpl', 'access' => '', // ALWAYS LEAVE EMPTY ! ), array('title' => 'Users', 'key' => 'users', 'uri' => 'tool_administration.php?toolmode=users', 'tpl' => 'tool_administration_users.tpl', 'access' => 'tool_admin_user', ), array('title' => 'Groups', 'key' => 'groups', 'uri' => 'tool_administration.php?toolmode=groups', 'tpl' => 'tool_administration_groups.tpl', 'access' => 'tool_admin_group', ), array('title' => 'Restarts', 'key' => 'restarts', 'uri' => 'tool_administration.php?toolmode=restarts', 'tpl' => 'tool_administration_restarts.tpl', 'access' => 'tool_admin_restart', ), array('title' => 'Applications', 'key' => 'applications', 'uri' => 'tool_administration.php?toolmode=applications', 'tpl' => 'tool_administration_applications.tpl', 'access' => 'tool_admin_application', ), array('title' => 'Domains', 'key' => 'domains', 'uri' => 'tool_administration.php?toolmode=domains', 'tpl' => 'tool_administration_domains.tpl', 'access' => 'tool_admin_domain', ), array('title' => 'Shards', 'key' => 'shards', 'uri' => 'tool_administration.php?toolmode=shards', 'tpl' => 'tool_administration_shards.tpl', 'access' => 'tool_admin_shard', ), array('title' => 'Logs', 'key' => 'logs', 'uri' => 'tool_administration.php?toolmode=logs', 'tpl' => 'tool_administration_logs.tpl', 'access' => 'tool_admin_logs', ), ); $tool_language_list = array(array('lang_id' => 'en', 'lang_name' => 'English', ), array('lang_id' => 'fr', 'lang_name' => 'French', ), array('lang_id' => 'de', 'lang_name' => 'German', ), ); function tool_admin_menu_get_item_from_key($key) { global $tool_admin_menu; reset($tool_admin_menu); foreach($tool_admin_menu as $tool_menu) { if ($tool_menu['key'] == $key) return $tool_menu; } return null; } function tool_admin_users_get_list($group_list) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_USER_TABLE ." ORDER BY user_name ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = array(); while ($row = $db->sql_fetchrow($result)) { $row['user_group_name'] = tool_admin_groups_get_name_from_id($group_list, $row['user_group_id']); $data[] = $row; } } } return $data; } function tool_admin_groups_get_user_list($group_id) { global $db; $data = array(); $sql = "SELECT * FROM ". NELDB_USER_TABLE ." WHERE user_group_id=". $group_id ." ORDER BY user_name ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrowset($result); } } return $data; } function tool_admin_groups_get_list() { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_GROUP_TABLE ." ORDER BY group_name ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { while ($row = $db->sql_fetchrow($result)) { $row['group_level_name'] = tool_admin_groups_get_level_name_from_id($row['group_level']); $data[] = $row; } } } return $data; } function tool_admin_groups_get_level_name_from_id($group_level) { global $nel_user_group_levels; reset($nel_user_group_levels); foreach($nel_user_group_levels as $level_data) { if ($group_level == $level_data['level_id']) { return $level_data['level_name']; } } return tool_admin_groups_get_level_name_from_id(0); } function tool_admin_groups_get_name_from_id($group_list, $group_id) { $data = 'unknown'; reset($group_list); foreach($group_list as $group_data) { if ($group_data['group_id'] == $group_id) { $data = $group_data['group_name']; } } return $data; } function tool_admin_users_get_id($user_id) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_USER_TABLE ." WHERE user_id=". $user_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function tool_admin_users_add($user_name, $user_password, $user_group, $user_active) { global $db; $user_name = trim($user_name); $user_password = trim($user_password); if ($user_name == '') return "/!\ Error: user name is empty!"; if ($user_password == '') return "/!\ Error: password is empty!"; $user_exists = tool_admin_users_name_exist($user_name); if (!$user_exists) { $sql = "INSERT INTO ". NELDB_USER_TABLE; $sql .= " (`user_name`,`user_password`,`user_group_id`,`user_created`,`user_active`)"; $sql .= " VALUES "; $sql .= " ('". $user_name ."','". md5($user_password) ."','". $user_group ."','". time() ."','". $user_active ."')"; $db->sql_query($sql); return ""; } return "/!\ Error: user name already exists in the database!"; } function tool_admin_users_name_exist($user_name) { global $db; $exists = false; $sql = "SELECT user_id, user_name FROM ". NELDB_USER_TABLE ." WHERE user_name='". $user_name ."'"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $exists = true; } } return $exists; } function tool_admin_users_del($user_id) { global $db; $sql = "DELETE FROM ". NELDB_USER_TABLE ." WHERE user_id=". $user_id; $db->sql_query($sql); } function tool_admin_users_update($user_id, $user_name, $user_password, $user_group, $user_active) { global $db; $user_name = trim($user_name); $user_password = trim($user_password); if ($user_name == "") return "/!\ Error: user name is empty!"; if (!ereg("^([[:alnum:]]+)$",$user_name)) return "/!\ Error: invalid user name, only alpha numerical characters allowed!"; $sql = "SELECT * FROM ". NELDB_USER_TABLE ." WHERE user_name='". $user_name ."' AND user_id<>". $user_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { return "/!\ Error: user name already exists in database!"; } } $sql_ext = ""; if ($user_password != '') $sql_ext = ",user_password='". md5($user_password) ."'"; $sql = "UPDATE ". NELDB_USER_TABLE ." SET user_name='". $user_name ."',user_group_id='". $user_group ."',user_active='". $user_active ."'". $sql_ext ." WHERE user_id=". $user_id; $db->sql_query($sql); return ""; } function tool_admin_groups_get_id($group_id) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_GROUP_TABLE ." WHERE group_id=". $group_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function tool_admin_groups_add($group_name, $group_level, $group_default, $group_active) { global $db; $group_name = trim($group_name); if ($group_name == '') return "/!\ Error: group name is empty!"; $group_exists = tool_admin_groups_name_exist($group_name); if (!$group_exists) { if ($group_default == 1) { $sql = "UPDATE ". NELDB_GROUP_TABLE ." SET group_default=0"; $db->sql_query($sql); } $sql = "INSERT INTO ". NELDB_GROUP_TABLE; $sql .= " (`group_name`,`group_level`,`group_default`,`group_active`) "; $sql .= " VALUES "; $sql .= " ('". $group_name ."',". $group_level .",". $group_default .",". $group_active .")"; $db->sql_query($sql); return ""; } return "/!\ Error: group name already exists in the database!"; } function tool_admin_groups_name_exist($group_name) { global $db; $exists = false; $sql = "SELECT group_id, group_name FROM ". NELDB_GROUP_TABLE ." WHERE group_name='". $group_name ."'"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $exists = true; } } return $exists; } function tool_admin_groups_del($group_id) { global $db; $sql = "DELETE FROM ". NELDB_GROUP_TABLE ." WHERE group_id=". $group_id; $db->sql_query($sql); } function tool_admin_groups_update($group_id, $group_name, $group_level, $group_default, $group_active) { global $db; $group_name = trim($group_name); if ($group_name == "") return "/!\ Error: group name is empty!"; if (!ereg("^([[:alnum:]]+)$",$group_name)) return "/!\ Error: invalid group name, only alpha numerical characters allowed!"; $sql = "SELECT * FROM ". NELDB_GROUP_TABLE ." WHERE group_name='". $group_name ."' AND group_id<>". $group_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { return "/!\ Error: group name already exists in database!"; } } if ($group_default == 1) { $sql = "UPDATE ". NELDB_GROUP_TABLE ." SET group_default=0"; $db->sql_query($sql); } $sql = "UPDATE ". NELDB_GROUP_TABLE ." SET group_name='". $group_name ."',group_level='". $group_level ."',group_default='". $group_default ."',group_active='". $group_active ."' WHERE group_id=". $group_id; $db->sql_query($sql); return ""; } function tool_admin_groups_update_default_domain($group_id, $domain_id) { global $db; $sql = "SELECT * FROM ". NELDB_GROUP_TABLE ." WHERE group_id=". $group_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $row = $db->sql_fetchrow($result); if ($row['group_default_domain_id'] != $domain_id) { $sql = "UPDATE ". NELDB_GROUP_TABLE ." SET group_default_domain_id=". $domain_id .",group_default_shard_id=0 WHERE group_id=". $group_id; $db->sql_query($sql); } } else { return "/!\ Error: invalid group id!"; } } return ""; } function tool_admin_groups_update_default_shard($group_id, $shard_id) { global $db; $sql = "SELECT * FROM ". NELDB_GROUP_TABLE ." WHERE group_id=". $group_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $sql = "UPDATE ". NELDB_GROUP_TABLE ." SET group_default_shard_id=". $shard_id ." WHERE group_id=". $group_id; $db->sql_query($sql); } else { return "/!\ Error: invalid group id!"; } } return ""; } function tool_admin_groups_update_default_application($group_id, $application_id) { global $db; $sql = "SELECT * FROM ". NELDB_GROUP_TABLE ." WHERE group_id=". $group_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $sql = "UPDATE ". NELDB_GROUP_TABLE ." SET group_default_application_id=". $application_id ." WHERE group_id=". $group_id; $db->sql_query($sql); } else { return "/!\ Error: invalid group id!"; } } return ""; } function tool_admin_applications_get_list() { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_APPLICATION_TABLE ." ORDER BY application_order ASC, application_name ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrowset($result); } } return $data; } function tool_admin_applications_get_id($application_id) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_APPLICATION_TABLE ." WHERE application_id=". $application_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function tool_admin_applications_add($application_name, $application_uri, $application_restriction, $application_icon, $application_order, $application_visible) { global $db; $application_name = trim($application_name); if ($application_name == '') return "/!\ Error: application name is empty!"; $application_exists = tool_admin_applications_name_exist($application_name); if (!$application_exists) { $sql = "INSERT INTO ". NELDB_APPLICATION_TABLE; $sql .= " (`application_name`,`application_uri`,`application_restriction`,`application_order`,`application_visible`,`application_icon`) "; $sql .= " VALUES "; $sql .= " ('". $application_name ."','". $application_uri ."','". $application_restriction ."','". $application_order ."','". $application_visible ."','". $application_icon ."')"; $db->sql_query($sql); return ""; } return "/!\ Error: application name already exists in the database!"; } function tool_admin_applications_name_exist($application_name) { global $db; $exists = false; $sql = "SELECT application_id, application_name FROM ". NELDB_APPLICATION_TABLE ." WHERE application_name='". $application_name ."'"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $exists = true; } } return $exists; } function tool_admin_applications_del($application_id) { global $db; $sql = "DELETE FROM ". NELDB_USER_APPLICATION_TABLE ." WHERE user_application_application_id=". $application_id; $db->sql_query($sql); $sql = "DELETE FROM ". NELDB_GROUP_APPLICATION_TABLE ." WHERE group_application_application_id=". $application_id; $db->sql_query($sql); $sql = "DELETE FROM ". NELDB_APPLICATION_TABLE ." WHERE application_id=". $application_id; $db->sql_query($sql); } function tool_admin_applications_update($application_id, $application_name, $application_uri, $application_restriction, $application_icon, $application_order, $application_visible) { global $db; $application_name = trim($application_name); if ($application_name == "") return "/!\ Error: application name is empty!"; $sql = "SELECT * FROM ". NELDB_APPLICATION_TABLE ." WHERE application_name='". $application_name ."' AND application_id<>". $application_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { return "/!\ Error: application name already exists in database!"; } } $sql = "UPDATE ". NELDB_APPLICATION_TABLE ." SET application_name='". $application_name ."',application_uri='". $application_uri ."',application_restriction='". $application_restriction ."',application_icon='". $application_icon ."',application_order='". $application_order ."',application_visible='". $application_visible ."' WHERE application_id=". $application_id; $db->sql_query($sql); return ""; } function tool_admin_domains_get_list() { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_DOMAIN_TABLE ." ORDER BY domain_name ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrowset($result); } } return $data; } function tool_admin_domains_add($domain_name, $domain_application, $domain_as_host, $domain_as_port, $domain_rrd_path, $domain_las_admin_path, $domain_las_local_path, $domain_sql_string, $domain_cs_sql_string, $domain_hd_check, $domain_mfs_web) { global $db; $domain_name = trim($domain_name); if ($domain_name == '') return "/!\ Error: domain name is empty!"; $domain_exists = tool_admin_domains_name_exist($domain_name); if (!$domain_exists) { $sql = "INSERT INTO ". NELDB_DOMAIN_TABLE; $sql .= " (`domain_name`,`domain_application`,`domain_as_host`,`domain_as_port`,`domain_rrd_path`,`domain_las_admin_path`,`domain_las_local_path`,`domain_sql_string`,`domain_hd_check`,`domain_mfs_web`,`domain_cs_sql_string`) "; $sql .= " VALUES "; $sql .= " ('". $domain_name ."','". $domain_application ."','". $domain_as_host ."','". $domain_as_port ."','". $domain_rrd_path ."','". $domain_las_admin_path ."','". $domain_las_local_path ."','". $domain_sql_string ."',". $domain_hd_check .",'". $domain_mfs_web ."','". $domain_cs_sql_string ."') "; $db->sql_query($sql); return ""; } return "/!\ Error: domain name already exists in the database!"; } function tool_admin_domains_name_exist($domain_name) { global $db; $exists = false; $sql = "SELECT domain_id, domain_name FROM ". NELDB_DOMAIN_TABLE ." WHERE domain_name='". $domain_name ."'"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $exists = true; } } return $exists; } function tool_admin_domains_get_id($domain_id) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_DOMAIN_TABLE ." WHERE domain_id=". $domain_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function tool_admin_domains_del($domain_id) { global $db; $sql = "DELETE FROM ". NELDB_USER_SHARD_TABLE ." WHERE user_shard_domain_id=". $domain_id; $db->sql_query($sql); $sql = "DELETE FROM ". NELDB_USER_DOMAIN_TABLE ." WHERE user_domain_domain_id=". $domain_id; $db->sql_query($sql); $sql = "DELETE FROM ". NELDB_GROUP_SHARD_TABLE ." WHERE group_shard_domain_id=". $domain_id; $db->sql_query($sql); $sql = "DELETE FROM ". NELDB_GROUP_DOMAIN_TABLE ." WHERE group_domain_domain_id=". $domain_id; $db->sql_query($sql); $sql = "DELETE FROM ". NELDB_SHARD_TABLE ." WHERE shard_domain_id=". $domain_id; $db->sql_query($sql); $sql = "DELETE FROM ". NELDB_DOMAIN_TABLE ." WHERE domain_id=". $domain_id; $db->sql_query($sql); } function tool_admin_domains_update($domain_id, $domain_name, $domain_application, $domain_as_host, $domain_as_port, $domain_rrd_path, $domain_las_admin_path, $domain_las_local_path, $domain_sql_string, $domain_cs_sql_string, $domain_hd_check, $domain_mfs_web) { global $db; $domain_name = trim($domain_name); if ($domain_name == "") return "/!\ Error: domain name is empty!"; $sql = "SELECT * FROM ". NELDB_DOMAIN_TABLE ." WHERE domain_name='". $domain_name ."' AND domain_id<>". $domain_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { return "/!\ Error: domain name already exists in database!"; } } $sql = "UPDATE ". NELDB_DOMAIN_TABLE ." SET domain_name='". $domain_name."',domain_application='". $domain_application ."',domain_as_host='". $domain_as_host ."',domain_as_port='". $domain_as_port ."',domain_rrd_path='". $domain_rrd_path ."',domain_las_admin_path='". $domain_las_admin_path ."',domain_las_local_path='". $domain_las_local_path ."',domain_sql_string='". $domain_sql_string ."',domain_hd_check=". $domain_hd_check .",domain_mfs_web='". $domain_mfs_web ."',domain_cs_sql_string='". $domain_cs_sql_string ."' WHERE domain_id=". $domain_id; $db->sql_query($sql); return ""; } function tool_admin_shards_get_list() { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_SHARD_TABLE ." LEFT JOIN ". NELDB_DOMAIN_TABLE ." ON (shard_domain_id=domain_id) ORDER BY domain_name ASC, shard_name ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrowset($result); } } return $data; } function tool_admin_shards_add($shard_name, $shard_as_id, $shard_domain_id, $shard_language) { global $db; $shard_name = trim($shard_name); if ($shard_name == '') return "/!\ Error: shard name is empty!"; $shard_as_id = trim($shard_as_id); //if (!is_numeric($shard_as_id)) return "/!\ Error: shard AS Id is invalid!"; //$shard_exists = tool_admin_shards_name_exist($shard_as_id); //if (!$shard_exists) //{ $sql = "INSERT INTO ". NELDB_SHARD_TABLE; $sql .= " (`shard_name`,`shard_as_id`,`shard_domain_id`,`shard_lang`) "; $sql .= " VALUES "; $sql .= " ('". $shard_name ."','". $shard_as_id ."','". $shard_domain_id ."','". $shard_language ."') "; $db->sql_query($sql); return ""; //} // //return "/!\ Error: shard AS Id already exists in the database!"; } function tool_admin_shards_name_exist($shard_as_id, $except_id=false) { global $db; if ($shard_as_id == '*' || $shard_as_id == '?') return false; $exists = false; $sql = "SELECT * FROM ". NELDB_SHARD_TABLE ." WHERE shard_as_id='". $shard_as_id ."'"; if ($except_id !== false) $sql .= " AND shard_id<>". $except_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $exists = true; } } return $exists; } function tool_admin_shards_get_id($shard_id) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_SHARD_TABLE ." WHERE shard_id=". $shard_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function tool_admin_shards_del($shard_id) { global $db; $sql = "DELETE FROM ". NELDB_USER_SHARD_TABLE ." WHERE user_shard_shard_id=". $shard_id; $db->sql_query($sql); $sql = "DELETE FROM ". NELDB_GROUP_SHARD_TABLE ." WHERE group_shard_shard_id=". $shard_id; $db->sql_query($sql); $sql = "DELETE FROM ". NELDB_SHARD_TABLE ." WHERE shard_id=". $shard_id; $db->sql_query($sql); } function tool_admin_shards_update($shard_id, $shard_name, $shard_as_id, $shard_domain_id, $shard_language) { global $db; $shard_name = trim($shard_name); if ($shard_name == '') return "/!\ Error: shard name is empty!"; $shard_as_id = trim($shard_as_id); //if (!is_numeric($shard_as_id)) return "/!\ Error: shard AS Id is invalid!"; //$shard_exists = tool_admin_shards_name_exist($shard_as_id, $shard_id); //if (!$shard_exists) //{ $sql = "UPDATE ". NELDB_SHARD_TABLE ." SET shard_name='". $shard_name ."',shard_as_id='". $shard_as_id ."',shard_domain_id='". $shard_domain_id ."',shard_lang='". $shard_language ."' WHERE shard_id=". $shard_id; $db->sql_query($sql); return ""; //} // //return "/!\ Error: shard AS Id already exists in the database!"; } function tool_admin_users_domains_update($user_id, $group_id, $domain_ids) { global $db; $user_domains = tool_admin_users_domains_get_list($user_id, true); $group_domains = tool_admin_groups_domains_get_list($group_id, true); $sql = "DELETE FROM ". NELDB_USER_DOMAIN_TABLE ." WHERE user_domain_user_id=". $user_id; $db->sql_query($sql); if (is_array($domain_ids) and sizeof($domain_ids)) { reset($domain_ids); foreach($domain_ids as $domain_id) { if (is_numeric($domain_id) && $domain_id > 0) { $sql = "INSERT INTO ". NELDB_USER_DOMAIN_TABLE ." (`user_domain_user_id`,`user_domain_domain_id`) VALUES ('". $user_id ."','". $domain_id ."')"; $db->sql_query($sql); } } } // now we remove all shards except those that belong to the user AND group $sql = "DELETE FROM ". NELDB_USER_SHARD_TABLE ." WHERE user_shard_user_id=". $user_id; if (is_array($domain_ids) && sizeof($domain_ids)) $sql .= " AND user_shard_domain_id NOT IN (". implode(',',array_values($domain_ids)) .")"; if (is_array($group_domains) && sizeof($group_domains)) $sql .= " AND user_shard_domain_id NOT IN (". implode(',',array_values($group_domains)) .")"; $db->sql_query($sql); } function tool_admin_users_domains_get_list($user_id, $compact = false) { global $db; $data = array(); $data1 = array(); $sql = "SELECT * FROM ". NELDB_USER_DOMAIN_TABLE ." LEFT JOIN ". NELDB_DOMAIN_TABLE ." ON (user_domain_domain_id=domain_id) WHERE user_domain_user_id=". $user_id ." ORDER BY domain_name ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data1 = $db->sql_fetchrowset($result); } } if ($compact) { reset($data1); foreach($data1 as $data_tmp) { $data[] = $data_tmp['user_domain_domain_id']; } } else { $data = $data1; } return $data; } function tool_admin_groups_domains_get_list($group_id, $compact = false) { global $db; $data = array(); $data1 = array(); $sql = "SELECT * FROM ". NELDB_GROUP_DOMAIN_TABLE ." LEFT JOIN ". NELDB_DOMAIN_TABLE ." ON (group_domain_domain_id=domain_id) WHERE group_domain_group_id=". $group_id ." ORDER BY domain_name ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data1 = $db->sql_fetchrowset($result); } } if ($compact) { reset($data1); foreach($data1 as $data_tmp) { $data[] = $data_tmp['group_domain_domain_id']; } } else { $data = $data1; } //nt_common_add_debug($data); return $data; } function tool_admin_users_domains_merge($domain_list, $user_list, $group_list) { $data = array(); if (is_array($domain_list) && sizeof($domain_list)) { reset($domain_list); foreach($domain_list as $domain) { if (in_array($domain['domain_id'], $group_list)) { $domain['domain_disabled'] = true; $domain['domain_visible'] = true; } elseif (in_array($domain['domain_id'], $user_list)) { $domain['domain_selected'] = true; $domain['domain_visible'] = true; } $data[] = $domain; } } return $data; } function tool_admin_users_shards_get_list($user_id, $compact = false) { global $db; $data = array(); $data1 = array(); $sql = "SELECT * FROM ". NELDB_USER_SHARD_TABLE ." LEFT JOIN ". NELDB_SHARD_TABLE ." ON (user_shard_shard_id=shard_id) WHERE user_shard_user_id=". $user_id ." ORDER BY shard_name ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data1 = $db->sql_fetchrowset($result); } } if ($compact) { reset($data1); foreach($data1 as $data_tmp) { $data[] = $data_tmp['user_shard_shard_id']; } } else { $data = $data1; } return $data; } function tool_admin_groups_shards_get_list($group_id, $compact = false) { global $db; $data = array(); $data1 = array(); $sql = "SELECT * FROM ". NELDB_GROUP_SHARD_TABLE ." LEFT JOIN ". NELDB_SHARD_TABLE ." ON (group_shard_shard_id=shard_id) WHERE group_shard_group_id=". $group_id ." ORDER BY shard_name ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data1 = $db->sql_fetchrowset($result); } } if ($compact) { reset($data1); foreach($data1 as $data_tmp) { $data[] = $data_tmp['group_shard_shard_id']; } } else { $data = $data1; } return $data; } function tool_admin_users_shards_merge($domain_list, $shard_list, $user_list, $group_list) { $data1 = array(); if (is_array($shard_list) && sizeof($shard_list)) { reset($shard_list); foreach($shard_list as $shard) { if (in_array($shard['shard_id'], $group_list)) { $shard['shard_disabled'] = true; } elseif (in_array($shard['shard_id'], $user_list)) { $shard['shard_selected'] = true; } $data1[] = $shard; } $shard_list = $data1; } $data2 = array(); // now we sort the shards by their domain if (is_array($domain_list) && sizeof($domain_list)) { reset($domain_list); foreach($domain_list as $domain) { // looks for the shards that belong to this domain reset($shard_list); foreach($shard_list as $shard) { if ($domain['domain_id'] == $shard['shard_domain_id']) { $domain['shard_list'][] = $shard; } } $data2[] = $domain; } $domain_list = $data2; } return $domain_list; } function tool_admin_users_shards_update($user_id, $group_id, $shard_ids) { global $db; $sql = "DELETE FROM ". NELDB_USER_SHARD_TABLE ." WHERE user_shard_user_id=". $user_id; $db->sql_query($sql); if (is_array($shard_ids) && sizeof($shard_ids)) { reset($shard_ids); foreach($shard_ids as $shard_tmp) { $tmp = explode('_', $shard_tmp); $domain_id = $tmp[0]; $shard_id = $tmp[1]; if (is_numeric($domain_id) && is_numeric($shard_id) && $domain_id > 0 && $shard_id > 0) { $sql = "INSERT INTO ". NELDB_USER_SHARD_TABLE ." (`user_shard_user_id`,`user_shard_shard_id`,`user_shard_domain_id`) VALUES ('". $user_id ."','". $shard_id ."','". $domain_id ."')"; $db->sql_query($sql); } } } } function tool_admin_groups_domains_update($group_id, $domain_ids) { global $db; $sql = "DELETE FROM ". NELDB_GROUP_DOMAIN_TABLE ." WHERE group_domain_group_id=". $group_id; $db->sql_query($sql); if (is_array($domain_ids) and sizeof($domain_ids)) { reset($domain_ids); foreach($domain_ids as $domain_id) { if (is_numeric($domain_id) && $domain_id > 0) { $sql = "INSERT INTO ". NELDB_GROUP_DOMAIN_TABLE ." (`group_domain_group_id`,`group_domain_domain_id`) VALUES ('". $group_id ."','". $domain_id ."')"; $db->sql_query($sql); } } } $sql = "DELETE FROM ". NELDB_GROUP_SHARD_TABLE ." WHERE group_shard_group_id=". $group_id; if (is_array($domain_ids) && sizeof($domain_ids)) $sql .= " AND group_shard_domain_id NOT IN (". implode(',',array_values($domain_ids)) .")"; $db->sql_query($sql); // we need to check some stuff for each user in this group // first we get the list of users that belong to his group $sql = "SELECT * FROM ". NELDB_USER_TABLE ." WHERE user_group_id=". $group_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { while ($row = $db->sql_fetchrow($result)) { // get a user $user_id = $row['user_id']; // get the domains specific to the user $user_domain_list = tool_admin_users_domains_get_list($user_id, true); // then we delete the shard that don't belong to the group nor user $sql = "DELETE FROM ". NELDB_USER_SHARD_TABLE ." WHERE user_shard_user_id=". $user_id; if (is_array($domain_ids) && sizeof($domain_ids)) $sql .= " AND user_shard_domain_id NOT IN (". implode(',', array_values($domain_ids)) .")"; if (is_array($user_domain_list) && sizeof($user_domain_list)) $sql .= " AND user_shard_domain_id NOT IN (". implode(',', array_values($user_domain_list)) .")"; $db->sql_query($sql); // make sure users don't have a domain that already belongs to a group $sql = "DELETE FROM ". NELDB_USER_DOMAIN_TABLE ." WHERE user_domain_user_id=". $user_id; if (is_array($domain_ids) && sizeof($domain_ids)) $sql .= " AND user_domain_domain_id IN (". implode(',', array_values($domain_ids)) .")"; $db->sql_query($sql); } } } } function tool_admin_groups_domains_merge($domain_list, $group_list) { $data = array(); if (is_array($domain_list) && sizeof($domain_list)) { reset($domain_list); foreach($domain_list as $domain) { if (in_array($domain['domain_id'], $group_list)) { $domain['domain_visible'] = true; $domain['domain_selected'] = true; } $data[] = $domain; } } return $data; } function tool_admin_groups_shards_merge($domain_list, $shard_list, $group_list) { $data1 = array(); if (is_array($shard_list) && sizeof($shard_list)) { reset($shard_list); foreach($shard_list as $shard) { if (in_array($shard['shard_id'], $group_list)) { $shard['shard_selected'] = true; } $data1[] = $shard; } $shard_list = $data1; } $data2 = array(); // now we sort the shards by their domain if (is_array($domain_list) && sizeof($domain_list) && is_array($shard_list) && sizeof($shard_list)) { reset($domain_list); foreach($domain_list as $domain) { // looks for the shards that belong to this domain reset($shard_list); foreach($shard_list as $shard) { if ($domain['domain_id'] == $shard['shard_domain_id']) { $domain['shard_list'][] = $shard; } } $data2[] = $domain; } $domain_list = $data2; } return $domain_list; } function tool_admin_groups_shards_update($group_id, $shard_ids) { global $db; $sql = "DELETE FROM ". NELDB_GROUP_SHARD_TABLE ." WHERE group_shard_group_id=". $group_id; $db->sql_query($sql); if (is_array($shard_ids) && sizeof($shard_ids)) { $user_shard_ids = array(); reset($shard_ids); foreach($shard_ids as $shard_tmp) { $tmp = explode('_', $shard_tmp); $domain_id = $tmp[0]; $shard_id = $tmp[1]; $group_shard_ids[] = $shard_id; if (is_numeric($domain_id) && is_numeric($shard_id) && $domain_id > 0 && $shard_id > 0) { $sql = "INSERT INTO ". NELDB_GROUP_SHARD_TABLE ." (`group_shard_group_id`,`group_shard_shard_id`,`group_shard_domain_id`) VALUES ('". $group_id ."','". $shard_id ."','". $domain_id ."')"; $db->sql_query($sql); } } // we need to check some stuff for each user in this group // first we get the list of users that belong to his group $sql = "SELECT * FROM ". NELDB_USER_TABLE ." WHERE user_group_id=". $group_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { while ($row = $db->sql_fetchrow($result)) { // get a user $user_ids[] = $row['user_id']; } $sql = "DELETE FROM ". NELDB_USER_SHARD_TABLE ." WHERE user_shard_user_id IN (". implode(',',array_values($user_ids)) .") AND user_shard_shard_id IN (". implode(',', array_values($group_shard_ids)) .")"; $db->sql_query($sql); } } } } function tool_admin_groups_applications_update($group_id, $application_ids) { global $db; $sql = "DELETE FROM ". NELDB_GROUP_APPLICATION_TABLE ." WHERE group_application_group_id=". $group_id; $db->sql_query($sql); if (is_array($application_ids) && sizeof($application_ids)) { reset($application_ids); foreach($application_ids as $application_id) { $sql = "INSERT INTO ". NELDB_GROUP_APPLICATION_TABLE ." (`group_application_group_id`,`group_application_application_id`) VALUES ('". $group_id ."','". $application_id ."')"; $db->sql_query($sql); } // we need to make sure no user in this group has this application $sql = "SELECT * FROM ". NELDB_USER_TABLE ." WHERE user_group_id=". $group_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { while ($row = $db->sql_fetchrow($result)) { // get a user $user_ids[] = $row['user_id']; } $sql = "DELETE FROM ". NELDB_USER_APPLICATION_TABLE ." WHERE user_application_user_id IN (". implode(',',array_values($user_ids)) .") AND user_application_application_id IN (". implode(',', array_values($application_ids)) .")"; $db->sql_query($sql); } } } } function tool_admin_groups_applications_get_list($group_id, $compact = false) { global $db; $data = array(); $data1 = array(); $sql = "SELECT * FROM ". NELDB_GROUP_APPLICATION_TABLE ." LEFT JOIN ". NELDB_APPLICATION_TABLE ." ON (group_application_application_id=application_id) WHERE group_application_group_id=". $group_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data1 = $db->sql_fetchrowset($result); } } if ($compact) { reset($data1); foreach($data1 as $data_tmp) { $data[] = $data_tmp['group_application_application_id']; } } else { $data = $data1; } return $data; } function tool_admin_groups_applications_merge($appl_list, $group_list) { $data1 = array(); if (is_array($appl_list) && sizeof($appl_list)) { reset($appl_list); foreach($appl_list as $appl) { if (in_array($appl['application_id'], $group_list)) { $appl['application_selected'] = true; } $data1[] = $appl; } $appl_list = $data1; } return $appl_list; } function tool_admin_users_applications_get_list($user_id, $compact = false) { global $db; $data = array(); $data1 = array(); $sql = "SELECT * FROM ". NELDB_USER_APPLICATION_TABLE ." LEFT JOIN ". NELDB_APPLICATION_TABLE ." ON (user_application_application_id=application_id) WHERE user_application_user_id=". $user_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data1 = $db->sql_fetchrowset($result); } } if ($compact) { reset($data1); foreach($data1 as $data_tmp) { $data[] = $data_tmp['user_application_application_id']; } } else { $data = $data1; } return $data; } function tool_admin_users_applications_merge($appl_list, $user_list, $group_list) { $data1 = array(); if (is_array($appl_list) && sizeof($appl_list)) { reset($appl_list); foreach($appl_list as $appl) { if (in_array($appl['application_id'], $group_list)) { $appl['application_disabled'] = true; } elseif (in_array($appl['application_id'], $user_list)) { $appl['application_selected'] = true; } $data1[] = $appl; } $appl_list = $data1; } return $appl_list; } function tool_admin_users_applications_update($user_id, $application_ids) { global $db; $sql = "DELETE FROM ". NELDB_USER_APPLICATION_TABLE ." WHERE user_application_user_id=". $user_id; $db->sql_query($sql); if (is_array($application_ids) && sizeof($application_ids)) { reset($application_ids); foreach($application_ids as $application_id) { if (is_numeric($application_id) && $application_id > 0) { $sql = "INSERT INTO ". NELDB_USER_APPLICATION_TABLE ." (`user_application_user_id`,`user_application_application_id`) VALUES ('". $user_id ."','". $application_id ."')"; $db->sql_query($sql); } } } } function tool_admin_applications_build_menu_list($user_access) { $menu = array(); // return $user_access['applications']; if (is_array($user_access['applications']) && sizeof($user_access['applications'])) { reset($user_access['applications']); foreach($user_access['applications'] as $appl_data) { if ($appl_data['application_visible'] == 1) { $user_check = tool_admin_applications_build_menu_check($appl_data['application_id'], $user_access['user_applications'], 'user_application_application_id'); $group_check = tool_admin_applications_build_menu_check($appl_data['application_id'], $user_access['group_applications'], 'group_application_application_id'); if ($appl_data['application_restriction'] == '') { $menu[] = $appl_data; } elseif ($user_check || $group_check) { $menu[] = $appl_data; } } } } return $menu; } function tool_admin_applications_get_default($data, $application_id) { if (is_array($data) && sizeof($data)) { reset($data); foreach($data as $dt) { if ($dt['application_id'] == $application_id) { return $dt; } } } return false; } function tool_admin_applications_build_menu_check($appl_id, $data, $data_name) { if (is_array($data) && sizeof($data)) { reset($data); foreach($data as $dt) { if ($dt[$data_name] == $appl_id) { return true; } } } return false; } function tool_admin_applications_check($appl) { global $nel_user; $ua = $nel_user['access']['user_applications']; $ga = $nel_user['access']['group_applications']; if (is_array($ua) && sizeof($ua)) { reset($ua); foreach($ua as $a) { if ($a['application_restriction'] == $appl) { return true; } } } if (is_array($ga) && sizeof($ga)) { reset($ga); foreach($ga as $a) { if ($a['application_restriction'] == $appl) { return true; } } } return false; } function tool_admin_menu_get_list($ie) { global $tool_admin_menu; global $nel_user; $new_menu = array(); reset($tool_admin_menu); foreach($tool_admin_menu as $menu_item) { if (($menu_item['access'] == '') || tool_admin_applications_check($menu_item['access'])) { if ($ie === false) { $new_menu[] = $menu_item; } } } return $new_menu; } function tool_admin_users_groups_domains_merge() { global $nel_user; $user_domains = array(); $ud = $nel_user['access']['user_domains']; $gd = $nel_user['access']['group_domains']; $dd = tool_admin_domains_get_list(); if (is_array($dd) && sizeof($dd)) { reset($dd); foreach($dd as $domain_item) { if (is_array($ud)) { reset($ud); foreach($ud as $udomain) { if ($domain_item['domain_id'] == $udomain['domain_id']) { $user_domains[] = $domain_item; } } } if (is_array($gd)) { reset($gd); foreach($gd as $gdomain) { if ($domain_item['domain_id'] == $gdomain['domain_id']) { $user_domains[] = $domain_item; } } } } } return $user_domains; } function tool_admin_users_groups_shards_merge() { global $nel_user; $user_shards = array(); $us = $nel_user['access']['user_shards']; $gs = $nel_user['access']['group_shards']; $ss = tool_admin_shards_get_list(); if (is_array($ss) && sizeof($ss)) { reset($ss); foreach($ss as $shard_item) { if (is_array($us)) { reset($us); foreach($us as $ushard) { if ($shard_item['shard_id'] == $ushard['shard_id']) { $user_shards[] = $shard_item; } } } if (is_array($gs)) { reset($gs); foreach($gs as $gshard) { if ($shard_item['shard_id'] == $gshard['shard_id']) { $user_shards[] = $shard_item; } } } } } return $user_shards; } function tool_admin_logs_get_count() { global $db; $total = 0; $sql = "SELECT * FROM ". NELDB_LOG_TABLE; if ($result = $db->sql_query($sql)) { $total = $db->sql_numrows($result); } return $total; } function tool_admin_logs_get_list($start=0,$limit=25) { global $db; $data = array(); $sql = "SELECT * FROM ". NELDB_LOG_TABLE ." ORDER BY logs_id DESC LIMIT ". $start .",". $limit; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrowset($result); } } return $data; } function tool_admin_domains_get_nel($application) { global $db; $domain_data = null; if ($db->sql_select_db('nel')) { $sql = "SELECT * FROM domain WHERE domain_name='". $application ."'"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $domain_data = $db->sql_fetchrow($result); } } $db->sql_reselect_db(); } return $domain_data; } //function tool_admin_domains_update_nel($domain_id, $domain_name, $domain_version, $domain_status) function tool_admin_domains_update_nel($domain_id, $domain_name, $domain_status) { global $db; if ($db->sql_select_db('nel')) { //$sql = "UPDATE domain SET status='". $domain_status ."',patch_version=". $domain_version ." WHERE domain_id=". $domain_id ." AND domain_name='". $domain_name ."'"; $sql = "UPDATE domain SET status='". $domain_status ."' WHERE domain_id=". $domain_id ." AND domain_name='". $domain_name ."'"; $db->sql_query($sql); $db->sql_reselect_db(); } } function tool_admin_restarts_get_list($order='ASC') { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_RESTART_GROUP_TABLE ." ORDER BY restart_group_order ". $order .", restart_group_name ". $order; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrowset($result); } } return $data; } function tool_admin_restarts_add($restart_name, $restart_list, $restart_order) { global $db; $restart_name = trim($restart_name); if ($restart_name == '') return "/!\ Error: restart group name is empty!"; $restart_list = trim($restart_list); if ($restart_list == '') return "/!\ Error: restart group list is empty!"; $restart_order = trim($restart_order); if (!is_numeric($restart_order)) return "/!\ Error: restart group order is not numeric!"; $sql = "INSERT INTO ". NELDB_RESTART_GROUP_TABLE; $sql .= " (`restart_group_id`,`restart_group_name`,`restart_group_list`,`restart_group_order`) "; $sql .= " VALUES "; $sql .= " (0,'". $restart_name ."','". $restart_list ."','". $restart_order ."') "; $db->sql_query($sql); return ""; } function tool_admin_restarts_get_id($restart_id) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_RESTART_GROUP_TABLE ." WHERE restart_group_id=". $restart_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function tool_admin_restarts_del($restart_id) { global $db; $sql = "DELETE FROM ". NELDB_RESTART_GROUP_TABLE ." WHERE restart_group_id=". $restart_id; $db->sql_query($sql); } function tool_admin_restarts_update($restart_id, $restart_name, $restart_list, $restart_order) { global $db; $restart_name = trim($restart_name); if ($restart_name == '') return "/!\ Error: restart group name is empty!"; $restart_list = trim($restart_list); if ($restart_list == '') return "/!\ Error: restart group list is empty!"; $restart_order = trim($restart_order); if (!is_numeric($restart_order)) return "/!\ Error: restart group order is not numeric!"; $sql = "UPDATE ". NELDB_RESTART_GROUP_TABLE ." SET restart_group_name='". $restart_name ."',restart_group_list='". $restart_list ."',restart_group_order='". $restart_order ."' WHERE restart_group_id=". $restart_id; $db->sql_query($sql); return ""; } function tool_admin_restart_messages_add($message_name, $message_value, $message_lang) { global $db; $message_name = trim($message_name); if ($message_name == '') return "/!\ Error: restart message name is empty!"; $message_value = trim($message_value); if ($message_value == '') return "/!\ Error: restart message value is empty!"; $sql = "INSERT INTO ". NELDB_RESTART_MESSAGE_TABLE; $sql .= " (`restart_message_id`,`restart_message_name`,`restart_message_value`,`restart_message_lang`) "; $sql .= " VALUES "; $sql .= " (0,'". $message_name ."','". $message_value ."','". $message_lang ."') "; $db->sql_query($sql); return ""; } function tool_admin_restart_messages_get_list() { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_RESTART_MESSAGE_TABLE ." ORDER BY restart_message_name ASC, restart_message_lang ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrowset($result); } } return $data; } function tool_admin_restart_messages_get_id($message_id) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_RESTART_MESSAGE_TABLE ." WHERE restart_message_id=". $message_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function tool_admin_restart_messages_get_list_from_name($message_name,$lang=null) { global $db; $data = null; $sql_ext = ''; if ($lang !== null) { $sql_ext = " AND restart_message_lang='". $lang ."'"; } $sql = "SELECT * FROM ". NELDB_RESTART_MESSAGE_TABLE ." WHERE restart_message_name='". $message_name ."' ". $sql_ext ." ORDER BY restart_message_lang ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrowset($result); } } return $data; } function tool_admin_restart_messages_del($message_id) { global $db; $sql = "DELETE FROM ". NELDB_RESTART_MESSAGE_TABLE ." WHERE restart_message_id=". $message_id; $db->sql_query($sql); } function tool_admin_restart_messages_update($message_id, $message_name, $message_value, $message_lang) { global $db; $message_name = trim($message_name); if ($message_name == '') return "/!\ Error: restart message name is empty!"; $message_value = trim($message_value); if ($message_value == '') return "/!\ Error: restart message value is empty!"; $sql = "UPDATE ". NELDB_RESTART_MESSAGE_TABLE ." SET restart_message_name='". $message_name ."',restart_message_value='". $message_value ."',restart_message_lang='". $message_lang ."' WHERE restart_message_id=". $message_id; $db->sql_query($sql); return ""; } ?> ================================================ FILE: tools/server/admin/functions_tool_applications.php ================================================ '' ORDER BY application_order ASC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrowset($result); } } return $data; } ?> ================================================ FILE: tools/server/admin/functions_tool_event_entities.php ================================================ (.*)$", $ais_line, $eregs)) { $values_read++; $entity['service_id'] = trim($eregs[1]); } elseif (ereg("^entity ->(.*)$", $ais_line, $eregs)) { $values_read++; $entity['entity'] = trim($eregs[1]); $entity_string = str_replace(array('(',')','0x'), '', $entity['entity']); $entity_string = str_replace(':','_', $entity_string); $entity['entity_string'] = $entity_string; } elseif (ereg("^NamedEntityName ->(.*)$", $ais_line, $eregs)) { $values_read++; $entity['entity_name'] = trim($eregs[1]); } elseif (ereg("^NamedEntityState ->(.*)$", $ais_line, $eregs)) { $values_read++; $entity['entity_state'] = trim($eregs[1]); } elseif (ereg("^NamedEntityParam1 ->(.*)$", $ais_line, $eregs)) { $values_read++; $entity['entity_param1'] = trim($eregs[1]); } elseif (ereg("^NamedEntityParam2 ->(.*)$", $ais_line, $eregs)) { $values_read++; $entity['entity_param2'] = trim($eregs[1]); } if (sizeof($entity) && ($values_read == $values) && ($values > 0)) { $entity['service'] = $service_name; $entity['service_code'] = md5($service_name); $entity_data[] = $entity; $entity = array(); $values = 0; $values_read = 0; } } } return $entity_data; } function tool_ee_get_entities($data) { $entities = array(); reset($data); foreach($data as $dkey => $dval) { $dkey_bits = explode('_', $dkey); $dkey_nums = sizeof($dkey_bits); if ($dkey_nums > 4) { $_entity_bit_4 = array_pop($dkey_bits); $_entity_bit_3 = array_pop($dkey_bits); $_entity_bit_2 = array_pop($dkey_bits); $_entity_bit_1 = array_pop($dkey_bits); $dkey_bits = array_reverse($dkey_bits); $_entity_service = array_pop($dkey_bits); $dkey_bits = array_reverse($dkey_bits); $dkey_entity = $_entity_bit_1 .'_'. $_entity_bit_2 .'_'. $_entity_bit_3 .'_'. $_entity_bit_4; $dkey_name = implode('_', $dkey_bits); if (!isset($entities[$_entity_service .'_'. $dkey_entity])) { $entities[$_entity_service .'_'. $dkey_entity] = array(); } $entities[$_entity_service .'_'. $dkey_entity][$dkey_name] = trim($dval); } } return $entities; } ?> ================================================ FILE: tools/server/admin/functions_tool_graphs.php ================================================ 'CCU', 'key' => 'ccu', 'uri' => 'tool_graphs.php?toolmode=ccu', 'tpl' => 'tool_graphs_ccu.tpl', 'access' => '', ), array('title' => 'Tech Shard', 'key' => 'tech', 'uri' => 'tool_graphs.php?toolmode=tech', 'tpl' => 'tool_graphs_tech.tpl', 'access' => '', ), array('title' => 'Hi-Res Shard', 'key' => 'hires', 'uri' => 'tool_graphs.php?toolmode=hires', 'tpl' => 'tool_graphs_hires.tpl', 'access' => '', ), array('title' => 'Old', 'key' => 'old', 'uri' => 'tool_graphs.php?toolmode=old', 'tpl' => 'tool_graphs.tpl', 'access' => '', ), ); $tool_hires_frames = array(array('title' => '10 seconds', 'value' => 10000, 'step' => 0, 'default' => false, ), array('title' => '30 seconds', 'value' => 30000, 'step' => 0, 'default' => true, ), array('title' => '90 seconds', 'value' => 90000, 'step' => 0, 'default' => false, ), ); $tool_lowres_frames = array(array('title' => '20 minutes', 'value' => 1200, 'default' => false, ), array('title' => '3 hours', 'value' => 10800, 'default' => false, ), array('title' => '24 hours', 'value' => 86400, 'default' => true, ), array('title' => '7 days', 'value' => 604800, 'default' => false, ), array('title' => '30 days', 'value' => 2592000, 'default' => false, ), array('title' => '90 days', 'value' => 7776000, 'default' => false, ), ); function tool_graphs_time_frame_get_default($list) { reset($list); foreach($list as $frame) { if ($frame['default'] == true) return $frame['value']; } } function tool_graphs_menu_get_list() { global $tool_graph_menu; global $nel_user; $new_menu = array(); reset($tool_graph_menu); foreach($tool_graph_menu as $menu_item) { if (($menu_item['access'] == '') || tool_admin_applications_check($menu_item['access'])) { $new_menu[] = $menu_item; } } return $new_menu; } function tool_graphs_menu_get_item_from_key($key) { global $tool_graph_menu; reset($tool_graph_menu); foreach($tool_graph_menu as $tool_menu) { if ($tool_menu['key'] == $key) return $tool_menu; } return null; } function tool_graphs_find($needles, $list) { $result = array(); reset($needles); foreach($needles as $needle) { if (isset($list[$needle['variable']])) { nt_common_add_debug("variable found ". $needle['variable']); reset($list[$needle['variable']]); foreach($list[$needle['variable']] as $var) { nt_common_add_debug("checking '". $needle['service'] ."' in '". $var['service'] ."'"); if (ereg("^". $needle['service'] .".*$",$var['service'])) { nt_common_add_debug("adding ". $var['service']); $result[] = $var; } } } } return $result; } function tool_graphs_get_list_v2($dir, $shard_match, $high=false, $domain=false) { $data = array(); //if (!ereg("^[a-zA-Z0-9_]+$",$shard_match) && !$domain) return $data; if (substr($dir, -1) != '/') $dir .= '/'; if (is_dir($dir)) { if ($handle = opendir($dir)) { while (($file = readdir($handle)) !== false) { if (($file != '.') && ($file != '..')) { $filelist[] = $file; } } closedir($handle); sort($filelist); nt_common_add_debug($filelist); //fes_arispotle_01.NetSpeedLoop.hrd //egs_arispotle.TickSpeedLoop.hrd //$my_ereg = "^([^_]+_(". $shard_match .")(_[^\ \.])?)\.([^\ ]+)\.([hr])rd$"; //$my_ereg = "^([^_]+_(". $shard_match .")(_[^\ \.])?)\.([^\ ]+)\.rrd$"; $my_ereg = "^([^_]+(_[^_]+)?_(". $shard_match .")(_[^\ \.])?)\.([^.]+)\.". ($high === true ? 'h':'r') ."rd$"; nt_common_add_debug("using regexp: ".$my_ereg); // 0: complete file name // 1: service alias (eg. fes_arispotle_01) // 2: n/a // 3: shard (eg. arispotle) // 4: n/a // 5: variable (eg. NetSpeedLoop) // this is special, mainly to catch domain wide variables, such as su.* which don't have a shard $my_ereg2 = "^([^_]+(_[^_]+)?(_[^\ \.])?)\.([^.]+)\.". ($high === true ? 'h':'r') ."rd$"; nt_common_add_debug("using regexp2: ".$my_ereg2); // 0: complete file name // 1: service alias (eg. fes_arispotle_01) // 2: n/a // 3: n/a // 4: variable (eg. NetSpeedLoop) reset($filelist); foreach($filelist as $file) //while (($file = readdir($handle)) !== false) { //nt_common_add_debug("checking : ". $file); if (ereg($my_ereg, $file, $params)) { nt_common_add_debug("ok".$file); //nt_common_add_debug($params); $tmp = array( 'rd_file' => $params[0], 'service' => $params[1], 'shard' => $params[3], 'variable' => $params[5]); $data[$params[5]][] = $tmp; } elseif (ereg($my_ereg2, $file, $params)) { nt_common_add_debug("ok2".$file); $tmp = array( 'rd_file' => $params[0], 'service' => $params[1], 'shard' => 'open', 'variable' => $params[4]); $data[$params[4]][] = $tmp; } } } } nt_common_add_debug(array(array_keys($data), $data)); return array('variables' => array_keys($data), 'datas' => $data); } function tool_graphs_get_list($dir, $shard_match) { $data = array(); if (substr($dir, -1) != '/') $dir .= '/'; if (is_dir($dir)) { if ($handle = opendir($dir)) { //fes_arispotle_01.NetSpeedLoop.hrd //egs_arispotle.TickSpeedLoop.hrd $my_ereg = "^([^_]+_(". $shard_match .")(_[^\ \.])?)\.([^\ ]+)\.([hr])rd$"; $my_ereg = "^([^_]+_(". $shard_match .")(_[^\ \.])?)\.([^\ ]+)\.rrd$"; $my_ereg = "^([^_]+(_[^_]+)?_(". $shard_match .")(_[^\ \.])?)\.([^.]+)\.rrd$"; //nt_common_add_debug($my_ereg); // 0: complete file name // 1: service alias (eg. fes_arispotle_01) // 2: n/a // 3: shard (eg. arispotle) // 4: n/a // 5: variable (eg. NetSpeedLoop) // 6: graph type, h/r : high/low (removed) while (($file = readdir($handle)) !== false) { if (($file != '.') && ($file != '..')) { //nt_common_add_debug("checking : ". $file); if (ereg($my_ereg, $file, $params)) { $high_file = str_replace('.rrd','.hrd',$file); if (!file_exists($dir . $high_file)) $high_file = ''; //nt_common_add_debug($params); $tmp = array( 'low_file' => $params[0], 'high_file' => $high_file, 'service' => $params[1], 'shard' => $params[3], 'variable' => $params[5]); $data[$params[5]][] = $tmp; } } } closedir($handle); } } nt_common_add_debug(array(array_keys($data), $data)); return array('variables' => array_keys($data), 'datas' => $data); } function tool_graphs_get_data($data, $variable, $service) { reset($data); foreach($data as $svar => $sdata) { if ($svar == $variable) { reset($sdata); foreach($sdata as $sidata) { if ($sidata['service'] == $service) { return $sidata; } } } } return null; } function tool_graphs_extract_mean_values($data) { $result = array('ref' => array(), 'val' => array()); $base = null; reset($data); foreach($data as $sdata) { $tmp_data = explode(':', $sdata); // get reference as t0 if (!$base) $base = trim($tmp_data[1]); $val_data = explode(' ', $tmp_data[2]); $result['ref'][] = $tmp_data[1] - $base; $result['val'][] = trim($val_data[1]); } return $result; } function tool_graphs_xaxis_callback($aVal) { return ($aVal / 1000) .'k'; } // ###################################################################################################################### // ###################################################################################################################### function tool_graphs_rrd_get_list($dir) { $dir_list = array(); if ($handle = opendir($dir)) { while (false !== ($file = readdir($handle))) { if (($file != ".") && ($file != "..") && (substr($file, -4) == '.rrd')) { $dir_list[] = array('name' => $file, 'code' => base64_encode($file)); } } closedir($handle); } return $dir_list; } function tool_graphs_build_rrd($fname,$period=0) { $rrdperiod = '-'. $period; $rrdfile = RRD_PATH . $fname; $webimage = GFX_PATH . $fname .'_'. $period .'.gif'; $opts = array( "--start", $rrdperiod, "DEF:val=". $rrdfile .":var:AVERAGE", "LINE2:val#0000FF"); $ret = rrd_graph($webimage, $opts, count($opts)); if ( is_array($ret) ) { return array('status' => true, 'img' => $webimage); } $err = rrd_error(); return array('status' => false, 'error' => "Error: rrd_graph() -- $err"); } ?> ================================================ FILE: tools/server/admin/functions_tool_guild_locator.php ================================================ $service_name, 'shardid' => $eregs[1], 'guildid' => $eregs[2], 'name' => $eregs[4], 'guildeid' => $eregs[3], 'members' => $eregs[5], ); } } } return $guild_data; } function tool_gl_parse_dump_guild($data) { $guild_data = array(); // this command can only handle 1 guild if (is_array($data) && (sizeof($data) == 1)) { $data = $data[0]; reset($data); foreach($data as $egs_line) { $egs_line = trim($egs_line); if (ereg("^===\[ Service ([^\ ]+) returned \]===$", $egs_line, $eregs)) { $guild_data['service_name'] = $eregs[1]; } elseif (ereg("^ Guild id: ([^\ ]+)\:([^\ ]+) \(Local\), name: '([^\']+)', eid: ([^\ ]+)$", $egs_line, $eregs)) { $guild_data['shard_id'] = $eregs[1]; $guild_data['guild_id'] = $eregs[2]; $guild_data['guild_name'] = $eregs[3]; $guild_data['guild_eid'] = $eregs[4]; } elseif (ereg("^Description: '([^\']+)'$", $egs_line, $eregs)) { $guild_data['guild_description'] = $eregs[1]; } elseif (ereg("^Money: ([^\ ]+)$", $egs_line, $eregs)) { $guild_data['guild_money'] = $eregs[1]; } elseif (ereg("^Creation date: ([^\ ]+)$", $egs_line, $eregs)) { $guild_data['guild_creation'] = $eregs[1]; } elseif (ereg("^Race: ([^\ ]+)$", $egs_line, $eregs)) { $guild_data['guild_race'] = $eregs[1]; } elseif (ereg("^Nb of members: ([^\ ]+)$", $egs_line, $eregs)) { $guild_data['members_count'] = $eregs[1]; } elseif (ereg("^Nb of members with grade 'Leader': ([^\ ]+)$", $egs_line, $eregs)) { $guild_data['members_leader_count'] = $eregs[1]; } elseif (ereg("^Nb of members with grade 'HighOfficer': ([^\ ]+)$", $egs_line, $eregs)) { $guild_data['members_highofficier_count'] = $eregs[1]; } elseif (ereg("^Nb of members with grade 'Officer': ([^\ ]+)$", $egs_line, $eregs)) { $guild_data['members_officer_count'] = $eregs[1]; } elseif (ereg("^Nb of members with grade 'Member': ([^\ ]+)$", $egs_line, $eregs)) { $guild_data['members_member_count'] = $eregs[1]; } elseif (ereg("^Member '([^\ ]+)\(([^\ ]+)\)' ([^\ ]+), index: ([^\ ]+), grade: ([^\ ]+), enter time: ([^\ ]+)$", $egs_line, $eregs)) { $member = array('name' => $eregs[1], 'shard' => $eregs[2], 'eid' => $eregs[3], 'index' => $eregs[4], 'grade' => $eregs[5], 'entertime' => $eregs[6]); $guild_data[$eregs[5]][] = $member; } elseif (ereg("^Owned Outpost: alias (\([^\ ]+\)), name '([^\ ]+)', sheet '([^\ ]+)'$", $egs_line, $eregs)) { $outpost = array( 'alias' => $eregs[1], 'name' => $eregs[2], 'sheet' => $eregs[3]); $guild_data['outposts'][] = $outpost; } elseif (ereg("^Challenged Outpost: alias (\([^\ ]+\)), name '([^\ ]+)', sheet '([^\ ]+)'$", $egs_line, $eregs)) { $outpost = array( 'alias' => $eregs[1], 'name' => $eregs[2], 'sheet' => $eregs[3]); $guild_data['challenged_outposts'][] = $outpost; } } } return $guild_data; } function tool_gl_parse_grade_change($data) { nt_common_add_debug($data); //Member 'Duff(too)' now has grade 'HighOfficer' //Cannot set 'Duff(too)' as 'HighOfficer' because max count for this grade (1) has been reached $guild_data = null; if (is_array($data) && (sizeof($data) == 1)) { $data = $data[0]; reset($data); foreach($data as $egs_line) { $egs_line = trim($egs_line); if (ereg("^Member '([^\ ]+)\(([^\ ]+)\)' now has grade '([^\ ]+)'$", $egs_line, $eregs)) { $guild_data[] = "Member ". $eregs[1] ." has now the grade of ". $eregs[3] ."!"; } elseif (ereg("^Cannot set '([^\ ]+)\(([^\ ]+)\)' as '([^\ ]+)' because max count for this grade \(([^\ ]+)\) has been reached$", $egs_line, $eregs)) { $guild_data[] = "Could not change grade of member ". $eregs[1] ." to ". $eregs[3] ." (grade is full)"; } } } return $guild_data; } function tool_gl_view_forum($host,$shard,$guild,$thread=null,$recover=null) { $ch = curl_init(); if (trim($host) == "") return "No MFS Web Host Configured for this domain!"; $url = "http://". $host ."/admin.php"; $uri_params = 'user_login=support'; $uri_params .= '&shard='. $shard; $uri_params .= '&forum='. $guild; if ($thread !== null && $recover === null) { $uri_params .= '&thread='. $thread; } elseif ($recover !== null && $thread !== null) { $uri_params .= '&recover_thread='. $guild; $uri_params .= '&recover_threadthread='. $thread; } nt_common_add_debug("curling '$url' with '$uri_params'"); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $uri_params); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 0 = debug , 1 = normal curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // 0 = debug , 1 = normal curl_setopt($ch, CURLOPT_NOPROGRESS, 0); curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)"); curl_setopt($ch, CURLOPT_HEADER, 1); // has to be 1 due to using redirections curl_setopt($ch, CURLOPT_TIMEOUT, 120); ob_start(); $curlOutput = curl_exec ($ch); ob_end_clean(); $curlError = curl_errno($ch); if ($curlError != 0) { $outp = "CURL Error [ $curlError ] : ". curl_error($ch); } else { $curlData = tool_gl_CurlParseResponse($curlOutput); $outp = $curlData[2]; } curl_close ($ch); return $outp; } function tool_gl_CurlParseResponse($response) { /* returns an array in the following format which varies depending on headers returned [0] => the HTTP error or response code such as 404 [1] => Array ( [Date] => Wed, 28 Apr 2004 23:29:20 GMT [Set-Cookie] => COOKIESTUFF [Expires] => Thu, 01 Dec 1994 16:00:00 GMT [Content-Type] => text/html ) [2] => Response body (string) */ do { list($response_headers,$response) = explode("\r\n\r\n",$response,2); $response_header_lines = explode("\r\n",$response_headers); // first line of headers is the HTTP response code $http_response_line = array_shift($response_header_lines); if (preg_match('@^HTTP/[0-9]\.[0-9] ([0-9]{3})@',$http_response_line, $matches)) { $response_code = $matches[1]; } else { $response_code = "Error"; } } while ((substr($response_code, 0,1) == "1") || (substr($response_code, 0,1) == "3")); $response_body = $response; // put the rest of the headers in an array $response_header_array = array(); foreach ($response_header_lines as $header_line) { list($header,$value) = explode(': ',$header_line,2); $response_header_array[$header] = $value; } return array($response_code,$response_header_array,$response_body); } function tool_gl_parse_forum_view($data) { if (strpos($data,'Warning') !== false) { $result = 'Failed to open forums!'; } else { $data = explode("\n",$data); $result = array(); reset($data); foreach($data as $line) { $line = trim($line); if (ereg("^FILE:thread\_([[:digit:]]+)\.index$",$line,$regs)) { $result[] = array( "raw" => $line, "file" => 'thread_'. $regs[1] .'.index', "thread" => $regs[1], "recover" => 0); } elseif (ereg("^FILE:\_thread\_([[:digit:]]+)\.index$",$line,$regs)) { $result[] = array( "raw" => $line, "file" => '_thread_'. $regs[1] .'.index', "thread" => $regs[1], "recover" => 1); } } } return $result; } function tool_gl_parse_thread_view($data) { /* SUPPORT MODE!-- THREAD Elementals of Atys thread_0.index TOPIC: Guild Website SUBMIT: Scar AUTHOR: Scar DATE: <i>date#06/10/06</i> 01:34 POST: is at http://www.elementals-of-atys.com AUTHOR: Scorp DATE: <i>date#06/10/06</i> 03:56 POST: can we please make sure that we all register there asap please, communication is going to be vital to this guild, I will get vent or TS setup in a few days, -- END THREAD Elementals of Atys thread_0.index */ if (strpos($data,'Warning') !== false) { $result = 'Failed to open thread!'; } else { $data = explode("\n",$data); $result = array(); reset($data); foreach($data as $line) { $line = trim($line); if (ereg("^SUPPORT.*THREAD (.*) ([\_]?thread\_[[:digit:]]+\.index)$",$line,$regs)) { $result['header'] = array( 'raw' => $line, 'guild' => $regs[1], 'file' => $regs[2]); } elseif (ereg("^TOPIC: (.*) SUBMIT: (.*)$",$line,$regs)) { $result['topic'] = array( 'raw' => $line, 'topic' => nl2br($regs[1]), 'who' => $regs[2]); } elseif (ereg("^AUTHOR: ([^\ ]+) DATE: ([^\ ]+ [[:digit:]]{2}\:[[:digit:]]{2}) POST: (.*)$",$line,$regs)) { $result['data'][] = array( 'raw' => $line, 'who' => $regs[1], 'date' => $regs[2], 'post' => nl2br($regs[3])); } } } return $result; } function tool_gl_recover_thread($shard, $forum, $thread) { } ?> ================================================ FILE: tools/server/admin/functions_tool_log_analyser.php ================================================ $file, 'path' => $path, 'size' => filesize($path . $file), 'date' => filemtime($path . $file), 'code' => base64_encode($file), ); $file_list[] = $tmp; } } if (is_array($file_list)) { reset($file_list); foreach($file_list as $tmp_key => $tmp_val) { $date_ary[$tmp_key] = $file_list['date']; } array_multisort($date_ary, SORT_DESC, $file_list); } closedir($handle); } return $file_list; } function tool_las_check_for_file($data, $name) { reset($data); foreach($data as $filedata) { if ($filedata['name'] == $name) return $filedata; } return null; } function tool_las_parse_eids_to_array($eids) { $eids = trim($eids); $eids = ereg_replace("[[:space:]]+"," ",$eids); $eids = str_replace(")(",") (",$eids); $tmp = explode(" ",$eids); reset($tmp); foreach($tmp as $ktmp => $vtmp) { $vtmp = trim($vtmp); if (!eregi("^\(0x[^\)]+\)$",$vtmp)) unset($tmp[$ktmp]); else $tmp[$ktmp] = $vtmp; } return $tmp; } function tool_las_read_file($filename, $max_lines, $line_start, &$line_previous, &$line_next) { $data = null; $line_previous = $line_start - $max_lines; $line_next = $line_start + $max_lines; if ($line_previous < 0) $line_previous = -1; $lines_read = 0; if ($fp = fopen($filename,'r')) { // skip lines up to $line_start for ($i = 0; $i < $line_start; ++$i) fgets($fp); for ($i = 0; $i < $max_lines; ++$i) { $tmp = fgets($fp); if ($tmp) { $tmp = trim($tmp); if ($tmp != '') $data[] = $tmp; $lines_read++; } else break; } fclose($fp); } if ($lines_read < $max_lines) { $line_next = -1; } nt_common_add_debug("tool_las_read_file() : ". $max_lines ." - ". $line_start ." - ". $line_previous ." - ". $line_next); return $data; } function tool_las_trim_leading_zero($data) { while ($data[0] === '0') { $data = substr($data, 1); } return $data; } function tool_las_parse_eid($eid, &$uid, &$slotid, &$charid) { $uid = 0; $slotid = 0; $charid = 0; $ret = false; $eid = trim($eid); if (ereg("^\(0x([[:alnum:]]{9})([[:digit:]])(\:[[:alnum:]]+)*[\)]?$", $eid, $eid_params)) { $uid = intval('0x'. tool_las_trim_leading_zero($eid_params[1]),16); $slotid = $eid_params[2]; $charid = ($uid * 16) + $slotid; $ret = true; } return $ret; } function tool_las_parse_file($fname) { $data = array(); if ($fp = fopen($fname, "r")) { while (!feof($fp)) { $input = fgets($fp); $input = trim($input); if (substr($input, 0, 2) == '#$') { $input = trim(substr($input, 2)); //echo $input ."
"; if (ereg("^[^\ ]+\: LogChat[[:space:]]+\: ([^\ ]+) says '(.*)' to (.*)$", $input, $params)) { tool_las_parse_eid($params[1], $_uid, $_slotid, $_charid); $data[$_charid] = $params[1]; foreach(explode(' ', $params[3]) as $eid_listener) { tool_las_parse_eid($eid_listener, $listener_uid, $listener_slotid, $listener_charid); if ($listener_uid != 0) { $data[$listener_charid] = $eid_listener; } } } } } fclose($fp); } return $data; } function tool_las_get_character_names($dbname, $data) { global $db; $char_data = array(); if ($db->sql_select_db($dbname)) { $sql = "SELECT char_id,char_name FROM characters WHERE char_id IN (". implode(',', array_keys($data)) .")"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { while ($row = $db->sql_fetchrow($result)) { $char_data[$row['char_id']] = $row['char_name']; } } } $db->sql_reselect_db(); } return $char_data; } function tool_las_fpassthru_replace($path, $fname, $search_eid_ary, $search_char_ary) { if ($fp = fopen($path . $fname, "r")) { stream_set_timeout($fp, 180); header("Content-type: text/plain"); header("Content-Disposition: attachment; filename=las_parsed_". $fname); header("Pragma: no-cache"); header("Expires: 0"); $data = ""; while (!feof($fp)) { $tmp = fgets($fp); $tmp = str_replace($search_eid_ary, $search_char_ary, $tmp); echo $tmp; } fclose($fp); } } ?> ================================================ FILE: tools/server/admin/functions_tool_main.php ================================================ 'Every 5 secs', 'secs' => 5, ), array('desc' => 'Every 30 secs', 'secs' => 30, ), array('desc' => 'Every 1 min.', 'secs' => 60, ), array('desc' => 'Every 5 min.', 'secs' => 300, ), array('desc' => 'Every 10 min.', 'secs' => 600, ), array('desc' => 'Every 30 min.', 'secs' => 1800, ), array('desc' => 'Never', 'secs' => 0, ), ); class MyAdminService extends CAdminServiceWeb { function commandResult($serviceModuleName, $result) { global $tpl; global $command_return_data; nt_common_add_debug("Service $serviceModuleName returned '$result'"); $data = "===[ Service ". strtoupper($serviceModuleName) ." returned ]===\n". trim($result) ."\n\n"; if (isset($command_return_data)) $command_return_data[] = explode("\n", $data); $tpl->append('tool_execute_result', $data); } function invokeError($methodName, $errorString) { global $tpl; nt_common_add_debug("AS Error in '$methodName' : $errorString"); $tpl->assign('tool_as_error', "AS Error in '$methodName' : $errorString"); } } function tool_main_check_user_domain($domain_id) { global $nel_user; if (!$domain_id) return false; $ud = $nel_user['access']['domains']; if (is_array($ud)) { reset($ud); foreach($ud as $udomain) { if ($domain_id == $udomain['domain_id']) return true; } } return false; } function tool_main_check_user_shard($shard_id) { global $nel_user; if (!$shard_id) return false; $us = $nel_user['access']['shards']; if (is_array($us)) { reset($us); foreach($us as $ushard) { if ($shard_id == $ushard['shard_id']) return true; } } return false; } function tool_main_get_domain_name($domain_id) { global $nel_user; reset($nel_user['access']['domains']); foreach($nel_user['access']['domains'] as $domain) { if ($domain['domain_id'] == $domain_id) { return $domain['domain_name']; } } return null; } function tool_main_get_domain_data($domain_id, $field) { global $nel_user; reset($nel_user['access']['domains']); foreach($nel_user['access']['domains'] as $domain) { if ($domain['domain_id'] == $domain_id) { // echo "ok $domain_id : $field : ".$domain[$field]; return $domain[$field]; } } return null; } function tool_main_get_domain_rrd_path($domain_id) { global $nel_user; reset($nel_user['access']['domains']); foreach($nel_user['access']['domains'] as $domain) { if ($domain['domain_id'] == $domain_id) { return $domain['domain_rrd_path']; } } return null; } function tool_main_get_shard_name($shard_id) { global $nel_user; reset($nel_user['access']['shards']); foreach($nel_user['access']['shards'] as $shard) { if ($shard['shard_id'] == $shard_id) { return $shard['shard_name']; } } return null; } function tool_main_get_shard_as_id($shard_id) { global $nel_user; reset($nel_user['access']['shards']); foreach($nel_user['access']['shards'] as $shard) { if ($shard['shard_id'] == $shard_id) { return $shard['shard_as_id']; } } return null; } function tool_main_get_shard_data($shard_id, $field) { global $nel_user; reset($nel_user['access']['shards']); foreach($nel_user['access']['shards'] as $shard) { if ($shard['shard_id'] == $shard_id) { return $shard[$field]; } } return null; } function tool_main_get_domain_host($domain_id) { global $nel_user; reset($nel_user['access']['domains']); foreach($nel_user['access']['domains'] as $domain) { if ($domain['domain_id'] == $domain_id) { return $domain['domain_as_host']; } } return null; } function tool_main_get_domain_port($domain_id) { global $nel_user; reset($nel_user['access']['domains']); foreach($nel_user['access']['domains'] as $domain) { if ($domain['domain_id'] == $domain_id) { return $domain['domain_as_port']; } } return null; } function tool_main_get_elapsed_time_string($seconds, &$string) { //returns an array of numeric values representing days, hours, minutes & seconds respectively $ret=array('days'=>0,'hours'=>0,'minutes'=>0,'seconds'=>0,'totalseconds'=>0); $totalsec = $seconds; $ret['totalseconds'] = $totalsec; //print $earlierDate. ":". $laterDate. ":". $totalsec ."
"; if ($totalsec >= 86400) { $ret['days'] = floor($totalsec/86400); $totalsec = $totalsec % 86400; } if ($totalsec >= 3600) { $ret['hours'] = floor($totalsec/3600); $totalsec = $totalsec % 3600; } if ($totalsec >= 60) { $ret['minutes'] = floor($totalsec/60); } $ret['seconds'] = $totalsec % 60; $string = ''; $string .= ($ret['days'] > 0) ? tool_main_leftpad($ret['days']).'d ' : ''; $string .= (($ret['hours'] > 0) || (strlen($string) > 0)) ? tool_main_leftpad($ret['hours']).'h ' : ''; $string .= (($ret['minutes'] > 0) || (strlen($string) > 0)) ? tool_main_leftpad($ret['minutes']).'m ' : ''; $string .= (($ret['seconds'] > 0) || (strlen($string) > 0)) ? tool_main_leftpad($ret['seconds']).'s ' : ''; $ret['string'] = trim($string); return $ret; } function tool_main_leftpad($n,$cc=2,$ch='0') { return str_pad($n, $cc, $ch, STR_PAD_LEFT); } function tool_main_get_shards_from_status($status, $filters) { $result = array(); if (is_array($status) && sizeof($status)) { reset($status); foreach($status as $sline) { $shard_name = trim($sline['ShardName']); if (($shard_name != '') && (isset($filters[$shard_name]) || isset($filters['_all_']))) { $result[] = $shard_name; } } $result = array_values(array_unique($result)); } return $result; } function tool_main_get_aes_from_status($status) { $result = array(); if (is_array($status) && sizeof($status)) { reset($status); foreach($status as $skey => $sline) { $short_name = trim($sline['ShortName']); $running_state = trim($sline['RunningState']); if (($short_name == 'AES') && ($running_state == 'online')) { $result[] = $sline['AliasName']; } } } return $result; } function tool_main_parse_status($status) { $check_graphs = tool_admin_applications_check('tool_main_graphs'); $_sort_list = array(); $domainServices = array(); $sortedServices = array(); if (is_array($status) && sizeof($status)) { reset($status); foreach($status as $sline) { $vars = array(); $vars['_flags_'] = array(); $sline_vars = explode("\t", $sline); reset($sline_vars); foreach($sline_vars as $sline_var) { $sline_parts = explode("=", $sline_var); if ($sline_parts[0] == 'RunningState') { // this is a small fix to an unknown server bug :) if (trim($sline_parts[1]) == 'topped') $sline_parts[1] = 'rs_stopped'; elseif (trim($sline_parts[1]) == 'nline') $sline_parts[1] = 'rs_online'; $vars['_flags_'][$sline_parts[1]] = true; $sline_parts[1] = substr($sline_parts[1], 3); } elseif ($sline_parts[0] == 'RunningOrders') { $vars['_flags_'][$sline_parts[1]] = true; $sline_parts[1] = substr($sline_parts[1], 3); } elseif ($sline_parts[0] == 'RunningTags') { $_tmp = explode(" ", trim($sline_parts[1])); reset($_tmp); foreach($_tmp as $_tmp_key => $_tmp_part) { $vars['_flags_'][$_tmp_part] = true; $_tmp_part = str_replace('_',' ',substr($_tmp_part, 3)); $_tmp[$_tmp_key] = $_tmp_part; } $sline_parts[1] = implode(' / ', $_tmp); } elseif ($sline_parts[0] == 'NoReportSince') { $_today = time(); $_day = date("d", $_today); $_month = date("m", $_today); $_year = date("Y", $_today); $_base_day = mktime(0, 0, 0, $_month, $_day, $_year); if ($sline_parts[1] >= $_base_day) { $sline_parts[1] = 'n/a'; } else { $time0 = 0 + $sline_parts[1]; // convert to a number ;) if ($time0 > 60) $vars['_flags_']['alert_red'] = true; elseif ($time0 > 40) $vars['_flags_']['alert_orange_dark'] = true; elseif ($time0 > 25) $vars['_flags_']['alert_orange_light'] = true; tool_main_get_elapsed_time_string($sline_parts[1],$sline_parts[1]); } } elseif ($sline_parts[0] == 'UpTime') { $_today = time(); $_day = date("d", $_today); $_month = date("m", $_today); $_year = date("Y", $_today); $_base_day = mktime(0, 0, 0, $_month, $_day, $_year); if ($sline_parts[1] >= $_base_day) { $sline_parts[1] = 'n/a'; } else { tool_main_get_elapsed_time_string($sline_parts[1],$sline_parts[1]); } } elseif ($sline_parts[0] == 'State') { if (strtolower($sline_parts[1]) == 'stalled') $vars['_flags_']['alert_red'] = true; elseif (strtolower($sline_parts[1]) == 'halted') $vars['_flags_']['alert_red'] = true; $vars['_flags_'][$sline_parts[1]] = true; } elseif ($sline_parts[0] == 'Hostname') { $sline_parts[1] = substr($sline_parts[1], 0, strpos($sline_parts[1], '.')); } elseif ($sline_parts[0] == 'AliasName') { $vars['_flags_']['alias_code'] = ''; } //print_r($sline_parts);print_r('
'); if( count($sline_parts)==2 ) { $vars[$sline_parts[0]] = $sline_parts[1]; } } // check is service is chain crashing if (in_array('rt_chain_crashing', array_keys($vars['_flags_']))) { // check is service is online (anything that is not stopped) if (!in_array('rs_stopped', array_keys($vars['_flags_']))) { // check the start counts for crashing age $crash_counts = explode(' ', $vars['StartCounter']); if ($crash_counts[0] >= 5) $vars['_flags_']['alert_red'] = true; elseif ($crash_counts[1] >= 5) $vars['_flags_']['alert_orange_dark'] = true; elseif ($crash_counts[2] >= 5) $vars['_flags_']['alert_orange_light'] = true; } } //$vars['_flags_']['has_graphs'] = tool_main_check_rrd_files($vars['AliasName']); $_sort_list[] = $vars['AliasName']; $domainServices[] = $vars; } /* һܼŹ󣬾ô li9chuan 2014-9-11 sort($_sort_list); reset($_sort_list); foreach($_sort_list as $_sort_name) { reset($domainServices); foreach($domainServices as $serviceRow) { if ($_sort_name == $serviceRow['AliasName']) { $sortedServices[] = $serviceRow; break; } } } //*/ } //return $sortedServices; return $domainServices; } function tool_main_check_rrd_files($service) { if ($handle = opendir(NELTOOL_RRDBASE)) { while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { $file_parts = explode(".", $file); if (sizeof($file_parts) == 3) { if (($service == $file_parts[0]) && (($file_parts[2] == 'rrd') || ($file_parts[2] == 'hrd'))) { closedir($handle); return true; } } } } closedir($handle); } return false; } function tool_main_get_checked_services() { global $NELTOOL; $services = array(); reset($NELTOOL['POST_VARS']); foreach($NELTOOL['POST_VARS'] as $post_key => $post_val) { $val = 'service_'. $post_val; if ($post_key == $val) { $services[] = $post_val; } } return $services; } function tool_main_get_shard_ids($shard_id) { global $nel_user; $data = array(); reset($nel_user['access']['shards']); foreach($nel_user['access']['shards'] as $shards) { if ($shards['shard_id'] == $shard_id) { $shards_tmp = trim($shards['shard_as_id']); if ($shards_tmp == '*') { $data['_all_'] = true; } elseif ($shards_tmp == '?') { $data['_unknown_'] = true; } else { $shard_parts = explode(':', $shards_tmp); reset($shard_parts); foreach($shard_parts as $shard_as_id) { if ($shard_as_id == '?') { $data['_unknown_'] = true; } else { $data[$shard_as_id] = true; } } } } } return $data; } function tool_main_get_shards_orders($orders) { $data = array(); if (is_array($orders) && sizeof($orders)) { reset($orders); foreach($orders as $order_line) { $order_items = explode("\t", $order_line); $shard_name = ""; $shard_order = ""; reset($order_items); foreach($order_items as $order_parts) { $order_bits = explode("=", $order_parts); $order_bits[0] = trim($order_bits[0]); $order_bits[1] = trim($order_bits[1]); if ($order_bits[0] == 'ShardName') { $shard_name = $order_bits[1]; } elseif ($order_bits[0] == 'Orders') { $shard_order = substr($order_bits[1],3); } } if ($shard_name != "" && $shard_order != "") { $data[$shard_name] = $shard_order; } } } return $data; } function tool_main_get_last_hd_time_for_domain($domain_id) { global $db; $timer = 0; $sql = "SELECT * FROM ". NELDB_STAT_HD_TIME_TABLE ." WHERE hd_domain_id=". $domain_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); $timer = $data['hd_last_time']; } } return $timer; } function tool_main_update_hd_time_for_domain($domain_id, $now) { global $db; //if ($stat_time == 0) $sql = "INSERT INTO ". NELDB_STAT_HD_TIME_TABLE ." (`hd_domain_id`,`hd_last_time`) VALUES (". $domain_id .",". $now .")"; //else $sql = "UPDATE ". NELDB_STAT_HD_TIME_TABLE ." SET hd_last_time=". $now ." WHERE hd_domain_id=". $domain_id; $sql = "SELECT * FROM ". NELDB_STAT_HD_TIME_TABLE ." WHERE hd_domain_id=". $domain_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $sql = "UPDATE ". NELDB_STAT_HD_TIME_TABLE ." SET hd_last_time=". $now ." WHERE hd_domain_id=". $domain_id; $db->sql_query($sql); } else { $sql = "INSERT INTO ". NELDB_STAT_HD_TIME_TABLE ." (`hd_domain_id`,`hd_last_time`) VALUES (". $domain_id .",". $now .")"; $db->sql_query($sql); } } } function tool_main_update_hd_data_for_domain($domain_id, $data) { global $db; $aes_status = array(); if (is_array($data) && sizeof($data)) { reset($data); foreach($data as $aes) { $aes_server = null; //$hd_found_slash_mount = null; //$hd_found_slash_home = null; //$hd_found_slash_home_nevrax = null; //$hd_found_slash = null; $aes_hd_ready = false; $aes_data = explode("\n", $aes); reset($aes_data); foreach($aes_data as $aes_line) { $aes_line = trim($aes_line); // clean up the multiple blank characters $aes_line = ereg_replace("[[:space:]]+"," ",$aes_line); if (ereg("^===\[ Service AES_([^[:space:]]+) returned \]===$", $aes_line, $regs)) { $aes_server = strtolower($regs[1]); $aes_status[$aes_server] = array(); } elseif (ereg("^-* Command output begin -*$", $aes_line, $regs)) { $aes_hd_ready = true; } elseif (ereg("^-* Command output end -*$", $aes_line, $regs)) { $aes_hd_ready = false; } if ($aes_hd_ready) { $aes_line_data = explode(" ", $aes_line); if (($aes_line_data[0] != 'Filesystem') && ($aes_line_data[1] != 'Command')) { //if ((strpos($aes_line_data[5],"/mnt/rsbk") == 0) // || ($aes_line_data[5] == "/home") // || ($aes_line_data[5] == "/home/nevrax") // || ($aes_line_data[5] == "/")) //{ $aes_status[$aes_server][] = array( 'device' => $aes_line_data[0], 'size' => $aes_line_data[1], 'used' => $aes_line_data[2], 'free' => $aes_line_data[3], 'usedpercent' => str_replace('%','',$aes_line_data[4]), 'mount' => $aes_line_data[5], ); //} } } //if ((substr($aes_line, 0, 5) == "/dev/") && $aes_server) //{ // // $aes_line_data = explode(" ", $aes_line); // // // 0 : device name // // 1 : device size // // 2 : used // // 3 : available // // 4 : used percentage // // 5 : mount point // // if ($aes_line_data[5] == "/home") // { // $hd_found_slash_home = $aes_line_data; // } // // if ($aes_line_data[5] == "/home/nevrax") // { // $hd_found_slash_home_nevrax = $aes_line_data; // } // // if ($aes_line_data[5] == "/") // { // $hd_found_slash = $aes_line_data; // } // // //if (($aes_line_data[5] == "/") || ($aes_line_data[5] == "/home/nevrax")) // //{ // // $aes_status[$aes_server][] = array( 'device' => $aes_line_data[0], // // 'size' => $aes_line_data[1], // // 'used' => $aes_line_data[2], // // 'free' => $aes_line_data[3], // // 'usedpercent' => str_replace('%','',$aes_line_data[4]), // // 'mount' => $aes_line_data[5], // // ); // //} // //} } //$tmp = null; // //if (is_array($hd_found_slash_mount)) $tmp = $hd_found_slash_mount; //elseif (is_array($hd_found_slash_home)) $tmp = $hd_found_slash_home; //elseif (is_array($hd_found_slash_home_nevrax)) $tmp = $hd_found_slash_home_nevrax; //elseif (is_array($hd_found_slash)) $tmp = $hd_found_slash; // //if (is_array($tmp)) //{ // $aes_status[$aes_server][] = array( 'device' => $tmp[0], // 'size' => $tmp[1], // 'used' => $tmp[2], // 'free' => $tmp[3], // 'usedpercent' => str_replace('%','',$tmp[4]), // 'mount' => $tmp[5], // ); //} } if (sizeof($aes_status)) { nt_common_add_debug($aes_status); //echo '
'. print_r($aes_status, true) .'
'; $sql = "DELETE FROM ". NELDB_STAT_HD_TABLE ." WHERE hd_domain_id=". $domain_id; $db->sql_query($sql); reset($aes_status); foreach($aes_status as $server_name => $server_datas) { reset($server_datas); foreach($server_datas as $server_hd) { if (trim($server_name) != '') { $sql = "INSERT INTO ". NELDB_STAT_HD_TABLE ." (`hd_domain_id`,`hd_server`,`hd_device`,`hd_size`,`hd_used`,`hd_free`,`hd_percent`,`hd_mount`)"; $sql .= " VALUES (". $domain_id .",'". $server_name ."','". $server_hd['device'] ."','". $server_hd['size'] ."',"; $sql .= "'". $server_hd['used'] ."','". $server_hd['free'] ."','". $server_hd['usedpercent'] ."','". $server_hd['mount'] ."')"; $db->sql_query($sql); } if (defined('NELTOOL_CRON_DEBUG')) echo "
SQL:$sql"; } } tool_main_update_hd_time_for_domain($domain_id, time()); } } } function tool_main_get_hd_data_for_domain($domain_id) { global $db; $data = array(); //$sql = "SELECT * FROM ". NELDB_STAT_HD_TABLE ." WHERE hd_domain_id=". $domain_id ." AND hd_mount='/' ORDER BY hd_percent DESC"; $sql = "SELECT * FROM ". NELDB_STAT_HD_TABLE ." WHERE hd_domain_id=". $domain_id ." ORDER BY hd_percent DESC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { while ($row = $db->sql_fetchrow($result)) { $outp = ''. $row['hd_server'] .' : '. $row['hd_device'] .'
'; $outp .= ' Mount : '. $row['hd_mount'] .'
'; $outp .= ' Size : '. $row['hd_size'] .'
'; $outp .= ' Used : '. $row['hd_used'] .'
'; $outp .= ' Free : '. $row['hd_free'] .'
'; $row['summary'] = $outp; $data[] = $row; } } } return $data; } function tool_main_get_annotation($domain_id, $shard_id) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_ANNOTATION_TABLE ." WHERE 1=0"; if ($domain_id > 0) $sql .= " OR annotation_domain_id=". $domain_id; if ($shard_id > 0) $sql .= " OR annotation_shard_id=". $shard_id; $sql .= " ORDER BY annotation_date DESC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function tool_main_get_lock($domain_id, $shard_id) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_LOCK_TABLE ." WHERE 1=0 "; if ($domain_id > 0) $sql .= " OR lock_domain_id=". $domain_id; if ($shard_id > 0) $sql .= " OR lock_shard_id=". $shard_id; $sql .= " ORDER BY lock_date DESC"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function tool_main_delete_lock_shard($shard_id) { global $db; global $nel_user; global $AS_Name, $AS_ShardName; nt_log("Shard Unlock (Domain: '". $AS_Name ."' - Shard: '". $AS_ShardName ."') by '". $nel_user['user_name'] ."'"); $sql = "DELETE FROM ". NELDB_LOCK_TABLE ." WHERE lock_shard_id=". $shard_id; $db->sql_query($sql); } function tool_main_delete_lock_domain($domain_id) { global $db; global $nel_user; global $AS_Name, $AS_ShardName; nt_log("Domain Unlock (Domain: '". $AS_Name ."') by '". $nel_user['user_name'] ."'"); $sql = "DELETE FROM ". NELDB_LOCK_TABLE ." WHERE lock_domain_id=". $domain_id; $db->sql_query($sql); } function tool_main_set_lock_shard($domain_id, $shard_id, $log=true) { global $db; global $nel_user; global $AS_Name, $AS_ShardName; // we need to check if the shard is *all* // if its the case, we go for a lock domain instead $sql = "SELECT * FROM ". NELDB_SHARD_TABLE ." WHERE shard_id=". $shard_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $shard_row = $db->sql_fetchrow($result); if ($shard_row['shard_as_id'] == "*") { return tool_main_set_lock_domain($domain_id, $log); } } } $data = tool_main_get_lock($domain_id, $shard_id); $now = time(); if (is_array($data) && ($data['lock_shard_id'] > 0)) { if ($log) nt_log("Shard Lock (Domain: '". $AS_Name ."' - Shard: '". $AS_ShardName ."') by '". $nel_user['user_name'] ."'"); $sql = "UPDATE ". NELDB_LOCK_TABLE ." SET lock_user_name='". $nel_user['user_name'] ."',lock_update=". $now ." WHERE lock_id=". $data['lock_id']; $db->sql_query($sql); } elseif (!$data) { if ($log) nt_log("Shard Lock (Domain: '". $AS_Name ."' - Shard: '". $AS_ShardName ."') by '". $nel_user['user_name'] ."'"); $sql = "INSERT INTO ". NELDB_LOCK_TABLE ." (`lock_shard_id`,`lock_user_name`,`lock_date`,`lock_update`) VALUES (". $shard_id .",'". $nel_user['user_name'] ."',". $now .",". $now .")"; $db->sql_query($sql); } } function tool_main_get_domain_shard_list($domain_id) { global $db; $data = array(); $sql = "SELECT * FROM ". NELDB_SHARD_TABLE ." WHERE shard_domain_id=". $domain_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { while ($row = $db->sql_fetchrow($result)) { $data[] = $row['shard_id']; } } } return $data; } function tool_main_set_lock_domain($domain_id, $log=true) { global $db; global $nel_user; global $AS_Name, $AS_ShardName; // to lock a domain you need to remove all locks from any shard in it $lock_data = tool_main_get_lock($domain_id, 0); $now = time(); if (is_array($lock_data)) { $sql = "UPDATE ". NELDB_LOCK_TABLE ." SET lock_user_name='". $nel_user['user_name'] ."',lock_update=". $now ." WHERE lock_id=". $lock_data['lock_id']; $db->sql_query($sql); } else { $shard_list = tool_main_get_domain_shard_list($domain_id); $shard_list = array_values($shard_list); $sql = "DELETE FROM ". NELDB_LOCK_TABLE ." WHERE lock_shard_id IN (". implode(',', $shard_list) .")"; $db->sql_query($sql); $sql = "INSERT INTO ". NELDB_LOCK_TABLE ." (`lock_domain_id`,`lock_user_name`,`lock_date`,`lock_update`) VALUES (". $domain_id .",'". $nel_user['user_name'] ."',". $now .",". $now .")"; $db->sql_query($sql); } if ($log) nt_log("Domain Lock (Domain: '". $AS_Name ."') by '". $nel_user['user_name'] ."'"); } function tool_main_set_annotation($domain_id, $shard_id, $annotation) { global $db; global $nel_user; global $AS_Name, $AS_ShardName; $annotation = htmlentities(trim($annotation), ENT_QUOTES); $data = tool_main_get_lock($domain_id, $shard_id); if ($data['lock_domain_id']) { // its a domain lock $shard_list = tool_main_get_domain_shard_list($domain_id); $shard_list = array_values($shard_list); $sql = "DELETE FROM ". NELDB_ANNOTATION_TABLE ." WHERE annotation_shard_id IN (". implode(',', $shard_list) .")"; $db->sql_query($sql); $annotation_data = tool_main_get_annotation($domain_id, 0); if ($annotation_data) { nt_log("Domain Annotation (Domain: '". $AS_Name ."') by '". $nel_user['user_name'] ."' : ". $annotation); $sql = "UPDATE ". NELDB_ANNOTATION_TABLE ." SET annotation_data='". $annotation ."',annotation_user_name='". $nel_user['user_name'] ."',annotation_date=". time() ." WHERE annotation_id=". $annotation_data['annotation_id']; $db->sql_query($sql); } else { nt_log("Domain Annotation (Domain: '". $AS_Name ."') by '". $nel_user['user_name'] ."' : ". $annotation); $sql = "INSERT INTO ". NELDB_ANNOTATION_TABLE ." (`annotation_domain_id`,`annotation_data`,`annotation_user_name`,`annotation_date`) VALUES "; $sql .= "(". $domain_id .",'". $annotation ."','". $nel_user['user_name'] ."',". time() .")"; $db->sql_query($sql); } } else { // its a shard lock $annotation_data = tool_main_get_annotation(0, $shard_id); if ($annotation_data) { nt_log("Shard Annotation (Domain: '". $AS_Name ."' - Shard: '". $AS_ShardName ."') by '". $nel_user['user_name'] ."' : ". $annotation); $sql = "UPDATE ". NELDB_ANNOTATION_TABLE ." SET annotation_data='". $annotation ."',annotation_user_name='". $nel_user['user_name'] ."',annotation_date=". time() ." WHERE annotation_id=". $annotation_data['annotation_id']; $db->sql_query($sql); } else { nt_log("Shard Annotation (Domain: '". $AS_Name ."' - Shard: '". $AS_ShardName ."') by '". $nel_user['user_name'] ."' : ". $annotation); $sql = "INSERT INTO ". NELDB_ANNOTATION_TABLE ." (`annotation_shard_id`,`annotation_data`,`annotation_user_name`,`annotation_date`) VALUES "; $sql .= "(". $shard_id .",'". $annotation ."','". $nel_user['user_name'] ."',". time() .")"; $db->sql_query($sql); } } } function tool_main_get_shards_info_from_db($application, $status, $filters, $ringsqlstring='') { $shard_list = array(); $shard_list_result = array(); //nt_common_add_debug('in tool_main_get_shards_info_from_db()'); //nt_common_add_debug($status); if (is_array($status) && sizeof($status)) { reset($status); foreach($status as $sline) { $shard_name = trim($sline['ShardName']); $shard_id = trim($sline['ShardId']); if (($shard_name != '' && $shard_id != '') && (isset($filters[$shard_name]) || isset($filters['_all_']))) { if (!in_array($shard_name, array_values($shard_list))) { $shard_list[$shard_id] = $shard_name; } } } } nt_common_add_debug('shard_list :'); nt_common_add_debug($shard_list); reset($shard_list); foreach($shard_list as $shard_key => $shard_application) { if (is_numeric($shard_key)) { $shard_list2[$shard_key] = $shard_application; } } //nt_common_add_debug('shard_list2 :'); //nt_common_add_debug($shard_list2); if ($ringsqlstring == '') { global $db; $db->sql_select_db('nel'); //$sql = "SELECT * FROM shard WHERE ShardId IN (". implode(',', array_keys($shard_list)) .")"; if (is_array($shard_list2) && sizeof($shard_list2)) { $sql = "SELECT * FROM shard, domain WHERE shard.domain_id=domain.domain_id AND shard.ShardId IN (". implode(',', array_keys($shard_list2)) .") AND domain.domain_name='". $application ."'"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { while ($row = $db->sql_fetchrow($result)) { // patch to support live and ats mysql changes $state = ''; if (isset($row['State'])) $state = $row['State']; elseif (isset($row['RequiredState'])) $state = $row['RequiredState']; $shard_name = $shard_list[$row['ShardId']]; $shard_list_result[$shard_name] = array('shard_id' => $row['ShardId'], 'version' => $row['Version'], 'state' => substr($state,3), 'motd' => $row['MOTD'], ); } } } } $db->sql_reselect_db(); } else { $db = new sql_db_string($ringsqlstring); if (is_object($db)) { if (is_array($shard_list2) && sizeof($shard_list2)) { //nt_common_add_debug("tool_main_get_shards_info_from_db()"); //nt_common_add_debug($shard_list2); $sql = "SELECT * FROM shard WHERE shard_id IN (". implode(',', array_keys($shard_list2)) .")"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { while ($row = $db->sql_fetchrow($result)) { // patch to support live and ats mysql changes $state = ''; if (isset($row['State'])) $state = $row['State']; elseif (isset($row['RequiredState'])) $state = $row['RequiredState']; $shard_name = $shard_list[$row['shard_id']]; $shard_list_result[$shard_name] = array('shard_id' => $row['shard_id'], //'version' => $row['Version'], 'state' => substr($state,3), 'motd' => $row['MOTD'], ); } } } } else { nt_common_add_debug('in tool_main_get_shards_info_from_db() : shard_list2 is empty !'); //nt_common_add_debug('dumping : filters'); //nt_common_add_debug($filters); } } else { // db error } } return $shard_list_result; } function tool_main_get_su_from_status($status) { if (is_array($status) && sizeof($status)) { reset($status); foreach($status as $sline) { if ($sline['ShortName'] == 'SU') { return $sline['AliasName']; } } } return null; } function tool_main_set_restart_mode($domain_id, $shard_id, $restart_mode=0) { global $db, $nel_user, $tpl; global $AS_ShardRestart, $AS_ShardDomainRestart; $sequence_info = tool_main_get_restart_sequence($nel_user['user_name'], $domain_id, $shard_id); if (!$sequence_info) { $sequence_info = tool_main_add_restart_sequence($nel_user['user_name'], $domain_id, $shard_id, $restart_mode); } if ($sequence_info) { $sql = "UPDATE ". NELDB_SHARD_TABLE ." SET shard_restart=". $sequence_info['restart_sequence_id'] ." WHERE shard_id=". $shard_id ." AND shard_domain_id=". $domain_id; $db->sql_query($sql); // update shards information $nel_user['access']['user_shards'] = tool_admin_users_shards_get_list($nel_user['user_id']); $nel_user['access']['group_shards'] = tool_admin_groups_shards_get_list($nel_user['user_group_id']); $nel_user['access']['shards'] = tool_admin_users_groups_shards_merge(); $tpl->assign('tool_shard_list', $nel_user['access']['shards']); // update shard restart information $AS_ShardRestart = tool_main_get_shard_data($shard_id, 'shard_restart'); $AS_ShardDomainRestart = tool_main_get_domain_shard_restart($view_domain_id); $tpl->assign('tool_shard_restart_status', $AS_ShardRestart); $tpl->assign('tool_domain_has_shard_restart', $AS_ShardDomainRestart); } return $sequence_info; } function tool_main_add_restart_sequence($user_name, $domain_id, $shard_id, $step=0) { global $db; global $nel_user; global $AS_Name, $AS_ShardName; global $restart_notification_emails; $now = time(); $sql = "INSERT INTO ". NELDB_RESTART_SEQUENCE_TABLE; $sql .= " (`restart_sequence_domain_id`,`restart_sequence_shard_id`,`restart_sequence_user_name`,"; $sql .= " `restart_sequence_step`,`restart_sequence_date_start`,`restart_sequence_date_end`) VALUES "; $sql .= " (". $domain_id .",". $shard_id .",'". $user_name ."',"; $sql .= $step .",". $now .",". $now .")"; $db->sql_query($sql); $sequence_info = tool_main_get_restart_sequence_by_id($db->sql_nextid()); nt_log("Shard Restart (Domain: '". $AS_Name ."' - Shard: '". $AS_ShardName ."' - Sequence: '". $sequence_info['restart_sequence_id'] ."') started by '". $nel_user['user_name'] ."'"); $email_subject = "[Shard Admin Tool] Restart Sequence Begins (id: ".$sequence_info['restart_sequence_id'].", step: ". $step .") for shard ".$AS_Name."/".$AS_ShardName." by ".$nel_user['user_name']; $email_message = $email_subject; nt_email($email_subject,$email_message,$restart_notification_emails); return $sequence_info; } function tool_main_get_restart_sequence($user_name, $domain_id, $shard_id) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_RESTART_SEQUENCE_TABLE ." WHERE restart_sequence_domain_id=". $domain_id ." AND restart_sequence_shard_id=". $shard_id ." AND restart_sequence_user_name='". $user_name ."' AND restart_sequence_step=0 AND restart_sequence_date_start=restart_sequence_date_end"; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function tool_main_get_restart_sequence_by_id($sequence_id) { global $db; $data = null; $sql = "SELECT * FROM ". NELDB_RESTART_SEQUENCE_TABLE ." WHERE restart_sequence_id=". $sequence_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function tool_main_set_next_restart_sequence_step($sequence_id, $step=null) { global $db; global $nel_user; global $AS_Name, $AS_ShardName; global $restart_notification_emails; $now = time(); if ($step === null) { $sequence_info = tool_main_get_restart_sequence_by_id($sequence_id); $step = $sequence_info['restart_sequence_step'] + 1; } $sql = "UPDATE ". NELDB_RESTART_SEQUENCE_TABLE ." SET restart_sequence_step=". $step .",restart_sequence_date_end=". $now ." WHERE restart_sequence_id=". $sequence_id; $db->sql_query($sql); nt_log("Shard Restart (Domain: '". $AS_Name ."' - Shard: '". $AS_ShardName ."' - Sequence: '". $sequence_id ."') - ". $nel_user['user_name'] ." moved to step ". $step); if ($step !== null) { $email_subject = "[Shard Admin Tool] Restart Sequence Updated (id: ".$sequence_id.", step: ". $step .") for shard ".$AS_Name."/".$AS_ShardName." by ".$nel_user['user_name']; $email_message = $email_subject; nt_email($email_subject,$email_message,$restart_notification_emails); } return tool_main_get_restart_sequence_by_id($sequence_id); } function tool_main_set_end_restart_sequence($sequence_id) { global $db; global $nel_user; global $AS_Name, $AS_ShardName; global $restart_notification_emails; //$sequence_info = tool_main_set_next_restart_sequence_step($sequence_id); $sequence_info = tool_main_get_restart_sequence_by_id($sequence_id); $sql = "UPDATE ". NELDB_SHARD_TABLE ." SET shard_restart=0 WHERE shard_domain_id=". $sequence_info['restart_sequence_domain_id'] ." AND shard_id=". $sequence_info['restart_sequence_shard_id']; $db->sql_query($sql); nt_log("Shard Restart (Domain: '". $AS_Name ."' - Shard: '". $AS_ShardName ."' - Sequence: '". $sequence_id ."') - ". $nel_user['user_name'] ." ended the sequence !". $step); $email_subject = "[Shard Admin Tool] Restart Sequence Ends (id: ".$sequence_info['restart_sequence_id'].", step: ". $sequence_info['restart_sequence_step'] .") for shard ".$AS_Name."/".$AS_ShardName." by ".$nel_user['user_name']; $email_message = $email_subject; nt_email($email_subject,$email_message,$restart_notification_emails); } function tool_main_get_domain_shard_restart($domain_id) { global $db; $num = 0; $sql = "SELECT * FROM ". NELDB_SHARD_TABLE ." WHERE shard_domain_id=". $domain_id ." AND shard_restart>0"; if ($result = $db->sql_query($sql)) { $num = $db->sql_numrows($result); } return $num; } function tool_main_get_restart_services($InternalName, $domainServices, $restart_list) { // lets sort each services by 'type' nt_common_add_debug("RESTART DEBUG"); nt_common_add_debug($domainServices); $sortedServices = array(); reset($domainServices); foreach($domainServices as $domainService) { if ($domainService['ShardName'] == $InternalName) { // this should be the real 'type' // $type = $domainService['ShortName']; // but instead we'll take the first part of the AliasName (as in "rws" or "rws_aniro") $type = explode('_',$domainService['AliasName']); $type = trim(strtolower($type[0])); if (!isset($sortedServices[$type])) { $sortedServices[$type] = array(); } $sortedServices[$type][] = $domainService['AliasName']; nt_common_add_debug("Adding '". $domainService['AliasName'] ."' to '$type'"); } } reset($restart_list); foreach($restart_list as $restart_key => $restart_group) { $group_list = explode(',', $restart_group['restart_group_list']); $tmp_list = array(); reset($group_list); foreach($group_list as $group_service_type) { $group_service_type = trim($group_service_type); nt_common_add_debug("looking for '$group_service_type'"); if (isset($sortedServices[$group_service_type])) { $tmp_list[] = implode(',',$sortedServices[$group_service_type]); } else { nt_common_add_debug("not found!"); } } $restart_list[$restart_key]['service_list'] = implode(',',$tmp_list); } nt_common_add_debug("RESTART SERVICES DEBUG"); nt_common_add_debug($restart_list); return $restart_list; } function tool_main_get_all_restart_services($restart_list) { $stop_data = array(); $stop_list = ''; reset($restart_list); foreach($restart_list as $restart_key => $restart_group) { $stop_data[] = $restart_group['service_list']; } $stop_list = implode(',', $stop_data); return $stop_list; } function tool_main_get_shardid_from_status($domainServices, $InternalName) { reset($domainServices); foreach($domainServices as $service) { if (($service['ShardName'] == $InternalName) && (is_numeric($service['ShardId']))) { return $service['ShardId']; } } return null; } function tool_main_get_egs_from_status($domainServices, $InternalName) { reset($domainServices); foreach ($domainServices as $service) { if (($service['ShardName'] == $InternalName) && ($service['ShortName'] == 'EGS')) { return $service['AliasName']; } } return null; } function tool_main_set_restart_sequence_timer($sequence_id, $timer) { global $db; $now = time(); $timer = $timer; $new_timer = $now + $timer; $sql = "UPDATE ". NELDB_RESTART_SEQUENCE_TABLE ." SET restart_sequence_date_end=". $now .",restart_sequence_timer=". $new_timer ." WHERE restart_sequence_id=". $sequence_id; $db->sql_query($sql); return array('start' => $now, 'end' => $new_timer); } function tool_main_change_restart_notification($event_list, $mode, $sql_connection) { if ($sql_connection != '' && sizeof($event_list)) { $csdb = new sql_db_string($sql_connection); if (is_object($csdb)) { $sql = "UPDATE Sorbot_events SET event_action=". $mode .",event_time=". time() .",event_lap=0 WHERE event_id IN (". implode(',', array_values($event_list)) .")"; $csdb->sql_query($sql); $csdb->sql_close(); } } } function tool_main_add_restart_notification($sequence_id, $service_su, $service_egs, $shard_id, $sorbot_message_type, $sql_connection, $shard_lang='en') { nt_common_add_debug('tool_main_add_restart_notification()'); if ($sql_connection != '') { $csdb = new sql_db_string($sql_connection); if (is_object($csdb)) { $sequence_info = tool_main_get_restart_sequence_by_id($sequence_id); $shard_info = tool_main_get_domain_shard_data($sequence_info['restart_sequence_domain_id'], $sequence_info['restart_sequence_shard_id']); if ($sorbot_message_type == 4102) { //$open_timer = 60*25; // 25 minutes before a shard opens itself // new timer $open_timer = 60*10; // 10 minutes before a shard opens itself } else // 4101 { $open_timer = 0; } if ($sequence_info && $shard_info) { // lets find the shard id used by the ticket system $sql = "SELECT * FROM ForumCS_tickets_shards WHERE shard_ca='". $shard_info['domain_application'] ."' AND shard_id='". $shard_id ."'"; if ($result = $csdb->sql_query($sql)) { if ($csdb->sql_numrows($result)) { $ticketsystem_shard_info = $csdb->sql_fetchrow($result); nt_common_add_debug($ticketsystem_shard_info); $ticketsystem_shard_id = $ticketsystem_shard_info['id']; // now we have the shard id, lets see which klients servers wants events for it $sql = "SELECT * FROM Sorbot_botconfig WHERE config_name='shardRestart' AND config_value LIKE '%:". $ticketsystem_shard_id .":%'"; if ($result2 = $csdb->sql_query($sql)) { if ($csdb->sql_numrows($result2)) { //$klients_servers = array(); //while ($row = $csdb->sql_fetchrow($result2)) //{ // $klients_servers[] = $row['server_name']; //} // NOTE: live but not in CVS yet ! $local_timer = $open_timer; $klients_servers = array(); while ($row = $csdb->sql_fetchrow($result2)) { $klients_servers[] = $row['server_name']; // lets find if there is any specific opening timer, and keep the lowest one $sql = "SELECT * FROM Sorbot_botconfig WHERE server_name='". $row['server_name'] ."' AND config_name='shardRestartOpenTimer'"; if ($result3 = $csdb->sql_query($sql)) { if ($csdb->sql_numrows($result3)) { $timer_row = $csdb->sql_fetchrow($result3); if ($timer_row['config_value'] < $local_timer) { $local_timer = $timer_row['config_value']; } } } } $open_timer = $local_timer; // END NOTE: live but not in CVS yet ! // ok now we the list of servers that want this event, lets give it to them // lets build some messages $klients_countdown = ''; tool_main_get_elapsed_time_string($sequence_info['restart_sequence_timer'] - $sequence_info['restart_sequence_date_end'], $klients_countdown); $klients_countdown = trim($klients_countdown); $klients_open_countdown = ''; tool_main_get_elapsed_time_string($open_timer, $klients_open_countdown); $klients_open_countdown = trim($klients_open_countdown); $opening_message = tool_admin_restart_messages_get_list_from_name('opening',$shard_lang); $opening_message = $opening_message[0]['restart_message_value']; $opened_message = tool_admin_restart_messages_get_list_from_name('opened',$shard_lang); $opened_message = $opening_message[0]['restart_message_value']; $klients_messages = array( 'before' => array( ".topic Shard Maintenance in progress for '". $ticketsystem_shard_info['shard_name'] ."' - Shard LOCKED - (". date("r",$sequence_info['restart_sequence_date_start']) ." - Countdown set to ". $klients_countdown .")", "[Shard Maintenance] A Shard Restart has been triggered for shard '". $ticketsystem_shard_info['shard_name'] ."' on ". date("r",$sequence_info['restart_sequence_date_start']), "[Shard Maintenance] Shard is LOCKED and should go down in ". $klients_countdown, ), 'at' => array( ".topic Shard Maintenance in progress for '". $ticketsystem_shard_info['shard_name'] ."' - Shard DOWN - (". date("r",$sequence_info['restart_sequence_date_start']) .")", "[Shard Maintenance] A Shard Restart has been triggered for shard '". $ticketsystem_shard_info['shard_name'] ."' on ". date("r",$sequence_info['restart_sequence_date_start']), "[Shard Maintenance] Shard is DOWN after a countdown of ". $klients_countdown, ), 'over' => array( ".topic Shard Maintenance in finished for '". $ticketsystem_shard_info['shard_name'] ."' - Shard LOCKED - Ready for CSRs ! ETA : |EventETA| - To Open : .sorOpenShard |EventID| 0", "[Shard Maintenance] The Shard Restart that has been triggered for shard '". $ticketsystem_shard_info['shard_name'] ."' on ". date("r",$sequence_info['restart_sequence_date_start']) ." is now finished !", "[Shard Maintenance] Shard is LOCKED and Ready for CSRs, it will OPEN automatically in |EventTIME| !",/*. $klients_open_countdown ." !",*/ "[Shard Maintenance] To change the OPEN countdown, you need to send me the command : .sorOpenShard |EventID| ", "[Shard Maintenance] Example to OPEN the Shard now, you need to send me the command : .sorOpenShard |EventID| 0", ), 'open' => array( ".topic Shard Maintenance over for '". $ticketsystem_shard_info['shard_name'] ."' - Shard OPEN ", "[Shard Maintenance] The shard '". $ticketsystem_shard_info['shard_name'] ."' should now be OPEN to all !", ), 'cancel' => array( ".topic Shard Maintenance has been cancelled for '". $ticketsystem_shard_info['shard_name'] ."' - Shard OPEN", "[Shard Maintenance] The shard restart has been CANCELLED for '". $ticketsystem_shard_info['shard_name'] ."', the shard is OPEN again !", ), 'giveup' => array( ".topic Shard Maintenance for '". $ticketsystem_shard_info['shard_name'] ."' is on hold for technical issues - Shard DOWN", "[Shard Maintenance] The shard restart has been set ON HOLD for technical issues !", ), 'opening' => $opening_message, 'opened' => $opened_message, ); $notification_info = array( 'sequence' => $sequence_info, 'ts' => $ticketsystem_shard_info, 'messages' => $klients_messages, 'shard' => $shard_info, 'opentimer' => $open_timer, 'shardid' => $shard_id, 'shardsu' => $service_su, 'shardegs' => $service_egs, ); $notification_data = base64_encode(serialize($notification_info)); $event_insert_ids = array(); $sql = "LOCK TABLES Sorbot_events WRITE"; $csdb->sql_query($sql); reset($klients_servers); foreach($klients_servers as $klient_server) { $sql = "INSERT INTO Sorbot_events (`server_name`,`event_action`,`event_time`,`event_lap`,`event_params`) "; $sql .= " VALUES ('". $klient_server ."',". $sorbot_message_type .",". time() .",". $open_timer .",'". $notification_data ."')"; $csdb->sql_query($sql); $event_insert_ids[] = $csdb->sql_nextid(); } // we have a list of all the events, lets save them somewhere // lets inform each events of all other events for the same sequence if (sizeof($event_insert_ids)) { $notification_info['eventlist'] = array_values($event_insert_ids); $notification_data = base64_encode(serialize($notification_info)); $sql = "UPDATE Sorbot_events SET event_params='". $notification_data ."' WHERE event_id IN (". implode(',', array_values($event_insert_ids)) .")"; $csdb->sql_query($sql); // save the events locally too tool_main_set_restart_sequence_events($sequence_id, implode(',',array_values($event_insert_ids))); } $sql = "UNLOCK TABLES"; $csdb->sql_query($sql); } else { nt_common_add_debug('no klients server found wanting to hear about this event'); } } } else { nt_common_add_debug('no shard found in TS matching the application and shard id'); } } else { nt_common_add_debug('query failed ?!'); } } else { nt_common_add_debug('missing some information about the sequence ?!'); } $csdb->sql_close(); } else { nt_common_add_debug('failed to init db!'); } } else { nt_common_add_debug('no db string to work with'); } } function tool_main_set_restart_sequence_events($sequence_id, $events) { global $db; $sql = "UPDATE ". NELDB_RESTART_SEQUENCE_TABLE ." SET restart_sequence_events='". $events ."' WHERE restart_sequence_id=". $sequence_id; $db->sql_query($sql); } function tool_main_get_domain_shard_data($domain_id, $shard_id) { global $db; $data = null; $sql = "SELECT ". NELDB_DOMAIN_TABLE .".domain_id,"; $sql .= NELDB_DOMAIN_TABLE .".domain_name,"; $sql .= NELDB_DOMAIN_TABLE .".domain_as_host,"; $sql .= NELDB_DOMAIN_TABLE .".domain_as_port,"; $sql .= NELDB_DOMAIN_TABLE .".domain_application,"; $sql .= NELDB_SHARD_TABLE .".shard_id,"; $sql .= NELDB_SHARD_TABLE .".shard_name,"; $sql .= NELDB_SHARD_TABLE .".shard_as_id,"; $sql .= NELDB_SHARD_TABLE .".shard_domain_id,"; $sql .= NELDB_SHARD_TABLE .".shard_lang,"; $sql .= NELDB_SHARD_TABLE .".shard_restart"; $sql .= " FROM ". NELDB_DOMAIN_TABLE .",". NELDB_SHARD_TABLE; $sql .= " WHERE domain_id=shard_domain_id AND domain_id=". $domain_id ." AND shard_id=". $shard_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); } } return $data; } function tool_main_set_restart_sequence_user($AS_ShardRestart) { global $db; global $AS_Name, $AS_ShardName; global $nel_user; global $restart_notification_emails; $sequence_info = tool_main_get_restart_sequence_by_id($AS_ShardRestart); if ($sequence_info) { $sql = "UPDATE ". NELDB_RESTART_SEQUENCE_TABLE ." SET restart_sequence_user_name='". $nel_user['user_name'] ."' WHERE restart_sequence_id=". $AS_ShardRestart; $db->sql_query($sql); nt_log("Shard Restart (Domain: '". $AS_Name ."' - Shard: '". $AS_ShardName ."' - Sequence: '". $AS_ShardRestart ."') owner set to '". $nel_user['user_name'] ."'"); $email_subject = "[Shard Admin Tool] Restart Sequence Takeover (id: ".$sequence_info['restart_sequence_id'].", step: ". $sequence_info['restart_sequence_step'] .") for shard ".$AS_Name."/".$AS_ShardName." by ".$nel_user['user_name']; $email_message = $email_subject; nt_email($email_subject,$email_message,$restart_notification_emails); } } ?> ================================================ FILE: tools/server/admin/functions_tool_mfs.php ================================================ the HTTP error or response code such as 404 [1] => Array ( [Date] => Wed, 28 Apr 2004 23:29:20 GMT [Set-Cookie] => COOKIESTUFF [Expires] => Thu, 01 Dec 1994 16:00:00 GMT [Content-Type] => text/html ) [2] => Response body (string) */ do { list($response_headers,$response) = explode("\r\n\r\n",$response,2); $response_header_lines = explode("\r\n",$response_headers); // first line of headers is the HTTP response code $http_response_line = array_shift($response_header_lines); if (preg_match('@^HTTP/[0-9]\.[0-9] ([0-9]{3})@',$http_response_line, $matches)) { $response_code = $matches[1]; } else { $response_code = "Error"; } } while ((substr($response_code, 0,1) == "1") || (substr($response_code, 0,1) == "3")); $response_body = $response; // put the rest of the headers in an array $response_header_array = array(); foreach ($response_header_lines as $header_line) { list($header,$value) = explode(': ',$header_line,2); $response_header_array[$header] = $value; } return array($response_code,$response_header_array,$response_body); } ?> ================================================ FILE: tools/server/admin/functions_tool_notes.php ================================================ sql_query($sql)) { if ($db->sql_numrows($result)) { while ($row = $db->sql_fetchrow($result)) { if ($active) { $row['note_data'] = addslashes(htmlentities(html_entity_decode(str_replace("\r\n","
",$row['note_data']), ENT_QUOTES), ENT_COMPAT)); $row['note_title2'] = addslashes(htmlentities(html_entity_decode($row['note_title'], ENT_QUOTES), ENT_COMPAT)); } $data[] = $row; } } } return $data; } function tool_notes_add($user_id, $note_title, $note_data, $note_active, $note_global, $note_mode, $note_uri, $note_restriction) { global $db; $note_title = trim(stripslashes($note_title)); $note_data = trim(stripslashes($note_data)); if ($note_title == '') return "/!\ Error: note title is empty!"; //if ($note_data == '') return "/!\ Error: note data is empty!"; if ($note_mode == 'text') $note_mode = 0; else $note_mode = 1; $sql = "INSERT INTO ". NELDB_NOTE_TABLE ." (`note_user_id`,`note_title`,`note_data`,`note_date`,`note_active`,`note_global`,`note_mode`,`note_popup_uri`,`note_popup_restriction`) VALUES "; $sql .= " ('". $user_id ."','". htmlentities($note_title, ENT_QUOTES) ."','". htmlentities($note_data, ENT_QUOTES) ."','". time() ."',". $note_active .",". $note_global .",". $note_mode .",'". $note_uri ."','". $note_restriction ."')"; $db->sql_query($sql); return ""; } function tool_notes_get_id($user_id, $note_id) { global $db; $data = array(); $sql = "SELECT * FROM ". NELDB_NOTE_TABLE ." WHERE note_id=". $note_id ." AND note_user_id=". $user_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $data = $db->sql_fetchrow($result); $data['note_title'] = $data['note_title']; $data['note_data'] = $data['note_data']; } } return $data; } function tool_notes_del($user_id, $note_id) { global $db; $sql = "DELETE FROM ". NELDB_NOTE_TABLE ." WHERE note_id=". $note_id ." AND note_user_id=". $user_id; $db->sql_query($sql); } function tool_notes_update($user_id, $note_id, $note_title, $note_data, $note_active, $note_global, $note_mode, $note_uri, $note_restriction) { global $db; if ($note_mode == 'text') $note_mode = 0; else $note_mode = 1; $sql = "SELECT * FROM ". NELDB_NOTE_TABLE ." WHERE note_id=". $note_id ." AND note_user_id=". $user_id; if ($result = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { // $sql = "UPDATE ". NELDB_NOTE_TABLE ." SET note_title='". htmlentities($note_title, ENT_QUOTES) ."',note_data='". htmlentities($note_data, ENT_QUOTES) ."',note_date='". time() ."',note_active='". $note_active ."',note_global='". $note_global ."',note_mode=". $note_mode .",note_popup_uri='". $note_uri ."',note_popup_restriction='". $note_restriction ."' WHERE note_id=". $note_id; $sql = "UPDATE ". NELDB_NOTE_TABLE ." SET note_title='". htmlentities($note_title, ENT_QUOTES) ."',note_data='". htmlentities($note_data, ENT_QUOTES) ."',note_date='". time() ."',note_active='". $note_active ."',note_global='". $note_global ."' WHERE note_id=". $note_id; $db->sql_query($sql); } else { return "/!\ Error: no such note for this user!"; } } return ""; } ?> ================================================ FILE: tools/server/admin/functions_tool_player_locator.php ================================================ $service_name, 'uid' => $eregs[2], 'charid' => $eregs[1], 'shardid' => $eregs[3], 'success' => 1, ); } elseif (ereg("^Can't reloc character because user ([^\ ]+) owner of char ([^\ ]+) is online$", $su_line, $eregs)) { $entity_data = array( 'service' => $service_name, 'uid' => $eregs[1], 'charid' => $eregs[2], 'shardid' => 'na', 'success' => 0, ); } } } return $entity_data; } function tool_pl_parse_locate($data) { $entity_data = array(); reset($data); foreach($data as $egs_data) { $service_name = 'n/a'; reset($egs_data); foreach($egs_data as $egs_line) { $egs_line = trim($egs_line); if (ereg("^===\[ Service ([^\ ]+) returned \]===$", $egs_line, $eregs)) { $service_name = $eregs[1]; } elseif (ereg("^UId ([^\ ]+) UserName '([^\ ]*)' EId ([^\ ]+) EntityName '([^\ ]*)' EntitySlot ([^\ ]+) SaveFile ([^\ ]+) ([^\ ]+)$", $egs_line, $eregs)) { $entity_data[] = array( 'service' => $service_name, 'uid' => $eregs[1], 'user_name' => $eregs[2], 'eid' => $eregs[3], 'entity_name' => $eregs[4], 'entity_slot' => $eregs[5], 'save_file' => $eregs[6], 'status' => $eregs[7], 'posx' => 'n/a', 'posy' => 'n/a', 'posz' => 'n/a', 'session' => 'n/a', ); } elseif (ereg("^UId ([^\ ]+) UserName '([^\ ]*)' EId ([^\ ]+) EntityName '([^\ ]*)' EntitySlot ([^\ ]+) SaveFile ([^\ ]+) Pos: ([^,\ ]+),([^,\ ]+),([^,\ ]+) Session: ([^\ ]+) ([^\ ]+)$", $egs_line, $eregs)) { $entity_data[] = array( 'service' => $service_name, 'uid' => $eregs[1], 'user_name' => $eregs[2], 'eid' => $eregs[3], 'entity_name' => $eregs[4], 'entity_slot' => $eregs[5], 'save_file' => $eregs[6], 'status' => $eregs[11], 'posx' => $eregs[7], 'posy' => $eregs[8], 'posz' => $eregs[9], 'session' => $eregs[10], ); } } } return $entity_data; } function tool_pl_parse_display_players($data) { $entity_data = array(); reset($data); foreach($data as $egs_data) { $service_name = 'n/a'; reset($egs_data); foreach($egs_data as $egs_line) { $egs_line = trim($egs_line); if (ereg("^===\[ Service ([^\ ]+) returned \]===$", $egs_line, $eregs)) { $service_name = $eregs[1]; } elseif (ereg("^Player: ([^\ ]+) Name: ([^\ ]+) ID: ([^\ ]+) FE: ([^\ ]+) Sheet: ([^\ ]+) - ([^\ ]+) Priv: '([^\ ]*)'$", $egs_line, $eregs)) { $entity_data[] = array( 'service' => $service_name, 'player' => $eregs[1], 'name' => $eregs[2], 'id' => $eregs[3], 'fe' => $eregs[4], 'sheet' => $eregs[5] .' - '. $eregs[6], 'priv' => $eregs[7], 'posx' => 'n/a', 'posy' => 'n/a', 'posz' => 'n/a', 'session' => 'n/a', ); } elseif (ereg("^Player: ([^\ ]+) Name: ([^\ ]+) ID: ([^\ ]+) FE: ([^\ ]+) Sheet: ([^\ ]+) - ([^\ ]+) Priv: '([^\ ]*)' Pos: ([^,\ ]+),([^,\ ]+),([^,\ ]+) Session: ([^\ ]+)$", $egs_line, $eregs)) { $entity_data[] = array( 'service' => $service_name, 'player' => $eregs[1], 'name' => $eregs[2], 'id' => $eregs[3], 'fe' => $eregs[4], 'sheet' => $eregs[5] .' - '. $eregs[6], 'priv' => $eregs[7], 'posx' => $eregs[8], 'posy' => $eregs[9], 'posz' => $eregs[10], 'session' => $eregs[11], ); } } } return $entity_data; } function tool_pl_get_character_check_list($AS_Application, $AS_RingSQL) { global $db; $data = null; if ($AS_RingSQL == '') { if ($db->sql_select_db('nel')) { $sql = "SELECT ring_db_name FROM domain WHERE domain_name='". $AS_Application ."'"; if ($resutl = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $domain_row = $db->sql_fetchrow($result); if ($db->sql_select_db($domain_row['ring_db_name'])) { $sql = "SELECT * FROM characters WHERE user_id=0"; if ($result2 = $db->sql_query($sql)) { if ($db->sql_numrows($result2)) { $data = $db->sql_fetchrowset($result2); } } } } } $db->sql_reselect_db(); } } else { $db2 = new sql_db_string($AS_RingSQL); if (is_object($db2)) { $sql = "SELECT * FROM characters WHERE user_id=0"; if ($result2 = $db2->sql_query($sql)) { if ($db2->sql_numrows($result2)) { $data = $db2->sql_fetchrowset($result2); } } } } return $data; } function tool_pl_fix_character_check_list($AS_Application) { global $db; if ($db->sql_select_db('nel')) { $sql = "SELECT ring_db_name FROM domain WHERE domain_name='". $AS_Application ."'"; if ($resutl = $db->sql_query($sql)) { if ($db->sql_numrows($result)) { $domain_row = $db->sql_fetchrow($result); if ($db->sql_select_db($domain_row['ring_db_name'])) { $sql = "UPDATE characters SET user_id=FLOOR(char_id/16) WHERE user_id=0"; $db->sql_query($sql); } } } $db->sql_reselect_db(); } } ?> ================================================ FILE: tools/server/admin/functions_tool_preferences.php ================================================ sql_query($sql); return true; } function tool_pref_update_menu_style($userinfo, $menu) { global $db; $sql = "UPDATE ". NELDB_USER_TABLE ." SET user_menu_style=". $menu ." WHERE user_id=". $userinfo['user_id']; $db->sql_query($sql); } function tool_pref_update_default_application($userinfo, $application_id) { global $db; $sql = "UPDATE ". NELDB_USER_TABLE ." SET user_default_application_id=". $application_id ." WHERE user_id=". $userinfo['user_id']; $db->sql_query($sql); } ?> ================================================ FILE: tools/server/admin/functions_tool_shop.php ================================================ $post_val) { $val = 'checkshoplist_'. $post_val; if ($post_key == $val) { $check_items = $check_items ."`". $post_val; } } return $check_items; } function tool_sp_parse_shop_list($data) { $entity_data = array(); reset($data); foreach($data as $egs_data) { $service_name = 'n/a'; reset($egs_data); foreach($egs_data as $egs_line) { $egs_line = trim($egs_line); if (ereg("^===\[ Service ([^\ ]+) returned \]===$", $egs_line, $eregs)) { $service_name = $eregs[1]; } elseif (ereg("^SID: ([^\ ]+) IDX: ([^\ ]+) TID: ([^\ ]+) Name: ([^\ ]+) NUM: ([^\ ]+) PRICE: ([^\ ]+)$", $egs_line, $eregs)) { $entity_data[] = array( 'service' => $service_name, 'shardid' => $eregs[1], 'idx' => $eregs[2], 'tid' => $eregs[3], 'name' => $eregs[4], 'num' => $eregs[5], 'price' => $eregs[6], ); } } } return $entity_data; } ?> ================================================ FILE: tools/server/admin/graphs_output/placeholder ================================================ ================================================ FILE: tools/server/admin/index.php ================================================ assign('tool_title', "Main"); $view_domain_id = nt_auth_get_session_var('view_domain_id'); $view_shard_id = nt_auth_get_session_var('view_shard_id'); if (!$view_domain_id) { $view_domain_id = $nel_user['group_default_domain_id']; $view_shard_id = $nel_user['group_default_shard_id']; nt_auth_set_session_var('view_domain_id', $view_domain_id); nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (isset($_GET['domain'])) { if ($view_domain_id != $_GET['domain']) { $view_domain_id = $_GET['domain']; nt_auth_set_session_var('view_domain_id', $view_domain_id); $view_shard_id = null; nt_auth_unset_session_var('view_shard_id'); } } if (isset($_GET['shard'])) { $view_shard_id = $_GET['shard']; nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (!tool_main_check_user_domain($view_domain_id)) $view_domain_id = null; if (!tool_main_check_user_shard($view_shard_id)) $view_shard_id = null; $current_refresh_rate = nt_auth_get_session_var('current_refresh_rate'); if (isset($_POST['services_refresh'])) { if ($current_refresh_rate != $_POST['services_refresh']) { $current_refresh_rate = $_POST['services_refresh']; nt_auth_set_session_var('current_refresh_rate',$current_refresh_rate); } } if ($current_refresh_rate == null) { $current_refresh_rate = 0; } elseif ($current_refresh_rate > 0) { $tpl->assign('nel_tool_refresh', ''); } $tpl->assign('tool_refresh_list', $refresh_rates); $tpl->assign('tool_refresh_rate', $current_refresh_rate); $tpl->assign('tool_domain_list', $nel_user['access']['domains']); $tpl->assign('tool_domain_selected', $view_domain_id); $tpl->assign('tool_shard_list', $nel_user['access']['shards']); $tpl->assign('tool_shard_selected', $view_shard_id); $tool_shard_filters = tool_main_get_shard_ids($view_shard_id); $tpl->assign('tool_shard_filters', $tool_shard_filters); $AS_Host = tool_main_get_domain_host($view_domain_id); $AS_Port = tool_main_get_domain_port($view_domain_id); $AS_Name = tool_main_get_domain_name($view_domain_id); $AS_Application = tool_main_get_domain_data($view_domain_id, 'domain_application'); $AS_RingSQL = tool_main_get_domain_data($view_domain_id, 'domain_sql_string'); $AS_CsSQL = tool_main_get_domain_data($view_domain_id, 'domain_cs_sql_string'); $AS_ShardName = tool_main_get_shard_name($view_shard_id); $AS_InternalName = tool_main_get_shard_as_id($view_shard_id); $AS_ShardRestart = tool_main_get_shard_data($view_shard_id, 'shard_restart'); $AS_ShardDomainRestart = tool_main_get_domain_shard_restart($view_domain_id); $AS_ShardLang = tool_main_get_shard_data($view_shard_id, 'shard_lang'); $tpl->assign('tool_shard_restart_status', $AS_ShardRestart); $tpl->assign('tool_domain_has_shard_restart', $AS_ShardDomainRestart); $tool_no_domain_lock = false; if (($AS_InternalName == '*') && ($AS_ShardDomainRestart > 0)) { $tool_no_domain_lock = true; $tpl->assign('tool_no_domain_lock', $tool_no_domain_lock); } $tpl->assign('tool_page_title', $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : '')); $tool_annotation_info = tool_main_get_annotation($view_domain_id, $view_shard_id); $tool_lock_info = tool_main_get_lock($view_domain_id, $view_shard_id); // we check if the last activity on the lock is too old, in which case we unlock // and only if there are no restart sequence going on (prevent loosing lock when inactive for too long during restart sequence - patch ...) if ((LOCK_TIMEOUT > 0) && is_array($tool_lock_info) && ($AS_ShardRestart == 0) && !$tool_no_domain_lock) { $now = time(); if ($tool_lock_info['lock_update'] + LOCK_TIMEOUT < $now) { if ($tool_lock_info['lock_domain_id']) tool_main_delete_lock_domain($view_domain_id); if ($tool_lock_info['lock_shard_id']) tool_main_delete_lock_shard($view_shard_id); $tool_lock_info = tool_main_get_lock($view_domain_id, $view_shard_id); } } // we update the lock data for the last activity time if (is_array($tool_lock_info) && $tool_lock_info['lock_user_name'] == $nel_user['user_name']) { if ($tool_lock_info['lock_domain_id']) tool_main_set_lock_domain($view_domain_id, false); if ($tool_lock_info['lock_shard_id']) tool_main_set_lock_shard($view_domain_id, $view_shard_id, false); $tool_lock_info = tool_main_get_lock($view_domain_id, $view_shard_id); } if (tool_admin_applications_check('tool_main_lock_shard') || tool_admin_applications_check('tool_main_lock_domain')) { if (isset($NELTOOL['POST_VARS']['lock'])) { $tool_lock_mode = $NELTOOL['POST_VARS']['lock']; switch ($tool_lock_mode) { case 'lock shard': if (tool_admin_applications_check('tool_main_lock_shard')) { tool_main_set_lock_shard($view_domain_id, $view_shard_id); $tool_lock_info = tool_main_get_lock($view_domain_id, $view_shard_id); if ($AS_ShardRestart > 0) { tool_main_set_restart_sequence_user($AS_ShardRestart); } } break; case 'lock domain': if (tool_admin_applications_check('tool_main_lock_domain')) { tool_main_set_lock_domain($view_domain_id); $tool_lock_info = tool_main_get_lock($view_domain_id, $view_shard_id); } break; case 'unlock shard': if (is_array($tool_lock_info) && $tool_lock_info['lock_user_name'] == $nel_user['user_name']) { tool_main_delete_lock_shard($view_shard_id); $tool_lock_info = tool_main_get_lock($view_domain_id, $view_shard_id); } break; case 'unlock domain': if (is_array($tool_lock_info) && $tool_lock_info['lock_user_name'] == $nel_user['user_name']) { tool_main_delete_lock_domain($view_domain_id); $tool_lock_info = tool_main_get_lock($view_domain_id, $view_shard_id); } break; case 'update annotation': if (is_array($tool_lock_info) && $tool_lock_info['lock_user_name'] == $nel_user['user_name']) { $tool_annotation = $NELTOOL['POST_VARS']['annotation']; tool_main_set_annotation($view_domain_id, $view_shard_id, $tool_annotation); $tool_annotation_info = tool_main_get_annotation($view_domain_id, $view_shard_id); } break; case 'restart sequence': if (is_array($tool_lock_info) && $tool_lock_info['lock_user_name'] == $nel_user['user_name'] && tool_admin_applications_check('tool_main_easy_restart')) { $restart_ws_state = $NELTOOL['POST_VARS']['restart_ws_state']; $restart_first_step = 0; // if restart_ws_state == '' means that i didn't find a shard_id // which means the shard has been shutdown completely including AES and RAS if ($restart_ws_state == 'close' || $restart_ws_state == '') $restart_first_step = 3; $tool_restart_info = tool_main_set_restart_mode($view_domain_id, $view_shard_id, $restart_first_step); } break; } } if (is_array($tool_lock_info) && $tool_lock_info['lock_user_name'] == $nel_user['user_name']) { if (tool_admin_applications_check('tool_main_start')) $tpl->assign('restriction_tool_main_start', true); if (tool_admin_applications_check('tool_main_stop')) $tpl->assign('restriction_tool_main_stop', true); if (tool_admin_applications_check('tool_main_restart')) $tpl->assign('restriction_tool_main_restart', true); if (tool_admin_applications_check('tool_main_kill')) $tpl->assign('restriction_tool_main_kill', true); if (tool_admin_applications_check('tool_main_abort')) $tpl->assign('restriction_tool_main_abort', true); if (tool_admin_applications_check('tool_main_execute')) $tpl->assign('restriction_tool_main_execute', true); if (tool_admin_applications_check('tool_main_ws')) $tpl->assign('restriction_tool_main_ws', true); if (tool_admin_applications_check('tool_main_ws_old')) $tpl->assign('restriction_tool_main_ws_old', true); if (tool_admin_applications_check('tool_main_reset_counters')) $tpl->assign('restriction_tool_main_reset_counters', true); if (tool_admin_applications_check('tool_main_service_autostart')) $tpl->assign('restriction_tool_main_service_autostart', true); if (tool_admin_applications_check('tool_main_shard_autostart')) $tpl->assign('restriction_tool_main_shard_autostart', true); if (tool_admin_applications_check('tool_main_easy_restart')) $tpl->assign('restriction_tool_main_easy_restart', true); $nel_user['has_lock'] = true; if ($tool_lock_info['lock_shard_id'] > 0) $tpl->assign('tool_has_shard_lock', true); elseif ($tool_lock_info['lock_domain_id'] > 0) $tpl->assign('tool_has_domain_lock', true); if ($AS_ShardRestart > 0) { // define the shards language $tpl->assign('tool_shard_language', $AS_ShardLang); $tpl->assign('tool_language_list', $tool_language_list); $tool_restart_message_reboot_list = tool_admin_restart_messages_get_list_from_name('reboot'); $tpl->assign('tool_restart_message_reboot_list', $tool_restart_message_reboot_list); $tool_restart_stop_list = tool_admin_restarts_get_list('DESC'); $tool_restart_start_list = tool_admin_restarts_get_list('ASC'); // they are assigned at the end of the script //$tpl->assign('tool_restart_stop_actions', $tool_restart_stop_list); //$tpl->assign('tool_restart_start_actions', $tool_restart_start_list); //$tool_restart_message_ready_list = tool_admin_restart_messages_get_list_from_name('ready'); //$tpl->assign('tool_restart_message_ready_list', $tool_restart_message_ready_list); //$tool_restart_message_list = tool_admin_restart_messages_get_list_from_name('open'); // restart information $tool_restart_info = tool_main_get_restart_sequence_by_id($AS_ShardRestart); $tpl->assign('tool_restart_info', $tool_restart_info); } $tpl->assign('tool_has_lock', true); } else { $tpl->assign('tool_no_lock', true); $tpl->assign('tool_no_annotation', true); } } if (tool_admin_applications_check('tool_main_lock_shard')) $tpl->assign('restriction_tool_main_lock_shard',true); if (tool_admin_applications_check('tool_main_lock_domain')) $tpl->assign('restriction_tool_main_lock_domain',true); elseif (!tool_admin_applications_check('tool_main_lock_domain') && tool_admin_applications_check('tool_main_lock_shard') && (tool_main_get_shard_as_id($view_shard_id) == "*")) { // you have shard lock access // but you don't have domain access // and you are viewing the * shard // locking the shard * will lock the domain // so you must not be able to lock this shard $tpl->assign('tool_cant_lock', true); } $tpl->assign('tool_lock_info', $tool_lock_info); $tpl->assign('tool_annotation_info', $tool_annotation_info); if (tool_admin_applications_check('tool_notes')) { $tool_note_list = tool_notes_get_list($nel_user['user_id'], 1); if (sizeof($tool_note_list)) { $tpl->assign('restriction_tool_notes', true); $tpl->assign('tool_note_list', $tool_note_list); } } $tool_as_error = null; if ($AS_Host && $AS_Port) { $adminService = new MyAdminService; if (@$adminService->connect($AS_Host, $AS_Port, $res) === false) { nt_common_add_debug($res); $tpl->assign('tool_domain_error', $res ); } else { if ($nel_user['has_lock']) { //nt_common_add_debug("HTTP_POST_VARS"); //nt_common_add_debug($HTTP_POST_VARS); //echo '
'. print_r($HTTP_POST_VARS,true) .'
'; //die(); // make sure you are the one who has its name in the restart info // as you can take over the lock and the restart sequence // we don't want more than 1 client executing the restart commands if they think they still have the lock if (isset($tool_restart_info) && ($tool_restart_info['restart_sequence_user_name'] == $nel_user['user_name']) && tool_admin_applications_check('tool_main_easy_restart')) { $tool_seq_id = $NELTOOL['POST_VARS']['restart_sequence_id']; $tool_seq_step = $NELTOOL['POST_VARS']['restart_sequence_step']; $restart_shard_id = $NELTOOL['POST_VARS']['restart_shard_id']; $service_su = $NELTOOL['POST_VARS']['restart_su']; $service_egs = $NELTOOL['POST_VARS']['restart_egs']; $restart_stop_services = $NELTOOL['POST_VARS']['restart_stop_services']; if (isset($NELTOOL['POST_VARS']['restart_check_ws'])) { // we are starting the restart sequence $restart_ws_state = $NELTOOL['POST_VARS']['restart_ws_state']; if ($restart_ws_state == 'open') { // shard needs a regular restart // - broadcast a message on the shard $restart_reboot_message_id = $NELTOOL['POST_VARS']['restart_message_reboot_id']; $restart_reboot_message_data = tool_admin_restart_messages_get_id($restart_reboot_message_id); $restart_reboot_message = $restart_reboot_message_data['restart_message_value']; if ($restart_reboot_message != '') { $service_command = "broadcast repeat=10 every=60 ". $restart_reboot_message; nt_log("Domain '$AS_Name' : '$service_command' on ". $service_egs); nt_common_add_debug("about to run command '$service_command' on '$service_egs' ..."); $adminService->serviceCmd($service_egs, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service_egs .'\' for command : '. $service_command); } $tpl->clear_assign('tool_execute_result'); } // - prepare next step (timer countdown to 10 minutes) if($restart_shard_id == 301) { // Fast restart for yubo shard (1mn) tool_main_set_restart_sequence_timer($tool_seq_id, 60); nt_common_add_debug("fast restart for yubo shard 301"); } else { tool_main_set_restart_sequence_timer($tool_seq_id, 600); nt_common_add_debug("normal restart for live shard"); } // - lets start by locking the WS $service_command = 'rsm.setWSState '. $restart_shard_id .' RESTRICTED ""'; nt_common_add_debug("about to run command '$service_command' on '$service_su' ..."); $adminService->serviceCmd($service_su, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service_su .'\' for command : '. $service_command); } $tpl->clear_assign('tool_execute_result'); nt_sleep(VIEW_DELAY); } else { // shard needs an immediate restart // - prepare next step (timer countdown to a few seconds) tool_main_set_restart_sequence_timer($tool_seq_id, 30); } // - inform CS about the restart tool_main_add_restart_notification($tool_seq_id, $service_su, $service_egs, $restart_shard_id, 4101, $AS_CsSQL, $AS_ShardLang); // - resend the services to stop for the next step $tpl->assign('tool_restart_stop_actions', $restart_stop_services); // - move on to the next step $tool_restart_info = tool_main_set_next_restart_sequence_step($tool_seq_id, $tool_seq_step + 1); $tpl->assign('tool_restart_info', $tool_restart_info); } elseif (isset($NELTOOL['POST_VARS']['restart_back'])) { // this makes you go to the next step if ($tool_seq_id == $tool_restart_info['restart_sequence_id']) { $tool_restart_info = tool_main_set_next_restart_sequence_step($tool_seq_id, $tool_seq_step - 1); $tpl->assign('tool_restart_info', $tool_restart_info); } } elseif (isset($NELTOOL['POST_VARS']['restart_end'])) { tool_main_set_end_restart_sequence($tool_seq_id); nt_common_redirect('index.php'); exit(); } elseif (isset($NELTOOL['POST_VARS']['restart_continue'])) { // this makes you go to the next step if ($tool_seq_id == $tool_restart_info['restart_sequence_id']) { $tool_restart_info = tool_main_set_next_restart_sequence_step($tool_seq_id, $tool_seq_step + 1); $tpl->assign('tool_restart_info', $tool_restart_info); } } elseif (isset($NELTOOL['POST_VARS']['restart_giveup'])) { // update klients events to giveup mode //$klients_events = explode(',',$tool_restart_info['restart_sequence_events']); //tool_main_change_restart_notification($klients_events, 4105, $AS_CsSQL); tool_main_add_restart_notification($tool_seq_id, $service_su, $service_egs, $restart_shard_id, 4105, $AS_CsSQL, $AS_ShardLang); tool_main_set_end_restart_sequence($tool_seq_id); nt_common_redirect('index.php'); exit(); } elseif (isset($NELTOOL['POST_VARS']['restart_cancel'])) { if ($restart_ws_state != 'open') { // - broadcast a message on the shard $restart_reboot_message_data = tool_admin_restart_messages_get_list_from_name('cancel', $AS_ShardLang); if (sizeof($restart_reboot_message_data)) { $restart_reboot_message = $restart_reboot_message_data[0]['restart_message_value']; if ($restart_reboot_message != '') { $service_command = "broadcast ". $restart_reboot_message; nt_log("Domain '$AS_Name' : '$service_command' on ". $service_egs); nt_common_add_debug("about to run command '$service_command' on '$service_egs' ..."); $adminService->serviceCmd($service_egs, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service_egs .'\' for command : '. $service_command); } $tpl->clear_assign('tool_execute_result'); } } // update the klients events to cancelled mode $klients_events = explode(',',$tool_restart_info['restart_sequence_events']); tool_main_change_restart_notification($klients_events, 4104, $AS_CsSQL); // - open the WS again $service_command = 'rsm.setWSState '. $restart_shard_id .' OPEN ""'; nt_common_add_debug("about to run command '$service_command' on '$service_su' ..."); $adminService->serviceCmd($service_su, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service_su .'\' for command : '. $service_command); } $tpl->clear_assign('tool_execute_result'); nt_sleep(VIEW_DELAY); // end the sequence and refresh tool_main_set_end_restart_sequence($tool_seq_id); nt_common_redirect('index.php'); exit(); } } elseif (isset($NELTOOL['POST_VARS']['restart_wait_timer'])) { // step 1, waited for the timer, lets shutdown the shard $service_list = explode(',', $restart_stop_services); if (sizeof($service_list)) { // comment out to prevent stopping services for testing purposes nt_log("Domain '$AS_Name' : 'stopService' on ". implode(', ',array_values($service_list))); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'stopService' on '$service' ..."); $adminService->controlCmd($service, 'stopService'); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for stopService'); } } nt_sleep(VIEW_DELAY); } // - prepare next step (timer countdown to a few seconds) tool_main_set_restart_sequence_timer($tool_seq_id, 30); // - move on to the next step $tool_restart_info = tool_main_set_next_restart_sequence_step($tool_seq_id, $tool_seq_step + 1); $tpl->assign('tool_restart_info', $tool_restart_info); } elseif (isset($NELTOOL['POST_VARS']['restart_shutdown_timer'])) { // step 2, waited for the shutdown timer, lets move on // - move on to the next step $tool_restart_info = tool_main_set_next_restart_sequence_step($tool_seq_id, $tool_seq_step + 1); $tpl->assign('tool_restart_info', $tool_restart_info); } elseif (isset($NELTOOL['POST_VARS']['restart_start_group'])) { // step 4, start a group of services $tool_seq_start_id = $NELTOOL['POST_VARS']['restart_start_group_id']; $tool_seq_start_list = $NELTOOL['POST_VARS']['restart_start_group_list']; if (isset($tool_restart_start_list)) { foreach($tool_restart_start_list as $restart_start_group) { if ($restart_start_group['restart_group_id'] == $tool_seq_start_id) { $service_list = explode(',', $tool_seq_start_list); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : 'startService' on ". implode(', ',array_values($service_list))); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'startService' on '$service' ..."); $adminService->controlCmd($service, 'startService'); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for startService'); } } nt_sleep(VIEW_DELAY); } break; } } } } elseif (isset($NELTOOL['POST_VARS']['restart_stop_group'])) { // step 3, stop a group of services $tool_seq_stop_id = $NELTOOL['POST_VARS']['restart_stop_group_id']; $tool_seq_stop_list = $NELTOOL['POST_VARS']['restart_stop_group_list']; if (isset($tool_restart_stop_list)) { $service_list = explode(',', $tool_seq_stop_list); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : 'stopService' on ". implode(', ',array_values($service_list))); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'stopService' on '$service' ..."); $adminService->controlCmd($service, 'stopService'); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for stopService'); } } nt_sleep(VIEW_DELAY); } } } elseif (isset($NELTOOL['POST_VARS']['restart_over'])) { // this makes you go to the next step if ($tool_seq_id == $tool_restart_info['restart_sequence_id']) { // - inform CS that the shard is ready and locked tool_main_add_restart_notification($tool_seq_id, $service_su, $service_egs, $restart_shard_id, 4102, $AS_CsSQL, $AS_ShardLang); $tool_restart_info = tool_main_set_next_restart_sequence_step($tool_seq_id, $tool_seq_step + 1); $tpl->assign('tool_restart_info', $tool_restart_info); } } //elseif (isset($NELTOOL['POST_VARS']['restart_broadcast_open'])) //{ // // step 6, open ws, end restart sequence // // // - open WS // $service = $NELTOOL['POST_VARS']['restart_su']; // $restart_shard_id = $NELTOOL['POST_VARS']['restart_shard_id']; // // $service_command = 'rsm.setWSState '. $restart_shard_id .' OPEN ""'; // nt_common_add_debug("about to run command '$service_command' on '$service' ..."); // // $adminService->serviceCmd($service, $service_command); // if (!$adminService->waitCallback()) // { // nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); // } // // $tpl->clear_assign('tool_execute_result'); // nt_sleep(VIEW_DELAY); // // // - end restart sequence // tool_main_set_end_restart_sequence($tool_seq_id); // nt_common_redirect('index.php'); // exit(); //} } elseif (isset($_POST['shards_update']) && tool_admin_applications_check('tool_main_shard_autostart')) { $shard_update_mode = $_POST['shards_update']; $shard_update_name = $_POST['shards_update_name']; switch ($shard_update_mode) { case 'auto restart on': $as_command = "setShardStartMode ". $shard_update_name ." on"; nt_log("Domain '$AS_Name' : $as_command"); nt_common_add_debug("about to run '$as_command' ..."); $adminService->globalCmd($as_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback for \''. $as_command .'\''); } nt_sleep(VIEW_DELAY); break; case 'auto restart off': $as_command = "setShardStartMode ". $shard_update_name ." off"; nt_log("Domain '$AS_Name' : $as_command"); nt_common_add_debug("about to run '$as_command' ..."); $adminService->globalCmd($as_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback for \''. $as_command .'\''); } nt_sleep(VIEW_DELAY); break; } } elseif (isset($_POST['ws_update']) && tool_admin_applications_check('tool_main_ws')) { $shard_ws_su = $_POST['ws_su']; $shard_ws_shard_name = $_POST['ws_shard_name']; $shard_ws_shard_id = $_POST['ws_shard_id']; $shard_ws_state = $_POST['ws_state_'. $shard_ws_shard_name]; $shard_ws_motd = $_POST['ws_motd_'. $shard_ws_shard_name]; // coders don't know how to write it seems // ace: now they know if ($shard_ws_state == 'close') $shard_ws_state = 'closed'; //nt_common_add_debug("request for ". $shard_ws_su ."/". $shard_ws_shard_name ." to set STATE:". $shard_ws_state ." (". $shard_ws_motd .")"); $service = $shard_ws_su; $service_command = 'rsm.setWSState '. $shard_ws_shard_id .' '. strtoupper($shard_ws_state) .' "'. $shard_ws_motd .'"'; nt_common_add_debug("about to run command '$service_command' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } $tpl->clear_assign('tool_execute_result'); nt_sleep(VIEW_DELAY); } elseif (isset($_POST['services_update'])) { $service_update_mode = $_POST['services_update']; switch ($service_update_mode) { case 'open ws': // 2 if (tool_admin_applications_check('tool_main_ws_old')) { $service_command = "ShardOpen 2"; $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); nt_common_add_debug(array_combine($service_list, $service_list)); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $tpl->assign('tool_execute_result', ''); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run command '$service_command' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } } $tpl->clear_assign('tool_execute_result'); nt_sleep(VIEW_DELAY); } } break; case 'lock ws': // 1 if (tool_admin_applications_check('tool_main_ws_old')) { $service_command = "ShardOpen 1"; $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); nt_common_add_debug(array_combine($service_list, $service_list)); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $tpl->assign('tool_execute_result', ''); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run command '$service_command' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } } $tpl->clear_assign('tool_execute_result'); nt_sleep(VIEW_DELAY); } } break; case 'close ws': if (tool_admin_applications_check('tool_main_ws_old')) { $service_command = "ShardOpen 0"; $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); nt_common_add_debug(array_combine($service_list, $service_list)); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $tpl->assign('tool_execute_result', ''); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run command '$service_command' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } } $tpl->clear_assign('tool_execute_result'); nt_sleep(VIEW_DELAY); } } break; case 'activate': if (tool_admin_applications_check('tool_main_service_autostart')) { $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : 'activateService' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'activateService' on '$service' ..."); $adminService->controlCmd($service, 'activateService'); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback for \''. $service .'\''); } } nt_sleep(VIEW_DELAY); } } break; case 'deactivate': if (tool_admin_applications_check('tool_main_service_autostart')) { $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : 'deactivateService' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'deactivateService' on '$service' ..."); $adminService->controlCmd($service, 'deactivateService'); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback for \''. $service .'\''); } } nt_sleep(VIEW_DELAY); } } break; case 'reset counters': if (tool_admin_applications_check('tool_main_reset_counters')) { $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : 'resetStartCounter' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'resetStartCounter' on '$service' ..."); $adminService->serviceCmd($service, 'aes.resetStartCounter'); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback for \''. $service .'\''); } } nt_sleep(VIEW_DELAY); } } break; case 'start': if (tool_admin_applications_check('tool_main_start')) { $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : 'startService' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'startService' on '$service' ..."); $adminService->controlCmd($service, 'startService'); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for startService'); } } nt_sleep(VIEW_DELAY); } } break; case 'stop': if (tool_admin_applications_check('tool_main_stop')) { $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : 'stopService' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'stopService' on '$service' ..."); $adminService->controlCmd($service, 'stopService'); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for stopService'); } } nt_sleep(VIEW_DELAY); } } break; case 'restart': if (tool_admin_applications_check('tool_main_restart')) { $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : 'restartService' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'restartService' on '$service' ..."); $adminService->controlCmd($service, 'restartService'); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for restartService'); } } nt_sleep(VIEW_DELAY); } } break; case 'kill': if (tool_admin_applications_check('tool_main_kill')) { $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : 'killService' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'killService' on '$service' ..."); $adminService->controlCmd($service, 'killService'); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for killService'); } } nt_sleep(VIEW_DELAY); } } break; case 'abort': if (tool_admin_applications_check('tool_main_abort')) { $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : 'abortService' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'abortService' on '$service' ..."); $adminService->controlCmd($service, 'abortService'); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for abortService'); } } nt_sleep(VIEW_DELAY); } } break; case 'execute': if (tool_admin_applications_check('tool_main_execute')) { if (isset($_POST['service_command'])) { $service_command = trim(stripslashes(html_entity_decode($_POST['service_command'], ENT_QUOTES))); $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); nt_common_add_debug(array_combine($service_list, $service_list)); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $tpl->assign('tool_execute_result', ''); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run command '$service_command' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { $tpl->assign('tool_execute_command', htmlentities($service_command, ENT_QUOTES)); } } } } } break; } } } // if ($nel_user['has_lock']) $status_orders = $adminService->getShardOrders(); $status = $adminService->getStates(); nt_common_add_debug($status_orders); nt_common_add_debug($status); $domainServices = tool_main_parse_status($status); $shardRunList = tool_main_get_shards_from_status($domainServices, $tool_shard_filters); $shardRunOrders = tool_main_get_shards_orders($status_orders); nt_common_add_debug($shardRunList); nt_common_add_debug($shardRunOrders); $shardInfos = tool_main_get_shards_info_from_db($AS_Application, $domainServices, $tool_shard_filters, $AS_RingSQL); nt_common_add_debug("shard infos :"); nt_common_add_debug($shardInfos); $tpl->assign('tool_services_list', $domainServices); $tpl->assign('tool_shard_run_list', $shardRunList); $tpl->assign('tool_shard_orders', $shardRunOrders); $tpl->assign('tool_shard_su_name', tool_main_get_su_from_status($domainServices)); $tpl->assign('tool_shard_infos', $shardInfos); $tpl->assign('tool_shard_ws_states',array('close','dev','restricted','open')); if (isset($shardInfos[$AS_InternalName])) { $tpl->assign('tool_restart_ws_state', $shardInfos[$AS_InternalName]['state']); } if (isset($tool_restart_stop_list) && isset($tool_restart_info) && tool_admin_applications_check('tool_main_easy_restart')) { // lets get a list of services for each group $tool_restart_start_group_list = tool_main_get_restart_services($AS_InternalName, $domainServices, $tool_restart_start_list); $tpl->assign('tool_restart_start_actions', $tool_restart_start_group_list); $tool_restart_stop_group_list = tool_main_get_all_restart_services($tool_restart_start_group_list); $tpl->assign('tool_restart_stop_actions', $tool_restart_stop_group_list); // get the shard id $tool_restart_shard_id = tool_main_get_shardid_from_status($domainServices, $AS_InternalName); $tpl->assign('tool_restart_shard_id', $tool_restart_shard_id); // find the shard egs for broadcasts $tool_restart_egs_name = tool_main_get_egs_from_status($domainServices, $AS_InternalName); $tpl->assign('tool_restart_egs_name', $tool_restart_egs_name); } } $tool_hd_list = tool_main_get_hd_data_for_domain($view_domain_id); nt_common_add_debug($tool_hd_list); $tpl->assign('tool_hd_list', $tool_hd_list); $tpl->assign('tool_hd_time', tool_main_get_last_hd_time_for_domain($view_domain_id)); } //else //{ // nt_common_add_debug('invalid host/port!'); //} $tpl->display('index.tpl'); ?> ================================================ FILE: tools/server/admin/jpgraph/imgdata_balls.inc ================================================ 'imgdata_large', MARK_IMG_MBALL => 'imgdata_small', MARK_IMG_SBALL => 'imgdata_xsmall', MARK_IMG_BALL => 'imgdata_xsmall'); var $colors_1 = array('blue','lightblue','brown','darkgreen', 'green','purple','red','gray','yellow','silver','gray'); var $index_1 = array('blue'=>9,'lightblue'=>1,'brown'=>6,'darkgreen'=>7, 'green'=>8,'purple'=>4,'red'=>0,'gray'=>5,'silver'=>3,'yellow'=>2); var $maxidx_1 = 9 ; var $colors_2 = array('blue','bluegreen','brown','cyan', 'darkgray','greengray','gray','green', 'greenblue','lightblue','lightred', 'purple','red','white','yellow'); var $index_2 = array('blue'=>9,'bluegreen'=>13,'brown'=>8,'cyan'=>12, 'darkgray'=>5,'greengray'=>6,'gray'=>2,'green'=>10, 'greenblue'=>3,'lightblue'=>1,'lightred'=>14, 'purple'=>7,'red'=>0,'white'=>11,'yellow'=>4); var $maxidx_2 = 14 ; var $colors_3 = array('bluegreen','cyan','darkgray','greengray', 'gray','graypurple','green','greenblue','lightblue', 'lightred','navy','orange','purple','red','yellow'); var $index_3 = array('bluegreen'=>1,'cyan'=>11,'darkgray'=>14,'greengray'=>10, 'gray'=>3,'graypurple'=>4,'green'=>9,'greenblue'=>7, 'lightblue'=>13,'lightred'=>0,'navy'=>2,'orange'=>12, 'purple'=>8,'red'=>5,'yellow'=>6); var $maxidx_3 = 14 ; var $colors,$index,$maxidx; var $imgdata_large ; var $imgdata_small ; var $imgdata_xsmall ; function GetImg($aMark,$aIdx) { switch( $aMark ) { case MARK_IMG_SBALL: case MARK_IMG_BALL: $this->colors = $this->colors_3; $this->index = $this->index_3 ; $this->maxidx = $this->maxidx_3 ; break; case MARK_IMG_MBALL: $this->colors = $this->colors_2; $this->index = $this->index_2 ; $this->maxidx = $this->maxidx_2 ; break; default: $this->colors = $this->colors_1; $this->index = $this->index_1 ; $this->maxidx = $this->maxidx_1 ; break; } return parent::GetImg($aMark,$aIdx); } function ImgData_Balls() { //========================================================== // File: bl_red.png //========================================================== $this->imgdata_large[0][0]= 1072 ; $this->imgdata_large[0][1]= 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAByF'. 'BMVEX/////////xsb/vb3/lIz/hIT/e3v/c3P/c2v/a2v/Y2P/'. 'UlL/Skr/SkL/Qjn/MTH/MSn/KSn/ISH/IRj/GBj/GBD/EBD/EA'. 'j/CAj/CAD/AAD3QkL3MTH3KSn3KSH3GBj3EBD3CAj3AAD1zMzv'. 'QkLvISHvIRjvGBjvEBDvEAjvAADnUlLnSkrnMTnnKSnnIRjnGB'. 'DnEBDnCAjnAADec3PeSkreISHeGBjeGBDeEAjWhITWa2vWUlLW'. 'SkrWISnWGBjWEBDWEAjWCAjWAADOnp7Oa2vOGCHOGBjOGBDOEB'. 'DOCAjOAADJrq7Gt7fGGBjGEBDGCAjGAADEpKS/v7+9QkK9GBC9'. 'EBC9CAi9AAC1e3u1a2u1Skq1KSm1EBC1CAi1AACtEBCtCBCtCA'. 'itAACngYGlCAilAACghIScOTmcCAicAACYgYGUGAiUCAiUAAiU'. 'AACMKSmMEACMAACEa2uEGAiEAAB7GBh7CAB7AABzOTlzGBBzCA'. 'BzAABrSkprOTlrGBhrAABjOTljAABaQkJaOTlaCABaAABSKSlS'. 'GBhSAABKKSlKGBhKAABCGBhCCABCAAA5CAA5AAAxCAAxAAApCA'. 'ApAAAhAAAYAACc9eRyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkRFD'. 'UHLytKAAAB4UlEQVR4nGNgIAK4mGjrmNq6BmFIWMmISUpKSmk5'. 'B8ZEokj4qoiLiQCBgqald3xaBpKMj6y4sLCQkJCIvIaFV0RaUR'. 'lCSk5cWEiAn19ASN7QwisuraihHiajKyEixM/NwckjoKrvEACU'. 'qumpg7pAUlREiJdNmZmLT9/cMzwps7Smc3I2WEpGUkxYkJuFiY'. 'lTxszePzY1v7Shc2oX2D+K4iLCgjzsrOw8embuYUmZeTVtPVOn'. 'gqSslYAOF+Ln4ZHWtXMPTcjMrWno7J82rRgoZWOsqaCgrqaqqm'. 'fn5peQmlsK1DR52vRaoFSIs5GRoYG5ub27n19CYm5pdVPnxKnT'. 'pjWDpLydnZwcHTz8QxMSEnJLgDL9U6dNnQ6Sio4PDAgICA+PTU'. 'zNzSkph8hADIxKS46Pj0tKTc3MLSksqWrtmQySAjuDIT8rKy0r'. 'Kz+vtLSmur6jb9JUIJgGdjxDQUVRUVFpaUVNQ1NrZ9+kKVOmTZ'. 'k6vR0sldJUAwQNTU2dnX0TgOJTQLrSIYFY2dPW1NbW2TNxwtQp'. 'U6ZMmjJt2rRGWNB3TO7vnzh5MsgSoB6gy7sREdY7bRrQEDAGOb'. 'wXOQW0TJsOEpwClmxBTTbZ7UDVIPkp7dkYaYqhuLa5trYYUxwL'. 'AADzm6uekAAcXAAAAABJRU5ErkJggg==' ; //========================================================== // File: bl_bluegreen.png //========================================================== $this->imgdata_large[1][0]= 1368 ; $this->imgdata_large[1][1]= 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. 'B3RJTUUH0wMMFi8hE9b2uAAABOVJREFUeNq9lk2sJFUVx3+3qv'. 'tW95t57zFvhiFxmCFRUJRoNCQiJARMhiFx/Igxii5goTG6ZDAu'. '/EhcSCIrTAgLEiKsJ8ywABNZEMJXEDYCukAmjgjzBkK/j35V1d'. '333FtV97io97pfzwxfG86qcu/N+Z3zP+fcW/Apmfk4hx57+R/6'. 'Rqmc9ykhsWjlsUngAA1fXIQ7b73pI/186IGHnn9dH/8frC8v4I'. 'PiG53uaerR4GmKkv31mB8cyfjd946ZTwR66qVX9OTWIi8UKUv9'. 'BOrZXpYZvFeiBvzI0fgSUSFKwbVG+Pl1V3HH0VvNR4KeeukV/f'. 'PmMmdHhst76aXD64AbeVQ9bjNHaiGOC2o3wLrAb2/4LL/84ffn'. 'fCdzkOdayKpLppBemrBsU5Y1Zdmm9LJdGU6E/t4M24Q26jRDRL'. 'j3mdc49cSTekFsMzs5XuTsyLDUNSDQ25NwKOly9YIl22MYhJr/'. 'uoDtBBoT0CxBRGYOAhibIaOCe//2MpfM6KHnX9cXipSlbkKWmS'. 'nk9iv38J0jixw7vJfrTMYBOvhSoQHJBS09ANELloAGDxW8tfoW'. 'J+5/UC8CPS0LU7r3SpYarr7M8rmFjMPLXT6/33L4si7Z2GCrQC'. '+0ctlOaNs9DReV8vSLr85ndPLpZ/WNvHW+01kAVFBOGvJx0wYg'. 'Sp47RIQ4Emwa8FGJXlDxSCFo5YlVgAo2hwPue/hRndboTV3EW2'. 'Wp3k6wBp8q56QiWzecW6vwQfnPRkAWhFgILnq08jQ+R2nlUzzN'. 'uES9Q7Vd+9fba7NmWJW61db2247qACmcjxXr45psYphsFGSLBu'. 'kIajxqtjNwHkvAjQt0sg3crhPA2+fPz0CuyNFOghsGsr19mnFg'. 'DGwrRm8UoAtNmQPQtRXDgdC4HImCFEKcCE0oieUWUYq2LtbiGp'. 'mBQmppfIkjw45DK0QNNkvQ0jMBtPL0UnDRM1rN+cxKwzvOo2NP'. 'tykR9a1kfpZNDLMG6QDYJqCTBvUe1+uxs+YKyPoGrTwY2HhvC4'. 'CDWQd5d4xNApNQEEMgjgLdUCLBQ5cprL/trwNwKG2IUmDqDFd5'. 'sr5BWrlxuSdLDFEFlqAzXGc4zFjupqh6uqYihpxJcEgp026l2w'. '7wFUv7Z6AvrfRo/n0OYzPwIKE3HUKAJg2otMBiElnsF7wngis9'. '3ZDjNnLi7huCWUZfueZKTu/M0V3HvmkOFDVxVKDG04ScejSgW5'. 'V0q5JYFEghuDLHlTmToqDeGOCKIVtrW9hsdmXufEcNLPSXuPHa'. 'a+bvuh9df5AH/v5PDFmbWQC3Mx+TVvfGVTRB2CodNgT2JBX003'. 'aANZAYS/BxCv32TV/l2C03G7jgmfjGiT/qmeEmibEYm7XzAO2k'. 'A+pbgHhBgydqu54YO5eRiLCy7yDvPP6Xqf+5Z+Lu277OYuOpiw'. 'H15oBmlNOMcmK5RbP+PrEscGU+DSAxdg4CICIkxnLP8aNz63Og'. 'H3/rdvOb795GVhuaYo0oBc3GGrEsUPVTwO6a7LYd+X51x3Hu/t'. 'lP5tS65FN+6okn9U+n/sqb596dTvhOF+02myXTmkQNrOw7yD3H'. 'j14E+UDQjp24/0E9/eKrbA4HH3aMK1b2ccvXvswjv//1J/s5ud'. 'Due/hRPfP+OmfOrk7vrn7a48ihA3zh8CH+8Iuffiw/n4r9H1ZZ'. '0zz7G56hAAAAAElFTkSuQmCC' ; //========================================================== // File: bl_yellow.png //========================================================== $this->imgdata_large[2][0]= 1101 ; $this->imgdata_large[2][1]= 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAB2l'. 'BMVEX//////////+///+f//9b//8b//73//7X//63//6X//5T/'. '/4z//4T//3P//2v//1r//0r//0L//zH//yn//yH//xj//xD//w'. 'j//wD/90L/9zn/9zH/9xj/9xD/9wj/9wD39yn37zn37zH37yH3'. '7xD37wj37wDv70Lv50rv50Lv5znv5yHv5xjv5wjv5wDn51Ln5x'. 'Dn3jHn3iHn3hjn3hDn3gje3oze3nPe3lLe1oze1nPe1lLe1ine'. '1iHe1hje1hDe1gje1gDW1qXW1mvWzqXWzkLWzhjWzhDWzgjWzg'. 'DOzrXOzq3OzpzOzgDOxkrOxinOxhjOxhDOxgjOxgDGxqXGxnvG'. 'xmvGvRjGvRDGvQjGvQDFxbnAvr6/v7+9vaW9vZS9vQi9vQC9tR'. 'C9tQi9tQC7u7W1tZS1tXu1tTG1tQi1rRC1rQi1rQCtrYytrSGt'. 'rQitrQCtpYStpSGtpQitpQClpYSlpXulpQClnBClnAilnACcnG'. 'ucnAicnACclAiclACUlFqUlCmUlAiUlACUjFKUjAiUjACMjFKM'. 'jEqMjACMhACEhACEewB7ezF7exB7ewB7cwBzcylzcwBzaxBzaw'. 'BraxhrawhrawBrYxBrYwBjYwBjWgBaWgBaUgCXBwRMAAAAAXRS'. 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. 'LdfvwAAAAHdElNRQfTAwkRFBKiJZ4hAAAB7ElEQVR4nI3S+1vS'. 'UBgHcB67WJmIMWAVdDHEDLBC6Go0slj3Ft0m9RRBWQEmFZFDEM'. 'Qgt0EMFBY7p/+198hj1kM/9N1+++x73rOd6XT/kStnTx4fPzd9'. 'uwfOjFhomj7smAhwj/6Cm2O0xUwy6g7cCL99uCW3jtBmE7lsdr'. 'fvejgpzP7uEDFRRoqy2k8xQPnypo2BUMP6waF9Vpf3ciiSzErL'. 'XTkPc0zDe3bsHDAcc00yoVgqL3UWN2iENpspff+2vn6D0+NnZ9'. '6lC5K6RuSqBTZn1O/a3rd7v/MSez+WyIpVFX8GuuCA9SjD4N6B'. 'oRNTfo5PCAVR0fBXoIuOQzab1XjwwNHx00GOj8/nKtV1DdeArk'. '24R+0ul9PjmbrHPYl+EipyU0OoQSjg8/m83kl/MMhx0fjCkqio'. 'SMOE7t4JMAzDsizH81AqSdW2hroLPg4/CEF4PhKNx98vlevrbY'. 'QQXgV6kXwVfjkTiSXmhYVcSa7DIE1DOENe7GM6lUym0l+EXKks'. 'K20VAeH2M0JvVgrZfL5Qqkiy0lRVaMBd7H7EZUmsiJJcrTdVja'. 'wGpdbTLj3/3qwrUOjAfGgg4LnNA5tdQx14Hm00QFBm65hfNzAm'. '+yIFhFtzuj+z2MI/MQn6Uez5pz4Ua41G7VumB/6RX4zMr1TKBr'. 'SXAAAAAElFTkSuQmCC' ; //========================================================== // File: bl_silver.png //========================================================== $this->imgdata_large[3][0]= 1481 ; $this->imgdata_large[3][1]= 'iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAADAF'. 'BMVEUAAADOzs7Gxsa9vb21tbXOxsbOzsbGzsb3///O1ta1vb2c'. 'paVSWlpKWlpSY2ve5+97hIze7/9aY2vO5/9zhJRaa3tSY3PGzt'. 'aMlJxrc3tja3NKUlpCSlK1vcZze4RSWmPW5/+Upb3G3v9zhJxS'. 'Y3t7jKVaa4TO3veltc6ElK1re5Rjc4ycpbV7hJRaY3M5QlLn7/'. '/Gzt6lrb2EjJzO3v9ja3vG1ve9zu+1xueltdacrc6UpcaMnL1C'. 'SlqElLV7jK1zhKVre5zW3u/O1ue1vc6ttcaMlKVze4xrc4RSWm'. 'tKUmPG1v+9zve1xu+tveeltd6crdbe5/+9xt6cpb17hJxaY3s5'. 'QlrW3vfO1u/Gzue1vdattc6lrcaUnLWMlK2EjKVze5Rrc4xja4'. 'RSWnNKUmtCSmO9xuecpcZ7hKVaY4TW3v/O1vfGzu+1vd6ttdal'. 'rc69xu+UnL2MlLWEjK1ze5xrc5R7hK1ja4zO1v+1veettd6lrd'. 'aMlL3Gzv/39//W1t7Gxs61tb29vcatrbWlpa2cnKWUlJyEhIx7'. 'e4TW1ufGxta1tcZSUlqcnK3W1u+UlKW9vda1tc57e4ytrcalpb'. '1ra3vOzu9jY3OUlK29vd6MjKWEhJxaWmtSUmNzc4xKSlpjY3tK'. 'SmNCQlqUjJzOxs7///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. 'AAAAAAAAAAAAAAAAAAAAAAAAD///9fnkWVAAAAAnRSTlP/AOW3'. 'MEoAAAABYktHRP+lB/LFAAAACXBIWXMAAABFAAAARQBP+QatAA'. 'AB/klEQVR42mNgxAsYqCdd3+lcb4hLmj8wMMvEu8DCMqYbU9op'. 'UEFB2MTb26eyysomFl06XEEhUCHLpAKo2z/fujikEUVaXUFBMB'. 'BouLePuV+VVWGRciIXknSEsImCQd3//xwmPr65llaFcSFJHkjS'. '3iYmWUDZ//8NfCr989NjNUMSUyTg0jneSiaCINn/gmlVQM12qg'. 'lJnp5waTMTE5NAkCyHWZW/lXWNfUlikmdYK0zax7siS4EDKJtd'. 'mQeU1XRwLBdLkRGASucWmGVnZ4dnhZvn5lmm29iVOWpnJqcuko'. 'JKR1Wm5eTkRKYF5eblp9sU2ZeUJiV7zbfVg0pH56UFBQXNjIqK'. 'jgkujItX1koKTVmYajsdKu2qETVhwgSXiUDZ2Bn9xqUeoZ5e0t'. 'LzYYZ3B092ndjtOnmKTmycW1s7SHa+l5dtB8zlccE6RlN0dGbM'. 'mDVbd5KupNBcL6+F82XgHouLj5vRP2PWLGNdd4+ppnxe8tJec6'. 'XnNsKkm0uVQ5RDRHQTPTym68nPlZbvkfYCexsa5rpJ2qXa5Umm'. 'ocmec3m8vHjmSs+fgxyhC5JDQ8WSPT2lvbzm8vDIe0nbtiBLN8'. '8BigNdu1B6Lsje+fPbUFMLi5TMfGmvHi/puUAv23q2YCTFNqH5'. 'MvPnSwPh3HasCbm3XUpv+nS5VtrkEkwAANSTpGHdye9PAAAASn'. 'RFWHRzaWduYXR1cmUANGJkODkyYmE4MWZhNTk4MTIyNDJjNjUx'. 'NzZhY2UxMDAzOGFhZjdhZWIyNzliNTM2ZGFmZDlkM2RiNDU3Zm'. 'NlNT9CliMAAAAASUVORK5CYII=' ; //========================================================== // File: bl_purple.png //========================================================== $this->imgdata_large[4][0]= 1149 ; $this->imgdata_large[4][1]= 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAACAV'. 'BMVEX/////////7///5///1v//xv//rf//pf//lP//jP//hP//'. 'c///a///Wv//Wvf/Uv//Sv//Qv//Qvf/Off/Mf//Kf//If//If'. 'f/GP//GPf/EP//EPf/CP//CPf/CO//AP//APf3Oe/3Kff3Ke/3'. 'Ie/3GO/3EO/3AO/vSu/vSufvOefvMefvIefvGOfvEOfvCOfvAO'. 'fnUufnSufnMd7nId7nGN7nGNbnEN7nCN7nAN7ejN7ejNbec97e'. 'c9beUtbeQtbeIdbeGNbeENbeCNbeANbWpdbWa9bWQs7WGM7WEM'. '7WCM7WAM7Otc7Orc7OnM7OSsbOIb3OGMbOEMbOCMbOAM7OAMbG'. 'pcbGnMbGe8bGa8bGKbXGEL3GCL3GAL3FucXBu73AvsC/v7+9pb'. '29Ka29GLW9ELW9CLW9AL29ALW5rrm1lLW1e7W1MbW1GKW1EK21'. 'CLW1CK21AK2tjK2thKWtMaWtIaWtGJytCK2tCKWtAK2tAKWlhK'. 'Wle6WlEJylCJylAKWlAJyca5ycGJScEJScCJScAJycAJSUWpSU'. 'UoyUKZSUEIyUCIyUAJSUAIyMUoyMSoyMIYSMEISMCISMAIyMAI'. 'SECHuEAISEAHt7MXt7EHt7CHt7AHt7AHNzKXNzEGtzAHNzAGtr'. 'GGtrEGNrCGtrAGtrAGNjCFpjAGNjAFpaAFpaAFIpZn4bAAAAAX'. 'RSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsS'. 'AdLdfvwAAAAHdElNRQfTAwkRFB0ymoOwAAAB9UlEQVR4nGNgIA'. 'K42hhqGtm5+WFIWClKycvLK6gbuARGoEj4aMjLSElISUir6Tt7'. 'x+aEIWR8leQlwEBSTc/CK7awLguuR0lGQkJMVFRUTFJVzwko1d'. 'oFk9OQl5IQE+Dh5hVR0TV3CkkvbJgyASJjDZIR5GBl5eRX0TH1'. 'DEqrbJ2ypBEspSgvJSXKw8bMxMavbOLoGZNf1TZlybw4oIyfLN'. 'BxotxsLEzsQiaOHkFpBQ2905esrAZK2SpIAaUEuDm5+LTNPAKj'. 'C+pbps1evrIDKGWnLictKSkuLKyoZQyUya9o7Z2+YMXKGUApew'. 'M9PTVdXR0TEwf3wOjUirruafOXL18xFyjl72Kpb25qaurg4REU'. 'EFVe2zJ5zpLlK1aCpbydnZ2dnDwDA6NTopLLeiZNXbB8BcTAyP'. 'TQ0JDg4KCY1NS83JKmiVOBepYvX9UPlAovzEiPSU/LLyior2vq'. 'mjZr3vLlIF01IC+XVhUWFlZW1Lc290ycOGfxohVATSsXx4Oksn'. 'vaWlsb2tq6J0+bM2/RohVA81asbIcEYueU3t7JU6ZNnwNyGkhm'. '+cp5CRCppJnzZ8+ZM3/JUogECBbBIixr8Yqly8FCy8F6ltUgoj'. 'lz7sqVK2ByK+cVMSCDxoUrwWDVysXt8WhJKqG4Y8bcuTP6qrGk'. 'QwwAABiMu7T4HMi4AAAAAElFTkSuQmCC' ; //========================================================== // File: bl_gray.png //========================================================== $this->imgdata_large[5][0]= 905 ; $this->imgdata_large[5][1]= 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAABO1'. 'BMVEX////////3///39/fv7+/e5+fW3t7Wzs7WxsbG1tbGzsbG'. 'xsbDxMS/v7++wMC+v7+9zsa9xsa9vb29tbW9ra29pa24uLi1xs'. 'a1vb21tbWxtrattbWmpqalra2cra2cpaWcnJycjIyUpaWUnJyU'. 'lJSUjIyMnJyMnJSMlJSMlIyMjJSMjIyElJSElIyEjIyEhIR7jI'. 'x7hIR7hHt7e3t7e3N7e2tzhIRze3tze3Nzc3Nre3trc3Nrc2tr'. 'a2tjc3Njc2tja3Nja2tjY2NjWlpaa2taY2taY2NaY1paWlpaUl'. 'JSY2NSY1pSWlpSWlJSUlJSUkpKWlpKWlJKUlpKUlJKUkpKSkpK'. 'SkJCUlJCUkJCSkpCSkJCQkI5Sko5QkI5Qjk5OUI5OTkxQkIxOT'. 'kxMTkxMTEpMTEhMTEhKSkYISEpy7AFAAAAAXRSTlMAQObYZgAA'. 'AAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdE'. 'lNRQfTAwkRFQfW40uLAAABx0lEQVR4nI3SbXfSMBQA4NV3nce5'. 'TecAHUywRMHSgFuBCFsQUqwBS1OsWQh0GTj//y8wZUzdwQ/efM'. 'tzcm/uuXdj4z9ic/PR9k4qk1qDnf0X2/uZzKt8GaRvSubg4LVp'. 'mkWzCGAT/i3Zsm2XNQHLsm2n2937LaaNnGoJFAEo27B50qN0ay'. 'Wg26lXsw8fP8nmzcJb2CbsnF5JmmCE8ncN404KvLfsYwd7/MdV'. 'Pdgl/VbKMIzbuwVgVZw2JlSKJTVJ3609vWUY957lgAUd1KNcqr'. 'yWnOcOPn8q7d5/8PywAqsOOiVDrn42NFk+HQ7dVuXNYeFdBTpN'. 'nY5JdZl8xI5Y+HXYaTVqEDp1hAnRohZM03EUjMdhn5wghOoNnD'. 'wSK7KiiDPqEtz+iD4ctdyAifNYzUnScBSxwPd6GLfRURW7Ay5i'. 'pS5bmrY8348C5vvUI+TLiIVSJrVA0heK/GDkJxYMRoyfCSmk4s'. 'uWc3yic/oBo4yF374LGQs5Xw0GyQljI8bYmEsxVUoKxa6HMpAT'. 'vgyhU2mR8uU1pXmsa8ezqb6U4mwWF/5MeY8uLtQ0nmmQ8UWYvb'. 'EcJaYWar7QhztrO5Wr4Q4hDbAG/4hfTAF2iCiWrCEAAAAASUVO'. 'RK5CYII=' ; //========================================================== // File: bl_brown.png //========================================================== $this->imgdata_large[6][0]= 1053 ; $this->imgdata_large[6][1]= 'iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAABoV'. 'BMVEX////Gzs7GvbXGrZTGpXu9nHO1nHO1nIy9taXGxs7GtaXO'. 'nHPGlFrGjEq9hEq1hEqte0Klczmcazmce1KtnIzGxsbGvb3OlF'. 'LOlFq9hFKte0qcc0KUYzGEWimMc1K9ta3OnGvOnGPWnGO9jFq9'. 'jFKlc0KUazmMYzl7UilzUjGtpZzGxr3GnGPWpWvepXO1hFJ7Wj'. 'FrSiFjUjG1ra3GnHPvxpT/5733zpythFKUa0KEYzlzUilaOSF7'. 'Wjm9jErvvYz/99b///f/78bnrYS1hFqle0p7UjFrSiljQiFCMR'. 'iMhHO9lGvGjFLWnGv/3q3////erXuthEqlc0paQiFKMRhSQin/'. '1qX/997//++cc0pjSilaQilKORhCKRiclIy9pYzGlGPntYT33q'. '3vvZSEWjlSOSE5KRB7c2O1lHutczmthFqte1JrWkqtjGtCKRBa'. 'SjmljGuca0KMYzGMaznOztaclISUYzmEWjFKOSF7a1qEYzFaSi'. 'GUjISEa0pKOSm9vb2llIxaQhg5IQiEc2tzY0paORilnJy1raVS'. 'OSljUkJjWkKTpvQWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. 'gAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkREiei'. 'zP2EAAAB9UlEQVR4nGWS/VfSUBjHL5QluhhBxtwyWcCus5Blpm'. 'wDC4ONaWXCyBi7RMZmpQ2Bypm9W/byV3cHHo/W88s95/s5z/d5'. 'uwCcCh/4L3zAf+bs0NC588On9QAYGSUuBINk6GI4cmnsBLk8Go'. '1SFEGMkzRzZeLq5JE8FvDHouw1lqXiCZJOcnCKnx4AcP0GBqmZ'. 'mRgRT9MMB4Wbs7cGSXNRik3dnp9fiMUzNCNKgpzN9bsaWaQo9s'. '7dfH7pXiFTZCBU1JK27LmtBO8TDx7mV1eXHqXXyiIUFLWiVzHx'. 'BxcJIvV4/cn6wkqmWOOwmVE3UQOAp6HxRKL5bGPj+VwhUhalFq'. '8alm5vAt+LlySZTsebzcKrraIIW4JqZC3N3ga+1+EQTZKZta1M'. 'pCZCSeDViqVrThsEdsLJZLJYLpZrHVGScrKBvTQNtQHY6XIM02'. 'E6Ik7odRW1Dzy3N28n3kGuB3tQagm7UMBFXI/sATAs7L5vdbEs'. '8Lycm923NB0j5wMe6KOsKIIyxcuqauxbrmlqyEWfPmPy5assY1'. 'U1SvWKZWom9nK/HfQ3+v2HYZSMStayTNN0PYKqg11P1nWsWq7u'. '4gJeY8g9PLrddNXRdW8Iryv86I3ja/9s26gvukhDdvUQnIjlKr'. 'IdZCNH+3Xw779qbG63f//ZOzb6C4+ofdbzERrSAAAAAElFTkSu'. 'QmCC' ; //========================================================== // File: bl_darkgreen.png //========================================================== $this->imgdata_large[7][0]= 1113 ; $this->imgdata_large[7][1]= 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAB2l'. 'BMVEX////////3///v///n/+/e99bW/+/W99bO786/v7++vr69'. '/96999a7wb24vbu1/9a1zqW1u7itxrWosq6l772l1qWlxrWlxq'. '2lva2cxpSU562U3q2UxqWUvaWUpZyM77WM57WMvYyMtZyMrZyM'. 'pZSMnJSEvZyEtYyErZSElIx7zpR7xpx7xpR7vZR7jIRz1pRzxp'. 'RzjIRrzpRrzoxrxoxrtYRrrYxrrXtrpYRrhHNjzoxjxoxjxoRj'. 'vYRjtYRjrXtjpXtjlGNje2tazoxazoRaxoxaxoRavYRatYRatX'. 'tarXtapXNanHNajFpae2tSzoRSxoRSvXtStXtSrXtSrXNSpXNS'. 'nHNSnGtSlGtSlGNSjGtSjGNKvXtKtXNKrXNKpWtKnGtKlGNKjG'. 'NKhGNKhFJKc1pKa1JCrWtCpWtCnGtClGNCjGNCjFpChFpCe1JC'. 'a1JCY1I5pWs5nGM5lGM5jFo5hFo5e1o5c0o5WkoxjFoxhFoxhF'. 'Ixe1Ixc1Ixc0oxa0ophFIpe0opc0opa0opa0IpY0IpWkIpWjkp'. 'UkIpUjkhc0oha0IhY0IhWjkhWjEhUjkhUjEhSjEhSikhQjEhQi'. 'kYWjkYSjEYSikYQjEYQikQSikQQikQQiEQOSExf8saAAAAAXRS'. 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. 'LdfvwAAAAHdElNRQfTAwkRFCaDkWqUAAAB+ElEQVR4nI3S+1vS'. 'UBgHcGZlPV0ks/vFrmQWFimJjiwiYUJWjFBWFhClyZCy5hLrwA'. 'x2EIwJC1w7zf2vnU0re+iHvs9++7x7zznvORbLf+TA6ct9fYMX'. 'jrfAUYefpp+/iM1ykxf/lmuhUZ/PTwXC8dml5Wcd23o5H5Mk6b'. '5NUU8icXbhS67rNzn9JDnguOEYGQtEEtwC+Crs3RJ76P5A/znr'. 'vsNX7wQnEiwHCtK7TTkW8rvdZ9uJtvZTLkxpHhSrP66bNEj7/P'. '3WNoLYeeSWQQCIpe9lQw7RNEU5rDsIYtcJ14Nocg7kRUlBNkxn'. 'YmGKcp7cv3vPwR7XOJPmc0VYU3Sv0e9NOBAYG7Hbz/cMjTMveZ'. 'CHkqxuTBv0PhYJB4N3XR6PJ5rMAPMnpGUxDX1IxSeMTEaZp1OZ'. 'nGAIQiYtsalUIhFlmGTy3sO3AizJCKn6DKYryxzHsWyaneMzr6'. 'cWxRVZVlFTe4SpE3zm+U/4+whyiwJcWVMQNr3XONirVWAklxcE'. 'EdbqchPhjhVzGpeqhUKhWBQhLElr9fo3pDaQPrw5xOl1CGG1JE'. 'k1uYEBIVkrb02+o6RItfq6rBhbw/tuINT96766KhuqYpY3UFPF'. 'BbY/19yZ1XF1U0UNBa9T7rZsz80K0jWk6bpWGW55UzbvTHZ+3t'. 'vbAv/IT+K1uCmhIrKJAAAAAElFTkSuQmCC' ; //========================================================== // File: bl_green.png //========================================================== $this->imgdata_large[8][0]= 1484 ; $this->imgdata_large[8][1]= 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. 'B3RJTUUH0wMMFjM4kcoDJQAABVlJREFUeNq9ll2MJFUVx3/11V'. 'Vd/TE9vU0v4zLDwJIF16jBqLAPhsRXEiDqg0QTJiQSjcSNvCzw'. 'sBEDDxizhvAAxBgf1oR9QF9NiE9ESFZkQyZB5WtddmdnZ3qqqr'. 'uqbt367Cofqu3ZZpWVaDzJfbkf53//55z/PVdZXV3l/2H6f7Lp'. '5VdOV/4Nb+GmHpUeA7AdBNxc3kafNb73jRPK9Xwon8ToxVefqU'. 'b91wibH5EkCQBCizFihTSviHUHR0hWws9xe3wvJ7/7nPKpgX5y'. '9oFqt3eOgWniRBoAbUBGGqZUibSYaeoT2B5bnkdaSA6793Cv/S'. 'QPPbihXBfo5VdOV+8dfgnvwAU62YH5fCZ12sDujFkwyegCqTrB'. 'iUOKTOJKj8jr88jS8zy6cXwBTP048nuHX0I0nDlIp7RpTG7kM0'. 'sdyAYsTVukUuWGhlWHMq0ITL92lnUp9R1Obz/GmTNnqn9bDD8/'. '+0D1oX0O0zQZZDYCsK2j3Gl9jQqDfHiei8GfiKVLlsZkJaBAN1'. '0i6PgwUbB0GxG5/PrtE/xLRr959Znqw9452oVNI+jiJhnr1pe4'. 'k29zB1/nFr5Kj7tpt1YYhJ0FJ7nUYbcJQBgahN2MzeCP/OipR6'. 'prgN6Qr6ELFQFUWoRpNVjlKwxZB8DCpE+PtfEKqV1cUzxpVudu'. 'GTBHA5Y1g99e+dUio9O/P1Vpq+/WE5GGjDSMoAtAQjrf3C52IP'. 'QxpY4WK2hpReka9Gfrhqgz0bACRoCWjDh56kQ1z9FeuUUQxVhK'. 'B92sD1VahM+bAJgcoJhGjP/6Ln8rAgDiRCVRKiIzxMkkodBJ85'. 'im1IlEHbE4k1xyNveL4YP8HarmGJIOpqyjeQmfNHmTvnqZTWBt'. 'vIJXpPwlukJSuSTKGK3pEwtJmiX00ZlInTyNscImO6XBITvH1c'. '8vVt2OucdKvIyeKRTNCivsEMgcpg6taYs30nfq0Gqg6hOSSFJ4'. 'BSnJPht0IqEjWmOGocEI6F0J94F0qaL6BntTF0MtUfweKQKAPU'. 'Wwp4OcVnQAmVb0p9DLOzjEhEKnGRmoRc7EzRGlwA6NujAKG4yP'. '6Sjwc4aVznZ7DK0xXdkDoJf0kGmFBniFBOBGcZSCCSKd0IwN0k'. 'IS+QZWCGVZex4BnUxya3+Zt9iugQbcRFpIAtuHvAZulPUdLhUJ'. 'RqegI3WcqaSXddlT3idsWMSRRGkEtNwmyTifAwyBo7LP+11J0e'. '7tM7pZOYblHkBLcqZ5LcYtw6Wbd4CM3SpE9foYZsIHoqDKCrbz'. 'mLSQtPwmuhXgtBLs0GBdbXOhFGB7WBKO2F8GXt9/VO97Ya3atF'. '7nUHnwGjGGQqcPxFEdFqURkEidiZszAERoYIsGju1hq21kWee3'. 'bw15+8WpsvAy3K1+i3JkkhZyPpxxjjPOsfOYiZ+TFhLPzQnHOU'. 'tpzGB2dgA4tscIkKIx19Cxg/fPL7vQJu47eXt1VvsDK8pwPueZ'. 'PuZoQMOqhRoJHSs0kKLBWjvjYinmeQGw1TaX1RFdfZ3LMzYLjA'. 'C++dkn6AaH2Nobk6cxEzdnuG0TdC8zvdJkN0hqkFkO/jwL0fxa'. 'so8sBcuFzQ+/+MRC+BeAHnpwQzn++ee5KT9Eshuy46dcKAXm32'. '0uzPQhS4GttkH2GQID2Wc0Y4LtAbDxhZ/x5A+e/uTG9+jGceXH'. '9/ySnnIXnUzOxXe1038mW3ZynNmam4yYWkO+f9cv+Oljz16/lV'. '9tDz/9nerc1hm8ZEScSRK7VvtYl1i1dklsOKyvc+zg/bzw1O8+'. '/efkajt56kR1ydlEJBc5H46xzbrJ3dY9wrB7hGcff+6/+279L+'. '0fHxyiE8XMLl4AAAAASUVORK5CYII=' ; //========================================================== // File: bl_blue.png //========================================================== $this->imgdata_large[9][0]= 1169 ; $this->imgdata_large[9][1]= 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAACEF'. 'BMVEX/////////7//35//v1v/exv/Wvf/Wrf/Wpf/Orf+/v7+9'. 'tc69jP+9hP+5ucW1tc6tlP+rq7Wlpdalpcalpb2cnM6cnMacc/'. '+cWv+UlLWUjN6UjK2Uc/+Ma/+MUv+EhKWEa/+EQvd7e8Z7e7V7'. 'e6V7c957Wv9za9Zza8ZzSv9ra5xrSv9rOf9rMe9jUudjQv9jOe'. '9aWpRaUt5aUpRaSu9aSudSUoxSSs5SSoxSMf9KQtZKOfdKMedK'. 'Kf9KKe9CKf9CKb1CKa1CIfdCIedCId45MXs5Kfc5If85Iec5Id'. 'Y5GP8xMbUxMXsxKc4xKZQxIf8xGP8xGO8xGN4xGNYxGL0xGK0p'. 'KXMpIYwpGP8pGO8pGOcpGNYpGM4pEP8pEPcpEOcpEN4pENYpEM'. 'YpEL0hGKUhEP8hEPchEO8hEOchEN4hENYhEM4hEMYhELUhCP8h'. 'CO8hCN4YGJwYGGsYEL0YEK0YEHMYCN4YCM4YCMYYCL0YCKUYAP'. '8QEJQQEIwQEHsQEGsQCM4QCLUQCK0QCKUQCJwQCJQQCIwQCHMQ'. 'CGsQAP8QAPcQAO8QAOcQAN4QANYQAM4QAMYQAL0QALUQAKUQAJ'. 'QQAIQICGsICGMIAO8IANYIAL0IALUIAK0IAKUIAJwIAJQIAIwI'. 'AIQIAHsIAHMIAGsIAGMAAN4AAMYAAK0AAJQAAIwAAIQAAHMAAG'. 'sAAGMAAFrR1dDlAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkRFRPMOZ'. '/2AAAB+klEQVR4nGNgIAIIqeqZmBqpi2JISNml5lVXV3d198Yo'. 'oUjwm1SnxsbGRsSm5ZfNXO4tjCTjVh0ABhFx6QV9E1Y0S8JkuN'. '3yAgLc7W3t/QPi4jPKJ8ye1yoIlTKpjvVy15eVUbN0i4zKLJ8w'. 'ae6qcKgLqmMj3PUFWFl5NJ0CExLLJzbNW7BWCyxlXR0ba6/Axs'. 'zELmfnkRBT0QiSKgXJCOflxUbYy3KyMHEoOrtEZ1c2TZ6/cMl6'. 'eaCUamdsbIC7tjgPr4SBS3BMMVDTwkXr1hsDpYy6UmMj/O0tdX'. 'QNbDxjknJLWqYsXLx0vStQynxGflpkZGCgs7Onp29SbtNkoMy6'. 'pevCgFJWy3oyMuKjgoKCPWNCvEuqWhcsWrJ06XqQlPnMvrKyrM'. 'TomJjkZAfHlNa2qdOWrlu63gcopbG8v7+hvLwip7g4JdSxsLZu'. '8dKlS9ettwBKic2eNXHChIkTG5tKqgpr2uo6loLAehWQx0LnzJ'. '49p6mpeXLLlNq6RUvqly6dvnR9Bx9ISnnlvLmT582bMr9t4aL2'. '+vrp60GaDCGB6Ld6wfwFCxYCJZYsXQ+SmL6+FBryInVrFi1atH'. 'jJkqVQsH6pNCzCJNvXrQW6CmQJREYFEc2CYevXrwMLAyXXl0oz'. 'IAOt0vVQUGSIkabkDV3DwlzNVDAksAAAfUbNQRCwr88AAAAASU'. 'VORK5CYII=' ; //========================================================== // File: bs_red.png //========================================================== $this->imgdata_small[0][0]= 437 ; $this->imgdata_small[0][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAk1'. 'BMVEX////////GxsbGra3/xsbOhITWhIT/hIT/e3v/c3P/a2vG'. 'UlK1SkrOUlL/Y2PWUlLGSkrnUlLeSkrnSkr/SkqEGBj/KSmlGB'. 'jeGBjvGBj3GBj/EBD/CAj/AAD3AADvAADnAADeAADWAADOAADG'. 'AAC9AAC1AACtAAClAACcAACUAACMAACEAAB7AABzAABrAABjAA'. 'BuukXBAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGDNEMgOYAAAAm0'. 'lEQVR4nI3Q3RKCIBAFYGZMy9RKzX7MVUAUlQTe/+kS0K49d3wD'. '7JlFaG+CvIR3FvzPXgpLatxevVVS+Jzv0BDGk/UJwOkQ1ph2g/'. 'Ct5ACX4wNT1o/zzUoJUFUGBiGfVnDTYGJgmrWy8iKEtp0Bpd2d'. 'jLGu56MB7f4JOOfDJAwoNwslk/jOUi+Jts6RVNrC1hkhPy50Ef'. 'u79/ADQMQSGQ8bBywAAAAASUVORK5CYII=' ; //========================================================== // File: bs_lightblue.png //========================================================== $this->imgdata_small[1][0]= 657 ; $this->imgdata_small[1][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABVl'. 'BMVEX////////d///AwMC7wcS08P+y+P+xxdCwxM+uws2twMur'. 'vsinzNynytylzuKhyN6e5v6d5P+d1fOcwNWcu8ub4f+at8iZ3v'. '+ZvdGY2/yW2f+VscGU1vuT1fqTr72Sx+SSxeKR0fWRz/GPz/OP'. 'rr+OyeqMy+6Myu2LyeyKxueJudSGw+SGorGDvt+Cvd6CvN2Aud'. 'p+uNd+t9Z9tdV8tdR8tNN6sc94r813rct2q8h0qcZ0qMVzp8Rx'. 'o8Bwor5tn7ptnrptnrlsnbhqmbRpmbNpi51ol7Flkqtkkqtkka'. 'pjj6hijaRhjaZgi6NfiqJfiaFdh55bhJtag5pZgphYgJZYf5VX'. 'cn9Ve5FSeI1RdopRdYlQdYlPc4dPcoZPcoVNcINLboBLbH9GZn'. 'hGZXdFZHZEY3RDYnJCXW4/W2s/WWg+Wmo7VmU7VGM7U2E6VGM6'. 'VGI5UV82T1wGxheQAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. 'gAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGTok'. '9Yp9AAAAtElEQVR4nGNgIBaw8wkpKghzwvksPAKiUsraprYiLF'. 'ARXkE2JiZ1PXMHXzGIAIekOFBE08TGLTCOCyzCLyvDxsZqZOnk'. 'E56kAhaRV9NQUjW2tPcMjs9wBYsY6Oobmlk7egRGpxZmgkW0zC'. '2s7Jy9giKT8gohaiQcnVzc/UNjkrMLCyHmcHr7BYREJKTlFxbm'. 'QOxiEIuKTUzJKgQCaZibpdOzQfwCOZibGRi4dcJyw3S4iQ4HAL'. 'qvIlIAMH7YAAAAAElFTkSuQmCC' ; //========================================================== // File: bs_gray.png //========================================================== $this->imgdata_small[2][0]= 550 ; $this->imgdata_small[2][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAMAAADH72RtAAABI1'. 'BMVEX///8AAAD8EAD8IAD8NAD8RAD8VAAYGBi/v7+goKCCgoJk'. 'ZGRGRkb8yAD83AD87AD8/AD4+ADo+ADY+ADI+AC0+ACk+ACU+A'. 'CE+AB0/ABk/ABU/ABE/AAw/AAg/AAQ/AAA/AAA+AAA6BAA2CAA'. 'yDQAtEQApFQAlGQAhHQAdIgAZJgAVKgARLgAMMgAINwAEOwAAP'. 'wAAPgIAPAQAOgYAOAkANgsANA0AMg8AMBEALhMALBUAKhcAKBo'. 'AJhwAJB4AIiAAID////4+Pjy8vLs7Ozm5ubg4ODa2trT09PNzc'. '3Hx8fBwcG7u7u1tbWurq6oqKiioqKcnJyWlpaQkJCJiYmDg4N9'. 'fX13d3dxcXFra2tkZGReXl5YWFhSUlJMTExGRkZAQEA1BLn4AA'. 'AAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIA'. 'AAsSAdLdfvwAAAAHdElNRQfTAwkUGiIctEHoAAAAfElEQVR4nI'. '2N2xKDIAwF+bZ2kAa8cNFosBD//yvKWGh9dN+yk9kjxH28R7ze'. 'wzBOYSX6CaNB927Z9qZ66KTSNmBM7UU9Hx2c5qjmJaWCaV5j4t'. 'o1ANr40sn5a+x4biElrqHgrXMeac/c1nEpFHG0LSFoo/jO/BeF'. 'lJnFbT58ayUf0BpA8wAAAABJRU5ErkJggg==' ; //========================================================== // File: bs_greenblue.png //========================================================== $this->imgdata_small[3][0]= 503 ; $this->imgdata_small[3][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAxl'. 'BMVEX///////+/v79znJQhSkJ7raU5hHtjraVKnJRCjIRClIyU'. '9++E595avbVaxr2/v7+ctbWcvb17nJxrjIx7paUxQkK9//+Mvb'. '17ra2Evb17tbVCY2MQGBiU5+ec9/eM5+d71tZanJxjra1rvb1j'. 'tbVSnJxara1rzs5jxsZKlJRChIQpUlIhQkJatbVSpaU5c3MxY2'. 'MYMTEQISFavb1Sra1KnJxCjIw5e3sxa2spWlpClJQhSkoYOTkp'. 'Y2MhUlIQKSkIGBgQMTH+e30mAAAAAXRSTlMAQObYZgAAAAFiS0'. 'dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfT'. 'AwkUGTIqLgJPAAAAqklEQVR4nI2QVxOCMBCEM6Mi2OiCvSslJB'. 'CUoqjn//9TYgCfubf9Zu9uZxFqO+rscO7b6l/LljMZX29J2pNr'. 'YjmX4ZaIEs2NeiWO19NNacl8rHAyD4LR6jjw6PMRdTjZE0JOiU'. 'dDv2ALTlzRvSdCCfAHGCc7yRPSrAQRQOWxKc3C/IUjBlDdUcM8'. '97vFGwBY9QsZGBc/A4DWZNbeXIPWZEZI0c2lqSute/gCO9MXGY'. '4/IOkAAAAASUVORK5CYII=' ; //========================================================== // File: bs_yellow.png //========================================================== $this->imgdata_small[4][0]= 507 ; $this->imgdata_small[4][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAzF'. 'BMVEX///////+/v79zYwCMewDOxoTWzoTezkr/5wj/5wDnzgDe'. 'xgC1pQCtnACllACcjACUhABjWgDGvVK1rUrOxlLGvUqEexilnB'. 'jv3hj35xj/7wj/7wD35wDv3gDn1gDezgDWxgDOvQDGtQC9rQCE'. 'ewB7cwBzawBrYwDWzlLn3lLe1krn3kre1hi9tQC1rQCtpQClnA'. 'CclACUjACMhAD/9wC/v7///8bOzoT//4T//3v//3P//2v//2Pn'. '50r//0r//yn39xj//xD//wBjYwDO8noaAAAAAXRSTlMAQObYZg'. 'AAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAH'. 'dElNRQfTAwkUGSDZl3MHAAAAqElEQVR4nI3QWRNDMBAA4My09E'. 'IF1SME0VT1okXvM/3//6kEfbZv+81eswA0DfHxRpOV+M+zkDGG'. 'rL63zCoJ2ef2RLZDIqNqYexyvFrY9ePkxGWdpvfzC7tEGtIRly'. 'nqzboFKMlizAXbNnZyiFUKAy4bZ+B6W0lRaQDLmg4h/k7eFwDL'. 'OWIky8qhXUBQ7gKGmsxpC+ah1TdriwByqG8GQNDNr6kLjf/wAx'. 'KgEq+FpPbfAAAAAElFTkSuQmCC' ; //========================================================== // File: bs_darkgray.png //========================================================== $this->imgdata_small[5][0]= 611 ; $this->imgdata_small[5][1]= 'iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAMAAAAMCGV4AAABJl'. 'BMVEX////////o8v/f6O7W4OnR3PXL1OTL0evEyLvCzePAwMC/'. 'v7a8wsq7t7C1xum1vtS1q6GzopmyxeKsrsOqvNWoq7anvN+nsb'. 'qhrcGgqbGfpq6cp7+bqMuVmJKRm7yPlKKMnL6FkKWFipOEkLSE'. 'j6qEhoqAiaB+jqd8haF7hZR4iJt4g5l3hZl2gIt2cod1hJVzeY'. 'VzboJvhp9sfJJsb41peY1pd5xpdoVod4xndI5lcHxka4BjcYVg'. 'Z3BfboFbb4lbZnZbYntaZ4laZYVZV3JYYWpXX3JWWm5VX4RVW2'. 'NUYX9SXHxPWn5OVFxNWWtNVXVMVWFKV3xHUGZGU3dGTldFSlxE'. 'Sk9ESXBCRlNBS3k/SGs/RU4+R1k9R2U6RFU2PUg0PEQxNU0ECL'. 'QWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAA'. 'CxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGQmbJetrAAAAtklEQV'. 'R4nGNgwAK4JZTNNOWlYDxhMT4ZDTOzQE1uMF9CiJWVU0LbxDlS'. 'G8QVF+FnZ2KRNHAIiPUHaZGSlmZj5lH19A1KjLUA8lXU5MWllF'. 'yjo30TYr2BfG19G11b37CEeN84H38gX1HbwTUkOjo+zjfG3hLI'. 'l1exCvCNCwnxjfMz0gTyRdXNHXx9fUNCQu2MwU6SN3ZwD42LCH'. 'W30IK4T8vUJSAkNMhDiwPqYiktXWN9JZj7UQAAjWEfhlG+kScA'. 'AAAASUVORK5CYII=' ; //========================================================== // File: bs_darkgreen.png //========================================================== $this->imgdata_small[6][0]= 666 ; $this->imgdata_small[6][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABX1'. 'BMVEX////////l/+nAwMC86r+8wb28wby8wLy78sCzw7SywrSx'. 'wLKwvrGuvK+syK+ryq2rx62n36ym3aumxKmk2qij0Keh16ahva'. 'Og1aSguKKe06KeuaCetZ+d0KGdtZ+bz6Cay56ZyZ2Zwp2Zr5qZ'. 'rpqYwJuXyZuXrJmVw5mUxZiTxJeTw5eTq5WRwJWPtJKOvZKKuI'. '6Kt42Kn4yJt42ItIuGsomFsYmEsIiEr4eDr4eBrIR/qoN+qIJ8'. 'poB7pH56o356on14nnt2nXl0mndzmnZzmXZymHVwlXNvlHJukn'. 'FtiHBqjm1qjW1oi2toiWpniWplh2hlhmdkhWdig2VggGNgf2Je'. 'fmFdfGBde19bbl1aeFxXdFpWclhVclhVcVdUcFZTb1VSbVRQal'. 'JPaVFKY0xKYkxJYUtIYEpHX0lEWkZCWERCV0NCVkM/U0A+U0A+'. 'UUA+UEA9Uj89UT48Tj45TDvewfrHAAAAAXRSTlMAQObYZgAAAA'. 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. 'RQfTAwkUGRjxlcuZAAAAtElEQVR4nGNgIBZw8osqqIpzw/msfI'. 'IiUmr6lo6SbFARASEOJiYtQ2uXADmIAJeEGFBE18LBMySBBywi'. 'LC/LwcFiZuvmH5WiAxZR0tRW1DC3dfYJS8zyAouYGBibWtm7+o'. 'TEpZfkgEX0rG3snNx9Q2NSCksgaqRd3Ty8gyLiU/NKSiDmcPsF'. 'BodHJ2UUlZTkQ+xikIlNSE7LLgECZagL2VQyc0H8YnV2uD94jS'. 'ILIo14iQ4HALarJBNwbJVNAAAAAElFTkSuQmCC' ; //========================================================== // File: bs_purple.png //========================================================== $this->imgdata_small[7][0]= 447 ; $this->imgdata_small[7][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAnF'. 'BMVEX///////+/v7/Gvca9rb3Grcb/xv+1hLWte629hL21e7XG'. 'hMbWhNbOe87We9b/hP//e/97OXv/c///a///Y/+cOZz/Sv/WOd'. 'bnOefvOe//Kf9jCGNrCGv/EP//CP/nCOf/AP/3APfvAO/nAOfe'. 'AN7WANbOAM7GAMa9AL21ALWtAK2lAKWcAJyUAJSMAIyEAIR7AH'. 'tzAHNrAGtjAGPP1sZnAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGS'. 'o5QpoZAAAAnElEQVR4nI3Q2xJDMBAG4MyQokWrZz3oSkJISJH3'. 'f7dK0Gv/Xb7J7vyzCK0NjtPsHuH/2wlhTE7LnTNLCO/TFQjjIp'. 'hHAA6bY06LSqppMAY47x+04HXTba2kAFlmQKr+YuVDCGUG2k6/'. 'rNwYK8rKwKCnPxHnVS0aA3rag4UQslUGhrlk0Kpv1+sx3tLZ6w'. 'dtYemMkOsnz8R3V9/hB87DEu2Wos5+AAAAAElFTkSuQmCC' ; //========================================================== // File: bs_brown.png //========================================================== $this->imgdata_small[8][0]= 677 ; $this->imgdata_small[8][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABaF'. 'BMVEX//////////8X/3oD/3nj/1HX/0Gr/xGP/rkv/gBf+iS/2'. 'bAL1agDxaQDuZwDrZwLpZQDmZQLlZADjcx7gZATeYQDdZgraXw'. 'DZXwHYXgDXiEvXZAvUjlfUXwXTjVfTbR7ShUvRbR7RWwDMWQDL'. 'WADKooLKWADJoYLJgkvHWATGoILFn4LFgEvFVgDEZx7EVQDDt6'. '/DVQDCt6/CnoLChlfCVADAwMC+hFe+UgC8UgC6UQC4gVe4UAC3'. 'gVe3UAC1gFe1eUu1TwC1TgCzTgCwTQKuTACrSgCqSgCpSgCpSQ'. 'CodEulSACkRwCiRgCdRACcRACaQwCYQgCWQgKVQQCVQACUQACS'. 'UR6RPwCOPgCNPQCLPACKPACJOwCEOQCBOAB+NwB9NgB8NgB7NQ'. 'B6NwJ4NAB3RR52MwB0MgBuLwBtLwBsLwBqLgBpLQBkLQJiKgBh'. 'KgBgKwRcKABbKQJbJwBaKQRaJwBYKAJVJQDZvdIYAAAAAXRSTl'. 'MAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLd'. 'fvwAAAAHdElNRQfTAwkUGho0tvl2AAAAtklEQVR4nGNgIBaoSg'. 'mLKGpowfkGMty8AqJKpi4mRlAROR5ONg4JFUv3YHOIgDo/HwsT'. 'q6yps29EsjZYREFIkJ2ZS9/OMzA20wEsIi8uKSZtaOPmH5WSFw'. 'YW0VRW07Vw8vCLSMguLwCL6FlaObp6B0TGZxSXQ9TouHv6+IXG'. 'JGYWlpdDzNEKCgmPjkvLKS0vL4LYxWAen5SelV8OBNZQFxrZ5h'. 'aC+GX2MDczMBh7pZakehkTHQ4AA0Am/jsB5gkAAAAASUVORK5C'. 'YII=' ; //========================================================== // File: bs_blue.png //========================================================== $this->imgdata_small[9][0]= 436 ; $this->imgdata_small[9][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAk1'. 'BMVEX///////+/v7+trcbGxv+EhM6EhNaEhP97e/9zc/9ra/9S'. 'UsZKSrVSUs5jY/9SUtZKSsZSUudKSt5KSudKSv8YGIQpKf8YGK'. 'UYGN4YGO8YGPcQEP8ICP8AAP8AAPcAAO8AAOcAAN4AANYAAM4A'. 'AMYAAL0AALUAAK0AAKUAAJwAAJQAAIwAAIQAAHsAAHMAAGsAAG'. 'ONFkFbAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGhNNakHSAAAAmk'. 'lEQVR4nI3P2xKCIBAGYGfM6SBWo1nauIqogaDA+z9dK9Lhrv47'. 'vtl/2A2CfxNlJRRp9IETYGraJeEb7ocLNKznia8A7Db7umWDUG'. 'sxAzhurxRHxok4KQGqCuEhlL45oU1D2w5BztY4KRhj/bCAsetM'. '2uObjwvY8/oX50JItYDxSyZSTrO2mNhvGMbaWAevnbFIcpuTr7'. 't+5AkyfBIKSJHdSQAAAABJRU5ErkJggg==' ; //========================================================== // File: bs_green.png //========================================================== $this->imgdata_small[10][0]= 452 ; $this->imgdata_small[10][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAn1'. 'BMVEX///////+/v7+/v7/G/8aUxpSMvYyUzpSMzoyM1oxarVqE'. '/4R7/3tavVpKnEpaxlpz/3Nr/2tKtUpj/2Na51pKzkpK1kpK50'. 'pK/0oYcxgp/ykYlBgY3hgY7xgY9xgQ/xAI/wgA/wAA9wAA7wAA'. '5wAA3gAA1gAAzgAAxgAAvQAAtQAArQAApQAAnAAAlAAAjAAAhA'. 'AAewAAcwAAawAAYwA0tyxUAAAAAXRSTlMAQObYZgAAAAFiS0dE'. 'AIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAw'. 'kUGgW5vvSDAAAAnklEQVR4nI3QSxKCMAwA0M4gqCgoiiJ+kEAL'. 'LQUq0PufzX7ENdnlJZNkgtDS2CYZvK6bf+7EoKLA9cH5SQzv6A'. 'YloTywsAbYr44FrlgrXCMJwHl3xxVtuuFkJAPIcw2tGB9GcFli'. 'oqEf5GTkSUhVMw2TtD0XSlnDOw3SznE5520vNEi7CwW9+Ayjyq'. 'U/3+yPuq5gvhkhL0xlGnqL//AFf14UIh4mkEkAAAAASUVORK5C'. 'YII=' ; //========================================================== // File: bs_white.png //========================================================== $this->imgdata_small[11][0]= 480 ; $this->imgdata_small[11][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. 'B3RJTUUH0wMLFTsY/ewvBQAAAW1JREFUeJytkz2u4jAUhT/jic'. 'gfBUKiZhE0bIKeVbCWrIKenp6eDiGlCEEEBArIxvzGU4xeZjLk'. 'jWb05lRXuvbx+exr4bouX1Xjyw7Atz81F4uFBYjjGIDhcCjq1o'. 'k6nN1uZwFerxfP55Msy1itVmRZBsB4PK6YveHkeW5d18XzPIIg'. 'wPd9Wq0WnU6HMAxJkoQoiuynOIfDwUopkVIihKAoCgAcx6Hdbm'. 'OMIU1T5vN55eBKEikljUYDIX6kFUKU9e8aDAZlmjcca+1b7TgO'. '1+uVy+VS9nzfr8e53++VzdZaiqIgz3OMMWitOZ/PaK0JgqDeRC'. 'mF53lIKYGfr3O73TDGoJQiTVO01nS73XqT4/FIs9kkCAIej0eZ'. 'brPZEMcxSZKgtQZgMpmIWpN+vy+m06n1PK9yTx8Gy+WS/X5Pr9'. 'er9GuHLYoiG4YhSilOpxPr9Zrtdlti/JriU5MPjUYjq7UuEWaz'. '2d+P/b/qv/zi75oetJcv7QQXAAAAAElFTkSuQmCC' ; //========================================================== // File: bs_cyan.png //========================================================== $this->imgdata_small[12][0]= 633 ; $this->imgdata_small[12][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABPl'. 'BMVEX////////F///AwMCvxsaC1NSC0dGCz8+CzMyA//94//91'. '//9q//9j//9X4uJX09NXz89Xx8dXxMRL//9L5uZL3d1L2NhLxs'. 'ZLt7cv//8e9fUe8fEe7u4e398epqYehoYX//8L+PgK//8F9fUE'. '/v4E5+cEb28EZ2cC//8C/v4C/f0CzMwCrq4Cjo4CdXUCaWkCZW'. 'UB/PwA//8A/f0A+/sA8/MA7e0A7OwA6+sA5eUA5OQA4uIA4eEA'. '3NwA2toA2NgA1dUA09MA0tIA0NAAysoAxsYAxcUAxMQAv78Avr'. '4AvLwAtrYAtbUAs7MAsLAAra0Aq6sAqKgApaUApKQAoqIAoKAA'. 'n58AmpoAlZUAk5MAkpIAkJAAj48AjIwAiYkAh4cAf38AfX0Ae3'. 'sAenoAcnIAcHAAa2sAaWkAaGgAYmIUPEuTAAAAAXRSTlMAQObY'. 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. 'AHdElNRQfTAwkUGQDi+VPPAAAAtElEQVR4nGNgIBawikipyIiy'. 'wfksfJpGRkamNtr8LFARPiMFHmFDcztXfwGoFi0jLiZuZRtnry'. 'BddrCIiJEGL6eklYO7X3iCOFhE2thESdHawdUnJDZFDiyiamZh'. 'aevk5h0UlZSpBhaRtbN3dPHwDY5MSM+EqBFzc/f0DgiLTkjLzI'. 'SYw6bjHxgaEZeckZmpD7GLQSAqJj4xNRMIBGFuFtRLA/ENhGBu'. 'ZmDgkJBXl5fgIDocAAKcINaFePT4AAAAAElFTkSuQmCC' ; //========================================================== // File: bs_bluegreen.png //========================================================== $this->imgdata_small[13][0]= 493 ; $this->imgdata_small[13][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAvV'. 'BMVEX///////+/v79j//855/8x3v851v9Spb1C1v8AOUqEtcZK'. 'lK1StdYxzv8hxv8AY4QASmNSlK1KpcZKtd4YQlIYnM4YrecIvf'. '8AtfcAre8AjL0AhLUAc5wAa5QAWnsAQloAKTkAGCFKhJxKrdYY'. 'jL0Ypd4Atf8ArfcApecAnN4AlM4AjMYAe60Ac6UAY4wAUnNSnL'. '0AlNYAWoQASmsAOVIAITGEtc4YWnsAUnsAMUqtvcaErcYAKUIA'. 'GCkAECHUyVh/AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAA'. 'AJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGxNUcXCT'. 'AAAAqUlEQVR4nI2Q1xKCMBREM2NHLCCogAGCjd6SqLT8/2cZKT'. '6zb3tm987OBWCsXoejp8rC35fi4+l6gXFZlD0Rz6fZ1tdDmKR9'. 'RdOmkzmP7DDpilfX3SzvRgQ/Vr1uiZplfsCBiVf03RJd140wgj'. 'kmNqMtuYXcxyYmNWJdRoYwzpM9qRvGujuCmSR7q7ARY00/MiWk'. 'sCnjkobNEm1+HknDZgAqR0GKU43+wxdu2hYzbsHU6AAAAABJRU'. '5ErkJggg==' ; //========================================================== // File: bs_lightred.png //========================================================== $this->imgdata_small[14][0]= 532 ; $this->imgdata_small[14][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAA3l'. 'BMVEX///////+/v7/Gvb0hGBj/5///3v//zu//1u//xucpGCG9'. 'nK21lKVSQkp7Wms5KTExISlaOUpjQlIhEBj/tdbOhKXnrcbGjK'. 'Wla4TetcbGnK2EWmv/rc73pcZ7UmOcY3vOpbW1jJzenLW9e5Rz'. 'Slq1c4xrQlJSOULGhJz/pcb3nL2chIzOnK33rcbelK3WjKWMWm'. 'vGe5SEUmM5ISnOtb3GrbXerb3vpb2ca3v/rcaUY3POhJxCKTF7'. 'SlrWnK21e4ytc4TvnLXnlK2la3taOUK1lJxrSlLGhJRjQkpSMT'. 'lw+q2nAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGjoP2Nm+AAAAr0'. 'lEQVR4nGNgIBaYiOk62imYwPnMkiIyso76yhJSzFARMxkRNk49'. 'a3t5OW6oFk1LVkYOfWUHKxUXiEYzLS12DnN3VXkjIRtFsIiSk5'. '6evqGqhYGKugAfWMRa1FpD2UHeQEXQRlgALCJur+rgbCUNFOAS'. 'hqjRkZe3MpBTcwEKCEPMMTGSs3Xz8OQHCnBBHckt6OJpIyAMBD'. 'wwN/MYc4H4LK4wNzMwmGrzcvFqmxIdDgDiHRT6VVQkrAAAAABJ'. 'RU5ErkJggg==' ; //========================================================== // File: bxs_lightred.png //========================================================== $this->imgdata_xsmall[0][0]= 432 ; $this->imgdata_xsmall[0][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAA3l'. 'BMVEX///////+/v7/Gvb0hGBj/5///3v//zu//1u//xucpGCG9'. 'nK21lKVSQkp7Wms5KTExISlaOUpjQlIhEBj/tdbOhKXnrcbGjK'. 'Wla4TetcbGnK2EWmv/rc73pcZ7UmOcY3vOpbW1jJzenLW9e5Rz'. 'Slq1c4xrQlJSOULGhJz/pcb3nL2chIzOnK33rcbelK3WjKWMWm'. 'vGe5SEUmM5ISnOtb3GrbXerb3vpb2ca3v/rcaUY3POhJxCKTF7'. 'SlrWnK21e4ytc4TvnLXnlK2la3taOUK1lJxrSlLGhJRjQkpSMT'. 'lw+q2nAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUKBOgGhWjAAAAS0'. 'lEQVR4nGNgQAEmunYmEJaMCKe1vBxYzJKVQ9lKBSSupKdnaKGi'. 'zgdkiqs6WKnYcIGYJnK2HvzCwmCNgi42wsLCECNMeXlNUY0HAL'. 'DaB7Du8MiEAAAAAElFTkSuQmCC' ; //========================================================== // File: bxs_bluegreen.png //========================================================== $this->imgdata_xsmall[1][0]= 397 ; $this->imgdata_xsmall[1][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAvV'. 'BMVEX///////+/v79j//855/8x3v851v9Spb1C1v8AOUqEtcZK'. 'lK1StdYxzv8hxv8AY4QASmNSlK1KpcZKtd4YQlIYnM4YrecIvf'. '8AtfcAre8AjL0AhLUAc5wAa5QAWnsAQloAKTkAGCFKhJxKrdYY'. 'jL0Ypd4Atf8ArfcApecAnN4AlM4AjMYAe60Ac6UAY4wAUnNSnL'. '0AlNYAWoQASmsAOVIAITGEtc4YWnsAUnsAMUqtvcaErcYAKUIA'. 'GCkAECHUyVh/AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAA'. 'AJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUKDVyF5Be'. 'AAAASUlEQVR4nGNgQAFmYqJcEJaEOJ+UrD5YTJKFTZrfGCQuaq'. 'glLWvMaQ5kqujo6hnbKIKYXPr68gp2dmCNJiZAlh3ECGsREWtU'. '4wF1kwdpAHfnSwAAAABJRU5ErkJggg==' ; //========================================================== // File: bxs_navy.png //========================================================== $this->imgdata_xsmall[2][0]= 353 ; $this->imgdata_xsmall[2][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAk1'. 'BMVEX///////+/v7+trcbGxv+EhM6EhNaEhP97e/9zc/9ra/9S'. 'UsZKSrVSUs5jY/9SUtZKSsZSUudKSt5KSudKSv8YGIQpKf8YGK'. 'UYGN4YGO8YGPcQEP8ICP8AAP8AAPcAAO8AAOcAAN4AANYAAM4A'. 'AMYAAL0AALUAAK0AAKUAAJwAAJQAAIwAAIQAAHsAAHMAAGsAAG'. 'ONFkFbAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUJxXO4axZAAAAR0'. 'lEQVR4nGNgQAGskhKsEJaslIi8ijpYTJaDU1FVAyQuKSujoKKh'. 'LQ5kSigpqWro6oOYrOoaWroGBmCNWiCWAdQwUVFWVOMBOp4GCJ'. 's5S60AAAAASUVORK5CYII=' ; //========================================================== // File: bxs_gray.png //========================================================== $this->imgdata_xsmall[3][0]= 492 ; $this->imgdata_xsmall[3][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABI1'. 'BMVEX///8AAAD8EAD8IAD8NAD8RAD8VAAYGBi/v7+goKCCgoJk'. 'ZGRGRkb8yAD83AD87AD8/AD4+ADo+ADY+ADI+AC0+ACk+ACU+A'. 'CE+AB0/ABk/ABU/ABE/AAw/AAg/AAQ/AAA/AAA+AAA6BAA2CAA'. 'yDQAtEQApFQAlGQAhHQAdIgAZJgAVKgARLgAMMgAINwAEOwAAP'. 'wAAPgIAPAQAOgYAOAkANgsANA0AMg8AMBEALhMALBUAKhcAKBo'. 'AJhwAJB4AIiAAID////4+Pjy8vLs7Ozm5ubg4ODa2trT09PNzc'. '3Hx8fBwcG7u7u1tbWurq6oqKiioqKcnJyWlpaQkJCJiYmDg4N9'. 'fX13d3dxcXFra2tkZGReXl5YWFhSUlJMTExGRkZAQEA1BLn4AA'. 'AAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEA'. 'AAsRAX9kX5EAAAAHdElNRQfTAwkUKC74clmyAAAAQklEQVR4nG'. 'NgQAVBYVCGt5dXYEQ0mOnp5h4QFgVmeri6+4dHxYMVeHoFRUTH'. 'gTUFBIZBWAwMkZEx8bFQM2Lj0UwHANc/DV6yq/BiAAAAAElFTk'. 'SuQmCC' ; //========================================================== // File: bxs_graypurple.png //========================================================== $this->imgdata_xsmall[4][0]= 542 ; $this->imgdata_xsmall[4][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABSl'. 'BMVEX////////11P/MqdvKrNfAwMC+u7+9u7+4rr24lsi3rby3'. 'lMe1rLq1o720q7i0oL20ksSzoryyqbaykMGxlb2wkL+vnbiujb'. '2sjLuri7qpl7GoirWoibenmK2mla6mjLKmhrSllauki7CjhrCj'. 'hLGihLChg6+ggq2fkqadkKOcfqqai6Gag6WYe6WXeqSWeaOTd6'. 'CTd5+Rdp6RdZ6RdZ2Qg5eOc5qMcpiLcZeJb5WIbpOHbZKGbJGE'. 'a4+CaY2AZ4t/Z4p/Zop/Zol+Zol7ZIZ6Y4V5YoR1ZH11X391Xn'. '9zXX1yXXtxXHtvWnluWXhsV3VqVnNpVXJoVHFnU3BmUm9jUGth'. 'VGdgTmheTGZcS2RcSmRaSWJYR19XRl5SQllRQlhQQVdPQFZOP1'. 'VLPlFJO09IPE5IOk5FOEtEN0lDOEpDOElDNklCNkc/M0XhbrfD'. 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. 'EAAAsRAX9kX5EAAAAHdElNRQfTAwkUKCgREfyHAAAATUlEQVR4'. 'nGNgQAEcIko8EBY3M5Ougy+IxSXMwmTsFsAHZMqrSRvZB0W7A5'. 'k6FlYugXEZICaPr394Um4uSAFDRFRCbm4uxAihsDAhVOMBHT0L'. 'hkeRpo8AAAAASUVORK5CYII=' ; //========================================================== // File: bxs_red.png //========================================================== $this->imgdata_xsmall[5][0]= 357 ; $this->imgdata_xsmall[5][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAk1'. 'BMVEX////////GxsbGra3/xsbOhITWhIT/hIT/e3v/c3P/a2vG'. 'UlK1SkrOUlL/Y2PWUlLGSkrnUlLeSkrnSkr/SkqEGBj/KSmlGB'. 'jeGBjvGBj3GBj/EBD/CAj/AAD3AADvAADnAADeAADWAADOAADG'. 'AAC9AAC1AACtAAClAACcAACUAACMAACEAAB7AABzAABrAABjAA'. 'BuukXBAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUIyjy5SVMAAAAS0'. 'lEQVR4nGNgQAFsUpJsEJastIi8ijpYTJaDU0FVgxXIlJKVUVDR'. '0BYHMiUUlVQ1dPVBTDZ1dS1dAwOQAgYtbSDLAGIEq6goK6rxAD'. 'yXBg73lwGUAAAAAElFTkSuQmCC' ; //========================================================== // File: bxs_yellow.png //========================================================== $this->imgdata_xsmall[6][0]= 414 ; $this->imgdata_xsmall[6][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAzF'. 'BMVEX///////+/v79zYwCMewDOxoTWzoTezkr/5wj/5wDnzgDe'. 'xgC1pQCtnACllACcjACUhABjWgDGvVK1rUrOxlLGvUqEexilnB'. 'jv3hj35xj/7wj/7wD35wDv3gDn1gDezgDWxgDOvQDGtQC9rQCE'. 'ewB7cwBzawBrYwDWzlLn3lLe1krn3kre1hi9tQC1rQCtpQClnA'. 'CclACUjACMhAD/9wC/v7///8bOzoT//4T//3v//3P//2v//2Pn'. '50r//0r//yn39xj//xD//wBjYwDO8noaAAAAAXRSTlMAQObYZg'. 'AAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAH'. 'dElNRQfTAwkUIzoBXFQEAAAAS0lEQVR4nGNgQAFsDhJsEJaTo5'. '2skj5YzMnSSk7ZwBzIlOSUklPiMxYHMnW4FXT5VNVBTDZeXiNV'. 'QUGQAgYBYyBLEGIEq5gYK6rxAH4kBmHBaMQQAAAAAElFTkSuQm'. 'CC' ; //========================================================== // File: bxs_greenblue.png //========================================================== $this->imgdata_xsmall[7][0]= 410 ; $this->imgdata_xsmall[7][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAxl'. 'BMVEX///////+/v79znJQhSkJ7raU5hHtjraVKnJRCjIRClIyU'. '9++E595avbVaxr2/v7+ctbWcvb17nJxrjIx7paUxQkK9//+Mvb'. '17ra2Evb17tbVCY2MQGBiU5+ec9/eM5+d71tZanJxjra1rvb1j'. 'tbVSnJxara1rzs5jxsZKlJRChIQpUlIhQkJatbVSpaU5c3MxY2'. 'MYMTEQISFavb1Sra1KnJxCjIw5e3sxa2spWlpClJQhSkoYOTkp'. 'Y2MhUlIQKSkIGBgQMTH+e30mAAAAAXRSTlMAQObYZgAAAAFiS0'. 'dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfT'. 'AwkUJy5/6kV9AAAATUlEQVR4nGNgQAGCyuyCEJaGugKHviVYzF'. 'hO3sxCWwDIVNLTM9PXtpEGMhW12Cy0DR1ATEFLSxZ7BweQAgYd'. 'HUMHBweIEQKiogKoxgMAo/4H5AfSehsAAAAASUVORK5CYII=' ; //========================================================== // File: bxs_purple.png //========================================================== $this->imgdata_xsmall[8][0]= 364 ; $this->imgdata_xsmall[8][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAnF'. 'BMVEX///////+/v7/Gvca9rb3Grcb/xv+1hLWte629hL21e7XG'. 'hMbWhNbOe87We9b/hP//e/97OXv/c///a///Y/+cOZz/Sv/WOd'. 'bnOefvOe//Kf9jCGNrCGv/EP//CP/nCOf/AP/3APfvAO/nAOfe'. 'AN7WANbOAM7GAMa9AL21ALWtAK2lAKWcAJyUAJSMAIyEAIR7AH'. 'tzAHNrAGtjAGPP1sZnAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. 'HUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUIj'. 'mBTjT/AAAASUlEQVR4nGNgQAGskhKsEJaCrJiSuhZYTEFASFlD'. 'GyQuqSCnrK6tJwpkiquoamgbGIGYrFpaugbGxmCNunpAljHECB'. 'ZBQRZU4wFSMAZsXeM71AAAAABJRU5ErkJggg==' ; //========================================================== // File: bxs_green.png //========================================================== $this->imgdata_xsmall[9][0]= 370 ; $this->imgdata_xsmall[9][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAn1'. 'BMVEX///////+/v7+/v7/G/8aUxpSMvYyUzpSMzoyM1oxarVqE'. '/4R7/3tavVpKnEpaxlpz/3Nr/2tKtUpj/2Na51pKzkpK1kpK50'. 'pK/0oYcxgp/ykYlBgY3hgY7xgY9xgQ/xAI/wgA/wAA9wAA7wAA'. '5wAA3gAA1gAAzgAAxgAAvQAAtQAArQAApQAAnAAAlAAAjAAAhA'. 'AAewAAcwAAawAAYwA0tyxUAAAAAXRSTlMAQObYZgAAAAFiS0dE'. 'AIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAw'. 'kUKBrZxq0HAAAATElEQVR4nGNgQAGccrIcEJaivISyhjaIxa7I'. 'I6CiqcMKZMopKqho6OhLA5kyqmqaOobGICartraeoYkJSAGDnj'. '6QZQIxgk1Skg3VeABlVgbItqEBUwAAAABJRU5ErkJggg==' ; //========================================================== // File: bxs_darkgreen.png //========================================================== $this->imgdata_xsmall[10][0]= 563 ; $this->imgdata_xsmall[10][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABX1'. 'BMVEX////////l/+nAwMC86r+8wb28wby8wLy78sCzw7SywrSx'. 'wLKwvrGuvK+syK+ryq2rx62n36ym3aumxKmk2qij0Keh16ahva'. 'Og1aSguKKe06KeuaCetZ+d0KGdtZ+bz6Cay56ZyZ2Zwp2Zr5qZ'. 'rpqYwJuXyZuXrJmVw5mUxZiTxJeTw5eTq5WRwJWPtJKOvZKKuI'. '6Kt42Kn4yJt42ItIuGsomFsYmEsIiEr4eDr4eBrIR/qoN+qIJ8'. 'poB7pH56o356on14nnt2nXl0mndzmnZzmXZymHVwlXNvlHJukn'. 'FtiHBqjm1qjW1oi2toiWpniWplh2hlhmdkhWdig2VggGNgf2Je'. 'fmFdfGBde19bbl1aeFxXdFpWclhVclhVcVdUcFZTb1VSbVRQal'. 'JPaVFKY0xKYkxJYUtIYEpHX0lEWkZCWERCV0NCVkM/U0A+U0A+'. 'UUA+UEA9Uj89UT48Tj45TDvewfrHAAAAAXRSTlMAQObYZgAAAA'. 'FiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElN'. 'RQfTAwkUKCFozUQjAAAATUlEQVR4nGNgQAGcoqrcEJYQB5OhSw'. 'CIxSXGwWThGcIDZCppK5o7hyV6AZl6NnbuoSmFICZ3YHB0RkkJ'. 'SAFDbEJaSUkJxAjeyEheVOMBQj4MOEkWew4AAAAASUVORK5CYI'. 'I=' ; //========================================================== // File: bxs_cyan.png //========================================================== $this->imgdata_xsmall[11][0]= 530 ; $this->imgdata_xsmall[11][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABPl'. 'BMVEX////////F///AwMCvxsaC1NSC0dGCz8+CzMyA//94//91'. '//9q//9j//9X4uJX09NXz89Xx8dXxMRL//9L5uZL3d1L2NhLxs'. 'ZLt7cv//8e9fUe8fEe7u4e398epqYehoYX//8L+PgK//8F9fUE'. '/v4E5+cEb28EZ2cC//8C/v4C/f0CzMwCrq4Cjo4CdXUCaWkCZW'. 'UB/PwA//8A/f0A+/sA8/MA7e0A7OwA6+sA5eUA5OQA4uIA4eEA'. '3NwA2toA2NgA1dUA09MA0tIA0NAAysoAxsYAxcUAxMQAv78Avr'. '4AvLwAtrYAtbUAs7MAsLAAra0Aq6sAqKgApaUApKQAoqIAoKAA'. 'n58AmpoAlZUAk5MAkpIAkJAAj48AjIwAiYkAh4cAf38AfX0Ae3'. 'sAenoAcnIAcHAAa2sAaWkAaGgAYmIUPEuTAAAAAXRSTlMAQObY'. 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAA'. 'AHdElNRQfTAwkUKQFKuFWqAAAATUlEQVR4nGNgQAGsUjJsEJaR'. 'grC5qz9YzIiL28YriB3IlDZRsnYNiZUDMmXtHT2CE9JBTDb/wI'. 'jkzEyQAoaomMTMzEyIERzy8hyoxgMAN2MLVPW0f4gAAAAASUVO'. 'RK5CYII=' ; //========================================================== // File: bxs_orange.png //========================================================== $this->imgdata_xsmall[12][0]= 572 ; $this->imgdata_xsmall[12][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABaF'. 'BMVEX//////////8X/3oD/3nj/1HX/0Gr/xGP/rkv/gBf+iS/2'. 'bAL1agDxaQDuZwDrZwLpZQDmZQLlZADjcx7gZATeYQDdZgraXw'. 'DZXwHYXgDXiEvXZAvUjlfUXwXTjVfTbR7ShUvRbR7RWwDMWQDL'. 'WADKooLKWADJoYLJgkvHWATGoILFn4LFgEvFVgDEZx7EVQDDt6'. '/DVQDCt6/CnoLChlfCVADAwMC+hFe+UgC8UgC6UQC4gVe4UAC3'. 'gVe3UAC1gFe1eUu1TwC1TgCzTgCwTQKuTACrSgCqSgCpSgCpSQ'. 'CodEulSACkRwCiRgCdRACcRACaQwCYQgCWQgKVQQCVQACUQACS'. 'UR6RPwCOPgCNPQCLPACKPACJOwCEOQCBOAB+NwB9NgB8NgB7NQ'. 'B6NwJ4NAB3RR52MwB0MgBuLwBtLwBsLwBqLgBpLQBkLQJiKgBh'. 'KgBgKwRcKABbKQJbJwBaKQRaJwBYKAJVJQDZvdIYAAAAAXRSTl'. 'MAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9k'. 'X5EAAAAHdElNRQfTAwkUJBSSy88MAAAATUlEQVR4nGNgQAGqwo'. 'paEBYPJ4eKezCIpc7HwmrqG6ENZMpLihm6RaWEAZl6Vo7ekRnF'. 'IKZWSHhcTnk5SAFDfFJWeXk5xAjj1FRjVOMBeFwNcWYSLjsAAA'. 'AASUVORK5CYII=' ; //========================================================== // File: bxs_lightblue.png //========================================================== $this->imgdata_xsmall[13][0]= 554 ; $this->imgdata_xsmall[13][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABVl'. 'BMVEX////////d///AwMC7wcS08P+y+P+xxdCwxM+uws2twMur'. 'vsinzNynytylzuKhyN6e5v6d5P+d1fOcwNWcu8ub4f+at8iZ3v'. '+ZvdGY2/yW2f+VscGU1vuT1fqTr72Sx+SSxeKR0fWRz/GPz/OP'. 'rr+OyeqMy+6Myu2LyeyKxueJudSGw+SGorGDvt+Cvd6CvN2Aud'. 'p+uNd+t9Z9tdV8tdR8tNN6sc94r813rct2q8h0qcZ0qMVzp8Rx'. 'o8Bwor5tn7ptnrptnrlsnbhqmbRpmbNpi51ol7Flkqtkkqtkka'. 'pjj6hijaRhjaZgi6NfiqJfiaFdh55bhJtag5pZgphYgJZYf5VX'. 'cn9Ve5FSeI1RdopRdYlQdYlPc4dPcoZPcoVNcINLboBLbH9GZn'. 'hGZXdFZHZEY3RDYnJCXW4/W2s/WWg+Wmo7VmU7VGM7U2E6VGM6'. 'VGI5UV82T1wGxheQAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. 'gAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUJziL'. 'PvAsAAAATUlEQVR4nGNgQAHsQgqcEJYgG5Oegy+IxSHOxmTiFs'. 'gFZMprKBnbB8e7AplaFlbOQUl5ICanX0BEWmEhSAFDVGxKYWEh'. 'xAjusDBuVOMBJO8LrFHRAykAAAAASUVORK5CYII=' ; //========================================================== // File: bxs_darkgray.png //========================================================== $this->imgdata_xsmall[14][0]= 574 ; $this->imgdata_xsmall[14][1]= 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABm'. 'JLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsRAAALEQF/ZF+RAAAB'. 'iElEQVR42k3QPU8TYRwA8P//ebkXrgdIColXRAOEkJqbaExMut'. 'DBhE1GNjYHPg+DG6ODiU6QOLjVxITBcFKBYCstlAC2Bz17fe76'. 'vLD6+wg/1FpTRFR5lpaub/u1eGBGaAT4HneD4OlXx7avtDYUjT'. 'HQabd2Ti8e3vVSKzxrtHS32wIpFVldno22Nqvvg2Bhl0gp/aNm'. 'vJ3qqXAtLIva+ks1H0wqlSXi4+d6+OFTfRsAfHJx2d1od24rZP'. 'xP2HzopINr1mkesX7ccojqif0v9crxWXODZTno3+dNGA7uWLsd'. 'mUYU4fHJCViMG9umLBmM4L6fagZGg9QKfjZ+Qfy3C3G/B3mugF'. 'IHHNcDf64E3KJALApk2p8CSolUUqLjFkyxOGMsTtFyJ+Wz57NQ'. '8DghS4sLB0svioeZZo7nPhFoUKZDIVFbglkTTnl5/rC8snjAkJ'. 'Bk/XV5LxHC/v7tR8jzTFPbg8LENK9WX0Vv31T2AEmCSmlKCCoh'. 'ROnP1U1tPFYjJBRcbtzSf+GPsFTAQBq1n4AAAABKdEVYdHNpZ2'. '5hdHVyZQBiYzYyMDIyNjgwYThjODMyMmUxNjk0NWUzZjljOGFh'. 'N2VmZWFhMjA4OTE2ZjkwOTdhZWE1MzYyMjk0MWRkM2I5EqaPDA'. 'AAAABJRU5ErkJggg==' ; } } ?> ================================================ FILE: tools/server/admin/jpgraph/imgdata_bevels.inc ================================================ 'imgdata'); var $colors = array('green','purple','orange','red','yellow'); var $index = array('green'=>1,'purple'=>4,'orange'=>2,'red'=>0,'yellow'=>3); var $maxidx = 4 ; var $imgdata ; function ImgData_Bevels() { //========================================================== // File: bullets_balls_red_013.png //========================================================== $this->imgdata[0][0]= 337 ; $this->imgdata[0][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. 'BMVEX////////27t/f3+LFwcmNxMuxm62DmqKth1VpZmIWg6fv'. 'HCa7K0BwMEytCjFnIyUlEBg9vhQvAAAAAXRSTlMAQObYZgAAAA'. 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. 'RQfTAxcBNhk+pYJVAAAAl0lEQVR4nE2Q2xLDIAgFHUWBKJf//9'. 'oekmbafVDZARRbK/pYTKP9WNcNv64zzUdd9BjmrgnsVXRNSzO3'. 'CJ5ahdhy0XKQkxld1kxb45j7dp0x2lBNOyVgQpMaoadX7Hs7zr'. 'P1yKj47DKBnKaBKiSAkNss7O6PkMx6kIgYXISQJpcZCqdY6KR+'. 'J1PkS5Xob/h7MNz8x6D3fz5DKQjpkZOBYAAAAABJRU5ErkJggg'. '==' ; //========================================================== // File: bullets_balls_green_013.png //========================================================== $this->imgdata[1][0]= 344 ; $this->imgdata[1][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. 'BMVEX////////27t/e3+K3vriUub/Dm18j4xc3ob10k0ItqQlU'. 'e5JBmwpxY1ENaKBgUh0iHgwsSre9AAAAAXRSTlMAQObYZgAAAA'. 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. 'RQfTAxcBNTfJXtxZAAAAnklEQVR4nE2QWY4EMQhDUVhSIRC4/2'. 'kbaqLp9p+f2AxAayAzDfiK9znPORuvH0x8Ss9z6I9sHp6tcxE9'. 'nLmWmebmt5F5p2AR0+C9AWpLBjXRaZsCAT3SqklVp0YkAWaGtd'. 'c5Z41/STYpPzW7BjyiRrwkVmQto/Cw9tNEMvsgcekyCyFPboIu'. 'IsuXiKffYB4NK4r/h6d4g9HPPwCR7i8+GscIiiaonUAAAAAASU'. 'VORK5CYII=' ; //========================================================== // File: bullets_balls_oy_035.png //========================================================== $this->imgdata[2][0]= 341 ; $this->imgdata[2][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. 'BMVEX////////27t/f3+K5tbqNwcjnkjXjbxR2i5anfEoNkbis'. 'PBxpU0sZbZejKgdqIRIlERIwYtkYAAAAAXRSTlMAQObYZgAAAA'. 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. 'RQfTAxcBNgK0wEu5AAAAm0lEQVR4nE3QVxIEIQgEUErAgTHA/U'. '+7zbipf9RXgoGo0liMmX6RdSPLPtZM9F4LuuSIaZtZWffiU6Iz'. 'Y8SOMF0NogBj30ioGRGLZgiPvce1TbIRz6oBQEbOFGK0rIoxrn'. '5hDomMA1cfGRCaRVhjS3gkzheM+4HtnlkXcvdZhWG4qZawewe6'. '9Jnz/TKLB/ML6HUepn//QczazuwFO/0Ivpolhi4AAAAASUVORK'. '5CYII=' ; //========================================================== // File: bullets_balls_oy_036.png //========================================================== $this->imgdata[3][0]= 340 ; $this->imgdata[3][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. 'BMVEX////////27t/e3+LO3hfYzz65ubiNwci6uQ12ipadgVGa'. 'fwsNkbhnVkcaZ5dwSA8lFg7CEepmAAAAAXRSTlMAQObYZgAAAA'. 'FiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElN'. 'RQfTAxcCBySi1nevAAAAjElEQVR4nFXPWw7EIAgFUNMoCMhj/6'. 'staKczc/2RkwjS2glQ+w3YytgXCXCZpRo8gJdGxZadJws13CUP'. '4SZI4MYiUxypeiGGw1XShVBTNN9kLXP2GRrZPFvKgd7z/sqGGV'. '7C7r7r3l09alYN3iA8Yn+ImdVrNoEeSRqJPAaHfhZzLYwXstdZ'. 'rP3n2bvdAI4INwtihiwAAAAASUVORK5CYII=' ; //========================================================== // File: bullets_balls_pp_019.png //========================================================== $this->imgdata[4][0]= 334 ; $this->imgdata[4][1]= 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. 'BMVEX////+/v7i4eO/w8eHxcvKroNVormtfkjrMN2BeXQrepPc'. 'Esy4IL+OFaR7F25LHF8mFRh5XXtUAAAAAXRSTlMAQObYZgAAAA'. 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. 'RQfTAxcBNgkjEpIxAAAAlElEQVR4nE2QAQ7FIAhDDTAVndL7n3'. 'ZV/7JfEwMvFIWUlkTMVNInbVv5ZeJqG7Smh2QTBwJBpsdizAZP'. '5NyW0awhK8kYodnZxS6ECvPRp2sI+y7PBv1mN02KH7h77QCJ8D'. '4VvY5NUgEmCwj6ZMzHtJRgRSXwC1gfcqJJH0GBnSnK1kUQ72DY'. 'CPBv+MCS/e0jib77eQAJxwiEWm7hFwAAAABJRU5ErkJggg==' ; } } ?> ================================================ FILE: tools/server/admin/jpgraph/imgdata_diamonds.inc ================================================ 'imgdata'); var $colors = array('lightblue','darkblue','gray', 'blue','pink','purple','red','yellow'); var $index = array('lightblue' =>7,'darkblue'=>2,'gray'=>6, 'blue'=>4,'pink'=>1,'purple'=>5,'red'=>0,'yellow'=>3); var $maxidx = 7 ; var $imgdata ; function ImgData_Diamonds() { //========================================================== // File: diam_red.png //========================================================== $this->imgdata[0][0]= 668 ; $this->imgdata[0][1]= 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/F'. 'BMVEX///////+cAAD/AADOAABjAABrAADWGBjOCAj/CAj/GBj/'. 'EBCcCAiMOTl7KSl7ISFzGBilGBjOEBBrCAjv5+eMQkK1QkKtMT'. 'GtKSnWKSn/KSlzEBCcEBDexsb/tbXOe3ucWlqcUlKUSkr/e3vn'. 'a2u9UlL/a2uEMTHeUlLeSkqtOTn/UlL/SkrWOTn/QkL/OTmlIS'. 'H/MTH/ISH39/f/9/f35+fezs7/5+fvzs7WtbXOra3nvb3/zs7G'. 'nJzvtbXGlJTepaW9jIy1hITWlJS1e3uta2ulY2P/lJTnhITne3'. 'vGY2O9Wlr/c3PeY2O1Skr/Y2P/WlreQkLWISGlEBCglEUaAAAA'. 'AXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAA'. 'sSAdLdfvwAAAAHdElNRQfTAwsWEw5WI4qnAAABGUlEQVR4nHXQ'. '1XLDMBAFUKUCM1NiO8zcpIxpp8z0//9SWY7b2LHv6EU6s1qtAN'. 'iMBAojLPkigpJvogKC4pxDuQipjanlICXof1RQDkYEF21mKIfg'. '/GGKtjAmOKt9oSyuCU7OhyiDCQnjowGfRnooCJIkiWJvv8NxnG'. 'nyNAwFcekvZpPP3mu7Vrp8fOq8DYbTyjdnAvBj7Jbd7nP95urs'. '+MC2D6unF+Cu0VJULQBAlsOQuueN3Hrp2nGUvqppemBZ0aU7Se'. 'SXvYZFMKaLJn7MH3btJmZEMEmGSOreqy0SI/4ffo3uiUOYEACy'. 'OFopmNWlP5uZd9uPWmUoxvK9ilO9NtBo6mS7KkZD0fOJYqgGBU'. 'S/T7OKCAA9tfsFOicXcbxt29cAAAAASUVORK5CYII=' ; //========================================================== // File: diam_pink.png //========================================================== $this->imgdata[1][0]= 262 ; $this->imgdata[1][1]= 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. 'BMVEX///+AgID/M5n/Zpn/zMz/mZn1xELhAAAAAXRSTlMAQObY'. 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. 'AHdElNRQfTAwsWEi3tX8qUAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. '==' ; //========================================================== // File: diam_blue.png //========================================================== $this->imgdata[2][0]= 662 ; $this->imgdata[2][1]= 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA+V'. 'BMVEX///+AgIAAAJwAAP8AAM4AAGMAAGsQEP8YGHMQEHMYGP8Q'. 'EKUICJwICM5KSpQxMYQpKXsYGNYQEM4ICGsICP97e85aWpw5OY'. 'xSUv85ObVCQt4xMa0pKa0hIaUpKf+9vd6EhLVra+dzc/9SUr1r'. 'a/9aWt5SUt5CQrVaWv9KSv8hIXs5Of8xMf8pKdYhIdYYGKUhIf'. '/Ozs739//v7/fn5+/v7//n5/fW1ufOzufOzu/W1v+trc69veel'. 'pc6trd6UlMa9vf+MjL21tfe1tf+UlNZzc61ra6Wlpf+EhOeMjP'. '9ra8ZSUpyEhP9CQoxKSrVCQv85Od4xMdYQENZnJhlWAAAAAXRS'. 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. 'LdfvwAAAAHdElNRQfTAwsWEx3Snct5AAABFklEQVR4nHXR5XbD'. 'IBgGYM6AuHsaqbvOfeuknev9X8xISbplSd5/8JyXwwcA/I0AKm'. 'PFchVBdvKNKggKQx2VIoRwMZihMiQE49YUlWBCcPL0hYq4ITh+'. 'qKECUoLDZWqoQNA766F/mJHlHXblPJJNiyURhM5eU9cNw5BlmS'. 'IrLOLxhzfotF7vwO2j3ez2ap/TmW4AIM7DoN9+tu+vLk6Pdg9O'. '6ufXjfXLm6pxPACSJIpRFAa+/26DhuK6qjbiON40k0N3skjOvm'. 'NijBmchF5mi+1jhQqDmWyIzPp1hUlrv8On5l+6mMm1tigFNyrt'. '5R97g+FKKyGKkTNKesXPJTZXOFIrUoKiypcTQVHjK4g8H2dWEQ'. 'B8bvUDLSQXSr41rmEAAAAASUVORK5CYII=' ; //========================================================== // File: diam_yellow.png //========================================================== $this->imgdata[3][0]= 262 ; $this->imgdata[3][1]= 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. 'BMVEX///+AgIBmMwCZZgD/zADMmQD/QLMZAAAAAXRSTlMAQObY'. 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. 'AHdElNRQfTAwsWEwcv/zIDAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. '==' ; //========================================================== // File: diam_lightblue.png //========================================================== $this->imgdata[4][0]= 671 ; $this->imgdata[4][1]= 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/1'. 'BMVEX///+AgIAAnP8A//8Azv8AY/8Aa/8I//8Y1v8Izv8Y//8Q'. '//8InP8Qzv8Ypf85jP8he/8Yc/8Ia/8pe/8p//8p1v9Ctf8xrf'. '8prf8QnP8Qc/9CjP+1//97//9r//9S//9K//9C//85//8x//8h'. '//9r5/9K3v9S3v851v97zv9Svf85rf8hpf/G3v9SnP9anP9KlP'. '8xhP/n7//v7+f3///n///O//+U//9z//9j//9a//975/9C3v8h'. '1v+E5/+17/9j3v/O7//n9/+95/+l3v9jxv+U1v8Qpf9avf9Ktf'. '+Uxv+11v97tf9rrf+cxv+Mvf9jpf+tzv+Etf/O3v/39/8Akkxr'. 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. 'IAAAsSAdLdfvwAAAAHdElNRQfTAwsWEiHk6Ya/AAABGUlEQVR4'. 'nHXQ13KDMBAF0J2o0E01GHDvJa7p3em95/+/JQJMYjDc0Yt0Zr'. 'VaAaxHgtxwbSGPkGQpOIeQ2ORxJiJmNWYZyAhZR0WcgQGhViU0'. 'nEGoedDHGxgRapRPcRpXhOr7XZzCmLjaXk9IIjvkOEmSRLG62+'. 'F5XlEElhA5sW21GvXj6mGlDBfnJ51lr9svnvEKwH1hu2QPbwd3'. 'N9eXVzuL7/Hn29frdKaamgcgy67L3HFG9gDefV+dm5qme4YRXL'. 'oVR374mRqUELZYosf84XAxISFRQuMh4rrH8YxGSP6HX6H97NNQ'. 'KEAaR08qCeuSnx2a8zIPWqUowtKHSRK91rAw0elmVYQFVc8mhq'. '7p5RD7Ps3IIwA9sfsFxFUX6eZ4Zh4AAAAASUVORK5CYII=' ; //========================================================== // File: diam_purple.png //========================================================== $this->imgdata[5][0]= 657 ; $this->imgdata[5][1]= 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/F'. 'BMVEX///////8xAP/OAP+cAP9jAP9rAP+cCP85CP/OEP9SKf/O'. 'CP9CEP9zGP9rCP+lGP/WOf/WIf9KIf9jOf+MQv+EMf97If9zEP'. '+1Sv+lIf/ne//eUv/na//n5//Oxv/Wzv+chP9zUv97Wv9rQv9a'. 'Mf9KGP/v5/+te/97Kf+9Y/+tOf+tKf+lEP/vtf/WMf/WKf/v7+'. 'f39/+tnP+9rf9rSv9jQv9CGP+ljP+EY//Gtf+tlP+Ma/9zSv/e'. 'zv+UUv+9lP+cWv+lY/+cUv+MOf+EKf+UQv/Opf/OhP/Ga/+1Qv'. '/Oe/+9Uv/ntf/eWv/eSv/WGP/3zv/vlP/WEP//9/+pL4oHAAAA'. 'AXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAA'. 'sSAdLdfvwAAAAHdElNRQfTAwsWEjX+M1LCAAABDklEQVR4nHXQ'. '1bLDIBAGYFqIEW+ksbr7cXd3ff93OUCamdOE/Mxw882yywLwPz'. '+gNKotlRFUVnNUQlCxTMRFCKEdE+MgpJaEiIOU4DKaoSIygtb3'. 'FBUQrm3xjPK4JvXjK0A5hFniYSBtIilQVYUm+X0KTVNiYah+2q'. 'ulFb8nUbSovD2+TCavwXQWmnMA6ro+di+uR5cPzfPhVqPV3N1p'. 'n3b3+rimAWAYhP3xnXd7P6oc9vadPsa1wYEs00dFQRAFehlX21'. '25Sg9NOgwF5jeNTjVL9om0TjDc1lmeCKZ17nFPzhPtSRt6J06R'. 'WKUoeG3MoXRa/wjLHGLodwZcotPqjsYngnWslRBZH91hWTbpD2'. 'EdF1ECWW1SAAAAAElFTkSuQmCC' ; //========================================================== // File: diam_gray.png //========================================================== $this->imgdata[6][0]= 262 ; $this->imgdata[6][1]= 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. 'BMVEX//////wAzMzNmZmbMzMyZmZlq4Qo5AAAAAXRSTlMAQObY'. 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. 'AHdElNRQfTAwsWExZFTxLxAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. '==' ; //========================================================== // File: diam_blgr.png //========================================================== $this->imgdata[7][0]= 262 ; $this->imgdata[7][1]= 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. 'BMVEX///+AgIBmzP9m///M//+Z//8hMmBVAAAAAXRSTlMAQObY'. 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. 'AHdElNRQfTAwsWEwCxm6egAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. '==' ; } } ?> ================================================ FILE: tools/server/admin/jpgraph/imgdata_pushpins.inc ================================================ 'imgdata_small', MARK_IMG_SPUSHPIN => 'imgdata_small', MARK_IMG_LPUSHPIN => 'imgdata_large'); var $colors = array('blue','green','orange','pink','red'); var $index = array('red' => 0, 'orange' => 1, 'pink' => 2, 'blue' => 3, 'green' => 4 ) ; var $maxidx = 4 ; var $imgdata_large, $imgdata_small ; function ImgData_PushPins() { // The anchor should be where the needle "hits" the paper // (bottom left corner) $this->anchor_x = 0; $this->anchor_y = 1; //========================================================== // File: ppl_red.png //========================================================== $this->imgdata_large[0][0]= 2490 ; $this->imgdata_large[0][1]= 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. 'B3RJTUUH0wMKBh4Ryh89CgAACUdJREFUeJy9mNtTFFcexz+/7p'. '4Lw1wZJKDGCAwmDAqUySamcCq1ed6k9mn3UfMP7F+1T3nYqn2J'. 'lZdoDEjpbq0KG8EBFBFBEJye6Zmenkv32Ydu5GYiUMmeqq6uqT'. '6Xz3zP73aOcIKmAQkIFyD3N/jrBPwlKjLQEglVlJKyUjR3u7cc'. 'WLoP3/4dvv03LNrQ8I6x1rFbDML9kOmHvh7IRHU9JKmUSG8vpF'. 'IoXX/TV0AiEM5A5jT0noFMFMJHXUt/d5f9TUAbhtQ3cPFruDog'. '8klHMnmO0dGYe/myOJGINEwTz3F2higFXgy8PpAkOC+h8hoaCt'. '4ppHFcQAWSgOQlyI/p+lUjmRxWAwNJd3xca/f34yoFi4tgmjtD'. 'NIFkJ4xcgBCgVqEBFJ9DqcZea/gNAAVEg7AOGYnHe9XoaJd3+X'. 'LISSSwnz6lsbKCZ9sHh4UVdBkwdA6cPwNnIfJPmC3Ctgft3wwQ'. 'QPkvTZJJnbExzfvsM2nMzVG7e5fG48d4lnXwTwEYCjJxuHQBog'. 'BHUfKkgAIIhiGk06hTp/Dm5qS1uYlXLvtWd4gPgIiCrAEcVckT'. 'Ab5p7TaYJrK1hQaEenrwSiVfQdc91P0kSp7Ii89D5ksY/kAkLy'. 'IZXFdXkQjS1YUSEbdcRu168V6+HTUNIKJDRwdE+sBIQmP9Ld59'. 'bEBA3of4F/D+uXb7rGaaCSmXI3pPj64PDaHCYfEqFVSjgWo2D2'. '73XlJNQTgCyQykIuBWoNKEeh1aLXBPBCggGdBOgxZVSjoajVhH'. 'o5HWlIpq4bCQSgm9vXhK4ZZKh5SUYygp4J1EQVUD9xlU18BJQD'. 'bUbJ5T5XJStyxN9fSI099P3baxV1dRloW2h2ivx/yakg2ot6F1'. 'EkCa4G1D+zVEq5ArKTWM42Q6HUczQV7U66w9e0ZpdRXlOIQ5vF'. 'VHUXILKify4jiEzkOqC3peQMoBQymFlMt4Dx6wUSxSsm2UZXEK'. 'P30QvOUt8/2Sd78CdWwFDTA+gsw3cOlPcPUD+CQB52oQ21RKXM'. 'eRhGXhOg7VoKrx8KuS4ygZhVg3ZI8FGIfwR9BVgAtfwxdXdP3L'. '86nUR91dXelNXTeWWy10paQHX602YAP1ADASAL7LJvFtMpOCc0'. 'cG3FHuGlz6Gr4YEpnoTCbzsdHRbOzy5RCRiLRMk5rjyOtAimwA'. 'U4U3SurBN/0wnAASBCVDIKpB4kiAB5Ub0/UvO9LpPAMDGfn005'. 'AxPCzxep3Q6iqPLUseBoufCZRsAE6g5g5kKIDfKUj3wnpAG8QB'. '/Z1OIqANQuI65AtwNScyYXR2XlAXL2YZHzcklRKWl5GVFXFtGx'. 'MoAiV/EQaAGH6BUQNWgQpwFngv+Ca8KUAQEBcwgTJHyMV7679R'. 'XS8YqdSI6u/PMD5ukMtJY3GR2uQkr5aXeWVZOEALmA8WsIAxfL'. 'd0goVLAdCOd+/YpgqeVtBv4yiA++q/RKKXixe7GB8PSyoljcVF'. 'yg8fyubyMpulEk2lyAIfAAvAC+B+oOQFoAt/+0rAejB/EzjNri'. 'vvqNnCd64jxcE39V8spnP+vMbAgDSePKE2NcXm06dslMuUlcID'. 'TuFvqwXMBU8N39bGgRR+ki0Dz4L5DSAe9NGD7zq+6kcN1L6H2b'. 'ao5WWaQHllRTafPmWrVMJUimoAQrBYJFjQwre7B6A8YAi8LCgD'. '5DVo6/hbb/iHK1KggvFeD3hHziQKEMuiNTNDbXGRTdtmw7Iwla'. 'KGH0oqwbscLOoG46rAY6AOzRhY74PT6QuUKEN4PegXxd/yEDTT'. 'YMWOk+oEaLkuFdNk0zTZwjfkavDUArXWgGXgFb4dEShXhfYqlI'. 'ow3w9rg3B6ED60IOOA5oEYQBrcpG+mj9bg0VG8GMJhVDZLyzAo'. 'VSq8rFYxXXefcjVgG9+uisDrXUCApoKSBcUHMBmHhfcgNwhtD3'. 'q9IG6Lr15b4OUTmPwBJt8JqGuapp05o0mhoHnptLQfPsR+8IBK'. 'uYyNH3yr+B77LHheA3tK1Ta+IrMeTL2C6Xl48TOsNWDDgAz7s5'. '/r+krP/eddCsbj8fDQ4GBm9MqVvvRXX2VULBayRGRzaYn1SoWa'. 'UjgB4PIB5QK4ZgBXBKaAHxQsrED1H7CRgCUPwgHZDqACmhWwXv'. '2aDRqGYeRyufS169cvThQKV88PDuYbW1vJ5VRK+5euqxWlPMdX'. 'SRqgreHbZGN3ijfKBXBTAeh2Fdwi2MofshP/dvKwCmKhp4m83Y'. 'vj8Xg4l8tlCoXC0MTExMTFkZE/1m37wvLGRvKRacoD1209E7Fc'. 'pZwYREOQqEJ4z3HskHLsz4AoXykPIBSN0t3dTTQafROoHdumXC'. '4fjoMiog0ODiauX7+eLxQKV3O53ETdti88nJnJ3rl505ifmWm3'. 'arWSodR8GNbycDoNHy5C5jFold1k8d+DyvELNwg93d18/vnn9P'. 'X1oes6nufx/Plz7t+/fxhQKSWJRCI5NjaWHxkZKdj1+sjSwkJm'. '+uZN/dZ337VqCwullGUVdZjsgIUC5LqhrUPvCugWuApeApPAzY'. 'PKHWyaphGNRunt7WVwcBARwfM8Ojo6sCzrMKBhGLphGFEF2Wq1'. '2jc7M5OZ/vHH0MPbt93awkJJmeZsC6ZaMK3DCwvWdNioQUb5B6'. 'AdBR+9SzkAz/NwHIeXL18iIui6TjgcJplMMjY2th8wHo+Hh4aG'. 'MsPDw6fddru7+Phxx51bt/RbN260qwsLpZhlFZsw9QJ+2Pbrga'. 'oJG2FY2oKwuTtVEz9uV34NbqdtbW0xPT1NNBoF4MyZM1y5coWu'. 'rq5dQBHRcrlc4tq1a/l8Pj9RMs38ndu3Ez//9JNXLRZNyuXZJk'. 'xVYKoExQpsK/+IaAuYb7no8zjC/R+A4zisrq7u+53NZjl16tQ+'. 'QIlEIslsNpuPRCJXZ2dnh2/duNFRW1oy07a96MKd575yxRqU1B'. '5vPMpF5HHa1tYW9+7do7Ozc/eQpZTSQ6FQt1Lq8pMnT/5w7969'. 'nuLcXE1rNufO9fRMhlKpOyvt9qPtVmvb25fFfvvWbrepVCqHwo'. 'xaX19vff/996ZhGC8qlkW9Wt1Onz073fXxxz+6MB+9e9dUjuO+'. '7ebq9wLdB9hoNCrr6+s/4wf3FCJW3fPmTZhXsNWCprjuW66Dfr'. '928KAfBhJAEgiJSLuzs7OSTqctoFkqlZRt26j/I+L/AGjPTN4d'. 'Nqn4AAAAAElFTkSuQmCC' ; //========================================================== // File: ppl_orange.png //========================================================== $this->imgdata_large[1][0]= 2753 ; $this->imgdata_large[1][1]= 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. 'B3RJTUUH0wMLFQ0VCkHCzQAACk5JREFUeJytmGtzG0d2hp8zNw'. 'AEcRdJ6EJK9FL0CqZUm9jWbkwq3vhDstl8dmLvz8rP2H8Q75ZT'. 'pkRfpLgqsS6WIFEKGYkiSBCDO+banQ8DUpRWEkklXQUUqlCDfv'. 'rp857pgfAOQ4AMOJdg4R/hX96Hf06bvDc5iT07i8yeg8ksiIAI'. '4TBi/ds9/vivD/njapNHvRBfHXMu410AM+BUoVSF05NQsi1sO4'. '8402AXwLQTuP31OAZO2aG0MEn14iSlnI1z3LnMk8IZYJyBwjIs'. '/TWsVIWPJkvMFS4zMfMhUp5BsoCpAAEBLYKaMFGn00jBxnvu02'. '35+JHmSJEnBpQEcPo38MmCxd/nS9Ry71Ga/g1W9a8gn0GsHkgA'. '6DGjxkqb5CoO+YxF3A3p+jGjQUzoK+L/V0ADzFMwtSR8eLbAr8'. 'uXOTf9NzhTc0geSLUQcYHgYEH786RMg0zWJHV2Aitv4x/HpHVS'. 'QA2YBqTTGIUq5qkPMWaWkVwPnPtAA/BevmZcjxaaUtHh8pJJGu'. 'DpCB9FvT7A7YT7S3p5vFMNzmWo/O0MSx/Ms3TqI8r59zFTfUQe'. 'I7SBODE3tnfoIxYnNHligwik0zAzDdVpyKbA8sff5YAeMEwgkV'. 'cufQeTJzZoCsaFLKXPTnNpoUTNsSgJmNoGsuNQjIDwYD2HlnZy'. 'k++yxTKXZfKTU8zOpjhneeQYkorSmGERtIlICBKRbLX+y98YN3'. 'ADcNIm+bJD4U3pPnmbEaRgYVRTGBkDSSsmxKfY7ZLuDJA4hdjl'. 'JEgyBB2SJOvQ9RzTpNKoEwNq0CNFvOXR3/HxMgYVPObaz8kPmh'. 'hkEWMatAfRONGGvLizyOE9P8KkpwhPDAgQKJQbELUD0oOIhbbH'. 'JeVTmowxjAgZutB5AoOngA+2DdYrcTyOyYZP9+QpBvI29vwEhb'. 'It042BVQgDy9KTMfkwQG1A9ACCLlgBBGUwxxoc52WDh2ATyEPp'. '1hoaPvrEBh0Dq5an9OUsl/9hylk5b5c+mowLc4E2Jtw4Eoljyf'. 'ogA/AGEAagNRjGyUxOmEycyVA5EWDBxrmUp3ytLIv/NJP69Goh'. '+9mFydIvS5PZYkvH1oY/RFtKymlwBFQAgQd+kAA6qSQ8pvn2mp'. 'SkJkuVFHPHBnQMrEt5Sl+e4/Lvp51PF1PF5Xy6WMvOWZXMom8z'. 'OZTQ8+j5sbQiMEwopsCIwRtBGIJSCdzbTGo9NimkDcgdC7Bg49'. 'TG5n4/nfr0Si77WdYp1YzyZEkWPdteaEnB7pPqBTxuIf/VgciE'. 'SgasCPwh+GNIkaNNag1RiPge5pEhMQVjfoLcF+eoXSvbKxedwn'. 'LKzC3KWbOi5/sW5a44/SHFUSgVA7SCzRG0AvA9mPOgFIETgu4n'. 'Ww0wNQWFAqRSL6D2ZQYBdDrQ7R7jXiwgRcvIL02makuTmWtpM/'. '+BlLMl5vuWzLVEuwH6oYnR1KS8kJINGXMM2YdfRlALoQoQQKeb'. 'bDVwoMdxQMaLCwLo96HZTF5HbrEhmOftianfZisfzueKv7ZmrX'. 'MsjhxKXZGBjzyeEHmSE3oWiggtyVGmE8DTIXTC5NxgAxOAGUM8'. 'fun9mnSSLQ/CxNzOTgJ3LIMgoGwkKBiiMyaVviHVkdCO4FEKNv'. 'LQzWBYHfITPa4UBVM0LR/WB7ARJsdDDTjA6deYFIFUOimJ3d0E'. 'sNdLavYYgBpthqKcjiiJRO8K6CK0CsJTjfQAGaJtD9vQFAxNNQ'. '1FB0yBAfA8gdMAIagLoCVAen0M00zMOTYShNDtoHs9CAIUoI4E'. '1IBihCdNhsMhsj6NuV7BCC2IBpBqQaaFOENCCeiEsO1BO4RQgy'. 'I5Hm4k4oIU9MrgZSAdBeTabZz+ODxKQRRBFBJo6IUc51anYRQo'. 'dto+24FNxYCiaWKkQsj00KkO4gxRRkAngJ868M0u3OkkM+hxQA'. 'cQ7YD7GO5XYSsPZybh/TCkFIYY+kWniTW4Q7jXgHvHMhiRpmuW'. 'ca08GZkkZ/nY6TZMNhCnf2CuPoDVJvxpB+q9BHA8Ag1uH+oP4c'. 'YEPCzDwmzSLquShHW/E0YRbG/BjZtw40hAy7aNzJlzRn75E6N0'. 'qiwTzafI7kOU3gWrhzZC2iHcbsPqLlxvJnCt4KC1RYAL3I5hzY'. 'Xv/huePYCtITQMKEnyB4KQvMURuJvw889HGSwUCs7CwkLpo6tX'. 'Ty/+7nel6VLGDn/8N9m+eZuo1UP8iNhLau6b3RfmOsHBGTUYw9'. 'WBNeDrGB4+h/4qNLKwTnLbHj9CJw/6GoIh9Jpvq0HHcayFhYXi'. 'l3/4w9LK8vLKexfma3G/mb/3n1njTivS7tNQaaU1grQDjJ868D'. 'Axx6vmxnBrY9C9IcSbSXbavNjb/S3eN6/0m1JcKBScixcvllZW'. 'Vi6uLC8v12q1v/M8b/HxVjP//YYr32yE4dYWvShO0ogi14xwxq'. 'F4rbnxZ3cMjtpvEEeMvwA0TdOYn5/PffHFF7Vr166tvPeLXyx7'. 'nrd4+/btyg/frFo//Xgncnd67qCn78earQqcmYD3fSi1wPCTSV'. '3gzqvm9uFOMl5nUAqFQn5paal26dKla57vf7D+6FHph9VV88af'. 'vgq79bo70e3VT2l9A3hYg4UiRALVHTCHSZvYBm4A//6quf8zoG'. '3bpuM4acMwKr1+//SDe/dK31+/bv90/Xrcq9fduNW6rbVeC+E7'. 'gWdD2DKg4UEpBmPcm10RuScida31ntb62HAigoigDw6Gh0axWH'. 'QWFhZKi4uLZ+I4PrVer2e+u37dXPvqq6hbr7tOp1NXWq89h6/b'. '8FBB34WGBesdcPrj38lkMkGlUuml0+mu53nR3t4eo9HoSLhMJk'. 'OlUiGdTuN5Hq7rvgA0TdO4cOFC7vPPP6/VarXldqdTu7m2lrv7'. '7beq++BBO263b/tKrfWSXlbvwJ6CuAtDgTYiaBFMw6BSqfDxxx'. '+rarWqGo0GN2/eZGtrC6XenAkRoVKpcPXqVWZmZmg0Gty6desF'. 'oIhIOp3Ol8vlmmVZK3fv3Lm09uc/Zwbr653ccPgoNIzvnmn99Z'. '7W9QG46lAaM5mM2l95GIYUi0VOnz7N7OwsWmsymQzyuse5Q8Mw'. 'DNLpNDMzM5w/f/7A6AGgUkoajYa9urpayOXzUz/fvZutr68Pim'. 'F4/2y1+n2o9Q/ru7uPesPhXnyo4A+vfHp6mmazybNnz9jZ2UFr'. 'TbPZJAhe+8/aS0Mphed5NBoNABqNBqPR6MWBVWstvu/nnj9/Pv'. 'vo0aPq5uZmPBgM/qcwPf39xV/9ajU1M3Nvq9PZaw8GoT50PjdN'. 'k6mpKa5cucL58+eJ45j19XWePHnCzs4OnudhmiaWZRGGIVH05r'. 'yEYYjrumxubrKxsfFyDQJ6NBp1Pc+7C4jWumBaVm+kVL2l1H2l'. '1G6otS+H6V6z8u3tbVzXpdFooJRicXGRqakptre3uXXr1ltrcT'. 'Qa8ezZszemWAE9rfUdYBOwtVLRbrPZ+48ff+wDvuu6Sr3MB4Dr'. 'uty6desgfa1WC3iRyrNnz4pSSmezWUzTfGtYtNYcdvC/9sMlgP'. 'n5N4cAAAAASUVORK5CYII=' ; //========================================================== // File: ppl_pink.png //========================================================== $this->imgdata_large[2][0]= 2779 ; $this->imgdata_large[2][1]= 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. 'B3RJTUUH0wMLFQolY9lkpgAACmhJREFUeJy9mOtzFNl5h5+3b9'. 'Mz0kzPBWmEVtIiWYhIiC0HCDhB8lb8ISk7nzdZ5+/zJ/8BTmpT'. '660CZLwG1pVFgBkgGIHECEaa+/T9nHzQCCQuRpCNz6mp6g893U'. '8/c37ve3qEjxiC4OA4n/Lp/EUu/tsMM/+aEWduVBx7WhdkShcY'. 'xUH2zo0Dwod/5N6vf8V//PoGdx8M8EOFPtK9jI8BdHCcMuVSmf'. 'LxHLmSZdm2U8xIbmKETDGDZZnIy4dBbCynyGhphurEDBOlHFnn'. 'qPcyPxTOwDCOccw7w5nlBRZWylI+ny/mZ6rL1dzUZ5/IWGZU3D'. 'ZIOMQDDaJcHDVGWUbJBi9odVr0QoVSPzigIEaZ8vgSS/8wZU3/'. 'k1fylipz5dLM2WlrZqHKaGCKbEbontq3KAKWQyZfZKTgYqc9Bp'. '2I2PcJ4ogk/UEBQcwipbFZmT13vDBx8fhnE1Ofnp9yJopFyT3X'. 'yANfks0QHSQMDaL37pOxMLIu2UyVkjVKLjyKSeuD8dAYCFkso1'. 'gYMaeWJ40T56cl8yAi/O4FSa2P6kYczIDsgVpAqcDImZPMuAB1'. 'dkLQtcc8a/bwox8IUHAxZVxGZMouSLVYwKuMkD5IxN+JSdsRJB'. 'pexuTVgYYM6EoGmxkmg3/hEhNUMr/hd7dqbOzExMn/GRDAxWZc'. 'j3I8HiXfMjF2FQowKw7pjoN6E/Llw/GBJj8qxVOMlX4ipxc/lY'. 'kl2zBLkmrTcEzMkoNoRLVidLi/9g+Z3I+1xRHX5EcAihxnbPRv'. 'OTU9kZSmpKPy9FTGrLimPZ1H+UiyGaF67w6n7E1DwMngFDxGvc'. 'w70v0xZUby5IxjlIyMssUJrJwVWkXBdbXvSvwEibcSdKCAFI16'. '4/sc0SRo9cGAGq1DwvQFzV6DVuBiV4zYnlEts6A2TSPcSiXoxo'. 'QqJCEEFMbQ2b69o5qMiOOPqIMQkagu/aSL7waE8101WFShLjk9'. 'yxgEvjRUiyYd+gwAjY2J9VpXfZ/JEXLhDp3OR6U4T97+hEnPwx'. 'tv4HsRjy2tTQSFzQgDUnwSLBQRI+x1ZgcH87Vcv4SF19Kt0ezS'. '1h9s0Ma25pgr/YJfnLnEysok0+ezjM6EBLldGqKIJYuDRhOQEJ'. 'Oih8X9Q0xmcXNjlCofBJgn78wxVz7L2YWf8tPPz1hnfjbjzfxN'. 'qVwutq2etZXUQSXikcXGIgUiUkJSDIQMJgYGJsaB3c7b1qQ4GZ'. 'xSkdGZIwMeNLfK6uezMnvJK3pLxeVixfvMsyVjSNSO6IV9adPG'. 'AArkEEz8oUkFmBjYGO80qfd6pCWIayD59wIKcsjcKqufn7JO/S'. 'xfyi+5c24pey5rZ09mJRNkiDdT/tzbkBr3SYkpMYpgEaIJSYhI'. 'kSOY1GhilAQk5ntDIojxCZ/kf87Pl85xbuWEnLiUy+cW3NNuJX'. 'MmY5meKf6mT7wZS+THdOjxlG06tIlIOMZxchSxcFFEGAwAGGME'. 'jwyZYSnWL3cXWiIUbUI6hO/vxXuFOV84ycmlBWthNeflTjuzTi'. 'lzJmM5s46Ej0J63/ZoPmoy6PYxtYVNhmfs0mbAND1mmKVMBY1L'. 'mxA1LN7WgXQbCApNhKJHRIM+DQbv7yQGhjnJ5NgFuXBuxpu5mD'. 'udm3LPuY7pmZLUE6L1SIJaIPFuDAqyw9lnwDYv6NFHkWJh4ZDB'. 'wCBFD3uMxsTAwcBAiElpE/KcPg36dIiOvpsRxDCyhmlP2YY9ZU'. 'v8NMb/1id+FGO0DTztkSXLOONUqeITsMkW2zwnJEIDFhYGx+A1'. 'kwK4mASkvKDPc3p0iYhRRwYUhZLUTyV6Eu0t4s1Y4kcx6W6KaM'. 'EZThcXH59RRhGEgIAddnBwNEBKqqpUtWBIF22YDIhJsbEkJqFN'. 'qLtERHs7GnUkwISEQAf0uj30bY39PzbiC6qrDu2cExJ69Nhhhz'. '59UlIUipCQOnVi4sjG7ubJBy6um0C+he/0iDHQKIQERYyKFLqr'. 'SI/W6kJCnvOcrWSLSquC1/Jw9Ks3R0FQKHr0uMc9bnCDGjX69A'. 'H0XlcJkibN5jOe/alCZStHbjJL9lSMLkXExvCXRiDV6GZEeGeX'. '3TvvBVQoEjfBL/v0rT75Th7VU5C8gktI6NLlMY+5yU3WWGODDf'. 'r098tHpNFNH7/2lKdXXdz7efLzVaqJIBOCmK8AJUlI6g0aV+9y'. '9+p7AR3bMQpTBWPy7yeN6fy0jNwewfpvC9Xe+3kFoUuXe9zj5n'. 'BusEGHjh6GIAGawC2FWuvSvbbF1maFylZAsC1ISZADBiVNSJrP'. 'eX73MY//skHP85z5+fnSxQsXj//4n39cmnPn7LbZlsajBmEnBL'. '1nuEGDG9x4aa5Ldz+h0RCuBqwBv1Wo+7vs9r7n++0MmYeAM+zB'. '+61EK1QUEnbbtN+9Bh3Hsebn54u//PdfLq9eWl2ZnZ1dSnaSwu'. 'Pin40b9g3doKE0WoNIl65xj3v75njd3BBubQi6ExKmDWkMRKSl'. 'tSbVKQcMao1Go5Ugb0+x53nOyZMnSysrKydXLq1cWlxa/McgCB'. 'Yev3hU+GPrD3I5/q94k3pXYQY58q6B5Bs0HB//neaGx00gyWaz'. 'VCoV7bquCoKAnZ0dfN/f03egLGj0m3XQNE1jdnY2/+WXXy6trq'. '6uzP3oR5eCIFi4detW5feXL1vr679Let37zVB3/mQytjXJwmSB'. 'wikHp9ShY0RESqObwPrr5oBERKhUKly4cIFqtUq9XufmzZtsbW'. '2hXvuDwTTNtxZq8TyvsLy8vLS4uLgahOHphw8elL69fNlc++qr'. 'uFOrNXPddm1cczVL5f5P+Lv5MuOJgTGxwYbZpZsCdeAq8M1Bcw'. 'CGYeC6LtVqlRMnTjAyMkKn0yGXyx0N0LZt03Ec1zCMSrfXO37v'. 'zp3S769csb+/ciXt1mrNdHf3ltZ6Lca8ZpJsduhtCdb2gEFJoQ'. 'xADYHuHDS3f32lFEEQUK/XGRkZoVAocP78eZaXl9FaI/Jq25Uk'. 'yWHAYrHozM/PlxYWFibTND32sFbLXrtyxVz76qukXas1M61WTW'. 'm99gx+20TdN9jqtfjP7QzOwwYNp037Zd0DukDnIByA1pqdnR2+'. '++472u02Z8+eZWJiAsMwDsEBRNGBzYJpmsaJEyfyX3zxxdLS0t'. 'KlVqu1dP3q1cLta9ekU6u1dat1J9b6Sk9kraV1rYXegW7apDYw'. 'kFY6fPc4MNTw88bwfZ/NzU2UUnieRxAEiAiGcXiXfcigiIjruo'. 'VyubxkWdbK7fX1xWvffFMInjzBM82uMT5+p++6V1UUrSe7u03t'. '+8lezlKt3gHyl0aSJDQaDa5fv876+vo+w6FzDq1BpZRsb2/bly'. '9f9vL5/Njdu3fzG0+eMJHNxsfn532vXN5NPG/7abPZal6/Hvfe'. 'kroPHfsm98f7AHW9Xo+//vrrlmVZm71+37QNw3JnZ9PK4uJGpV'. 'pt4Dh+vLGhsrmcfv1iHzu01m89HjIdCon2fb8TBMHtvYeRUn50'. '1Oj4vqp3Ok1f5LYSadfr9dQfDN642P/XeF2DA+SBAuA4jkOhUK'. 'BQKESO43S11p3BYBDt7u4y+CtB/i/q7jp1GMiw2AAAAABJRU5E'. 'rkJggg==' ; //========================================================== // File: ppl_blue.png //========================================================== $this->imgdata_large[3][0]= 2284 ; $this->imgdata_large[3][1]= 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. 'B3RJTUUH0wMLFRAiTZAL3gAACHlJREFUeJy9mGtv29YZgJ9zKF'. 'F3y/Q9jh05tuQkarKgbYasde0UBdZgwNou/Vqga/sD9mP2B4a1'. 'BbZ9atFPxb5sqOtmXbI19bqsluPYiR3HN90vFEWRZx/IJI5zqa'. 'x0OwBBSgR5Hj7v+55zSEFXTUgIJyA9C6/9RsjMjAyFIxxJCDc7'. 'iBqKgyZACGg3G2x9+xXf/fG33P3mC9qNKsp1O+1JdkEnQTdgIO'. 'ttCSMUi8gj072MnugllAyB9G8rBGi6RsToJTF6iuRoFi1kHKZf'. '7fB8Iggj0/Dy23D2dakNTR3JDsXPvzstxmZGRMER1EwHhQAEgE'. 'CLhIkPD6InY9S3djGLJVBtQP1Qb4HDAyoJYQOOZkPx49nhTH9i'. '7MUBGT7egxkJgd70wZS/CUkoZtA/fRoE1DZ2ACiv52ibReCp4e'. '7CIEHomxDiuVdGTqUnf/ZeOjR8fpiVXZul5ZrY3bWwbdcLr/dA'. 'AAIpAwQjUWIjQ+g9HZvswiCgBVF9/SI6OSLGzo0i+oLi6+Utbq'. '+bKEftgwOE/0Ohocf66M+cBjo22U2RQLIHMhmYnvaOpR9S8bSU'. 'UqCURGpRkuMZMm9cIvPGJZLj0yBjT2LprkiSkykx9cuXIhOnUs'. 'm+QNC2XdG02ggBTcvFabsPWwTPpBAChSCgh4kYBpoeplWp47Qs'. '7EYDt21xINzd5GCAxLExRl89Z+nHjpbKMmjbmkgfDzI0JEW53K'. 'Jaa6NcAOEX8v52uJzsBlAS6u0hcnTIccPRqhWPCUcLD+s1EaUp'. 'HCEhEMCyHNpt9SjgIU12A6iw6xb123vYhaaKjB9tlgMD5X+uBp'. 'zdkpg6azA8EaNQtKlVba+Xez4eCntnJrsDdFsW5nYFpxlFN846'. 'DXe8utkM4mhi+EgQmjYbS2WqexZKk6BpjwJ2YlK5VjeA3pNDiH'. 'YjRWPzPE7tmBo8EWwGhkXx+z3uXL7D3rU97LIF8RBEAl6lK/Uo'. '6JNM1rZ2aTcr3eUgIQOGTgbdwXMGyRejenLYTvQGbAdRuetSud'. 'OivVuFZgtCEgICghICnZoMhmlVTPR49LCAEkQUhk/B7KXe0MWf'. 'nxj8xVR/cDheK14WZmtVMJSBnlGoN6FmQq0FLfdwJgORKPHRo/'. 'Snzx4G0F/FjJ4KiOdmjPCrrx8bffnMybMv9MQGNG3rzlVqtR1B'. 'sh/CYXCD4Aag1oCW7ZnUOjSp6WFi/QNEB8Y7BfTNjZyCmUvJ0I'. 'XXT47MTp98Ybon9VZCk8cVazfqlNargsY34G7ByAlIjkHd9CCr'. 'LbBdiHViUgiECuDKYCdz8b2cywREdiYZOj8zNnLuzOTzx6ODp+'. 'OaGaqwVzBFqz0Idhz2loE7YEwBLaAJLQcKbW8qjAcBF5Jh0AMP'. 'IOHe6kxgtb3UMO2OxkF//ffK28nQqxfvm3szrtnDVa799Qb/+v'. 'NtsbNSpm3tAv8B+w7Ub0FhAyoBcMPec9oK6raXk48ziQBXQcmC'. 'pT3YqHa0mpEBkTR6wz/Jjo2cy04+fzwxdDquNfQKO7sFUbpu0c'. 'wp3JoAYsA42Bbkl4GCryUNDEM7Avm6Z/CgSYBWG8pNuFuDu1Wo'. 'tjoxKIJGeHIiM/jmK9NnX5ycuJQMtUcqXPvLDTa+qIie4hAJ1U'. 'vdrmO2HaDfB931twJgAn1A4lGT96obPHPLBbhVgUoTHHWo9aAA'. 'JVAKpyKEmQNzWRENAsL18ycKjAFN/9gCNvzLB/390MMmE7pnDi'. 'Bvwt0K5Jv3O+0oB22nJ1Vvjb/UMhOpcKknqN1OiMB2DNHU2G5s'. 'sVndpGJVcZXjX1IAlvw9PmhRQcOFPhsSDkiBrQR1G7brgs0a7D'. 'ag3FK4rguqBXarI4Nt1SJv5gls7TEWtJDRBO2GwnIs8maevFnA'. 'Gx6awLZvzeTBu4kFbLigijC47pscpx0xyDfkvtUEnlarCDtrUC'. 't2HGIhvPHVdVwqjTIrxRU2a5uUrYoP0QZ2gMvACl7+3V/LuKDq'. 'sJuDy597516+CEezIHXv7vcgXQu2l+Bvn8He9Y4AE4kgk5P9DE'. 'R6aFdq5Et5Nit3yTf3m9sBcsAN3+D98c0Fit5JawE25r1zg1Fo'. '5B8GFD7g+nVYnu8EUEop9XTa0N/9dUbqcphP/rDJzbUClVbpgR'. 'y2fXM3fND95qj75J8AC6BWPINfVSBieK+x+6cS5UCzCLu3oFV9'. 'GqCMx2NGOp2Znpv7aXZudsool3T5J/179sxVlHJ4kGPrP2COBX'. '/7DmiApWCjxIMXpYNznYuXM+6TAKWUMppOZzLvv//ery5cuDCT'. 'SqVS336bCwr1JfAPB9r+2KAFwJS+OcETzZHz/7v3etl6ipz77X'. 'GAMh6PG+l0OjM3NzczOzs3k0pNnFlbW43+e/GKtMqrblSsF03V'. 'WHcJA0PjIAzvg9JTze2H67g9DjAwOTmZ+uCDD96anZ2dnZiYmF'. '5dW41++Lvfa1fnr7qllVK9103mXNTnJgPA+YugsvB3HTaEl+Qs'. 'AZ/yeHPPDCiTyaRx5syZbGoilV1dW00szC9oV+avusuLy0Xd0X'. 'MgFkDM+zkYBZEHV8f7wwKu84zmngQoNU0LaZoWUa4K31y5qX/8'. '4cfyyvwVN5/L10NOKNeg8UmDxoKF5Vfj1xXAgD0JrgAcvBDfel'. 'a4g4AykUgY6XR6emJiIru2ttZXq9S0K19eUcuLy8WQE8o5OAsN'. 'Ggsmpl+NpoL1g9X4UBU+C9xDgEKIwNTUVOqdd955M9mbnJ3/cj'. '6Vu5aTheXCQXNdVeMzAwJSCGEA2XKpnF1cXIzlFnOVhJPIKdR+'. 'c88ctq4AlVKsrKzw0UcfKcC5uXqzXnNqSzb2pwLxOHP/l7Z/BN'. 'eB01LKt4HTrusKvGr8jB+hGn8MQAkYQMrfw4Nq/MFPtf+rdvDb'. 'k8QL+/5Z4Uepxm7bfwHuTAVUWpWaqAAAAABJRU5ErkJggg==' ; //========================================================== // File: ppl_green.png //========================================================== $this->imgdata_large[4][0]= 2854 ; $this->imgdata_large[4][1]= 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. 'B3RJTUUH0wMLFQ4hANhluwAACrNJREFUeJytmF1zE1eagJ+3u9'. 'XdkvUty2AbmLEtEzDBgZ0UpDBOalNTUzU3czl7tct/2n+wt3M/'. 'NVM12SSTQQSyW2TA+QAJQogtYYFtyfrqL3WfvWj5g8AEjzfvhS'. 'SXjk8//Zz3Pf3qCMcJAWxMKlT4kH+jwu/FknnJSUItKFHzCrKA'. 'BggBQx5ziz/wn/yBz3hED4/oaJfSjgVoYjJJgTLTZCjohp7IGT'. 'k5aZ4kb+bRTR30Q7djj8f/kpPMUSCFedRL6W8e8qMQNE6S4xpv'. 'c5HrTPFubiJ3ZnlyOXV59rJYU5Z00h1c3d0brxAiUkScRijisk'. '6XLTyiN3s8HuAJpniXa/q8/pt8Or+0kF8oXJm5YiydWcIpOrJu'. 'rjOQwd54AQwsMpTJYhPSoYuLQ58An/DnBQSdImXO8avsTPbqpc'. 'lLp67OXDVzMznZLGxSs2qyIRu4at8gKHQEC50kE1icxqCAdxST'. 'xjEA44tqaJlERl8uLWvvnX5PHuQfcCdxh5qq0aX76vj4WgWyXO'. 'QiNgBP8IAaddr08X8+wHFmJSQhBbPAZGoSZSt5wQs6qoNC7UEd'. '4AEoLIQSCaCCy78Dv8Tiv1hjjW1CRj8XIAgEKqDtt9keboMJZa'. 'vMjuzQVd3Xr9prTJo+GF/jKZea95R25Lxs8jg5qFGiwDnOS0mW'. 'NE0rjNRIt3WbklUCA9mV3Zdz8OBT/JfCQLB0SKYVVjGFYSfx/E'. '26ow4e6uDujlPFQpE0FU6P8qNTHdXJdEdda0qf0itWBVM3pa/3'. 'ccUlIECJet0cAJoeYk5EZCeS5IwEoerSxccJBwRqFFf38QCTaO'. 'TRVFKJm3NTbtLNSyh2IkhIXsvLCesEGNCWdmwyruSD/z9kUlRc'. '3bqNlSxhJNJ43p5JITrOEis8Qtr0cXEpU/JT/pmO18n2vb42pU'. '3JnDnHMBqyPlpnoAaxhr2llv1ZUBqEGlqYwDQMsskMOcMgVL3Y'. 'ZOQTHAcQQiIGjHCwCaiovjrv4hbcpKuJJjIcDHm685RGr4GLCx'. 'YHkAcrLoAoDSLBiAQrMkjqybHJCbxgh+7xAC1MpsgzwRwD3qHL'. 'WyTIBdlAa6u2rHfXaew06PV78ZZjAwleNnkolECoH5i090wOcY'. '+TgwYzFHiPi1zkOkXexeAMASnVU+LiyiA1wFUuaqggACLizeWw'. 'ycMzyssmVYKkbpGyC5T+OUALk2mKLHKWf+ED/az+YW42d66YL+'. 'aNrmEEzQCFEnKw368EgEvcN1m80eTIQIt0TFOjMJHkzNEBBYPp'. 'sblf8QHzrORO5JaWZ5ZLl6cuJyyxpNPv4PZdoT+GyIxBfI5uUg'. 'eJMCwP2/bIHO1JEudcgUUWOceKNq99mCvnzs5PzRcuTV4y5mRO'. 'SMIjo47z5S7a94oQCNKgJsZwO7D/IDNg3/LLhRNXt4JohBb4aG'. '82GLdXcf93mQ+Y43r2RHZp+cRy6cqJK4l8MS+tdItaqiYtc0Mm'. 'QpfJARh98HYh9IiXVcaAo58wGb+LBAjbSPgCOcoSa0wzxXtc08'. '/pv8mfyL+9MLVQvDJ1JVHJV6SZbFI1qtTsB+KlehRtRTGE8Afo'. 'P4DRcAxiEudhAHjjzz+ubgX4oHowakHQOlqzICQwyVPITGVOXi'. 'xfLF6aumzmczl5lHzMff2+fCdPaGttEkXoLQAO9B7C6EugPYby'. 'gVPjGXc5eIbNAJPjGwiAbaAJUQv8wVG7GROkJFpyOqn/ovgLba'. '44L0+sDaraXb6jzq7aBQWjBOyUoHcaopOgmaA3IRyNDZnA1HjO'. 'HSBkr7eEFDAEngHrQCf+/s2A8cSiSkqcKUeeTjwFy2Jd78t3+L'. 'TR4itIiBLwLQhzkJyB5Cx4HXDaENVQCBAQcRqFIHTRaBIvuYXg'. 'AdsouuNxEL0ZUBHnSQp66R73zYfUtQ6OytKT8RckQAJQoLtgO5'. 'BJgj0D/WfgdyHaAHx8THoUcbGx8ciwhUl3bDEiToURPooeI7pH'. 'MziK9Yd9nU5a6GgKjOH41vsgI4hAcyC5AZkapF+AoYNrjjsuhx'. 'FbtPmeB5ykyQQzTPAWAQWC8S9oAI0QRRuPb9jkmyMZNAOTklvC'. 'GGYZaFkGmkVAh8h4DtKFMIBunG+pB5B5AIkGBDsQ+qBiL20caj'. 'zhJknq5KlgMkLjJHJos4kYEbFJi5vc5eYbATVN02bNWe19+32t'. 'aJWlFm3wbf8Rz5NbDFJdlOFBF/g7cBf0JkrbBb+F6j1DOduEkU'. '8bWCOiSofPWadBnSZDWmgUkEMGhZCINut8S/0NBtPptFlZrBSu'. 'vnt1+ndnflfIp9OJ/279Ubbbd+lP7KBKPoEBsgnqLph/BRzwdS'. 'LnBUFvHcfdpRsGPAGqwMco6jynz+e0SPKYCHMfLX5VKHwcenR+'. 'Igd1XTcqlUr+xn/cePv91fevzy8sLO2OtrOpWkqL7gXKSAVRdh'. 'ZFEmEXoYkwBNqovoc/3GHH3aUR+jwC1oD/AWrANi4hGwyBzqEG'. 'Vvb77Dgi0eT1VZzJZMxKpVJYXV1dXF1dXVm6sPSvruue3Xzcyj'. '6/syvDzwj0lNazK6Fj5LFCRZouZpBABj6jXouu3+Np6HNvDHaf'. 'g91t74msbMuOJicnSSaTKKUQEUQEpRSO69But1/dB0VEm5uby9'. 'y4cWNpdXX1+sLCworrume//PuXpeqnVeOban0U1PW2kcx+O9L7'. 'Te9sUB4lWFR9SqNtNGcHx+/RDD2+Am4D94CnQA8OjjlEhMnyJC'. 'srK8zOzu7BiYioMAzZ2Njg9u3brwIqpSSXy2WXl5eXLly4sOo4'. 'zoV6vV6oflrVP/7Tx8Hmw1Zb6ydqmpWp7ha8h4O3gjOhzVANmF'. 'XPMNQWvdDnCXCXuHR+APqH4fbCtm2mp6eZn59H13WJuYXRaKSU'. 'UiSTyVcBdV3XDcOwRaTU7/en19bWCn/79G+JL/76RbhZ22y7u+'. '6ahl71nPDz/nO17m7wAxlabFOihy4+DvAcqAMbPzZ3OFzX5dmz'. 'Z2iahoiosUUVhiGNRgPHcV4GzGQy5uLiYuH8+fMzo9FoslarJW'. '9+elP75E+fBJu1zY7qqpqBUW3T/niohnVvy+1zm5aVtp+WE2XT'. 'nrHFzbjh1tYLz3XdPjD4R3BKKba2tqhWq4dzUO3noBPn4H5PKy'. 'LaO++8U7hx48byhQsXVne7u6tf3/v64t3P7mbq9+odt+OuaWi3'. 'PLxbW2ytubjbQCgiMnt6VlaurWgz0zM0m02q1WrUaDSUUuqI56'. 'ivDxE5MCgiYllWtlwuL5mmufLV/a/O/uXPf9Ff1F+80Lv6Yx29'. '2qHzyZBh3cdvc7gaTZuZkzPh/Py8ACqVSv1/uPZDKXUAGEWRtF'. 'qtxEcffZTL5XLF+2v39fqjeivshA/TpP83JLwzYFBzcA4370Cc'. 'S81nTRBUs9lkOByi1GuOPI4Rh3+26JZlnSkWi781DOPXvV4v3+'. '/2G0R8kSBxB/jew+tERK+c49m2TblcxrZtXNfl+fPneJ6HZVmU'. 'y2VJJpNyaJ9TSinlOA5bW1u4rntkQA0oAG8D54gb9W3ianxM3A'. 'e/cn73U3Hq1Cm5du2aPjs7a+ztcSIShmE4ajQa6tatWzQajZ+0'. 'fbiKI+It4SvijVUj7kL2qvGfgkskEqTTaZmcnDROnTplJhIJTU'. 'QiwPd9P/Q8T6XTaQzDIAiCfzjP/wFVfszuFqdHXgAAAABJRU5E'. 'rkJggg==' ; //========================================================== // File: pp_red.png //========================================================== $this->imgdata_small[0][0]= 384 ; $this->imgdata_small[0][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. 'B3RJTUUH0wMJFhouFobZrQAAAQ1JREFUeJyV1dFtwyAQBuD/og'. 'xQdYxa8gRY6hJ0jK6QdohMkTEuE5wUj5ERen05IoLvID7Jkn2G'. 'j8MgTMyMXqRlUQBYq9ydmaL2h1cwqD7l30t+L1iwlbYFRegY7I'. 'SHjkEifGg4ww3aBa/l4+9AhxWWr/dLhEunXUGHq6yGniw3QkOw'. '3jJ7UBd82n/VVAlAtvsfp98lAj2sAJOhU4AeQ7DC1ubVBODWDJ'. 'TtCsEWa6u5M1NeFs1NzgdtuhHGtj+9Q2IDppQUAL6Cyrlz0gDN'. 'ohSMiJCt861672EiAhEhESG3woJ9V9OKTkwRKbdqz4cHmFLSFg'. 's69+LvAZKdeZ/n89uLnd2g0S+gjd5g8zzjH5Y/eLLi+NPEAAAA'. 'AElFTkSuQmCC' ; //========================================================== // File: pp_orange.png //========================================================== $this->imgdata_small[1][0]= 403 ; $this->imgdata_small[1][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. 'B3RJTUUH0wMJFhwAnApz5AAAASBJREFUeJyN1dFthDAMBuDf7S'. '3BCm2VCRKpS4QxbhikW6IewzcBqm6Fm6JyH7iEEByCn5AJH38g'. 'BBIRHNUzBAWAGNfe/SrUGv92CtNt309BrfFdMGPjvt9CD8Fyml'. 'ZZaDchRgA/59FDMD18pvNoNyHxMnUmgLmPHoJ+CqqfMaNAH22C'. 'fgqKRwR+GRpxGjXBEiuXDBWQhTK3plxijyWWvtKVS5KNG1xM8I'. 'OBr7geV1WupDqpmTAPKjCqLhxk/z0PImQmjKrAuI6vMXlhFroD'. 'vfdqITXWqg2YMSJEAFcReoag6UXU2DzPG8w5t09YYsAyLWvHrL'. 'HUy6D3XmvMAAhAay8kAJpBosX4vt0G4+4Jam6s6Rz1fgFG0ncA'. 'f3XfOQcA+Acv5IUSdQw9hgAAAABJRU5ErkJggg==' ; //========================================================== // File: pp_pink.png //========================================================== $this->imgdata_small[2][0]= 419 ; $this->imgdata_small[2][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. 'B3RJTUUH0wMJFhsQzvz1RwAAATBJREFUeJyd1MFthDAQheF/oi'. 'gF+JYWQKICkCJRA1vGtrDbxFbhGvY0HVjCLeS2BeTiHFgTB2wg'. 'eRISstCnmcG2qCpbuXf3ADBQzWsPfZfS9y9HsEu4/Fo33Wf4Fx'. 'gxL3a1XkI3wbTNXHLoboVeLFUYDqObYBy+Fw/Uh9DdCmtOwIjF'. 'YvG76CZoOhNGRmpO8zz30CJoOhMAqlDxFzQLppgXj2XaNlP7FF'. 'GLL7ccMYCBgZERgCvXLBrfi2DEclmiKZwFY4tp6sW26bVfnede'. 'e5Hc5dC2bUgrXGKqWrwcXnNYDjmCrcCIiQgDcFYV05kQ8SXmnB'. 'NgPiVN06wrTDGAhz5EWY/FOccTk+cTnHM/YNu2YYllgFxCWuUM'. 'ikzGx+2Gc+4N+CoJW8n+5a2UKm2aBoBvGA6L7wfl8aoAAAAASU'. 'VORK5CYII=' ; //========================================================== // File: pp_blue.png //========================================================== $this->imgdata_small[3][0]= 883 ; $this->imgdata_small[3][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAACi1'. 'BMVEX///8AAAAAADMAAGYAAJkAAMwAAP8zAAAzADMzAGYzAJkz'. 'AMwzAP9mAABmADNmAGZmAJlmAMxmAP+ZAACZADOZAGaZAJmZAM'. 'yZAP/MAADMADPMAGbMAJnMAMzMAP//AAD/ADP/AGb/AJn/AMz/'. 'AP8AMwAAMzMAM2YAM5kAM8wAM/8zMwAzMzMzM2YzM5kzM8wzM/'. '9mMwBmMzNmM2ZmM5lmM8xmM/+ZMwCZMzOZM2aZM5mZM8yZM//M'. 'MwDMMzPMM2bMM5nMM8zMM///MwD/MzP/M2b/M5n/M8z/M/8AZg'. 'AAZjMAZmYAZpkAZswAZv8zZgAzZjMzZmYzZpkzZswzZv9mZgBm'. 'ZjNmZmZmZplmZsxmZv+ZZgCZZjOZZmaZZpmZZsyZZv/MZgDMZj'. 'PMZmbMZpnMZszMZv//ZgD/ZjP/Zmb/Zpn/Zsz/Zv8AmQAAmTMA'. 'mWYAmZkAmcwAmf8zmQAzmTMzmWYzmZkzmcwzmf9mmQBmmTNmmW'. 'ZmmZlmmcxmmf+ZmQCZmTOZmWaZmZmZmcyZmf/MmQDMmTPMmWbM'. 'mZnMmczMmf//mQD/mTP/mWb/mZn/mcz/mf8AzAAAzDMAzGYAzJ'. 'kAzMwAzP8zzAAzzDMzzGYzzJkzzMwzzP9mzABmzDNmzGZmzJlm'. 'zMxmzP+ZzACZzDOZzGaZzJmZzMyZzP/MzADMzDPMzGbMzJnMzM'. 'zMzP//zAD/zDP/zGb/zJn/zMz/zP8A/wAA/zMA/2YA/5kA/8wA'. '//8z/wAz/zMz/2Yz/5kz/8wz//9m/wBm/zNm/2Zm/5lm/8xm//'. '+Z/wCZ/zOZ/2aZ/5mZ/8yZ///M/wDM/zPM/2bM/5nM/8zM////'. '/wD//zP//2b//5n//8z///9jJVUgAAAAAXRSTlMAQObYZgAAAA'. 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. 'RQfTAwkWGTNerea3AAAAYUlEQVR4nHXNwQ3AIAxDUUfyoROxRZ'. 'icARin0EBTIP3Hp1gBRqSqYo0seqjZpnngojlWBir5+b8o06lM'. 'ha5uFKEpDZulV8l52axhVzqaCdxQp32qVSSwC1wN3fYiw7b76w'. 'bN4SMue4/KbwAAAABJRU5ErkJggg==' ; //========================================================== // File: pp_green.png //========================================================== $this->imgdata_small[4][0]= 447 ; $this->imgdata_small[4][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. 'B3RJTUUH0wMJFhkLdq9eKQAAAUxJREFUeJyN1LFVwzAQxvH/8f'. 'IeDS0FLKABlN6eIwPYAzCHB0gWYI2jj+i1ABUTQN4TRSQ7iiWZ'. 'qxLn9Mt9ydmiqrSq930AYFiu6YdKrf/hP1gYQn6960PxwBaYMG'. 'E9UA3dBFtVQjdBOQmBakLennK0CapRwbZRZ3N0O/IeEsqp3HKL'. 'Smtt5pUZgTPg4gdDud+6xoS97wM2rsxxmRSoTgoVcMZsXJkBho'. 'SmKqCuOuEtls6nmGMFPTUmxBKx/MeyNfQGLoOOiC2ddsxb1Kzv'. 'ZzUqu5IXbGDvBJf+hDisi77qFSuhq7Xpuu66TyJLRGbsXVUPxV'. 'SxsgkzDMt0mKT3/RcjL8C5hHnvJToXY0xYRZ4xnVKsV/S+a8YA'. 'AvCb3s9g13UhYj+TTo93B3fApRV1FVlEAD6H42DjN9/WvzDYuJ'. 'dL5b1/ji+/IX8EGWP4AwRii8PdFHTqAAAAAElFTkSuQmCC' ; } } ?> ================================================ FILE: tools/server/admin/jpgraph/imgdata_squares.inc ================================================ 'imgdata'); var $colors = array('bluegreen','blue','green', 'lightblue','orange','purple','red','yellow'); var $index = array('bluegreen' =>2,'blue'=>5,'green'=>6, 'lightblue'=>0,'orange'=>7,'purple'=>4,'red'=>3,'yellow'=>1); var $maxidx = 7 ; var $imgdata ; function ImgData_Squares () { //========================================================== //sq_lblue.png //========================================================== $this->imgdata[0][0]= 362 ; $this->imgdata[0][1]= 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAAABm'. 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. 'B3RJTUUH0wMLFgojiPx/ygAAAPdJREFUeNpj/P377+kzHx89/c'. 'VAHNBQ5VBX52HavPWWjg6nnDQbkXoUFTnnL7zD9PPXrz17HxCj'. 'E6Jn6fL7H7/+ZWJgYCBGJ7IeBgYGJogofp1oehDa8OjE1IOiDa'. 'tOrHoYGBhY0NwD0enirMDAwMDFxYRVD7ptyDrNTAU0NXix6sGu'. 'jYGBgZOT9e/f/0xMjFyczFgVsGAKCfBza2kKzpl3hIuT1c9Xb/'. 'PW58/foKchJqx6tmy98vbjj8cvPm/afMnXW1JShA2fNmQ9EBFc'. 'Opnw6MGjkwm/Hlw6mQjqwaqTiRg9mDoZv//4M2/+UYJ64EBWgj'. 'cm2hwA8l24oNDl+DMAAAAASUVORK5CYII=' ; //========================================================== //sq_yellow.png //========================================================== $this->imgdata[1][0]= 338 ; $this->imgdata[1][1]= 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAWl'. 'BMVEX////+/+H+/9/9/9v8/8P8/8H8/7v8/7n6/4P5/335/3n5'. '/3X4/1f4/1P3/031/w30/wn0/wPt+ADp9ADm8ADk7gDc5gDa5A'. 'DL1ADFzgCwuACqsgClrABzeAC9M0MzAAAAAWJLR0QAiAUdSAAA'. 'AAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEDlOgDj'. 'EAAAB+SURBVHjaVcpbCsQgDEDRGERGKopjDa2a/W9zfLWj9/Nw'. 'Ac21ZRBOtZlRN9ApzSYFaDUj79KIorRDbJNO9bN/GUSh2ZRJFJ'. 'S18iorURBiyksO8buT0zkfYaUqzI91ckfhWhoGXTLzsDjI68Sz'. 'pGMjrzPzauA/iXk1AtykmvgBC8UcWUdc9HkAAAAASUVORK5CYI'. 'I=' ; //========================================================== //sq_blgr.png //========================================================== $this->imgdata[2][0]= 347 ; $this->imgdata[2][1]= 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAZl'. 'BMVEX////0+vv0+vrz+fry+frv+Png7e/d7e/a6+zY6+250tSz'. '0tSyztCtztGM0NWIz9SDzdNfsLVcrrRZrbJOp61MpqtIr7dHn6'. 'RErrZArLQ6q7M2g4kygYcsp68npa4ctr8QZ20JnqepKsl4AAAA'. 'AWJLR0QAiAUdSAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU'. '1FB9MDCxYEByp8tpUAAAB7SURBVHjaVcjRFoIgDADQWZpWJpjY'. 'MsnG//9kzIFn3McLzfArDA3MndFjrhvgfDHFBEB9pt0CVzwrY3'. 'n2yicjhY4vTSp0nbXtN+hCV53SHDWe61dZY+/9463r2XuifHAM'. '0SoH+6xEcovUlCfefeFSIwfTTQ3fB+pi4lV/bTIgvmaA7a0AAA'. 'AASUVORK5CYII=' ; //========================================================== //sq_red.png //========================================================== $this->imgdata[3][0]= 324 ; $this->imgdata[3][1]= 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAXV'. 'BMVEX////++Pn99/j99ff99fb98/X98/T98PL55uj43+P24+bw'. 'kKPvjaHviJ3teJHpxMnoL2Pjs73WW3rWNljVWXnUVnbUK1DTJk'. '3SUHPOBz/KQmmxPVmuOFasNFOeIkWVka/fAAAAAWJLR0QAiAUd'. 'SAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEHd'. 'ceT+8AAABtSURBVHjaVchbAkMwEAXQq6i3VrQiQfa/zDYTw8z5'. 'PCjGt9JVWFt1XWPh1fWNdfDy+tq6WPfRUPENNKnSnXNWPB4uv2'. 'b54nSZ8jHrMtOxvWZZZtpD4KP6xLkO9/AhzhaCOMhJh68cOjzV'. '/K/4Ac2cG+nBcaRuAAAAAElFTkSuQmCC' ; //========================================================== //sq_pink.png //========================================================== $this->imgdata[4][0]= 445 ; $this->imgdata[4][1]= 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAApV'. 'BMVEX////6+Pz69/v49Pr38/r17/jr4+/l3Onj2efh1ua/L+i+'. 'q8m+Lue9Lua8qsS8LuW8LeS7pca5LOG4LN+2Y9O2YNW1ZdO1Kt'. 'y0atC0aNGzb82zbc6zKtuzKdqycsuwa8qtJtOISZ2GRpuFN6GE'. 'NqCDQpmCMZ+BPpd/LJ1/K519S5B9Jpx9Jpt9JZt6RY11BJZ1BJ'. 'V0BJV0BJRzBJNvNoRtIoJUEmdZ/XbrAAAAAWJLR0QAiAUdSAAA'. 'AAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYDF3iKMD'. 'YAAACeSURBVHjaVczbEoIgGARgCiMtrexoWpaa2FHUgvd/tH4Y'. 'BnEvv9ldhNPradPnnGBUTtPDzMRPSIF46SaBoR25dYjz3I20Lb'. 'ek6BgQz73Il7KKpSgCO0pTHU0886J1sCe0ZYbALjGhjFnEM2es'. 'VhZVI4d+B1QtfnV47ywCEaKeP/p7JdLejSYt0j6NIiOq1wJZIs'. 'QTDA0ELHwhPBCwyR/Cni9cOmzJtwAAAABJRU5ErkJggg==' ; //========================================================== //sq_blue.png //========================================================== $this->imgdata[5][0]= 283 ; $this->imgdata[5][1]= 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAQl'. 'BMVEX////4+fz39/z19vvy8vru7/ni4+7g4fHW1ue8vteXmt6B'. 'hdhiZ7FQVaZETcxCSJo1Oq4zNoMjKakhJHcKFaMEC2jRVYdWAA'. 'AAAWJLR0QAiAUdSAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0'. 'SU1FB9MDCxYDN0PkEP4AAABfSURBVHjaVchHAoAgDATAVcCCIF'. 'j4/1elJEjmOFDHKVgDv4iz640gLs+LMF6ZUv/VqcXXplU7Gqpy'. 'PFzBT5qml9NzlOX259riWHlS4kOffviHD8PQYZx2EFMPRkw+9Q'. 'FSnRPeWEDzKAAAAABJRU5ErkJggg==' ; //========================================================== //sq_green.png //========================================================== $this->imgdata[6][0]= 325 ; $this->imgdata[6][1]= 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAXV'. 'BMVEX////2+vX1+vX1+fT0+fPz+PPx9/Dv9u7u9e3h7uHe697a'. '6dnO2s3I1sa10LOvza2ay5aEwYBWlE9TqE5Tkk1RkEpMrUJMg0'. 'hKiUNGpEFBojw8oTcsbScaYBMWlwmMT0NtAAAAAWJLR0QAiAUd'. 'SAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEFd'. 'nFx90AAABuSURBVHjaVc9HAoAgDADB2HuJWLDx/2cKBITscW4L'. '5byzMIWtZobNDZIZtrcCGZsRQ8GwvRSRNxIiMuysODKG3alikl'. 'ueOPlpKTLBaRmOZxQxaXlfb5ZWI9om4WntrXiDSJzp7SBkwMQa'. 'FEy0VR/NAB2kNuj7rgAAAABJRU5ErkJggg==' ; //========================================================== //sq_orange.png //========================================================== $this->imgdata[7][0]= 321 ; $this->imgdata[7][1]= 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAUV'. 'BMVEX/////8+n/8uf/8OP/59H/5Mv/zqH/zJ3/ypv/yJf/vYH/'. 'u33/uXn/n0n/nUX/m0H/lzn/ljf/lDP/kS3/kCv/iR//hxv/fg'. 'n/fAX/eQDYZgDW6ia5AAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAL'. 'EgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEJIgbx+cAAAB2SURBVH'. 'jaVczRCoQwDETRbLAWLZSGUA35/w/dVI0283i4DODew3YESmWW'. 'kg5gWkoQAe6TleUQI/66Sy7i56+kLk7cht2N0+hcnJgQu0SqiC'. '1SzSIbzWSi6gavqJ63wSduRi2f+kwyD5rEukwCdZ1kGAMGMfv9'. 'AbWuGMOr5COSAAAAAElFTkSuQmCC' ; } } ?> ================================================ FILE: tools/server/admin/jpgraph/imgdata_stars.inc ================================================ 'imgdata'); var $colors = array('bluegreen','lightblue','purple','blue','green','pink','red','yellow'); var $index = array('bluegreen'=>3,'lightblue'=>4,'purple'=>1, 'blue'=>5,'green'=>0,'pink'=>7,'red'=>2,'yellow'=>6); var $maxidx = 7 ; var $imgdata ; function ImgData_Stars() { //========================================================== // File: bstar_green_001.png //========================================================== $this->imgdata[0][0]= 329 ; $this->imgdata[0][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAAUV'. 'BMVEX///////+/v7+83rqcyY2Q/4R7/15y/1tp/05p/0lg/zdX'. '/zdX/zVV/zdO/zFJ9TFJvDFD4yg+8Bw+3iU68hwurhYotxYosx'. 'YokBoTfwANgQFUp7DWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJj'. 'CRyxgTAAAAcUlEQVR4nH3MSw6AIAwEUBL/IKBWwXL/g0pLojUS'. 'ZzGLl8ko9Zumhr5iy66/GH0dp49llNPB5sTotDY5PVuLG6tnM9'. 'CVKSIe1joSgPsAKSuANNaENFQvTAGzmheSkUpMBWeJZwqBT8wo'. 'hmysD4bnnPsC/x8ItUdGPfAAAAAASUVORK5CYII=' ; //========================================================== // File: bstar_blred.png //========================================================== $this->imgdata[1][0]= 325 ; $this->imgdata[1][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. 'BMVEX///+/v79uRJ6jWPOSUtKrb+ejWO+gWPaGTruJTr6rZvF2'. 'RqC2ocqdVuCeV+egV/GsnLuIXL66rMSpcOyATbipY/OdWOp+VK'. 'aTU9WhV+yJKBoLAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJwynv1'. 'XVAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; //========================================================== // File: bstar_red_001.png //========================================================== $this->imgdata[2][0]= 325 ; $this->imgdata[2][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. 'BMVEX///+/v7+eRFHzWG3SUmHnb37vWGr2WHG7Tlm+TljxZneg'. 'Rk3KoaXgVmXnV2nxV227nJ++XGzErK3scIS4TVzzY3fqWG2mVF'. 'zVU2PsV2rJFw9VAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJzCI0C'. 'lSAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; //========================================================== // File: bstar_blgr_001.png //========================================================== $this->imgdata[3][0]= 325 ; $this->imgdata[3][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. 'BMVEX///+/v79Ehp5Yx/NSq9Jvw+dYwu9YzfZOmbtOmb5myPFG'. 'gqChvcpWteBXvedXxvGcsbtcpb6su8RwzOxNmrhjyvNYwupUjK'. 'ZTr9VXwOyJhmWNAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJTC65k'. 'vQAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; //========================================================== // File: bstar_blgr_002.png //========================================================== $this->imgdata[4][0]= 325 ; $this->imgdata[4][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. 'BMVEX///+/v79EnpxY8/FS0dJv5+dY7+9Y9vBOubtOur5m8fFG'. 'nKChycpW3uBX5+ZX8e2curtcvrqswsRw7OdNuLZj8/BY6udUpK'. 'ZT1dRX7OtNkrW5AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJgXHeN'. 'wwAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; //========================================================== // File: bstar_blue_001.png //========================================================== $this->imgdata[5][0]= 325 ; $this->imgdata[5][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. 'BMVEX///+/v79EY55Yi/NSetJvledYiO9YkPZOb7tObr5mkvFG'. 'X6ChrcpWgOBXhedXi/Gcpbtcf76sssRwnOxNcbhjk/NYiepUbK'. 'ZTfdVXh+ynNEzzAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJhStyP'. 'zCAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; //========================================================== // File: bstar_oy_007.png //========================================================== $this->imgdata[6][0]= 325 ; $this->imgdata[6][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. 'BMVEX///+/v7+ejUTz11jSvVLn02/v1lj21li7q06+r07x2mag'. 'lUbKxKHgy1bnz1fx1Ve7t5y+qlzEwqzs03C4pE3z2WPqz1imml'. 'TVv1Ps01dGRjeyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJjsGGc'. 'GbAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; //========================================================== // File: bstar_lred.png //========================================================== $this->imgdata[7][0]= 325 ; $this->imgdata[7][1]= 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. 'BMVEX///+/v7+eRJPzWN3SUr7nb9TvWNj2WOS7Tqi+TqnxZtyg'. 'Ro/KocPgVsjnV9LxV927nLa+XLTErL7scN24TarzY9/qWNemVJ'. 'jVU8LsV9VCwcc9AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJxi9ZY'. 'GoAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; } } ?> ================================================ FILE: tools/server/admin/jpgraph/jpg-config.inc ================================================ ================================================ FILE: tools/server/admin/jpgraph/jpgraph.php ================================================ Get(11,$file,$lineno); die($msg); } else { DEFINE('CACHE_DIR', $_SERVER['TEMP'] . '/'); } } else { DEFINE('CACHE_DIR','/tmp/jpgraph_cache/'); } } } elseif( !defined('CACHE_DIR') ) { DEFINE('CACHE_DIR', ''); } if (!defined('TTF_DIR')) { if (strstr( PHP_OS, 'WIN') ) { $sroot = getenv('SystemRoot'); if( empty($sroot) ) { $t = new ErrMsgText(); $msg = $t->Get(12,$file,$lineno); die($msg); } else { DEFINE('TTF_DIR', $sroot.'/fonts/'); } } else { DEFINE('TTF_DIR','/usr/X11R6/lib/X11/fonts/truetype/'); } } //------------------------------------------------------------------ // Constants which are used as parameters for the method calls //------------------------------------------------------------------ // TTF Font families DEFINE("FF_COURIER",10); DEFINE("FF_VERDANA",11); DEFINE("FF_TIMES",12); DEFINE("FF_COMIC",14); DEFINE("FF_ARIAL",15); DEFINE("FF_GEORGIA",16); DEFINE("FF_TREBUCHE",17); // Gnome Vera font // Available from http://www.gnome.org/fonts/ DEFINE("FF_VERA",19); DEFINE("FF_VERAMONO",20); DEFINE("FF_VERASERIF",21); // Chinese font DEFINE("FF_SIMSUN",30); DEFINE("FF_CHINESE",31); DEFINE("FF_BIG5",31); // Japanese font DEFINE("FF_MINCHO",40); DEFINE("FF_PMINCHO",41); DEFINE("FF_GOTHIC",42); DEFINE("FF_PGOTHIC",43); // Limits for TTF fonts DEFINE('_FF_FIRST',10); DEFINE('_FF_LAST',43); // Older deprecated fonts DEFINE("FF_BOOK",91); // Deprecated fonts from 1.9 DEFINE("FF_HANDWRT",92); // Deprecated fonts from 1.9 // TTF Font styles DEFINE("FS_NORMAL",9001); DEFINE("FS_BOLD",9002); DEFINE("FS_ITALIC",9003); DEFINE("FS_BOLDIT",9004); DEFINE("FS_BOLDITALIC",9004); //Definitions for internal font, new style DEFINE("FF_FONT0",1); DEFINE("FF_FONT1",2); DEFINE("FF_FONT2",4); // Tick density DEFINE("TICKD_DENSE",1); DEFINE("TICKD_NORMAL",2); DEFINE("TICKD_SPARSE",3); DEFINE("TICKD_VERYSPARSE",4); // Side for ticks and labels. DEFINE("SIDE_LEFT",-1); DEFINE("SIDE_RIGHT",1); DEFINE("SIDE_DOWN",-1); DEFINE("SIDE_BOTTOM",-1); DEFINE("SIDE_UP",1); DEFINE("SIDE_TOP",1); // Legend type stacked vertical or horizontal DEFINE("LEGEND_VERT",0); DEFINE("LEGEND_HOR",1); // Mark types for plot marks DEFINE("MARK_SQUARE",1); DEFINE("MARK_UTRIANGLE",2); DEFINE("MARK_DTRIANGLE",3); DEFINE("MARK_DIAMOND",4); DEFINE("MARK_CIRCLE",5); DEFINE("MARK_FILLEDCIRCLE",6); DEFINE("MARK_CROSS",7); DEFINE("MARK_STAR",8); DEFINE("MARK_X",9); DEFINE("MARK_LEFTTRIANGLE",10); DEFINE("MARK_RIGHTTRIANGLE",11); DEFINE("MARK_FLASH",12); DEFINE("MARK_IMG",13); DEFINE("MARK_FLAG1",14); DEFINE("MARK_FLAG2",15); DEFINE("MARK_FLAG3",16); DEFINE("MARK_FLAG4",17); // Builtin images DEFINE("MARK_IMG_PUSHPIN",50); DEFINE("MARK_IMG_SPUSHPIN",50); DEFINE("MARK_IMG_LPUSHPIN",51); DEFINE("MARK_IMG_DIAMOND",52); DEFINE("MARK_IMG_SQUARE",53); DEFINE("MARK_IMG_STAR",54); DEFINE("MARK_IMG_BALL",55); DEFINE("MARK_IMG_SBALL",55); DEFINE("MARK_IMG_MBALL",56); DEFINE("MARK_IMG_LBALL",57); DEFINE("MARK_IMG_BEVEL",58); // Inline defines DEFINE("INLINE_YES",1); DEFINE("INLINE_NO",0); // Format for background images DEFINE("BGIMG_FILLPLOT",1); DEFINE("BGIMG_FILLFRAME",2); DEFINE("BGIMG_COPY",3); DEFINE("BGIMG_CENTER",4); // Depth of objects DEFINE("DEPTH_BACK",0); DEFINE("DEPTH_FRONT",1); // Direction DEFINE("VERTICAL",1); DEFINE("HORIZONTAL",0); // Axis styles for scientific style axis DEFINE('AXSTYLE_SIMPLE',1); DEFINE('AXSTYLE_BOXIN',2); DEFINE('AXSTYLE_BOXOUT',3); DEFINE('AXSTYLE_YBOXIN',4); DEFINE('AXSTYLE_YBOXOUT',5); // Style for title backgrounds DEFINE('TITLEBKG_STYLE1',1); DEFINE('TITLEBKG_STYLE2',2); DEFINE('TITLEBKG_STYLE3',3); DEFINE('TITLEBKG_FRAME_NONE',0); DEFINE('TITLEBKG_FRAME_FULL',1); DEFINE('TITLEBKG_FRAME_BOTTOM',2); DEFINE('TITLEBKG_FRAME_BEVEL',3); DEFINE('TITLEBKG_FILLSTYLE_HSTRIPED',1); DEFINE('TITLEBKG_FILLSTYLE_VSTRIPED',2); DEFINE('TITLEBKG_FILLSTYLE_SOLID',3); // Style for background gradient fills DEFINE('BGRAD_FRAME',1); DEFINE('BGRAD_MARGIN',2); DEFINE('BGRAD_PLOT',3); // Width of tab titles DEFINE('TABTITLE_WIDTHFIT',0); DEFINE('TABTITLE_WIDTHFULL',-1); // Defines for 3D skew directions DEFINE('SKEW3D_UP',0); DEFINE('SKEW3D_DOWN',1); DEFINE('SKEW3D_LEFT',2); DEFINE('SKEW3D_RIGHT',3); // // Get hold of gradient class (In Version 2.x) // A client of the library has to manually include this // require_once 'jpgraph_gradient.php'; class ErrMsgText { var $lt=NULL; var $supportedLocales = array('en'); function ErrMsgText() { GLOBAL $__jpg_err_locale; if( !in_array($__jpg_err_locale,$this->supportedLocales) ) $aLoc = 'en'; require_once('lang/'.$__jpg_err_locale.'.inc.php'); $this->lt = $_jpg_messages; } function Get($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) { if( !isset($this->lt[$errnbr]) ) { return 'Internal error: The specified error message does not exist in the chosen locale. (Please blame the translator...))'; } $ea = $this->lt[$errnbr]; $j=0; if( $a1 !== null ) { $argv[$j++] = $a1; if( $a2 !== null ) { $argv[$j++] = $a2; if( $a3 !== null ) { $argv[$j++] = $a3; if( $a4 !== null ) { $argv[$j++] = $a4; if( $a5 !== null ) { $argv[$j++] = $a5; } } } } } $numargs = $j; if( $ea[1] != $numargs ) { // Error message argument count do not match. // Just return the error message without arguments. return $ea[0]; } switch( $numargs ) { case 1: $msg = sprintf($ea[0],$argv[0]); break; case 2: $msg = sprintf($ea[0],$argv[0],$argv[1]); break; case 3: $msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2]); break; case 4: $msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3]); break; case 5: $msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3],$argv[4]); break; case 0: default: $msg = sprintf($ea[0]); break; } return $msg; } } // // A wrapper class that is used to access the specified error object // (to hide the global error parameter and avoid having a GLOBAL directive // in all methods. // GLOBAL $__jpg_err; GLOBAL $__jpg_err_locale ; $__jpg_err_locale = 'en'; class JpGraphError { function Install($aErrObject) { GLOBAL $__jpg_err; $__jpg_err = $aErrObject; } function Raise($aMsg,$aHalt=true){ GLOBAL $__jpg_err; $tmp = new $__jpg_err; $tmp->Raise($aMsg,$aHalt); } function RaiseL($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) { GLOBAL $__jpg_err; $t = new ErrMsgText(); $msg = $t->Get($errnbr,$a1,$a2,$a3,$a4,$a5); $tmp = new $__jpg_err; $tmp->Raise($msg); } } // // ... and install the default error handler // if( USE_IMAGE_ERROR_HANDLER ) { $__jpg_err = "JpGraphErrObjectImg"; } else { $__jpg_err = "JpGraphErrObject"; } // // Make GD sanity check // if( !function_exists("imagetypes") || !function_exists('imagecreatefromstring') ) { JpGraphError::RaiseL(25001); //("This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)"); } // // Routine to determine if GD1 or GD2 is installed // function CheckGDVersion() { $GDfuncList = get_extension_funcs('gd'); if( !$GDfuncList ) return 0 ; else { if( in_array('imagegd2',$GDfuncList) && in_array('imagecreatetruecolor',$GDfuncList)) return 2; else return 1; } } // // Check what version of the GD library is installed. // $GLOBALS['gd2'] = false; if( USE_LIBRARY_GD2 === 'auto' ) { $gdversion = CheckGDVersion(); if( $gdversion == 2 ) { $GLOBALS['gd2'] = true; $GLOBALS['copyfunc'] = 'imagecopyresampled'; } elseif( $gdversion == 1 ) { $GLOBALS['gd2'] = false; $GLOBALS['copyfunc'] = 'imagecopyresized'; } else { JpGraphError::RaiseL(25002); //(" Your PHP installation does not seem to have the required GD library. Please see the PHP documentation on how to install and enable the GD library."); } } else { $GLOBALS['gd2'] = USE_LIBRARY_GD2; $GLOBALS['copyfunc'] = USE_LIBRARY_GD2 ? 'imagecopyresampled' : 'imagecopyresized'; } // // First of all set up a default error handler // //============================================================= // The default trivial text error handler. //============================================================= class JpGraphErrObject { var $iTitle = "JpGraph Error"; var $iDest = false; function JpGraphErrObject() { // Empty. Reserved for future use } function SetTitle($aTitle) { $this->iTitle = $aTitle; } function SetStrokeDest($aDest) { $this->iDest = $aDest; } // If aHalt is true then execution can't continue. Typical used for fatal errors. function Raise($aMsg,$aHalt=true) { $aMsg = $this->iTitle.' '.$aMsg; if ($this->iDest) { $f = @fopen($this->iDest,'a'); if( $f ) { @fwrite($f,$aMsg); @fclose($f); } } else { echo $aMsg; } if( $aHalt ) die(); } } //============================================================== // An image based error handler //============================================================== class JpGraphErrObjectImg extends JpGraphErrObject { function Raise($aMsg,$aHalt=true) { $img_iconerror = 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaV'. 'BMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'. 'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpY'. 'iYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'. 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. 'IAAAsSAdLdfvwAAAAHdElNRQfTBgISOCqusfs5AAABLUlEQVR4'. '2tWV3XKCMBBGWfkranCIVClKLd/7P2Q3QsgCxjDTq+6FE2cPH+'. 'xJ0Ogn2lQbsT+Wrs+buAZAV4W5T6Bs0YXBBwpKgEuIu+JERAX6'. 'wM2rHjmDdEITmsQEEmWADgZm6rAjhXsoMGY9B/NZBwJzBvn+e3'. 'wHntCAJdGu9SviwIwoZVDxPB9+Rc0TSEbQr0j3SA1gwdSn6Db0'. '6Tm1KfV6yzWGQO7zdpvyKLKBDmRFjzeB3LYgK7r6A/noDAfjtS'. 'IXaIzbJSv6WgUebTMV4EoRB8a2mQiQjgtF91HdKDKZ1gtFtQjk'. 'YcWaR5OKOhkYt+ZsTFdJRfPAApOpQYJTNHvCRSJR6SJngQadfc'. 'vd69OLMddVOPCGVnmrFD8bVYd3JXfxXPtLR/+mtv59/ALWiiMx'. 'qL72fwAAAABJRU5ErkJggg==' ; if( function_exists("imagetypes") ) $supported = imagetypes(); else $supported = 0; if( !function_exists('imagecreatefromstring') ) $supported = 0; if( ob_get_length() || headers_sent() || !($supported & IMG_PNG) ) { // Special case for headers already sent or that the installation doesn't support // the PNG format (which the error icon is encoded in). // Dont return an image since it can't be displayed die($this->iTitle.' '.$aMsg); } $aMsg = wordwrap($aMsg,55); $lines = substr_count($aMsg,"\n"); // Create the error icon GD $erricon = Image::CreateFromString(base64_decode($img_iconerror)); // Create an image that contains the error text. $w=400; $h=100 + 15*max(0,$lines-3); $img = new Image($w,$h); // Drop shadow $img->SetColor("gray"); $img->FilledRectangle(5,5,$w-1,$h-1,10); $img->SetColor("gray:0.7"); $img->FilledRectangle(5,5,$w-3,$h-3,10); // Window background $img->SetColor("lightblue"); $img->FilledRectangle(1,1,$w-5,$h-5); $img->CopyCanvasH($img->img,$erricon,5,30,0,0,40,40); // Window border $img->SetColor("black"); $img->Rectangle(1,1,$w-5,$h-5); $img->Rectangle(0,0,$w-4,$h-4); // Window top row $img->SetColor("darkred"); for($y=3; $y < 18; $y += 2 ) $img->Line(1,$y,$w-6,$y); // "White shadow" $img->SetColor("white"); // Left window edge $img->Line(2,2,2,$h-5); $img->Line(2,2,$w-6,2); // "Gray button shadow" $img->SetColor("darkgray"); // Gray window shadow $img->Line(2,$h-6,$w-5,$h-6); $img->Line(3,$h-7,$w-5,$h-7); // Window title $m = floor($w/2-5); $l = 100; $img->SetColor("lightgray:1.3"); $img->FilledRectangle($m-$l,2,$m+$l,16); // Stroke text $img->SetColor("darkred"); $img->SetFont(FF_FONT2,FS_BOLD); $img->StrokeText($m-50,15,$this->iTitle); $img->SetColor("black"); $img->SetFont(FF_FONT1,FS_NORMAL); $txt = new Text($aMsg,52,25); $txt->Align("left","top"); $txt->Stroke($img); if ($this->iDest) { $img->Stream($this->iDest); } else { $img->Headers(); $img->Stream(); } if( $aHalt ) die(); } } // // Setup PHP error handler // function _phpErrorHandler($errno,$errmsg,$filename, $linenum, $vars) { // Respect current error level if( $errno & error_reporting() ) { JpGraphError::RaiseL(25003,basename($filename),$linenum,$errmsg); } } if( INSTALL_PHP_ERR_HANDLER ) { set_error_handler("_phpErrorHandler"); } // //Check if there were any warnings, perhaps some wrong includes by the user // if( isset($GLOBALS['php_errormsg']) && CATCH_PHPERRMSG && !preg_match('|Deprecated|', $GLOBALS['php_errormsg'])) { JpGraphError::RaiseL(25004,$GLOBALS['php_errormsg']); } // Useful mathematical function function sign($a) {return $a >= 0 ? 1 : -1;} // Utility function to generate an image name based on the filename we // are running from and assuming we use auto detection of graphic format // (top level), i.e it is safe to call this function // from a script that uses JpGraph function GenImgName() { global $_SERVER; // Determine what format we should use when we save the images $supported = imagetypes(); if( $supported & IMG_PNG ) $img_format="png"; elseif( $supported & IMG_GIF ) $img_format="gif"; elseif( $supported & IMG_JPG ) $img_format="jpeg"; if( !isset($_SERVER['PHP_SELF']) ) JpGraphError::RaiseL(25005); //(" Can't access PHP_SELF, PHP global variable. You can't run PHP from command line if you want to use the 'auto' naming of cache or image files."); $fname = basename($_SERVER['PHP_SELF']); if( !empty($_SERVER['QUERY_STRING']) ) { $q = @$_SERVER['QUERY_STRING']; $fname .= '?'.preg_replace("/\W/", "_", $q).'.'.$img_format; } else { $fname = substr($fname,0,strlen($fname)-4).'.'.$img_format; } return $fname; } class LanguageConv { var $g2312 = null ; function Convert($aTxt,$aFF) { if( LANGUAGE_CYRILLIC ) { if( CYRILLIC_FROM_WINDOWS ) { $aTxt = convert_cyr_string($aTxt, "w", "k"); } $isostring = convert_cyr_string($aTxt, "k", "i"); $unistring = LanguageConv::iso2uni($isostring); return $unistring; } elseif( $aFF === FF_SIMSUN ) { // Do Chinese conversion if( $this->g2312 == null ) { include_once 'jpgraph_gb2312.php' ; $this->g2312 = new GB2312toUTF8(); } return $this->g2312->gb2utf8($aTxt); } elseif( $aFF === FF_CHINESE ) { if( !function_exists('iconv') ) { JpGraphError::RaiseL(25006); //('Usage of FF_CHINESE (FF_BIG5) font family requires that your PHP setup has the iconv() function. By default this is not compiled into PHP (needs the "--width-iconv" when configured).'); } return iconv('BIG5','UTF-8',$aTxt); } else return $aTxt; } // Translate iso encoding to unicode function iso2uni ($isoline){ $uniline=''; for ($i=0; $i < strlen($isoline); $i++){ $thischar=substr($isoline,$i,1); $charcode=ord($thischar); $uniline.=($charcode>175) ? "&#" . (1040+($charcode-176)). ";" : $thischar; } return $uniline; } } //=================================================== // CLASS JpgTimer // Description: General timing utility class to handle // time measurement of generating graphs. Multiple // timers can be started. //=================================================== class JpgTimer { var $start; var $idx; //--------------- // CONSTRUCTOR function JpgTimer() { $this->idx=0; } //--------------- // PUBLIC METHODS // Push a new timer start on stack function Push() { list($ms,$s)=explode(" ",microtime()); $this->start[$this->idx++]=floor($ms*1000) + 1000*$s; } // Pop the latest timer start and return the diff with the // current time function Pop() { assert($this->idx>0); list($ms,$s)=explode(" ",microtime()); $etime=floor($ms*1000) + (1000*$s); $this->idx--; return $etime-$this->start[$this->idx]; } } // Class $gJpgBrandTiming = BRAND_TIMING; //=================================================== // CLASS DateLocale // Description: Hold localized text used in dates //=================================================== class DateLocale { var $iLocale = 'C'; // environmental locale be used by default var $iDayAbb = null; var $iShortDay = null; var $iShortMonth = null; var $iMonthName = null; //--------------- // CONSTRUCTOR function DateLocale() { settype($this->iDayAbb, 'array'); settype($this->iShortDay, 'array'); settype($this->iShortMonth, 'array'); settype($this->iMonthName, 'array'); $this->Set('C'); } //--------------- // PUBLIC METHODS function Set($aLocale) { if ( in_array($aLocale, array_keys($this->iDayAbb)) ){ $this->iLocale = $aLocale; return TRUE; // already cached nothing else to do! } $pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME $res = @setlocale(LC_TIME, $aLocale); if ( ! $res ){ JpGraphError::RaiseL(25007,$aLocale); //("You are trying to use the locale ($aLocale) which your PHP installation does not support. Hint: Use '' to indicate the default locale for this geographic region."); return FALSE; } $this->iLocale = $aLocale; for ( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ){ $day = strftime('%a', strtotime("$ofs day")); $day{0} = strtoupper($day{0}); $this->iDayAbb[$aLocale][]= $day{0}; $this->iShortDay[$aLocale][]= $day; } for($i=1; $i<=12; ++$i) { list($short ,$full) = explode('|', strftime("%b|%B",strtotime("2001-$i-01"))); $this->iShortMonth[$aLocale][] = ucfirst($short); $this->iMonthName [$aLocale][] = ucfirst($full); } // Return to original locale setlocale(LC_TIME, $pLocale); return TRUE; } function GetDayAbb() { return $this->iDayAbb[$this->iLocale]; } function GetShortDay() { return $this->iShortDay[$this->iLocale]; } function GetShortMonth() { return $this->iShortMonth[$this->iLocale]; } function GetShortMonthName($aNbr) { return $this->iShortMonth[$this->iLocale][$aNbr]; } function GetLongMonthName($aNbr) { return $this->iMonthName[$this->iLocale][$aNbr]; } function GetMonth() { return $this->iMonthName[$this->iLocale]; } } $gDateLocale = new DateLocale(); $gJpgDateLocale = new DateLocale(); //======================================================= // CLASS Footer // Description: Encapsulates the footer line in the Graph //======================================================= class Footer { var $left,$center,$right; var $iLeftMargin = 3; var $iRightMargin = 3; var $iBottomMargin = 3; function Footer() { $this->left = new Text(); $this->left->ParagraphAlign('left'); $this->center = new Text(); $this->center->ParagraphAlign('center'); $this->right = new Text(); $this->right->ParagraphAlign('right'); } function Stroke(&$aImg) { $y = $aImg->height - $this->iBottomMargin; $x = $this->iLeftMargin; $this->left->Align('left','bottom'); $this->left->Stroke($aImg,$x,$y); $x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2; $this->center->Align('center','bottom'); $this->center->Stroke($aImg,$x,$y); $x = $aImg->width - $this->iRightMargin; $this->right->Align('right','bottom'); $this->right->Stroke($aImg,$x,$y); } } //=================================================== // CLASS Graph // Description: Main class to handle graphs //=================================================== class Graph { var $cache=null; // Cache object (singleton) var $img=null; // Img object (singleton) var $plots=array(); // Array of all plot object in the graph (for Y 1 axis) var $y2plots=array();// Array of all plot object in the graph (for Y 2 axis) var $ynplots=array(); var $xscale=null; // X Scale object (could be instance of LinearScale or LogScale var $yscale=null,$y2scale=null, $ynscale=array(); var $iIcons = array(); // Array of Icons to add to var $cache_name; // File name to be used for the current graph in the cache directory var $xgrid=null; // X Grid object (linear or logarithmic) var $ygrid=null,$y2grid=null; var $doframe=true,$frame_color=array(0,0,0), $frame_weight=1; // Frame around graph var $boxed=false, $box_color=array(0,0,0), $box_weight=1; // Box around plot area var $doshadow=false,$shadow_width=4,$shadow_color=array(102,102,102); // Shadow for graph var $xaxis=null; // X-axis (instane of Axis class) var $yaxis=null, $y2axis=null, $ynaxis=array(); // Y axis (instance of Axis class) var $margin_color=array(200,200,200); // Margin color of graph var $plotarea_color=array(255,255,255); // Plot area color var $title,$subtitle,$subsubtitle; // Title and subtitle(s) text object var $axtype="linlin"; // Type of axis var $xtick_factor; // Factot to determine the maximum number of ticks depending on the plot with var $texts=null, $y2texts=null; // Text object to ge shown in the graph var $lines=null, $y2lines=null; var $bands=null, $y2bands=null; var $text_scale_off=0, $text_scale_abscenteroff=-1; // Text scale offset in fractions and for centering bars in absolute pixels var $background_image="",$background_image_type=-1,$background_image_format="png"; var $background_image_bright=0,$background_image_contr=0,$background_image_sat=0; var $image_bright=0, $image_contr=0, $image_sat=0; var $inline; var $showcsim=0,$csimcolor="red"; //debug stuff, draw the csim boundaris on the image if <>0 var $grid_depth=DEPTH_BACK; // Draw grid under all plots as default var $iAxisStyle = AXSTYLE_SIMPLE; var $iCSIMdisplay=false,$iHasStroked = false; var $footer; var $csimcachename = '', $csimcachetimeout = 0; var $iDoClipping = false; var $y2orderback=true; var $tabtitle; var $bkg_gradtype=-1,$bkg_gradstyle=BGRAD_MARGIN; var $bkg_gradfrom='navy', $bkg_gradto='silver'; var $titlebackground = false; var $titlebackground_color = 'lightblue', $titlebackground_style = 1, $titlebackground_framecolor = 'blue', $titlebackground_framestyle = 2, $titlebackground_frameweight = 1, $titlebackground_bevelheight = 3 ; var $titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID; var $titlebkg_scolor1='black',$titlebkg_scolor2='white'; var $framebevel = false, $framebeveldepth = 2 ; var $framebevelborder = false, $framebevelbordercolor='black'; var $framebevelcolor1='white@0.4', $framebevelcolor2='black@0.4'; var $background_image_mix=100; var $background_cflag = ''; var $background_cflag_type = BGIMG_FILLPLOT; var $background_cflag_mix = 100; var $iImgTrans=false, $iImgTransHorizon = 100,$iImgTransSkewDist=150, $iImgTransDirection = 1, $iImgTransMinSize = true, $iImgTransFillColor='white',$iImgTransHighQ=false, $iImgTransBorder=false,$iImgTransHorizonPos=0.5; var $iYAxisDeltaPos=50; var $iIconDepth=DEPTH_BACK; var $iAxisLblBgType = 0, $iXAxisLblBgFillColor = 'lightgray', $iXAxisLblBgColor = 'black', $iYAxisLblBgFillColor = 'lightgray', $iYAxisLblBgColor = 'black'; var $iTables=NULL; //--------------- // CONSTRUCTOR // aWIdth Width in pixels of image // aHeight Height in pixels of image // aCachedName Name for image file in cache directory // aTimeOut Timeout in minutes for image in cache // aInline If true the image is streamed back in the call to Stroke() // If false the image is just created in the cache function Graph($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) { GLOBAL $gJpgBrandTiming; // If timing is used create a new timing object if( $gJpgBrandTiming ) { global $tim; $tim = new JpgTimer(); $tim->Push(); } if( !is_numeric($aWidth) || !is_numeric($aHeight) ) { JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric'); } // Automatically generate the image file name based on the name of the script that // generates the graph if( $aCachedName=="auto" ) $aCachedName=GenImgName(); // Should the image be streamed back to the browser or only to the cache? $this->inline=$aInline; $this->img = new RotImage($aWidth,$aHeight); $this->cache = new ImgStreamCache($this->img); $this->cache->SetTimeOut($aTimeOut); $this->title = new Text(); $this->title->ParagraphAlign('center'); $this->title->SetFont(FF_FONT2,FS_BOLD); $this->title->SetMargin(3); $this->title->SetAlign('center'); $this->subtitle = new Text(); $this->subtitle->ParagraphAlign('center'); $this->subtitle->SetMargin(2); $this->subtitle->SetAlign('center'); $this->subsubtitle = new Text(); $this->subsubtitle->ParagraphAlign('center'); $this->subsubtitle->SetMargin(2); $this->subsubtitle->SetAlign('center'); $this->legend = new Legend(); $this->footer = new Footer(); // Window doesn't like '?' in the file name so replace it with an '_' $aCachedName = str_replace("?","_",$aCachedName); // If the cached version exist just read it directly from the // cache, stream it back to browser and exit if( $aCachedName!="" && READ_CACHE && $aInline ) if( $this->cache->GetAndStream($aCachedName) ) { exit(); } $this->cache_name = $aCachedName; $this->SetTickDensity(); // Normal density $this->tabtitle = new GraphTabTitle(); } //--------------- // PUBLIC METHODS // Enable final image perspective transformation function Set3DPerspective($aDir=1,$aHorizon=100,$aSkewDist=120,$aQuality=false,$aFillColor='#FFFFFF',$aBorder=false,$aMinSize=true,$aHorizonPos=0.5) { $this->iImgTrans = true; $this->iImgTransHorizon = $aHorizon; $this->iImgTransSkewDist= $aSkewDist; $this->iImgTransDirection = $aDir; $this->iImgTransMinSize = $aMinSize; $this->iImgTransFillColor=$aFillColor; $this->iImgTransHighQ=$aQuality; $this->iImgTransBorder=$aBorder; $this->iImgTransHorizonPos=$aHorizonPos; } // Set Image format and optional quality function SetImgFormat($aFormat,$aQuality=75) { $this->img->SetImgFormat($aFormat,$aQuality); } // Should the grid be in front or back of the plot? function SetGridDepth($aDepth) { $this->grid_depth=$aDepth; } function SetIconDepth($aDepth) { $this->iIconDepth=$aDepth; } // Specify graph angle 0-360 degrees. function SetAngle($aAngle) { $this->img->SetAngle($aAngle); } function SetAlphaBlending($aFlg=true) { $this->img->SetAlphaBlending($aFlg); } // Shortcut to image margin function SetMargin($lm,$rm,$tm,$bm) { $this->img->SetMargin($lm,$rm,$tm,$bm); } function SetY2OrderBack($aBack=true) { $this->y2orderback = $aBack; } // Rotate the graph 90 degrees and set the margin // when we have done a 90 degree rotation function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) { $lm = $lm ==0 ? floor(0.2 * $this->img->width) : $lm ; $rm = $rm ==0 ? floor(0.1 * $this->img->width) : $rm ; $tm = $tm ==0 ? floor(0.2 * $this->img->height) : $tm ; $bm = $bm ==0 ? floor(0.1 * $this->img->height) : $bm ; $adj = ($this->img->height - $this->img->width)/2; $this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj); $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2)); $this->SetAngle(90); if( empty($this->yaxis) || empty($this->xaxis) ) { JpgraphError::RaiseL(25009);//('You must specify what scale to use with a call to Graph::SetScale()'); } $this->xaxis->SetLabelAlign('right','center'); $this->yaxis->SetLabelAlign('center','bottom'); } function SetClipping($aFlg=true) { $this->iDoClipping = $aFlg ; } // Add a plot object to the graph function Add(&$aPlot) { if( $aPlot == null ) JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph."); if( is_array($aPlot) && count($aPlot) > 0 ) $cl = $aPlot[0]; else $cl = $aPlot; if( is_a($cl,'Text') ) $this->AddText($aPlot); elseif( is_a($cl,'PlotLine') ) $this->AddLine($aPlot); elseif( is_a($cl,'PlotBand') ) $this->AddBand($aPlot); elseif( is_a($cl,'IconPlot') ) $this->AddIcon($aPlot); elseif( is_a($cl,'GTextTable') ) $this->AddTable($aPlot); else $this->plots[] = &$aPlot; } function AddTable(&$aTable) { if( is_array($aTable) ) { for($i=0; $i < count($aTable); ++$i ) $this->iTables[]=&$aTable[$i]; } else { $this->iTables[] = &$aTable ; } } function AddIcon(&$aIcon) { if( is_array($aIcon) ) { for($i=0; $i < count($aIcon); ++$i ) $this->iIcons[]=&$aIcon[$i]; } else { $this->iIcons[] = &$aIcon ; } } // Add plot to second Y-scale function AddY2(&$aPlot) { if( $aPlot == null ) JpGraphError::RaiseL(25011);//("Graph::AddY2() You tried to add a null plot to the graph."); if( is_array($aPlot) && count($aPlot) > 0 ) $cl = $aPlot[0]; else $cl = $aPlot; if( is_a($cl,'Text') ) $this->AddText($aPlot,true); elseif( is_a($cl,'PlotLine') ) $this->AddLine($aPlot,true); elseif( is_a($cl,'PlotBand') ) $this->AddBand($aPlot,true); else $this->y2plots[] = &$aPlot; } // Add plot to second Y-scale function AddY($aN,&$aPlot) { if( $aPlot == null ) JpGraphError::RaiseL(25012);//("Graph::AddYN() You tried to add a null plot to the graph."); if( is_array($aPlot) && count($aPlot) > 0 ) $cl = $aPlot[0]; else $cl = $aPlot; if( is_a($cl,'Text') || is_a($cl,'PlotLine') || is_a($cl,'PlotBand') ) JpGraph::RaiseL(25013);//('You can only add standard plots to multiple Y-axis'); else $this->ynplots[$aN][] = &$aPlot; } // Add text object to the graph function AddText(&$aTxt,$aToY2=false) { if( $aTxt == null ) JpGraphError::RaiseL(25014);//("Graph::AddText() You tried to add a null text to the graph."); if( $aToY2 ) { if( is_array($aTxt) ) { for($i=0; $i < count($aTxt); ++$i ) $this->y2texts[]=&$aTxt[$i]; } else $this->y2texts[] = &$aTxt; } else { if( is_array($aTxt) ) { for($i=0; $i < count($aTxt); ++$i ) $this->texts[]=&$aTxt[$i]; } else $this->texts[] = &$aTxt; } } // Add a line object (class PlotLine) to the graph function AddLine(&$aLine,$aToY2=false) { if( $aLine == null ) JpGraphError::RaiseL(25015);//("Graph::AddLine() You tried to add a null line to the graph."); if( $aToY2 ) { if( is_array($aLine) ) { for($i=0; $i < count($aLine); ++$i ) $this->y2lines[]=&$aLine[$i]; } else $this->y2lines[] = &$aLine; } else { if( is_array($aLine) ) { for($i=0; $i < count($aLine); ++$i ) $this->lines[]=&$aLine[$i]; } else $this->lines[] = &$aLine; } } // Add vertical or horizontal band function AddBand(&$aBand,$aToY2=false) { if( $aBand == null ) JpGraphError::RaiseL(25016);//(" Graph::AddBand() You tried to add a null band to the graph."); if( $aToY2 ) { if( is_array($aBand) ) { for($i=0; $i < count($aBand); ++$i ) $this->y2bands[] = &$aBand[$i]; } else $this->y2bands[] = &$aBand; } else { if( is_array($aBand) ) { for($i=0; $i < count($aBand); ++$i ) $this->bands[] = &$aBand[$i]; } else $this->bands[] = &$aBand; } } function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=2,$aStyle=BGRAD_FRAME) { $this->bkg_gradtype=$aGradType; $this->bkg_gradstyle=$aStyle; $this->bkg_gradfrom = $aFrom; $this->bkg_gradto = $aTo; } // Set a country flag in the background function SetBackgroundCFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) { $this->background_cflag = $aName; $this->background_cflag_type = $aBgType; $this->background_cflag_mix = $aMix; } // Alias for the above method function SetBackgroundCountryFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) { $this->background_cflag = $aName; $this->background_cflag_type = $aBgType; $this->background_cflag_mix = $aMix; } // Specify a background image function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat="auto") { if( $GLOBALS['gd2'] && !USE_TRUECOLOR ) { JpGraphError::RaiseL(25017);//("You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x you must enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts."); } // Get extension to determine image type if( $aImgFormat == "auto" ) { $e = explode('.',$aFileName); if( !$e ) { JpGraphError::RaiseL(25018,$aFileName);//('Incorrect file name for Graph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type'); } $valid_formats = array('png', 'jpg', 'gif'); $aImgFormat = strtolower($e[count($e)-1]); if ($aImgFormat == 'jpeg') { $aImgFormat = 'jpg'; } elseif (!in_array($aImgFormat, $valid_formats) ) { JpGraphError::RaiseL(25019,$aImgFormat);//('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName); } } $this->background_image = $aFileName; $this->background_image_type=$aBgType; $this->background_image_format=$aImgFormat; } function SetBackgroundImageMix($aMix) { $this->background_image_mix = $aMix ; } // Adjust brightness and constrast for background image function AdjBackgroundImage($aBright,$aContr=0,$aSat=0) { $this->background_image_bright=$aBright; $this->background_image_contr=$aContr; $this->background_image_sat=$aSat; } // Adjust brightness and constrast for image function AdjImage($aBright,$aContr=0,$aSat=0) { $this->image_bright=$aBright; $this->image_contr=$aContr; $this->image_sat=$aSat; } // Specify axis style (boxed or single) function SetAxisStyle($aStyle) { $this->iAxisStyle = $aStyle ; } // Set a frame around the plot area function SetBox($aDrawPlotFrame=true,$aPlotFrameColor=array(0,0,0),$aPlotFrameWeight=1) { $this->boxed = $aDrawPlotFrame; $this->box_weight = $aPlotFrameWeight; $this->box_color = $aPlotFrameColor; } // Specify color for the plotarea (not the margins) function SetColor($aColor) { $this->plotarea_color=$aColor; } // Specify color for the margins (all areas outside the plotarea) function SetMarginColor($aColor) { $this->margin_color=$aColor; } // Set a frame around the entire image function SetFrame($aDrawImgFrame=true,$aImgFrameColor=array(0,0,0),$aImgFrameWeight=1) { $this->doframe = $aDrawImgFrame; $this->frame_color = $aImgFrameColor; $this->frame_weight = $aImgFrameWeight; } function SetFrameBevel($aDepth=3,$aBorder=false,$aBorderColor='black',$aColor1='white@0.4',$aColor2='darkgray@0.4',$aFlg=true) { $this->framebevel = $aFlg ; $this->framebeveldepth = $aDepth ; $this->framebevelborder = $aBorder ; $this->framebevelbordercolor = $aBorderColor ; $this->framebevelcolor1 = $aColor1 ; $this->framebevelcolor2 = $aColor2 ; $this->doshadow = false ; } // Set the shadow around the whole image function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor=array(102,102,102)) { $this->doshadow = $aShowShadow; $this->shadow_color = $aShadowColor; $this->shadow_width = $aShadowWidth; $this->footer->iBottomMargin += $aShadowWidth; $this->footer->iRightMargin += $aShadowWidth; } // Specify x,y scale. Note that if you manually specify the scale // you must also specify the tick distance with a call to Ticks::Set() function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) { $this->axtype = $aAxisType; if( $aYMax < $aYMin || $aXMax < $aXMin ) JpGraphError::RaiseL(25020);//('Graph::SetScale(): Specified Max value must be larger than the specified Min value.'); $yt=substr($aAxisType,-3,3); if( $yt=="lin" ) $this->yscale = new LinearScale($aYMin,$aYMax); elseif( $yt == "int" ) { $this->yscale = new LinearScale($aYMin,$aYMax); $this->yscale->SetIntScale(); } elseif( $yt=="log" ) $this->yscale = new LogScale($aYMin,$aYMax); else JpGraphError::RaiseL(25021,$aAxisType);//("Unknown scale specification for Y-scale. ($aAxisType)"); $xt=substr($aAxisType,0,3); if( $xt == "lin" || $xt == "tex" ) { $this->xscale = new LinearScale($aXMin,$aXMax,"x"); $this->xscale->textscale = ($xt == "tex"); } elseif( $xt == "int" ) { $this->xscale = new LinearScale($aXMin,$aXMax,"x"); $this->xscale->SetIntScale(); } elseif( $xt == "dat" ) { $this->xscale = new DateScale($aXMin,$aXMax,"x"); } elseif( $xt == "log" ) $this->xscale = new LogScale($aXMin,$aXMax,"x"); else JpGraphError::RaiseL(25022,$aAxisType);//(" Unknown scale specification for X-scale. ($aAxisType)"); $this->xaxis = new Axis($this->img,$this->xscale); $this->yaxis = new Axis($this->img,$this->yscale); $this->xgrid = new Grid($this->xaxis); $this->ygrid = new Grid($this->yaxis); $this->ygrid->Show(); } // Specify secondary Y scale function SetY2Scale($aAxisType="lin",$aY2Min=1,$aY2Max=1) { if( $aAxisType=="lin" ) $this->y2scale = new LinearScale($aY2Min,$aY2Max); elseif( $aAxisType == "int" ) { $this->y2scale = new LinearScale($aY2Min,$aY2Max); $this->y2scale->SetIntScale(); } elseif( $aAxisType=="log" ) { $this->y2scale = new LogScale($aY2Min,$aY2Max); } else JpGraphError::RaiseL(25023,$aAxisType);//("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)"); $this->y2axis = new Axis($this->img,$this->y2scale); $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT); $this->y2axis->SetLabelSide(SIDE_RIGHT); $this->y2axis->SetPos('max'); $this->y2axis->SetTitleSide(SIDE_RIGHT); // Deafult position is the max x-value $this->y2grid = new Grid($this->y2axis); } // Set the delta position (in pixels) between the multiple Y-axis function SetYDeltaDist($aDist) { $this->iYAxisDeltaPos = $aDist; } // Specify secondary Y scale function SetYScale($aN,$aAxisType="lin",$aYMin=1,$aYMax=1) { if( $aAxisType=="lin" ) $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax); elseif( $aAxisType == "int" ) { $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax); $this->ynscale[$aN]->SetIntScale(); } elseif( $aAxisType=="log" ) { $this->ynscale[$aN] = new LogScale($aYMin,$aYMax); } else JpGraphError::RaiseL(25024,$aAxisType);//("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)"); $this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]); $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT); $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT); } // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse' // The dividing factor have been determined heuristically according to my aesthetic // sense (or lack off) y.m.m.v ! function SetTickDensity($aYDensity=TICKD_NORMAL,$aXDensity=TICKD_NORMAL) { $this->xtick_factor=30; $this->ytick_factor=25; switch( $aYDensity ) { case TICKD_DENSE: $this->ytick_factor=12; break; case TICKD_NORMAL: $this->ytick_factor=25; break; case TICKD_SPARSE: $this->ytick_factor=40; break; case TICKD_VERYSPARSE: $this->ytick_factor=100; break; default: JpGraphError::RaiseL(25025,$densy);//("JpGraph: Unsupported Tick density: $densy"); } switch( $aXDensity ) { case TICKD_DENSE: $this->xtick_factor=15; break; case TICKD_NORMAL: $this->xtick_factor=30; break; case TICKD_SPARSE: $this->xtick_factor=45; break; case TICKD_VERYSPARSE: $this->xtick_factor=60; break; default: JpGraphError::RaiseL(25025,$densx);//("JpGraph: Unsupported Tick density: $densx"); } } // Get a string of all image map areas function GetCSIMareas() { if( !$this->iHasStroked ) $this->Stroke(_CSIM_SPECIALFILE); $csim = $this->title->GetCSIMAreas(); $csim .= $this->subtitle->GetCSIMAreas(); $csim .= $this->subsubtitle->GetCSIMAreas(); $csim .= $this->legend->GetCSIMAreas(); if( $this->y2axis != NULL ) { $csim .= $this->y2axis->title->GetCSIMAreas(); } if( $this->texts != null ) { $n = count($this->texts); for($i=0; $i < $n; ++$i ) { $csim .= $this->texts[$i]->GetCSIMAreas(); } } if( $this->y2texts != null && $this->y2scale != null ) { $n = count($this->y2texts); for($i=0; $i < $n; ++$i ) { $csim .= $this->y2texts[$i]->GetCSIMAreas(); } } if( $this->yaxis != null && $this->xaxis != null ) { $csim .= $this->yaxis->title->GetCSIMAreas(); $csim .= $this->xaxis->title->GetCSIMAreas(); } $n = count($this->plots); for( $i=0; $i < $n; ++$i ) $csim .= $this->plots[$i]->GetCSIMareas(); $n = count($this->y2plots); for( $i=0; $i < $n; ++$i ) $csim .= $this->y2plots[$i]->GetCSIMareas(); $n = count($this->ynaxis); for( $i=0; $i < $n; ++$i ) { $m = count($this->ynplots[$i]); for($j=0; $j < $m; ++$j ) { $csim .= $this->ynplots[$i][$j]->GetCSIMareas(); } } $n = count($this->iTables); for( $i=0; $i < $n; ++$i ) { $csim .= $this->iTables[$i]->GetCSIMareas(); } return $csim; } // Get a complete .. tag for the final image map function GetHTMLImageMap($aMapName) { //$im = "\n"; $im = "\n"; $im .= $this->GetCSIMareas(); $im .= ""; return $im; } function CheckCSIMCache($aCacheName,$aTimeOut=60) { global $_SERVER; if( $aCacheName=='auto' ) $aCacheName=basename($_SERVER['PHP_SELF']); $this->csimcachename = CSIMCACHE_DIR.$aCacheName; $this->csimcachetimeout = $aTimeOut; // First determine if we need to check for a cached version // This differs from the standard cache in the sense that the // image and CSIM map HTML file is written relative to the directory // the script executes in and not the specified cache directory. // The reason for this is that the cache directory is not necessarily // accessible from the HTTP server. if( $this->csimcachename != '' ) { $dir = dirname($this->csimcachename); $base = basename($this->csimcachename); $base = strtok($base,'.'); $suffix = strtok('.'); $basecsim = $dir.'/'.$base.'_csim_.html'; $baseimg = $dir.'/'.$base.'.'.$this->img->img_format; $timedout=false; // Does it exist at all ? if( file_exists($basecsim) && file_exists($baseimg) ) { // Check that it hasn't timed out $diff=time()-filemtime($basecsim); if( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) { $timedout=true; @unlink($basecsim); @unlink($baseimg); } else { if ($fh = @fopen($basecsim, "r")) { fpassthru($fh); return true; } else JpGraphError::RaiseL(25027,$basecsim);//(" Can't open cached CSIM \"$basecsim\" for reading."); } } } return false; } function StrokeCSIM($aScriptName='auto',$aCSIMName='',$aBorder=0) { if( $aCSIMName=='' ) { // create a random map name srand ((double) microtime() * 1000000); $r = rand(0,100000); $aCSIMName='__mapname'.$r.'__'; } if( $aScriptName=='auto' ) $aScriptName=basename($_SERVER['PHP_SELF']); if( empty($_GET[_CSIM_DISPLAY]) ) { // First determine if we need to check for a cached version // This differs from the standard cache in the sense that the // image and CSIM map HTML file is written relative to the directory // the script executes in and not the specified cache directory. // The reason for this is that the cache directory is not necessarily // accessible from the HTTP server. if( $this->csimcachename != '' ) { $dir = dirname($this->csimcachename); $base = basename($this->csimcachename); $base = strtok($base,'.'); $suffix = strtok('.'); $basecsim = $dir.'/'.$base.'_csim_.html'; $baseimg = $base.'.'.$this->img->img_format; // Check that apache can write to directory specified if( file_exists($dir) && !is_writeable($dir) ) { JpgraphError::RaiseL(25028,$dir);//('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.'); } // Make sure directory exists $this->cache->MakeDirs($dir); // Write the image file $this->Stroke(CSIMCACHE_DIR.$baseimg); // Construct wrapper HTML and write to file and send it back to browser $htmlwrap = $this->GetHTMLImageMap($aCSIMName)."\n". 'title->GetTextHeight($this->img) + $this->title->margin + 5 : 0 ) + ($this->subtitle->t != '' ? $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 : 0 ) + ($this->subsubtitle->t != '' ? $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 : 0 ) ; $btotrequired = 0; if($this->xaxis != null && !$this->xaxis->hide && !$this->xaxis->hide_labels ) { // Minimum bottom margin if( $this->xaxis->title->t != '' ) { if( $this->img->a == 90 ) $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 5 ; else $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 5 ; } else $btotrequired = 0; if( $this->img->a == 90 ) { $this->img->SetFont($this->yaxis->font_family,$this->yaxis->font_style, $this->yaxis->font_size); $lh = $this->img->GetTextHeight('Mg',$this->yaxis->label_angle); } else { $this->img->SetFont($this->xaxis->font_family,$this->xaxis->font_style, $this->xaxis->font_size); $lh = $this->img->GetTextHeight('Mg',$this->xaxis->label_angle); } $btotrequired += $lh + 5; } if( $this->img->a == 90 ) { // DO Nothing. It gets too messy to do this properly for 90 deg... } else{ if( $this->img->top_margin < $totrequired ) { $this->SetMargin($this->img->left_margin,$this->img->right_margin, $totrequired,$this->img->bottom_margin); } if( $this->img->bottom_margin < $btotrequired ) { $this->SetMargin($this->img->left_margin,$this->img->right_margin, $this->img->top_margin,$btotrequired); } } } // Stroke the graph // $aStrokeFileName If != "" the image will be written to this file and NOT // streamed back to the browser function Stroke($aStrokeFileName="") { // Fist make a sanity check that user has specified a scale if( empty($this->yscale) ) { JpGraphError::RaiseL(25031);//('You must specify what scale to use with a call to Graph::SetScale().'); } // Start by adjusting the margin so that potential titles will fit. $this->AdjustMarginsForTitles(); // Setup scale constants if( $this->yscale ) $this->yscale->InitConstants($this->img); if( $this->xscale ) $this->xscale->InitConstants($this->img); if( $this->y2scale ) $this->y2scale->InitConstants($this->img); $n=count($this->ynscale); for($i=0; $i < $n; ++$i) { if( $this->ynscale[$i] ) $this->ynscale[$i]->InitConstants($this->img); } // If the filename is the predefined value = '_csim_special_' // we assume that the call to stroke only needs to do enough // to correctly generate the CSIM maps. // We use this variable to skip things we don't strictly need // to do to generate the image map to improve performance // a best we can. Therefor you will see a lot of tests !$_csim in the // code below. $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); // We need to know if we have stroked the plot in the // GetCSIMareas. Otherwise the CSIM hasn't been generated // and in the case of GetCSIM called before stroke to generate // CSIM without storing an image to disk GetCSIM must call Stroke. $this->iHasStroked = true; // Do any pre-stroke adjustment that is needed by the different plot types // (i.e bar plots want's to add an offset to the x-labels etc) for($i=0; $i < count($this->plots) ; ++$i ) { $this->plots[$i]->PreStrokeAdjust($this); $this->plots[$i]->DoLegend($this); } // Any plots on the second Y scale? if( $this->y2scale != null ) { for($i=0; $iy2plots) ; ++$i ) { $this->y2plots[$i]->PreStrokeAdjust($this); $this->y2plots[$i]->DoLegend($this); } } // Any plots on the extra Y axises? $n = count($this->ynaxis); for($i=0; $i<$n ; ++$i ) { if( $this->ynplots == null || $this->ynplots[$i] == null) { JpGraphError::RaiseL(25032,$i);//("No plots for Y-axis nbr:$i"); } $m = count($this->ynplots[$i]); for($j=0; $j < $m; ++$j ) { $this->ynplots[$i][$j]->PreStrokeAdjust($this); $this->ynplots[$i][$j]->DoLegend($this); } } // Bail out if any of the Y-axis not been specified and // has no plots. (This means it is impossible to do autoscaling and // no other scale was given so we can't possible draw anything). If you use manual // scaling you also have to supply the tick steps as well. if( (!$this->yscale->IsSpecified() && count($this->plots)==0) || ($this->y2scale!=null && !$this->y2scale->IsSpecified() && count($this->y2plots)==0) ) { //$e = "n=".count($this->y2plots)."\n"; // $e = "Can't draw unspecified Y-scale.
\nYou have either:
\n"; // $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots
\n"; // $e .= "2. Specified a scale manually but have forgot to specify the tick steps"; JpGraphError::RaiseL(25026); } // Bail out if no plots and no specified X-scale if( (!$this->xscale->IsSpecified() && count($this->plots)==0 && count($this->y2plots)==0) ) JpGraphError::RaiseL(25034);//("JpGraph: Can't draw unspecified X-scale.
No plots.
"); //Check if we should autoscale y-axis if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) { list($min,$max) = $this->GetPlotsYMinMax($this->plots); $lres = $this->GetLinesYMinMax($this->lines); if( is_array($lres) ) { list($linmin,$linmax) = $lres ; $min = min($min,$linmin); $max = max($max,$linmax); } $tres = $this->GetTextsYMinMax(); if( is_array($tres) ) { list($tmin,$tmax) = $tres ; $min = min($min,$tmin); $max = max($max,$tmax); } $this->yscale->AutoScale($this->img,$min,$max, $this->img->plotheight/$this->ytick_factor); } elseif( $this->yscale->IsSpecified() && ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) { // The tick calculation will use the user suplied min/max values to determine // the ticks. If auto_ticks is false the exact user specifed min and max // values will be used for the scale. // If auto_ticks is true then the scale might be slightly adjusted // so that the min and max values falls on an even major step. $min = $this->yscale->scale[0]; $max = $this->yscale->scale[1]; $this->yscale->AutoScale($this->img,$min,$max, $this->img->plotheight/$this->ytick_factor, $this->yscale->auto_ticks); } if( $this->y2scale != null) { if( !$this->y2scale->IsSpecified() && count($this->y2plots)>0 ) { list($min,$max) = $this->GetPlotsYMinMax($this->y2plots); $lres = $this->GetLinesYMinMax($this->y2lines); if( is_array($lres) ) { list($linmin,$linmax) = $lres ; $min = min($min,$linmin); $max = max($max,$linmax); } $tres = $this->GetTextsYMinMax(true); if( is_array($tres) ) { list($tmin,$tmax) = $tres ; $min = min($min,$tmin); $max = max($max,$tmax); } $this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); } elseif( $this->y2scale->IsSpecified() && ( $this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified()) ) { // The tick calculation will use the user suplied min/max values to determine // the ticks. If auto_ticks is false the exact user specifed min and max // values will be used for the scale. // If auto_ticks is true then the scale might be slightly adjusted // so that the min and max values falls on an even major step. $min = $this->y2scale->scale[0]; $max = $this->y2scale->scale[1]; $this->y2scale->AutoScale($this->img,$min,$max, $this->img->plotheight/$this->ytick_factor, $this->y2scale->auto_ticks); } } // // Autoscale the multiple Y-axis // $n = count($this->ynaxis); for( $i=0; $i < $n; ++$i ) { if( $this->ynscale[$i] != null) { if( !$this->ynscale[$i]->IsSpecified() && count($this->ynplots[$i])>0 ) { list($min,$max) = $this->GetPlotsYMinMax($this->ynplots[$i]); $this->ynscale[$i]->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); } elseif( $this->ynscale[$i]->IsSpecified() && ( $this->ynscale[$i]->auto_ticks || !$this->ynscale[$i]->ticks->IsSpecified()) ) { // The tick calculation will use the user suplied min/max values to determine // the ticks. If auto_ticks is false the exact user specifed min and max // values will be used for the scale. // If auto_ticks is true then the scale might be slightly adjusted // so that the min and max values falls on an even major step. $min = $this->ynscale[$i]->scale[0]; $max = $this->ynscale[$i]->scale[1]; $this->ynscale[$i]->AutoScale($this->img,$min,$max, $this->img->plotheight/$this->ytick_factor, $this->ynscale[$i]->auto_ticks); } } } //Check if we should autoscale x-axis if( !$this->xscale->IsSpecified() ) { if( substr($this->axtype,0,4) == "text" ) { $max=0; $n = count($this->plots); for($i=0; $i < $n; ++$i ) { $p = $this->plots[$i]; // We need some unfortunate sub class knowledge here in order // to increase number of data points in case it is a line plot // which has the barcenter set. If not it could mean that the // last point of the data is outside the scale since the barcenter // settings means that we will shift the entire plot half a tick step // to the right in oder to align with the center of the bars. if( is_a($p,'BarPlot') || empty($p->barcenter)) { $max=max($max,$p->numpoints-1); } else { $max=max($max,$p->numpoints); } } $min=0; if( $this->y2axis != null ) { foreach( $this->y2plots as $p ) { $max=max($max,$p->numpoints-1); } } $n = count($this->ynaxis); for( $i=0; $i < $n; ++$i ) { if( $this->ynaxis[$i] != null) { foreach( $this->ynplots[$i] as $p ) { $max=max($max,$p->numpoints-1); } } } $this->xscale->Update($this->img,$min,$max); $this->xscale->ticks->Set($this->xaxis->tick_step,1); $this->xscale->ticks->SupressMinorTickMarks(); } else { list($min,$max) = $this->GetXMinMax(); $lres = $this->GetLinesXMinMax($this->lines); if( $lres ) { list($linmin,$linmax) = $lres ; $min = min($min,$linmin); $max = max($max,$linmax); } $lres = $this->GetLinesXMinMax($this->y2lines); if( $lres ) { list($linmin,$linmax) = $lres ; $min = min($min,$linmin); $max = max($max,$linmax); } $tres = $this->GetTextsXMinMax(); if( $tres ) { list($tmin,$tmax) = $tres ; $min = min($min,$tmin); $max = max($max,$tmax); } $tres = $this->GetTextsXMinMax(true); if( $tres ) { list($tmin,$tmax) = $tres ; $min = min($min,$tmin); $max = max($max,$tmax); } $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor)); } //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale if( !is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos) ) $this->yaxis->SetPos($this->xscale->GetMinVal()); if( $this->y2axis != null ) { if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) ) $this->y2axis->SetPos($this->xscale->GetMaxVal()); $this->y2axis->SetTitleSide(SIDE_RIGHT); } $n = count($this->ynaxis); $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0; for( $i=0; $i < $n; ++$i ) { if( $this->ynaxis[$i] != null ) { if( !is_numeric($this->ynaxis[$i]->pos) && !is_string($this->ynaxis[$i]->pos) ) { $this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal()); $this->ynaxis[$i]->SetPosAbsDelta($i*$this->iYAxisDeltaPos + $nY2adj); } $this->ynaxis[$i]->SetTitleSide(SIDE_RIGHT); } } } elseif( $this->xscale->IsSpecified() && ( $this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified()) ) { // The tick calculation will use the user suplied min/max values to determine // the ticks. If auto_ticks is false the exact user specifed min and max // values will be used for the scale. // If auto_ticks is true then the scale might be slightly adjusted // so that the min and max values falls on an even major step. $min = $this->xscale->scale[0]; $max = $this->xscale->scale[1]; $this->xscale->AutoScale($this->img,$min,$max, $this->img->plotwidth/$this->xtick_factor, false); if( $this->y2axis != null ) { if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) ) $this->y2axis->SetPos($this->xscale->GetMaxVal()); $this->y2axis->SetTitleSide(SIDE_RIGHT); } } // If we have a negative values and x-axis position is at 0 // we need to supress the first and possible the last tick since // they will be drawn on top of the y-axis (and possible y2 axis) // The test below might seem strange the reasone being that if // the user hasn't specified a value for position this will not // be set until we do the stroke for the axis so as of now it // is undefined. // For X-text scale we ignore all this since the tick are usually // much further in and not close to the Y-axis. Hence the test // for 'text' if( ($this->yaxis->pos==$this->xscale->GetMinVal() || (is_string($this->yaxis->pos) && $this->yaxis->pos=='min')) && !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 && substr($this->axtype,0,4) != 'text' && $this->xaxis->pos!="min" ) { //$this->yscale->ticks->SupressZeroLabel(false); $this->xscale->ticks->SupressFirst(); if( $this->y2axis != null ) { $this->xscale->ticks->SupressLast(); } } elseif( !is_numeric($this->yaxis->pos) && $this->yaxis->pos=='max' ) { $this->xscale->ticks->SupressLast(); } if( !$_csim ) { $this->StrokePlotArea(); if( $this->iIconDepth == DEPTH_BACK ) { $this->StrokeIcons(); } } $this->StrokeAxis(); // Stroke bands if( $this->bands != null && !$_csim) for($i=0; $i < count($this->bands); ++$i) { // Stroke all bands that asks to be in the background if( $this->bands[$i]->depth == DEPTH_BACK ) $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale); } if( $this->y2bands != null && $this->y2scale != null && !$_csim ) for($i=0; $i < count($this->y2bands); ++$i) { // Stroke all bands that asks to be in the foreground if( $this->y2bands[$i]->depth == DEPTH_BACK ) $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale); } if( $this->grid_depth == DEPTH_BACK && !$_csim) { $this->ygrid->Stroke(); $this->xgrid->Stroke(); } // Stroke Y2-axis if( $this->y2axis != null && !$_csim) { $this->y2axis->Stroke($this->xscale); $this->y2grid->Stroke(); } // Stroke yn-axis $n = count($this->ynaxis); for( $i=0; $i < $n; ++$i ) { $this->ynaxis[$i]->Stroke($this->xscale); } $oldoff=$this->xscale->off; if(substr($this->axtype,0,4)=="text") { if( $this->text_scale_abscenteroff > -1 ) { // For a text scale the scale factor is the number of pixel per step. // Hence we can use the scale factor as a substitute for number of pixels // per major scale step and use that in order to adjust the offset so that // an object of width "abscenteroff" becomes centered. $this->xscale->off += round($this->xscale->scale_factor/2)-round($this->text_scale_abscenteroff/2); } else { $this->xscale->off += ceil($this->xscale->scale_factor*$this->text_scale_off*$this->xscale->ticks->minor_step); } } if( $this->iDoClipping ) { $oldimage = $this->img->CloneCanvasH(); } if( ! $this->y2orderback ) { // Stroke all plots for Y axis for($i=0; $i < count($this->plots); ++$i) { $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); $this->plots[$i]->StrokeMargin($this->img); } } // Stroke all plots for Y2 axis if( $this->y2scale != null ) for($i=0; $i< count($this->y2plots); ++$i ) { $this->y2plots[$i]->Stroke($this->img,$this->xscale,$this->y2scale); } if( $this->y2orderback ) { // Stroke all plots for Y1 axis for($i=0; $i < count($this->plots); ++$i) { $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); $this->plots[$i]->StrokeMargin($this->img); } } $n = count($this->ynaxis); for( $i=0; $i < $n; ++$i ) { $m = count($this->ynplots[$i]); for( $j=0; $j < $m; ++$j ) { $this->ynplots[$i][$j]->Stroke($this->img,$this->xscale,$this->ynscale[$i]); $this->ynplots[$i][$j]->StrokeMargin($this->img); } } if( $this->iIconDepth == DEPTH_FRONT) { $this->StrokeIcons(); } if( $this->iDoClipping ) { // Clipping only supports graphs at 0 and 90 degrees if( $this->img->a == 0 ) { $this->img->CopyCanvasH($oldimage,$this->img->img, $this->img->left_margin,$this->img->top_margin, $this->img->left_margin,$this->img->top_margin, $this->img->plotwidth+1,$this->img->plotheight); } elseif( $this->img->a == 90 ) { $adj = ($this->img->height - $this->img->width)/2; $this->img->CopyCanvasH($oldimage,$this->img->img, $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, $this->img->plotheight+1,$this->img->plotwidth); } else { JpGraphError::RaiseL(25035,$this->img->a);//('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.'); } $this->img->Destroy(); $this->img->SetCanvasH($oldimage); } $this->xscale->off=$oldoff; if( $this->grid_depth == DEPTH_FRONT && !$_csim ) { $this->ygrid->Stroke(); $this->xgrid->Stroke(); } // Stroke bands if( $this->bands!= null ) for($i=0; $i < count($this->bands); ++$i) { // Stroke all bands that asks to be in the foreground if( $this->bands[$i]->depth == DEPTH_FRONT ) $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale); } if( $this->y2bands!= null && $this->y2scale != null ) for($i=0; $i < count($this->y2bands); ++$i) { // Stroke all bands that asks to be in the foreground if( $this->y2bands[$i]->depth == DEPTH_FRONT ) $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale); } // Stroke any lines added if( $this->lines != null ) { for($i=0; $i < count($this->lines); ++$i) { $this->lines[$i]->Stroke($this->img,$this->xscale,$this->yscale); } } if( $this->y2lines != null && $this->y2scale != null ) { for($i=0; $i < count($this->y2lines); ++$i) { $this->y2lines[$i]->Stroke($this->img,$this->xscale,$this->y2scale); } } // Finally draw the axis again since some plots may have nagged // the axis in the edges.However we do no stroke the labels again // since any user defined callback would be called twice. It also // enhances performance. if( !$_csim ) $this->StrokeAxis(false); if( $this->y2scale != null && !$_csim ) $this->y2axis->Stroke($this->xscale,false); if( !$_csim ) { $this->StrokePlotBox(); } // The titles and legends never gets rotated so make sure // that the angle is 0 before stroking them $aa = $this->img->SetAngle(0); $this->StrokeTitles(); $this->footer->Stroke($this->img); $this->legend->Stroke($this->img); $this->img->SetAngle($aa); $this->StrokeTexts(); $this->StrokeTables(); if( !$_csim ) { $this->img->SetAngle($aa); // Draw an outline around the image map if(_JPG_DEBUG) { $this->DisplayClientSideaImageMapAreas(); } // Adjust the appearance of the image $this->AdjustSaturationBrightnessContrast(); // Should we do any final image transformation if( $this->iImgTrans ) { if( !class_exists('ImgTrans') ) { require_once('jpgraph_imgtrans.php'); //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.'); } $tform = new ImgTrans($this->img->img); $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, $this->iImgTransDirection,$this->iImgTransHighQ, $this->iImgTransMinSize,$this->iImgTransFillColor, $this->iImgTransBorder); } // If the filename is given as the special "__handle" // then the image handler is returned and the image is NOT // streamed back if( $aStrokeFileName == _IMG_HANDLER ) { return $this->img->img; } else { // Finally stream the generated picture $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); } } } function SetAxisLabelBackground($aType,$aXFColor='lightgray',$aXColor='black',$aYFColor='lightgray',$aYColor='black') { $this->iAxisLblBgType = $aType; $this->iXAxisLblBgFillColor = $aXFColor; $this->iXAxisLblBgColor = $aXColor; $this->iYAxisLblBgFillColor = $aYFColor; $this->iYAxisLblBgColor = $aYColor; } //--------------- // PRIVATE METHODS function StrokeAxisLabelBackground() { // Types // 0 = No background // 1 = Only X-labels, length of axis // 2 = Only Y-labels, length of axis // 3 = As 1 but extends to width of graph // 4 = As 2 but extends to height of graph // 5 = Combination of 3 & 4 // 6 = Combination of 1 & 2 $t = $this->iAxisLblBgType ; if( $t < 1 ) return; // Stroke optional X-axis label background color if( $t == 1 || $t == 3 || $t == 5 || $t == 6 ) { $this->img->PushColor($this->iXAxisLblBgFillColor); if( $t == 1 || $t == 6 ) { $xl = $this->img->left_margin; $yu = $this->img->height - $this->img->bottom_margin + 1; $xr = $this->img->width - $this->img->right_margin ; $yl = $this->img->height-1-$this->frame_weight; } else { // t==3 || t==5 $xl = $this->frame_weight; $yu = $this->img->height - $this->img->bottom_margin + 1; $xr = $this->img->width - 1 - $this->frame_weight; $yl = $this->img->height-1-$this->frame_weight; } $this->img->FilledRectangle($xl,$yu,$xr,$yl); $this->img->PopColor(); // Check if we should add the vertical lines at left and right edge if( $this->iXAxisLblBgColor !== '' ) { $this->img->PushColor($this->iXAxisLblBgColor); if( $t == 1 || $t == 6 ) { $this->img->Line($xl,$yu,$xl,$yl); $this->img->Line($xr,$yu,$xr,$yl); } else { $xl = $this->img->width - $this->img->right_margin ; $this->img->Line($xl,$yu-1,$xr,$yu-1); } $this->img->PopColor(); } } if( $t == 2 || $t == 4 || $t == 5 || $t == 6 ) { $this->img->PushColor($this->iYAxisLblBgFillColor); if( $t == 2 || $t == 6 ) { $xl = $this->frame_weight; $yu = $this->frame_weight+$this->img->top_margin; $xr = $this->img->left_margin - 1; $yl = $this->img->height - $this->img->bottom_margin + 1; } else { $xl = $this->frame_weight; $yu = $this->frame_weight; $xr = $this->img->left_margin - 1; $yl = $this->img->height-1-$this->frame_weight; } $this->img->FilledRectangle($xl,$yu,$xr,$yl); $this->img->PopColor(); // Check if we should add the vertical lines at left and right edge if( $this->iXAxisLblBgColor !== '' ) { $this->img->PushColor($this->iXAxisLblBgColor); if( $t == 2 || $t == 6 ) { $this->img->Line($xl,$yu-1,$xr,$yu-1); $this->img->Line($xl,$yl-1,$xr,$yl-1); } else { $this->img->Line($xr+1,$yu,$xr+1,$this->img->top_margin); } $this->img->PopColor(); } } } function StrokeAxis($aStrokeLabels=true) { if( $aStrokeLabels ) { $this->StrokeAxisLabelBackground(); } // Stroke axis if( $this->iAxisStyle != AXSTYLE_SIMPLE ) { switch( $this->iAxisStyle ) { case AXSTYLE_BOXIN : $toppos = SIDE_DOWN; $bottompos = SIDE_UP; $leftpos = SIDE_RIGHT; $rightpos = SIDE_LEFT; break; case AXSTYLE_BOXOUT : $toppos = SIDE_UP; $bottompos = SIDE_DOWN; $leftpos = SIDE_LEFT; $rightpos = SIDE_RIGHT; break; case AXSTYLE_YBOXIN: $toppos = -100; $bottompos = SIDE_UP; $leftpos = SIDE_RIGHT; $rightpos = SIDE_LEFT; break; case AXSTYLE_YBOXOUT: $toppos = -100; $bottompos = SIDE_DOWN; $leftpos = SIDE_LEFT; $rightpos = SIDE_RIGHT; break; default: JpGRaphError::RaiseL(25036,$this->iAxisStyle); //('Unknown AxisStyle() : '.$this->iAxisStyle); break; } $this->xaxis->SetPos('min'); // By default we hide the first label so it doesn't cross the // Y-axis in case the positon hasn't been set by the user. // However, if we use a box we always want the first value // displayed so we make sure it will be displayed. $this->xscale->ticks->SupressFirst(false); $this->xaxis->SetLabelSide(SIDE_DOWN); $this->xaxis->scale->ticks->SetSide($bottompos); $this->xaxis->Stroke($this->yscale); if( $toppos != -100 ) { // To avoid side effects we work on a new copy $maxis = $this->xaxis; $maxis->SetPos('max'); $maxis->SetLabelSide(SIDE_UP); $maxis->SetLabelMargin(7); $this->xaxis->scale->ticks->SetSide($toppos); $maxis->Stroke($this->yscale); } $this->yaxis->SetPos('min'); $this->yaxis->SetLabelMargin(10); $this->yaxis->SetLabelSide(SIDE_LEFT); $this->yaxis->scale->ticks->SetSide($leftpos); $this->yaxis->Stroke($this->xscale); $myaxis = $this->yaxis; $myaxis->SetPos('max'); $myaxis->SetLabelMargin(10); $myaxis->SetLabelSide(SIDE_RIGHT); $myaxis->title->Set(''); $myaxis->scale->ticks->SetSide($rightpos); $myaxis->Stroke($this->xscale); } else { $this->xaxis->Stroke($this->yscale,$aStrokeLabels); $this->yaxis->Stroke($this->xscale,$aStrokeLabels); } } // Private helper function for backgound image function LoadBkgImage($aImgFormat='',$aFile='',$aImgStr='') { if( $aImgStr != '' ) { return Image::CreateFromString($aImgStr); } if( $aFile == '' ) $aFile = $this->background_image; // Remove case sensitivity and setup appropriate function to create image // Get file extension. This should be the LAST '.' separated part of the filename $e = explode('.',$aFile); $ext = strtolower($e[count($e)-1]); if ($ext == "jpeg") { $ext = "jpg"; } if( trim($ext) == '' ) $ext = 'png'; // Assume PNG if no extension specified if( $aImgFormat == '' ) $imgtag = $ext; else $imgtag = $aImgFormat; $supported = imagetypes(); if( ( $ext == 'jpg' && !($supported & IMG_JPG) ) || ( $ext == 'gif' && !($supported & IMG_GIF) ) || ( $ext == 'png' && !($supported & IMG_PNG) ) ) { JpGraphError::RaiseL(25037,$aFile);//('The image format of your background image ('.$aFile.') is not supported in your system configuration. '); } if( $imgtag == "jpg" || $imgtag == "jpeg") { $f = "imagecreatefromjpeg"; $imgtag = "jpg"; } else { $f = "imagecreatefrom".$imgtag; } // Compare specified image type and file extension if( $imgtag != $ext ) { //$t = "Background image seems to be of different type (has different file extension) than specified imagetype. Specified: '".$aImgFormat."'File: '".$aFile."'"; JpGraphError::RaiseL(25038, $aImgFormat, $aFile); } $img = @$f($aFile); if( !$img ) { JpGraphError::RaiseL(25039,$aFile);//(" Can't read background image: '".$aFile."'"); } return $img; } function StrokeBackgroundGrad() { if( $this->bkg_gradtype < 0 ) return; $grad = new Gradient($this->img); if( $this->bkg_gradstyle == BGRAD_PLOT ) { $xl = $this->img->left_margin; $yt = $this->img->top_margin; $xr = $xl + $this->img->plotwidth+1 ; $yb = $yt + $this->img->plotheight ; $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype); } else { $xl = 0; $yt = 0; $xr = $xl + $this->img->width - 1; $yb = $yt + $this->img->height; if( $this->doshadow ) { $xr -= $this->shadow_width; $yb -= $this->shadow_width; } if( $this->doframe ) { $yt += $this->frame_weight; $yb -= $this->frame_weight; $xl += $this->frame_weight; $xr -= $this->frame_weight; } $aa = $this->img->SetAngle(0); $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype); $aa = $this->img->SetAngle($aa); } } function StrokeFrameBackground() { if( $this->background_image != "" && $this->background_cflag != "" ) { JpGraphError::RaiseL(25040);//('It is not possible to specify both a background image and a background country flag.'); } if( $this->background_image != "" ) { $bkgimg = $this->LoadBkgImage($this->background_image_format); $this->img->_AdjBrightContrast($bkgimg,$this->background_image_bright, $this->background_image_contr); $this->img->_AdjSat($bkgimg,$this->background_image_sat); } elseif( $this->background_cflag != "" ) { if( ! class_exists('FlagImages') ) { JpGraphError::RaiseL(25041);//('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.'); } $fobj = new FlagImages(FLAGSIZE4); $dummy=''; $bkgimg = $fobj->GetImgByName($this->background_cflag,$dummy); $this->background_image_mix = $this->background_cflag_mix; $this->background_image_type = $this->background_cflag_type; } else { return ; } $bw = ImageSX($bkgimg); $bh = ImageSY($bkgimg); // No matter what the angle is we always stroke the image and frame // assuming it is 0 degree $aa = $this->img->SetAngle(0); switch( $this->background_image_type ) { case BGIMG_FILLPLOT: // Resize to just fill the plotarea $this->FillMarginArea(); $this->StrokeFrame(); $this->FillPlotArea(); $this->img->CopyMerge($bkgimg, $this->img->left_margin,$this->img->top_margin, 0,0,$this->img->plotwidth+1,$this->img->plotheight, $bw,$bh,$this->background_image_mix); break; case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit $hadj=0; $vadj=0; if( $this->doshadow ) { $hadj = $this->shadow_width; $vadj = $this->shadow_width; } $this->FillMarginArea(); $this->FillPlotArea(); $this->img->CopyMerge($bkgimg,0,0,0,0,$this->img->width-$hadj,$this->img->height-$vadj, $bw,$bh,$this->background_image_mix); $this->StrokeFrame(); break; case BGIMG_COPY: // Just copy the image from left corner, no resizing $this->FillMarginArea(); $this->FillPlotArea(); $this->img->CopyMerge($bkgimg,0,0,0,0,$bw,$bh, $bw,$bh,$this->background_image_mix); $this->StrokeFrame(); break; case BGIMG_CENTER: // Center original image in the plot area $this->FillMarginArea(); $this->FillPlotArea(); $centerx = round($this->img->plotwidth/2+$this->img->left_margin-$bw/2); $centery = round($this->img->plotheight/2+$this->img->top_margin-$bh/2); $this->img->CopyMerge($bkgimg,$centerx,$centery,0,0,$bw,$bh, $bw,$bh,$this->background_image_mix); $this->StrokeFrame(); break; default: JpGraphError::RaiseL(25042);//(" Unknown background image layout"); } $this->img->SetAngle($aa); } // Private // Draw a frame around the image function StrokeFrame() { if( !$this->doframe ) return; if( $this->background_image_type <= 1 && ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_PLOT)) ) { $c = $this->margin_color; } else { $c = false; } if( $this->doshadow ) { $this->img->SetColor($this->frame_color); $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height, $c,$this->shadow_width,$this->shadow_color); } elseif( $this->framebevel ) { if( $c ) { $this->img->SetColor($this->margin_color); $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); } $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2, $this->framebeveldepth, $this->framebevelcolor1,$this->framebevelcolor2); if( $this->framebevelborder ) { $this->img->SetColor($this->framebevelbordercolor); $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); } } else { $this->img->SetLineWeight($this->frame_weight); if( $c ) { $this->img->SetColor($this->margin_color); $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); } $this->img->SetColor($this->frame_color); $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); } } function FillMarginArea() { $hadj=0; $vadj=0; if( $this->doshadow ) { $hadj = $this->shadow_width; $vadj = $this->shadow_width; } $this->img->SetColor($this->margin_color); // $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->height-1-$vadj); $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->top_margin); $this->img->FilledRectangle(0,$this->img->top_margin,$this->img->left_margin,$this->img->height-1-$hadj); $this->img->FilledRectangle($this->img->left_margin+1, $this->img->height-$this->img->bottom_margin, $this->img->width-1-$hadj, $this->img->height-1-$hadj); $this->img->FilledRectangle($this->img->width-$this->img->right_margin, $this->img->top_margin+1, $this->img->width-1-$hadj, $this->img->height-$this->img->bottom_margin-1); } function FillPlotArea() { $this->img->PushColor($this->plotarea_color); $this->img->FilledRectangle($this->img->left_margin, $this->img->top_margin, $this->img->width-$this->img->right_margin, $this->img->height-$this->img->bottom_margin); $this->img->PopColor(); } // Stroke the plot area with either a solid color or a background image function StrokePlotArea() { // Note: To be consistent we really should take a possible shadow // into account. However, that causes some problem for the LinearScale class // since in the current design it does not have any links to class Graph which // means it has no way of compensating for the adjusted plotarea in case of a // shadow. So, until I redesign LinearScale we can't compensate for this. // So just set the two adjustment parameters to zero for now. $boxadj = 0; //$this->doframe ? $this->frame_weight : 0 ; $adj = 0; //$this->doshadow ? $this->shadow_width : 0 ; if( $this->background_image != "" || $this->background_cflag != "" ) { $this->StrokeFrameBackground(); } else { $aa = $this->img->SetAngle(0); $this->StrokeFrame(); $aa = $this->img->SetAngle($aa); $this->StrokeBackgroundGrad(); if( $this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_MARGIN) ) { $this->FillPlotArea(); } } } function StrokeIcons() { $n = count($this->iIcons); for( $i=0; $i < $n; ++$i ) { $this->iIcons[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); } } function StrokePlotBox() { // Should we draw a box around the plot area? if( $this->boxed ) { $this->img->SetLineWeight(1); $this->img->SetLineStyle('solid'); $this->img->SetColor($this->box_color); for($i=0; $i < $this->box_weight; ++$i ) { $this->img->Rectangle( $this->img->left_margin-$i,$this->img->top_margin-$i, $this->img->width-$this->img->right_margin+$i, $this->img->height-$this->img->bottom_margin+$i); } } } function SetTitleBackgroundFillStyle($aStyle,$aColor1='black',$aColor2='white') { $this->titlebkg_fillstyle = $aStyle; $this->titlebkg_scolor1 = $aColor1; $this->titlebkg_scolor2 = $aColor2; } function SetTitleBackground($aBackColor='gray', $aStyle=TITLEBKG_STYLE1, $aFrameStyle=TITLEBKG_FRAME_NONE, $aFrameColor='black', $aFrameWeight=1, $aBevelHeight=3, $aEnable=true) { $this->titlebackground = $aEnable; $this->titlebackground_color = $aBackColor; $this->titlebackground_style = $aStyle; $this->titlebackground_framecolor = $aFrameColor; $this->titlebackground_framestyle = $aFrameStyle; $this->titlebackground_frameweight = $aFrameWeight; $this->titlebackground_bevelheight = $aBevelHeight ; } function StrokeTitles() { $margin=3; if( $this->titlebackground ) { // Find out height $this->title->margin += 2 ; $h = $this->title->GetTextHeight($this->img)+$this->title->margin+$margin; if( $this->subtitle->t != "" && !$this->subtitle->hide ) { $h += $this->subtitle->GetTextHeight($this->img)+$margin+ $this->subtitle->margin; $h += 2; } if( $this->subsubtitle->t != "" && !$this->subsubtitle->hide ) { $h += $this->subsubtitle->GetTextHeight($this->img)+$margin+ $this->subsubtitle->margin; $h += 2; } $this->img->PushColor($this->titlebackground_color); if( $this->titlebackground_style === TITLEBKG_STYLE1 ) { // Inside the frame if( $this->framebevel ) { $x1 = $y1 = $this->framebeveldepth + 1 ; $x2 = $this->img->width - $this->framebeveldepth - 2 ; $this->title->margin += $this->framebeveldepth + 1 ; $h += $y1 ; $h += 2; } else { $x1 = $y1 = $this->frame_weight; $x2 = $this->img->width - 2*$x1; } } elseif( $this->titlebackground_style === TITLEBKG_STYLE2 ) { // Cover the frame as well $x1 = $y1 = 0; $x2 = $this->img->width - 1 ; } elseif( $this->titlebackground_style === TITLEBKG_STYLE3 ) { // Cover the frame as well (the difference is that // for style==3 a bevel frame border is on top // of the title background) $x1 = $y1 = 0; $x2 = $this->img->width - 1 ; $h += $this->framebeveldepth ; $this->title->margin += $this->framebeveldepth ; } else { JpGraphError::RaiseL(25043);//('Unknown title background style.'); } if( $this->titlebackground_framestyle === 3 ) { $h += $this->titlebackground_bevelheight*2 + 1 ; $this->title->margin += $this->titlebackground_bevelheight ; } if( $this->doshadow ) { $x2 -= $this->shadow_width ; } $indent=0; if( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) { $ind = $this->titlebackground_bevelheight; } if( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_HSTRIPED ) { $this->img->FilledRectangle2($x1+$ind,$y1+$ind,$x2-$ind,$h-$ind, $this->titlebkg_scolor1, $this->titlebkg_scolor2); } elseif( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_VSTRIPED ) { $this->img->FilledRectangle2($x1+$ind,$y1+$ind,$x2-$ind,$h-$ind, $this->titlebkg_scolor1, $this->titlebkg_scolor2,2); } else { // Solid fill $this->img->FilledRectangle($x1,$y1,$x2,$h); } $this->img->PopColor(); $this->img->PushColor($this->titlebackground_framecolor); $this->img->SetLineWeight($this->titlebackground_frameweight); if( $this->titlebackground_framestyle == TITLEBKG_FRAME_FULL ) { // Frame background $this->img->Rectangle($x1,$y1,$x2,$h); } elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM ) { // Bottom line only $this->img->Line($x1,$h,$x2,$h); } elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) { $this->img->Bevel($x1,$y1,$x2,$h,$this->titlebackground_bevelheight); } $this->img->PopColor(); // This is clumsy. But we neeed to stroke the whole graph frame if it is // set to bevel to get the bevel shading on top of the text background if( $this->framebevel && $this->doframe && $this->titlebackground_style === 3 ) { $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2, $this->framebeveldepth, $this->framebevelcolor1,$this->framebevelcolor2); if( $this->framebevelborder ) { $this->img->SetColor($this->framebevelbordercolor); $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); } } } // Stroke title $y = $this->title->margin; if( $this->title->halign == 'center' ) $this->title->Center(0,$this->img->width,$y); elseif( $this->title->halign == 'left' ) { $this->title->SetPos($this->title->margin+2,$y); } elseif( $this->title->halign == 'right' ) { $indent = 0; if( $this->doshadow ) $indent = $this->shadow_width+2; $this->title->SetPos($this->img->width-$this->title->margin-$indent,$y,'right'); } $this->title->Stroke($this->img); // ... and subtitle $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin; if( $this->subtitle->halign == 'center' ) $this->subtitle->Center(0,$this->img->width,$y); elseif( $this->subtitle->halign == 'left' ) { $this->subtitle->SetPos($this->subtitle->margin+2,$y); } elseif( $this->subtitle->halign == 'right' ) { $indent = 0; if( $this->doshadow ) $indent = $this->shadow_width+2; $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right'); } $this->subtitle->Stroke($this->img); // ... and subsubtitle $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin; if( $this->subsubtitle->halign == 'center' ) $this->subsubtitle->Center(0,$this->img->width,$y); elseif( $this->subsubtitle->halign == 'left' ) { $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y); } elseif( $this->subsubtitle->halign == 'right' ) { $indent = 0; if( $this->doshadow ) $indent = $this->shadow_width+2; $this->subsubtitle->SetPos($this->img->width-$this->subsubtitle->margin-$indent,$y,'right'); } $this->subsubtitle->Stroke($this->img); // ... and fancy title $this->tabtitle->Stroke($this->img); } function StrokeTexts() { // Stroke any user added text objects if( $this->texts != null ) { for($i=0; $i < count($this->texts); ++$i) { $this->texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); } } if( $this->y2texts != null && $this->y2scale != null ) { for($i=0; $i < count($this->y2texts); ++$i) { $this->y2texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->y2scale); } } } function StrokeTables() { if( $this->iTables != null ) { $n = count($this->iTables); for( $i=0; $i < $n; ++$i ) { $this->iTables[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); } } } function DisplayClientSideaImageMapAreas() { // Debug stuff - display the outline of the image map areas $csim=''; foreach ($this->plots as $p) { $csim.= $p->GetCSIMareas(); } $csim .= $this->legend->GetCSIMareas(); if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) { $this->img->SetColor($this->csimcolor); $n = count($coords[0]); for ($i=0; $i < $n; $i++) { if ($coords[1][$i]=="poly") { preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts); $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]); $m = count($pts[0]); for ($j=0; $j < $m; $j++) { $this->img->LineTo($pts[1][$j],$pts[2][$j]); } } else if ($coords[1][$i]=="rect") { $pts = preg_split('/,/', $coords[2][$i]); $this->img->SetStartPoint($pts[0],$pts[1]); $this->img->LineTo($pts[2],$pts[1]); $this->img->LineTo($pts[2],$pts[3]); $this->img->LineTo($pts[0],$pts[3]); $this->img->LineTo($pts[0],$pts[1]); } } } } function AdjustSaturationBrightnessContrast() { // Adjust the brightness and contrast of the image if( $this->image_contr || $this->image_bright ) $this->img->AdjBrightContrast($this->image_bright,$this->image_contr); if( $this->image_sat ) $this->img->AdjSat($this->image_sat); } // Text scale offset in fractions of a major scale step function SetTextScaleOff($aOff) { $this->text_scale_off = $aOff; $this->xscale->text_scale_off = $aOff; } // Text width of bar to be centered in absolute pixels function SetTextScaleAbsCenterOff($aOff) { $this->text_scale_abscenteroff = $aOff; } // Get Y min and max values for added lines function GetLinesYMinMax( $aLines ) { $n = count($aLines); if( $n == 0 ) return false; $min = $aLines[0]->scaleposition ; $max = $min ; $flg = false; for( $i=0; $i < $n; ++$i ) { if( $aLines[$i]->direction == HORIZONTAL ) { $flg = true ; $v = $aLines[$i]->scaleposition ; if( $min > $v ) $min = $v ; if( $max < $v ) $max = $v ; } } return $flg ? array($min,$max) : false ; } // Get X min and max values for added lines function GetLinesXMinMax( $aLines ) { $n = count($aLines); if( $n == 0 ) return false ; $min = $aLines[0]->scaleposition ; $max = $min ; $flg = false; for( $i=0; $i < $n; ++$i ) { if( $aLines[$i]->direction == VERTICAL ) { $flg = true ; $v = $aLines[$i]->scaleposition ; if( $min > $v ) $min = $v ; if( $max < $v ) $max = $v ; } } return $flg ? array($min,$max) : false ; } // Get min and max values for all included plots function GetPlotsYMinMax(&$aPlots) { $n = count($aPlots); $i=0; do { list($xmax,$max) = $aPlots[$i]->Max(); } while( ++$i < $n && !is_numeric($max) ); $i=0; do { list($xmin,$min) = $aPlots[$i]->Min(); } while( ++$i < $n && !is_numeric($min) ); if( !is_numeric($min) || !is_numeric($max) ) { JpGraphError::RaiseL(25044);//('Cannot use autoscaling since it is impossible to determine a valid min/max value of the Y-axis (only null values).'); } list($xmax,$max) = $aPlots[0]->Max(); list($xmin,$min) = $aPlots[0]->Min(); for($i=0; $i < count($aPlots); ++$i ) { list($xmax,$ymax)=$aPlots[$i]->Max(); list($xmin,$ymin)=$aPlots[$i]->Min(); if (is_numeric($ymax)) $max=max($max,$ymax); if (is_numeric($ymin)) $min=min($min,$ymin); } if( $min == '' ) $min = 0; if( $max == '' ) $max = 0; if( $min == 0 && $max == 0 ) { // Special case if all values are 0 $min=0;$max=1; } return array($min,$max); } } // Class //=================================================== // CLASS TTF // Description: Handle TTF font names //=================================================== class TTF { var $font_files,$style_names; //--------------- // CONSTRUCTOR function TTF() { $this->style_names=array(FS_NORMAL=>'normal',FS_BOLD=>'bold',FS_ITALIC=>'italic',FS_BOLDITALIC=>'bolditalic'); // File names for available fonts $this->font_files=array( FF_COURIER => array(FS_NORMAL=>'cour.ttf', FS_BOLD=>'courbd.ttf', FS_ITALIC=>'couri.ttf', FS_BOLDITALIC=>'courbi.ttf' ), FF_GEORGIA => array(FS_NORMAL=>'georgia.ttf', FS_BOLD=>'georgiab.ttf', FS_ITALIC=>'georgiai.ttf', FS_BOLDITALIC=>'' ), FF_TREBUCHE =>array(FS_NORMAL=>'trebuc.ttf', FS_BOLD=>'trebucbd.ttf', FS_ITALIC=>'trebucit.ttf', FS_BOLDITALIC=>'trebucbi.ttf' ), FF_VERDANA => array(FS_NORMAL=>'verdana.ttf', FS_BOLD=>'verdanab.ttf', FS_ITALIC=>'verdanai.ttf', FS_BOLDITALIC=>'' ), FF_TIMES => array(FS_NORMAL=>'times.ttf', FS_BOLD=>'timesbd.ttf', FS_ITALIC=>'timesi.ttf', FS_BOLDITALIC=>'timesbi.ttf' ), FF_COMIC => array(FS_NORMAL=>'comic.ttf', FS_BOLD=>'comicbd.ttf', FS_ITALIC=>'', FS_BOLDITALIC=>'' ), FF_ARIAL => array(FS_NORMAL=>'arial.ttf', FS_BOLD=>'arialbd.ttf', FS_ITALIC=>'ariali.ttf', FS_BOLDITALIC=>'arialbi.ttf' ) , FF_VERA => array(FS_NORMAL=>'Vera.ttf', FS_BOLD=>'VeraBd.ttf', FS_ITALIC=>'VeraIt.ttf', FS_BOLDITALIC=>'VeraBI.ttf' ), FF_VERAMONO => array(FS_NORMAL=>'VeraMono.ttf', FS_BOLD=>'VeraMoBd.ttf', FS_ITALIC=>'VeraMoIt.ttf', FS_BOLDITALIC=>'VeraMoBI.ttf' ), FF_VERASERIF => array(FS_NORMAL=>'VeraSe.ttf', FS_BOLD=>'VeraSeBd.ttf', FS_ITALIC=>'', FS_BOLDITALIC=>'' ) , FF_SIMSUN => array(FS_NORMAL=>'simsun.ttc', FS_BOLD=>'simhei.ttf', FS_ITALIC=>'', FS_BOLDITALIC=>'' ), FF_CHINESE => array(FS_NORMAL=>CHINESE_TTF_FONT, FS_BOLD=>'', FS_ITALIC=>'', FS_BOLDITALIC=>'' ), FF_MINCHO => array(FS_NORMAL=>MINCHO_TTF_FONT, FS_BOLD=>'', FS_ITALIC=>'', FS_BOLDITALIC=>'' ), FF_PMINCHO => array(FS_NORMAL=>PMINCHO_TTF_FONT, FS_BOLD=>'', FS_ITALIC=>'', FS_BOLDITALIC=>'' ), FF_GOTHIC => array(FS_NORMAL=>GOTHIC_TTF_FONT, FS_BOLD=>'', FS_ITALIC=>'', FS_BOLDITALIC=>'' ), FF_PGOTHIC => array(FS_NORMAL=>PGOTHIC_TTF_FONT, FS_BOLD=>'', FS_ITALIC=>'', FS_BOLDITALIC=>'' ), FF_MINCHO => array(FS_NORMAL=>PMINCHO_TTF_FONT, FS_BOLD=>'', FS_ITALIC=>'', FS_BOLDITALIC=>'' ) ); } //--------------- // PUBLIC METHODS // Create the TTF file from the font specification function File($family,$style=FS_NORMAL) { if( $family == FF_HANDWRT || $family==FF_BOOK ) { JpGraphError::RaiseL(25045);//('Font families FF_HANDWRT and FF_BOOK are no longer available due to copyright problem with these fonts. Fonts can no longer be distributed with JpGraph. Please download fonts from http://corefonts.sourceforge.net/'); } $fam = @$this->font_files[$family]; if( !$fam ) { JpGraphError::RaiseL(25046,$family);//("Specified TTF font family (id=$family) is unknown or does not exist. Please note that TTF fonts are not distributed with JpGraph for copyright reasons. You can find the MS TTF WEB-fonts (arial, courier etc) for download at http://corefonts.sourceforge.net/"); } $f = @$fam[$style]; if( $f==='' ) JpGraphError::RaiseL(25047,$this->style_names[$style],$this->font_files[$family][FS_NORMAL]);//('Style "'.$this->style_names[$style].'" is not available for font family '.$this->font_files[$family][FS_NORMAL].'.'); if( !$f ) { JpGraphError::RaiseL(25048,$fam);//("Unknown font style specification [$fam]."); } if ($family >= FF_MINCHO && $family <= FF_PGOTHIC) { $f = MBTTF_DIR.$f; } else { $f = TTF_DIR.$f; } if( file_exists($f) === false || is_readable($f) === false ) { JpGraphError::RaiseL(25049,$f);//("Font file \"$f\" is not readable or does not exist."); } return $f; } } // Class //=================================================== // CLASS LineProperty // Description: Holds properties for a line //=================================================== class LineProperty { var $iWeight=1, $iColor="black",$iStyle="solid"; var $iShow=true; //--------------- // PUBLIC METHODS function SetColor($aColor) { $this->iColor = $aColor; } function SetWeight($aWeight) { $this->iWeight = $aWeight; } function SetStyle($aStyle) { $this->iStyle = $aStyle; } function Show($aShow=true) { $this->iShow=$aShow; } function Stroke(&$aImg,$aX1,$aY1,$aX2,$aY2) { if( $this->iShow ) { $aImg->PushColor($this->iColor); $oldls = $aImg->line_style; $oldlw = $aImg->line_weight; $aImg->SetLineWeight($this->iWeight); $aImg->SetLineStyle($this->iStyle); $aImg->StyleLine($aX1,$aY1,$aX2,$aY2); $aImg->PopColor($this->iColor); $aImg->line_style = $oldls; $aImg->line_weight = $oldlw; } } } //=================================================== // CLASS Text // Description: Arbitrary text object that can be added to the graph //=================================================== class Text { var $t,$x=0,$y=0,$halign="left",$valign="top",$color=array(0,0,0); var $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12; var $hide=false, $dir=0; var $boxed=false; // Should the text be boxed var $paragraph_align="left"; var $margin=0; var $icornerradius=0,$ishadowwidth=3; var $iScalePosY=null,$iScalePosX=null; var $iWordwrap=0; var $fcolor='white',$bcolor='black',$shadow=false; var $iCSIMarea='',$iCSIMalt='',$iCSIMtarget=''; //--------------- // CONSTRUCTOR // Create new text at absolute pixel coordinates function Text($aTxt="",$aXAbsPos=0,$aYAbsPos=0) { if( ! is_string($aTxt) ) { JpGraphError::RaiseL(25050);//('First argument to Text::Text() must be s atring.'); } $this->t = $aTxt; $this->x = round($aXAbsPos); $this->y = round($aYAbsPos); $this->margin = 0; } //--------------- // PUBLIC METHODS // Set the string in the text object function Set($aTxt) { $this->t = $aTxt; } // Alias for Pos() function SetPos($aXAbsPos=0,$aYAbsPos=0,$aHAlign="left",$aVAlign="top") { $this->Pos($aXAbsPos,$aYAbsPos,$aHAlign,$aVAlign); } // Specify the position and alignment for the text object function Pos($aXAbsPos=0,$aYAbsPos=0,$aHAlign="left",$aVAlign="top") { $this->x = $aXAbsPos; $this->y = $aYAbsPos; $this->halign = $aHAlign; $this->valign = $aVAlign; } function SetScalePos($aX,$aY) { $this->iScalePosX = $aX; $this->iScalePosY = $aY; } // Specify alignment for the text function Align($aHAlign,$aVAlign="top",$aParagraphAlign="") { $this->halign = $aHAlign; $this->valign = $aVAlign; if( $aParagraphAlign != "" ) $this->paragraph_align = $aParagraphAlign; } // Alias function SetAlign($aHAlign,$aVAlign="top",$aParagraphAlign="") { $this->Align($aHAlign,$aVAlign,$aParagraphAlign); } // Specifies the alignment for a multi line text function ParagraphAlign($aAlign) { $this->paragraph_align = $aAlign; } // Specifies the alignment for a multi line text function SetParagraphAlign($aAlign) { $this->paragraph_align = $aAlign; } function SetShadow($aShadowColor='gray',$aShadowWidth=3) { $this->ishadowwidth=$aShadowWidth; $this->shadow=$aShadowColor; $this->boxed=true; } function SetWordWrap($aCol) { $this->iWordwrap = $aCol ; } // Specify that the text should be boxed. fcolor=frame color, bcolor=border color, // $shadow=drop shadow should be added around the text. function SetBox($aFrameColor=array(255,255,255),$aBorderColor=array(0,0,0),$aShadowColor=false,$aCornerRadius=4,$aShadowWidth=3) { if( $aFrameColor==false ) $this->boxed=false; else $this->boxed=true; $this->fcolor=$aFrameColor; $this->bcolor=$aBorderColor; // For backwards compatibility when shadow was just true or false if( $aShadowColor === true ) $aShadowColor = 'gray'; $this->shadow=$aShadowColor; $this->icornerradius=$aCornerRadius; $this->ishadowwidth=$aShadowWidth; } // Hide the text function Hide($aHide=true) { $this->hide=$aHide; } // This looks ugly since it's not a very orthogonal design // but I added this "inverse" of Hide() to harmonize // with some classes which I designed more recently (especially) // jpgraph_gantt function Show($aShow=true) { $this->hide=!$aShow; } // Specify font function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { $this->font_family=$aFamily; $this->font_style=$aStyle; $this->font_size=$aSize; } // Center the text between $left and $right coordinates function Center($aLeft,$aRight,$aYAbsPos=false) { $this->x = $aLeft + ($aRight-$aLeft )/2; $this->halign = "center"; if( is_numeric($aYAbsPos) ) $this->y = $aYAbsPos; } // Set text color function SetColor($aColor) { $this->color = $aColor; } function SetAngle($aAngle) { $this->SetOrientation($aAngle); } // Orientation of text. Note only TTF fonts can have an arbitrary angle function SetOrientation($aDirection=0) { if( is_numeric($aDirection) ) $this->dir=$aDirection; elseif( $aDirection=="h" ) $this->dir = 0; elseif( $aDirection=="v" ) $this->dir = 90; else JpGraphError::RaiseL(25051);//(" Invalid direction specified for text."); } // Total width of text function GetWidth(&$aImg) { $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); $w = $aImg->GetTextWidth($this->t,$this->dir); return $w; } // Hight of font function GetFontHeight(&$aImg) { $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); $h = $aImg->GetFontHeight(); return $h; } function GetTextHeight(&$aImg) { $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); $h = $aImg->GetTextHeight($this->t,$this->dir); return $h; } function GetHeight(&$aImg) { // Synonym for GetTextHeight() $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); $h = $aImg->GetTextHeight($this->t,$this->dir); return $h; } // Set the margin which will be interpretated differently depending // on the context. function SetMargin($aMarg) { $this->margin = $aMarg; } function StrokeWithScale(&$aImg,$axscale,$ayscale) { if( $this->iScalePosX === null || $this->iScalePosY === null ) { $this->Stroke($aImg); } else { $this->Stroke($aImg, round($axscale->Translate($this->iScalePosX)), round($ayscale->Translate($this->iScalePosY))); } } function SetCSIMTarget($aTarget,$aAlt=null) { $this->iCSIMtarget = $aTarget; $this->iCSIMalt = $aAlt; } function GetCSIMareas() { if( $this->iCSIMtarget !== '' ) return $this->iCSIMarea; else return ''; } // Display text in image function Stroke(&$aImg,$x=null,$y=null) { if( !empty($x) ) $this->x = round($x); if( !empty($y) ) $this->y = round($y); // Insert newlines if( $this->iWordwrap > 0 ) { $this->t = wordwrap($this->t,$this->iWordwrap,"\n"); } // If position been given as a fraction of the image size // calculate the absolute position if( $this->x < 1 && $this->x > 0 ) $this->x *= $aImg->width; if( $this->y < 1 && $this->y > 0 ) $this->y *= $aImg->height; $aImg->PushColor($this->color); $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); $aImg->SetTextAlign($this->halign,$this->valign); if( $this->boxed ) { if( $this->fcolor=="nofill" ) $this->fcolor=false; $aImg->SetLineWeight(1); $bbox = $aImg->StrokeBoxedText($this->x,$this->y,$this->t, $this->dir,$this->fcolor,$this->bcolor,$this->shadow, $this->paragraph_align,5,5,$this->icornerradius, $this->ishadowwidth); } else { $bbox = $aImg->StrokeText($this->x,$this->y,$this->t,$this->dir,$this->paragraph_align); } // Create CSIM targets $coords = $bbox[0].','.$bbox[1].','.$bbox[2].','.$bbox[3].','.$bbox[4].','.$bbox[5].','.$bbox[6].','.$bbox[7]; $this->iCSIMarea = "iCSIMtarget."\""; $this->iCSIMarea .= " alt=\"".$this->iCSIMalt."\" title=\"".$this->iCSIMalt."\" />\n"; $aImg->PopColor($this->color); } } // Class class GraphTabTitle extends Text{ var $corner = 6 , $posx = 7, $posy = 4; var $color='darkred',$fillcolor='lightyellow',$bordercolor='black'; var $align = 'left', $width=TABTITLE_WIDTHFIT; function GraphTabTitle() { $this->t = ''; $this->font_style = FS_BOLD; $this->hide = true; } function SetColor($aTxtColor,$aFillColor='lightyellow',$aBorderColor='black') { $this->color = $aTxtColor; $this->fillcolor = $aFillColor; $this->bordercolor = $aBorderColor; } function SetFillColor($aFillColor) { $this->fillcolor = $aFillColor; } function SetTabAlign($aAlign) { // Synonym for SetPos $this->align = $aAlign; } function SetPos($aAlign) { $this->align = $aAlign; } function SetWidth($aWidth) { $this->width = $aWidth ; } function Set($t) { $this->t = $t; $this->hide = false; } function SetCorner($aD) { $this->corner = $aD ; } function Stroke(&$aImg) { if( $this->hide ) return; $this->boxed = false; $w = $this->GetWidth($aImg) + 2*$this->posx; $h = $this->GetTextHeight($aImg) + 2*$this->posy; $x = $aImg->left_margin; $y = $aImg->top_margin; if( $this->width === TABTITLE_WIDTHFIT ) { if( $this->align == 'left' ) { $p = array($x, $y, $x, $y-$h+$this->corner, $x + $this->corner,$y-$h, $x + $w - $this->corner, $y-$h, $x + $w, $y-$h+$this->corner, $x + $w, $y); } elseif( $this->align == 'center' ) { $x += round($aImg->plotwidth/2) - round($w/2); $p = array($x, $y, $x, $y-$h+$this->corner, $x + $this->corner, $y-$h, $x + $w - $this->corner, $y-$h, $x + $w, $y-$h+$this->corner, $x + $w, $y); } else { $x += $aImg->plotwidth -$w; $p = array($x, $y, $x, $y-$h+$this->corner, $x + $this->corner,$y-$h, $x + $w - $this->corner, $y-$h, $x + $w, $y-$h+$this->corner, $x + $w, $y); } } else { if( $this->width === TABTITLE_WIDTHFULL ) $w = $aImg->plotwidth ; else $w = $this->width ; // Make the tab fit the width of the plot area $p = array($x, $y, $x, $y-$h+$this->corner, $x + $this->corner,$y-$h, $x + $w - $this->corner, $y-$h, $x + $w, $y-$h+$this->corner, $x + $w, $y); } if( $this->halign == 'left' ) { $aImg->SetTextAlign('left','bottom'); $x += $this->posx; $y -= $this->posy; } elseif( $this->halign == 'center' ) { $aImg->SetTextAlign('center','bottom'); $x += $w/2; $y -= $this->posy; } else { $aImg->SetTextAlign('right','bottom'); $x += $w - $this->posx; $y -= $this->posy; } $aImg->SetColor($this->fillcolor); $aImg->FilledPolygon($p); $aImg->SetColor($this->bordercolor); $aImg->Polygon($p,true); $aImg->SetColor($this->color); $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); $aImg->StrokeText($x,$y,$this->t,0,'center'); } } //=================================================== // CLASS SuperScriptText // Description: Format a superscript text //=================================================== class SuperScriptText extends Text { var $iSuper=""; var $sfont_family="",$sfont_style="",$sfont_size=8; var $iSuperMargin=2,$iVertOverlap=4,$iSuperScale=0.65; var $iSDir=0; var $iSimple=false; function SuperScriptText($aTxt="",$aSuper="",$aXAbsPos=0,$aYAbsPos=0) { parent::Text($aTxt,$aXAbsPos,$aYAbsPos); $this->iSuper = $aSuper; } function FromReal($aVal,$aPrecision=2) { // Convert a floating point number to scientific notation $neg=1.0; if( $aVal < 0 ) { $neg = -1.0; $aVal = -$aVal; } $l = floor(log10($aVal)); $a = sprintf("%0.".$aPrecision."f",round($aVal / pow(10,$l),$aPrecision)); $a *= $neg; if( $this->iSimple && ($a == 1 || $a==-1) ) $a = ''; if( $a != '' ) $this->t = $a.' * 10'; else { if( $neg == 1 ) $this->t = '10'; else $this->t = '-10'; } $this->iSuper = $l; } function Set($aTxt,$aSuper="") { $this->t = $aTxt; $this->iSuper = $aSuper; } function SetSuperFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=8) { $this->sfont_family = $aFontFam; $this->sfont_style = $aFontStyle; $this->sfont_size = $aFontSize; } // Total width of text function GetWidth(&$aImg) { $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); $w = $aImg->GetTextWidth($this->t); $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); $w += $aImg->GetTextWidth($this->iSuper); $w += $this->iSuperMargin; return $w; } // Hight of font (approximate the height of the text) function GetFontHeight(&$aImg) { $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); $h = $aImg->GetFontHeight(); $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); $h += $aImg->GetFontHeight(); return $h; } // Hight of text function GetTextHeight(&$aImg) { $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); $h = $aImg->GetTextHeight($this->t); $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); $h += $aImg->GetTextHeight($this->iSuper); return $h; } function Stroke(&$aImg,$ax=-1,$ay=-1) { // To position the super script correctly we need different // cases to handle the alignmewnt specified since that will // determine how we can interpret the x,y coordinates $w = parent::GetWidth($aImg); $h = parent::GetTextHeight($aImg); switch( $this->valign ) { case 'top': $sy = $this->y; break; case 'center': $sy = $this->y - $h/2; break; case 'bottom': $sy = $this->y - $h; break; default: JpGraphError::RaiseL(25052);//('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text'); exit(); } switch( $this->halign ) { case 'left': $sx = $this->x + $w; break; case 'center': $sx = $this->x + $w/2; break; case 'right': $sx = $this->x; break; default: JpGraphError::RaiseL(25053);//('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text'); exit(); } $sx += $this->iSuperMargin; $sy += $this->iVertOverlap; // Should we automatically determine the font or // has the user specified it explicetly? if( $this->sfont_family == "" ) { if( $this->font_family <= FF_FONT2 ) { if( $this->font_family == FF_FONT0 ) { $sff = FF_FONT0; } elseif( $this->font_family == FF_FONT1 ) { if( $this->font_style == FS_NORMAL ) $sff = FF_FONT0; else $sff = FF_FONT1; } else { $sff = FF_FONT1; } $sfs = $this->font_style; $sfz = $this->font_size; } else { // TTF fonts $sff = $this->font_family; $sfs = $this->font_style; $sfz = floor($this->font_size*$this->iSuperScale); if( $sfz < 8 ) $sfz = 8; } $this->sfont_family = $sff; $this->sfont_style = $sfs; $this->sfont_size = $sfz; } else { $sff = $this->sfont_family; $sfs = $this->sfont_style; $sfz = $this->sfont_size; } parent::Stroke($aImg,$ax,$ay); // For the builtin fonts we need to reduce the margins // since the bounding bx reported for the builtin fonts // are much larger than for the TTF fonts. if( $sff <= FF_FONT2 ) { $sx -= 2; $sy += 3; } $aImg->SetTextAlign('left','bottom'); $aImg->SetFont($sff,$sfs,$sfz); $aImg->PushColor($this->color); $aImg->StrokeText($sx,$sy,$this->iSuper,$this->iSDir,'left'); $aImg->PopColor(); } } //=================================================== // CLASS Grid // Description: responsible for drawing grid lines in graph //=================================================== class Grid { var $img; var $scale; var $grid_color='#DDDDDD',$grid_mincolor='#DDDDDD'; var $type="solid"; var $show=false, $showMinor=false,$weight=1; var $fill=false,$fillcolor=array('#EFEFEF','#BBCCFF'); //--------------- // CONSTRUCTOR function Grid(&$aAxis) { $this->scale = &$aAxis->scale; $this->img = &$aAxis->img; } //--------------- // PUBLIC METHODS function SetColor($aMajColor,$aMinColor=false) { $this->grid_color=$aMajColor; if( $aMinColor === false ) $aMinColor = $aMajColor ; $this->grid_mincolor = $aMinColor; } function SetWeight($aWeight) { $this->weight=$aWeight; } // Specify if grid should be dashed, dotted or solid function SetLineStyle($aType) { $this->type = $aType; } // Decide if both major and minor grid should be displayed function Show($aShowMajor=true,$aShowMinor=false) { $this->show=$aShowMajor; $this->showMinor=$aShowMinor; } function SetFill($aFlg=true,$aColor1='lightgray',$aColor2='lightblue') { $this->fill = $aFlg; $this->fillcolor = array( $aColor1, $aColor2 ); } // Display the grid function Stroke() { if( $this->showMinor ) { $tmp = $this->grid_color; $this->grid_color = $this->grid_mincolor; $this->DoStroke($this->scale->ticks->ticks_pos); $this->grid_color = $tmp; $this->DoStroke($this->scale->ticks->maj_ticks_pos); } else { $this->DoStroke($this->scale->ticks->maj_ticks_pos); } } //-------------- // Private methods // Draw the grid function DoStroke(&$aTicksPos) { if( !$this->show ) return; $nbrgrids = count($aTicksPos); if( $this->scale->type=="y" ) { $xl=$this->img->left_margin; $xr=$this->img->width-$this->img->right_margin; if( $this->fill ) { // Draw filled areas $y2 = $aTicksPos[0]; $i=1; while( $i < $nbrgrids ) { $y1 = $y2; $y2 = $aTicksPos[$i++]; $this->img->SetColor($this->fillcolor[$i & 1]); $this->img->FilledRectangle($xl,$y1,$xr,$y2); } } $this->img->SetColor($this->grid_color); $this->img->SetLineWeight($this->weight); // Draw grid lines for($i=0; $i<$nbrgrids; ++$i) { $y=$aTicksPos[$i]; if( $this->type == "solid" ) $this->img->Line($xl,$y,$xr,$y); elseif( $this->type == "dotted" ) $this->img->DashedLine($xl,$y,$xr,$y,1,6); elseif( $this->type == "dashed" ) $this->img->DashedLine($xl,$y,$xr,$y,2,4); elseif( $this->type == "longdashed" ) $this->img->DashedLine($xl,$y,$xr,$y,8,6); } } elseif( $this->scale->type=="x" ) { $yu=$this->img->top_margin; $yl=$this->img->height-$this->img->bottom_margin; $limit=$this->img->width-$this->img->right_margin; if( $this->fill ) { // Draw filled areas $x2 = $aTicksPos[0]; $i=1; while( $i < $nbrgrids ) { $x1 = $x2; $x2 = min($aTicksPos[$i++],$limit) ; $this->img->SetColor($this->fillcolor[$i & 1]); $this->img->FilledRectangle($x1,$yu,$x2,$yl); } } $this->img->SetColor($this->grid_color); $this->img->SetLineWeight($this->weight); // We must also test for limit since we might have // an offset and the number of ticks is calculated with // assumption offset==0 so we might end up drawing one // to many gridlines $i=0; $x=$aTicksPos[$i]; while( $itype == "solid" ) $this->img->Line($x,$yl,$x,$yu); elseif( $this->type == "dotted" ) $this->img->DashedLine($x,$yl,$x,$yu,1,6); elseif( $this->type == "dashed" ) $this->img->DashedLine($x,$yl,$x,$yu,2,4); elseif( $this->type == "longdashed" ) $this->img->DashedLine($x,$yl,$x,$yu,8,6); ++$i; } } else { JpGraphError::RaiseL(25054,$this->scale->type);//('Internal error: Unknown grid axis ['.$this->scale->type.']'); } return true; } } // Class //=================================================== // CLASS Axis // Description: Defines X and Y axis. Notes that at the // moment the code is not really good since the axis on // several occasion must know wheter it's an X or Y axis. // This was a design decision to make the code easier to // follow. //=================================================== class Axis { var $pos = false; var $weight=1; var $color=array(0,0,0),$label_color=array(0,0,0); var $img=null,$scale=null; var $hide=false; var $ticks_label=false, $ticks_label_colors=null; var $show_first_label=true,$show_last_label=true; var $label_step=1; // Used by a text axis to specify what multiple of major steps // should be labeled. var $tick_step=1; var $labelPos=0; // Which side of the axis should the labels be? var $title=null,$title_adjust,$title_margin,$title_side=SIDE_LEFT; var $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12,$label_angle=0; var $tick_label_margin=5; var $label_halign = '',$label_valign = '', $label_para_align='left'; var $hide_line=false,$hide_labels=false; var $iDeltaAbsPos=0; //var $hide_zero_label=false; //--------------- // CONSTRUCTOR function Axis(&$img,&$aScale,$color=array(0,0,0)) { $this->img = &$img; $this->scale = &$aScale; $this->color = $color; $this->title=new Text(""); if( $aScale->type=="y" ) { $this->title_margin = 25; $this->title_adjust="middle"; $this->title->SetOrientation(90); $this->tick_label_margin=7; $this->labelPos=SIDE_LEFT; //$this->SetLabelFormat('%.1f'); } else { $this->title_margin = 5; $this->title_adjust="high"; $this->title->SetOrientation(0); $this->tick_label_margin=5; $this->labelPos=SIDE_DOWN; $this->title_side=SIDE_DOWN; //$this->SetLabelFormat('%.0f'); } } //--------------- // PUBLIC METHODS function SetLabelFormat($aFormStr) { $this->scale->ticks->SetLabelFormat($aFormStr); } function SetLabelFormatString($aFormStr,$aDate=false) { $this->scale->ticks->SetLabelFormat($aFormStr,$aDate); } function SetLabelFormatCallback($aFuncName) { $this->scale->ticks->SetFormatCallback($aFuncName); } function SetLabelAlign($aHAlign,$aVAlign="top",$aParagraphAlign='left') { $this->label_halign = $aHAlign; $this->label_valign = $aVAlign; $this->label_para_align = $aParagraphAlign; } // Don't display the first label function HideFirstTickLabel($aShow=false) { $this->show_first_label=$aShow; } function HideLastTickLabel($aShow=false) { $this->show_last_label=$aShow; } // Manually specify the major and (optional) minor tick position and labels function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) { $this->scale->ticks->SetTickPositions($aMajPos,$aMinPos,$aLabels); } // Manually specify major tick positions and optional labels function SetMajTickPositions($aMajPos,$aLabels=NULL) { $this->scale->ticks->SetTickPositions($aMajPos,NULL,$aLabels); } // Hide minor or major tick marks function HideTicks($aHideMinor=true,$aHideMajor=true) { $this->scale->ticks->SupressMinorTickMarks($aHideMinor); $this->scale->ticks->SupressTickMarks($aHideMajor); } // Hide zero label function HideZeroLabel($aFlag=true) { $this->scale->ticks->SupressZeroLabel(); //$this->hide_zero_label = $aFlag; } function HideFirstLastLabel() { // The two first calls to ticks method will supress // automatically generated scale values. However, that // will not affect manually specified value, e.g text-scales. // therefor we also make a kludge here to supress manually // specified scale labels. $this->scale->ticks->SupressLast(); $this->scale->ticks->SupressFirst(); $this->show_first_label = false; $this->show_last_label = false; } // Hide the axis function Hide($aHide=true) { $this->hide=$aHide; } // Hide the actual axis-line, but still print the labels function HideLine($aHide=true) { $this->hide_line = $aHide; } function HideLabels($aHide=true) { $this->hide_labels = $aHide; } // Weight of axis function SetWeight($aWeight) { $this->weight = $aWeight; } // Axis color function SetColor($aColor,$aLabelColor=false) { $this->color = $aColor; if( !$aLabelColor ) $this->label_color = $aColor; else $this->label_color = $aLabelColor; } // Title on axis function SetTitle($aTitle,$aAdjustAlign="high") { $this->title->Set($aTitle); $this->title_adjust=$aAdjustAlign; } // Specify distance from the axis function SetTitleMargin($aMargin) { $this->title_margin=$aMargin; } // Which side of the axis should the axis title be? function SetTitleSide($aSideOfAxis) { $this->title_side = $aSideOfAxis; } // Utility function to set the direction for tick marks function SetTickDirection($aDir) { // Will be deprecated from 1.7 if( ERR_DEPRECATED ) JpGraphError::RaiseL(25055);//('Axis::SetTickDirection() is deprecated. Use Axis::SetTickSide() instead'); $this->scale->ticks->SetSide($aDir); } function SetTickSide($aDir) { $this->scale->ticks->SetSide($aDir); } // Specify text labels for the ticks. One label for each data point function SetTickLabels($aLabelArray,$aLabelColorArray=null) { $this->ticks_label = $aLabelArray; $this->ticks_label_colors = $aLabelColorArray; } // How far from the axis should the labels be drawn function SetTickLabelMargin($aMargin) { if( ERR_DEPRECATED ) JpGraphError::RaiseL(25056);//('SetTickLabelMargin() is deprecated. Use Axis::SetLabelMargin() instead.'); $this->tick_label_margin=$aMargin; } function SetLabelMargin($aMargin) { $this->tick_label_margin=$aMargin; } // Specify that every $step of the ticks should be displayed starting // at $start // DEPRECATED FUNCTION: USE SetTextTickInterval() INSTEAD function SetTextTicks($step,$start=0) { JpGraphError::RaiseL(25057);//(" SetTextTicks() is deprecated. Use SetTextTickInterval() instead."); } // Specify that every $step of the ticks should be displayed starting // at $start function SetTextTickInterval($aStep,$aStart=0) { $this->scale->ticks->SetTextLabelStart($aStart); $this->tick_step=$aStep; } // Specify that every $step tick mark should have a label // should be displayed starting function SetTextLabelInterval($aStep,$aStart=0) { if( $aStep < 1 ) JpGraphError::RaiseL(25058);//(" Text label interval must be specified >= 1."); $this->scale->ticks->SetTextLabelStart($aStart); $this->label_step=$aStep; } // Which side of the axis should the labels be on? function SetLabelPos($aSidePos) { // This will be deprecated from 1.7 if( ERR_DEPRECATED ) JpGraphError::RaiseL(25059);//('SetLabelPos() is deprecated. Use Axis::SetLabelSide() instead.'); $this->labelPos=$aSidePos; } function SetLabelSide($aSidePos) { $this->labelPos=$aSidePos; } // Set the font function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { $this->font_family = $aFamily; $this->font_style = $aStyle; $this->font_size = $aSize; } // Position for axis line on the "other" scale function SetPos($aPosOnOtherScale) { $this->pos=$aPosOnOtherScale; } // Set the position of the axis to be X-pixels delta to the right // of the max X-position (used to position the multiple Y-axis) function SetPosAbsDelta($aDelta) { $this->iDeltaAbsPos=$aDelta; } // Specify the angle for the tick labels function SetLabelAngle($aAngle) { $this->label_angle = $aAngle; } // Stroke the axis. function Stroke($aOtherAxisScale,$aStrokeLabels=true) { if( $this->hide ) return; if( is_numeric($this->pos) ) { $pos=$aOtherAxisScale->Translate($this->pos); } else { // Default to minimum of other scale if pos not set if( ($aOtherAxisScale->GetMinVal() >= 0 && $this->pos==false) || $this->pos=="min" ) { $pos = $aOtherAxisScale->scale_abs[0]; } elseif($this->pos == "max") { $pos = $aOtherAxisScale->scale_abs[1]; } else { // If negative set x-axis at 0 $this->pos=0; $pos=$aOtherAxisScale->Translate(0); } } $pos += $this->iDeltaAbsPos; $this->img->SetLineWeight($this->weight); $this->img->SetColor($this->color); $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); if( $this->scale->type == "x" ) { if( !$this->hide_line ) $this->img->FilledRectangle($this->img->left_margin,$pos, $this->img->width-$this->img->right_margin,$pos+$this->weight-1); if( $this->title_side == SIDE_DOWN ) { $y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin; $yalign = 'top'; } else { $y = $pos - $this->img->GetFontHeight() - $this->title_margin - $this->title->margin; $yalign = 'bottom'; } if( $this->title_adjust=="high" ) $this->title->Pos($this->img->width-$this->img->right_margin,$y,"right",$yalign); elseif( $this->title_adjust=="middle" || $this->title_adjust=="center" ) $this->title->Pos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin,$y,"center",$yalign); elseif($this->title_adjust=="low") $this->title->Pos($this->img->left_margin,$y,"left",$yalign); else { JpGraphError::RaiseL(25060,$this->title_adjust);//('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')'); } } elseif( $this->scale->type == "y" ) { // Add line weight to the height of the axis since // the x-axis could have a width>1 and we want the axis to fit nicely together. if( !$this->hide_line ) $this->img->FilledRectangle($pos-$this->weight+1,$this->img->top_margin, $pos,$this->img->height-$this->img->bottom_margin+$this->weight-1); $x=$pos ; if( $this->title_side == SIDE_LEFT ) { $x -= $this->title_margin; $x -= $this->title->margin; $halign="right"; } else { $x += $this->title_margin; $x += $this->title->margin; $halign="left"; } // If the user has manually specified an hor. align // then we override the automatic settings with this // specifed setting. Since default is 'left' we compare // with that. (This means a manually set 'left' align // will have no effect.) if( $this->title->halign != 'left' ) $halign = $this->title->halign; if( $this->title_adjust=="high" ) $this->title->Pos($x,$this->img->top_margin,$halign,"top"); elseif($this->title_adjust=="middle" || $this->title_adjust=="center") $this->title->Pos($x,($this->img->height-$this->img->top_margin-$this->img->bottom_margin)/2+$this->img->top_margin,$halign,"center"); elseif($this->title_adjust=="low") $this->title->Pos($x,$this->img->height-$this->img->bottom_margin,$halign,"bottom"); else JpGraphError::RaiseL(25061,$this->title_adjust);//('Unknown alignment specified for Y-axis title. ('.$this->title_adjust.')'); } $this->scale->ticks->Stroke($this->img,$this->scale,$pos); if( $aStrokeLabels ) { if( !$this->hide_labels ) $this->StrokeLabels($pos); $this->title->Stroke($this->img); } } //--------------- // PRIVATE METHODS // Draw all the tick labels on major tick marks function StrokeLabels($aPos,$aMinor=false,$aAbsLabel=false) { $this->img->SetColor($this->label_color); $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); $yoff=$this->img->GetFontHeight()/2; // Only draw labels at major tick marks $nbr = count($this->scale->ticks->maj_ticks_label); // We have the option to not-display the very first mark // (Usefull when the first label might interfere with another // axis.) $i = $this->show_first_label ? 0 : 1 ; if( !$this->show_last_label ) --$nbr; // Now run through all labels making sure we don't overshoot the end // of the scale. $ncolor=0; if( isset($this->ticks_label_colors) ) $ncolor=count($this->ticks_label_colors); while( $i<$nbr ) { // $tpos holds the absolute text position for the label $tpos=$this->scale->ticks->maj_ticklabels_pos[$i]; // Note. the $limit is only used for the x axis since we // might otherwise overshoot if the scale has been centered // This is due to us "loosing" the last tick mark if we center. if( $this->scale->type=="x" && $tpos > $this->img->width-$this->img->right_margin+1 ) { return; } // we only draw every $label_step label if( ($i % $this->label_step)==0 ) { // Set specific label color if specified if( $ncolor > 0 ) $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]); // If the label has been specified use that and in other case // just label the mark with the actual scale value $m=$this->scale->ticks->GetMajor(); // ticks_label has an entry for each data point and is the array // that holds the labels set by the user. If the user hasn't // specified any values we use whats in the automatically asigned // labels in the maj_ticks_label if( isset($this->ticks_label[$i*$m]) ) $label=$this->ticks_label[$i*$m]; else { if( $aAbsLabel ) $label=abs($this->scale->ticks->maj_ticks_label[$i]); else $label=$this->scale->ticks->maj_ticks_label[$i]; if( $this->scale->textscale && $this->scale->ticks->label_formfunc == '' ) { ++$label; } } //if( $this->hide_zero_label && $label==0.0 ) { // ++$i; // continue; //} if( $this->scale->type == "x" ) { if( $this->labelPos == SIDE_DOWN ) { if( $this->label_angle==0 || $this->label_angle==90 ) { if( $this->label_halign=='' && $this->label_valign=='') $this->img->SetTextAlign('center','top'); else $this->img->SetTextAlign($this->label_halign,$this->label_valign); } else { if( $this->label_halign=='' && $this->label_valign=='') $this->img->SetTextAlign("right","top"); else $this->img->SetTextAlign($this->label_halign,$this->label_valign); } $this->img->StrokeText($tpos,$aPos+$this->tick_label_margin,$label, $this->label_angle,$this->label_para_align); } else { if( $this->label_angle==0 || $this->label_angle==90 ) { if( $this->label_halign=='' && $this->label_valign=='') $this->img->SetTextAlign("center","bottom"); else $this->img->SetTextAlign($this->label_halign,$this->label_valign); } else { if( $this->label_halign=='' && $this->label_valign=='') $this->img->SetTextAlign("right","bottom"); else $this->img->SetTextAlign($this->label_halign,$this->label_valign); } $this->img->StrokeText($tpos,$aPos-$this->tick_label_margin,$label, $this->label_angle,$this->label_para_align); } } else { // scale->type == "y" //if( $this->label_angle!=0 ) //JpGraphError::Raise(" Labels at an angle are not supported on Y-axis"); if( $this->labelPos == SIDE_LEFT ) { // To the left of y-axis if( $this->label_halign=='' && $this->label_valign=='') $this->img->SetTextAlign("right","center"); else $this->img->SetTextAlign($this->label_halign,$this->label_valign); $this->img->StrokeText($aPos-$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align); } else { // To the right of the y-axis if( $this->label_halign=='' && $this->label_valign=='') $this->img->SetTextAlign("left","center"); else $this->img->SetTextAlign($this->label_halign,$this->label_valign); $this->img->StrokeText($aPos+$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align); } } } ++$i; } } } // Class //=================================================== // CLASS Ticks // Description: Abstract base class for drawing linear and logarithmic // tick marks on axis //=================================================== class Ticks { var $minor_abs_size=3, $major_abs_size=5; var $direction=1; // Should ticks be in(=1) the plot area or outside (=-1)? var $scale; var $is_set=false; var $precision; var $supress_zerolabel=false,$supress_first=false; var $supress_last=false,$supress_tickmarks=false,$supress_minor_tickmarks=false; var $mincolor="",$majcolor=""; var $weight=1; var $label_formatstr=''; // C-style format string to use for labels var $label_formfunc=''; var $label_dateformatstr=''; var $label_usedateformat=FALSE; //--------------- // CONSTRUCTOR function Ticks(&$aScale) { $this->scale=&$aScale; $this->precision = -1; } //--------------- // PUBLIC METHODS // Set format string for automatic labels function SetLabelFormat($aFormatString,$aDate=FALSE) { $this->label_formatstr=$aFormatString; $this->label_usedateformat=$aDate; } function SetLabelDateFormat($aFormatString) { $this->label_dateformatstr=$aFormatString; } function SetFormatCallback($aCallbackFuncName) { $this->label_formfunc = $aCallbackFuncName; } // Don't display the first zero label function SupressZeroLabel($aFlag=true) { $this->supress_zerolabel=$aFlag; } // Don't display minor tick marks function SupressMinorTickMarks($aHide=true) { $this->supress_minor_tickmarks=$aHide; } // Don't display major tick marks function SupressTickMarks($aHide=true) { $this->supress_tickmarks=$aHide; } // Hide the first tick mark function SupressFirst($aHide=true) { $this->supress_first=$aHide; } // Hide the last tick mark function SupressLast($aHide=true) { $this->supress_last=$aHide; } // Size (in pixels) of minor tick marks function GetMinTickAbsSize() { return $this->minor_abs_size; } // Size (in pixels) of major tick marks function GetMajTickAbsSize() { return $this->major_abs_size; } function SetSize($aMajSize,$aMinSize=3) { $this->major_abs_size = $aMajSize; $this->minor_abs_size = $aMinSize; } // Have the ticks been specified function IsSpecified() { return $this->is_set; } // Set the distance between major and minor tick marks function Set($aMaj,$aMin) { // "Virtual method" // Should be implemented by the concrete subclass // if any action is wanted. } // Specify number of decimals in automatic labels // Deprecated from 1.4. Use SetFormatString() instead function SetPrecision($aPrecision) { if( ERR_DEPRECATED ) JpGraphError::RaiseL(25063);//('Ticks::SetPrecision() is deprecated. Use Ticks::SetLabelFormat() (or Ticks::SetFormatCallback()) instead'); $this->precision=$aPrecision; } function SetSide($aSide) { $this->direction=$aSide; } // Which side of the axis should the ticks be on function SetDirection($aSide=SIDE_RIGHT) { $this->direction=$aSide; } // Set colors for major and minor tick marks function SetMarkColor($aMajorColor,$aMinorColor="") { $this->SetColor($aMajorColor,$aMinorColor); } function SetColor($aMajorColor,$aMinorColor="") { $this->majcolor=$aMajorColor; // If not specified use same as major if( $aMinorColor=="" ) $this->mincolor=$aMajorColor; else $this->mincolor=$aMinorColor; } function SetWeight($aWeight) { $this->weight=$aWeight; } } // Class //=================================================== // CLASS LinearTicks // Description: Draw linear ticks on axis //=================================================== class LinearTicks extends Ticks { var $minor_step=1, $major_step=2; var $xlabel_offset=0,$xtick_offset=0; var $label_offset=0; // What offset should the displayed label have // i.e should we display 0,1,2 or 1,2,3,4 or 2,3,4 etc var $text_label_start=0; var $iManualTickPos = NULL, $iManualMinTickPos = NULL, $iManualTickLabels = NULL; var $maj_ticks_pos = array(), $maj_ticklabels_pos = array(), $ticks_pos = array(), $maj_ticks_label = array(); //--------------- // CONSTRUCTOR function LinearTicks() { $this->precision = -1; } //--------------- // PUBLIC METHODS // Return major step size in world coordinates function GetMajor() { return $this->major_step; } // Return minor step size in world coordinates function GetMinor() { return $this->minor_step; } // Set Minor and Major ticks (in world coordinates) function Set($aMajStep,$aMinStep=false) { if( $aMinStep==false ) $aMinStep=$aMajStep; if( $aMajStep <= 0 || $aMinStep <= 0 ) { JpGraphError::RaiseL(25064); //(" Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem."); } $this->major_step=$aMajStep; $this->minor_step=$aMinStep; $this->is_set = true; } function SetMajTickPositions($aMajPos,$aLabels=NULL) { $this->SetTickPositions($aMajPos,NULL,$aLabels); } function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) { if( !is_array($aMajPos) || ($aMinPos!==NULL && !is_array($aMinPos)) ) { JpGraphError::RaiseL(25065);//('Tick positions must be specifued as an array()'); return; } $n=count($aMajPos); if( is_array($aLabels) && (count($aLabels) != $n) ) { JpGraphError::RaiseL(25066);//('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.'); return; } $this->iManualTickPos = $aMajPos; $this->iManualMinTickPos = $aMinPos; $this->iManualTickLabels = $aLabels; } // Specify all the tick positions manually and possible also the exact labels function _doManualTickPos($aScale) { $n=count($this->iManualTickPos); $m=count($this->iManualMinTickPos); $doLbl=count($this->iManualTickLabels) > 0; $this->use_manualtickpos=true; $this->maj_ticks_pos = array(); $this->maj_ticklabels_pos = array(); $this->ticks_pos = array(); // Now loop through the supplied positions and translate them to screen coordinates // and store them in the maj_label_positions $minScale = $aScale->scale[0]; $maxScale = $aScale->scale[1]; $j=0; for($i=0; $i < $n ; ++$i ) { // First make sure that the first tick is not lower than the lower scale value if( !isset($this->iManualTickPos[$i]) || $this->iManualTickPos[$i] < $minScale || $this->iManualTickPos[$i] > $maxScale) { continue; } $this->maj_ticks_pos[$j] = $aScale->Translate($this->iManualTickPos[$i]); $this->maj_ticklabels_pos[$j] = $this->maj_ticks_pos[$j]; // Set the minor tick marks the same as major if not specified if( $m <= 0 ) { $this->ticks_pos[$j] = $this->maj_ticks_pos[$j]; } if( $doLbl ) { $this->maj_ticks_label[$j] = $this->iManualTickLabels[$i]; } else { $this->maj_ticks_label[$j]=$this->_doLabelFormat($this->iManualTickPos[$i],$i,$n); } ++$j; } // Some sanity check if( count($this->maj_ticks_pos) < 2 ) { JpGraphError::RaiseL(25067);//('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tickl marks.'); } // Setup the minor tick marks $j=0; for($i=0; $i < $m; ++$i ) { if( empty($this->iManualMinTickPos[$i]) || $this->iManualMinTickPos[$i] < $minScale || $this->iManualMinTickPos[$i] > $maxScale) continue; $this->ticks_pos[$j] = $aScale->Translate($this->iManualMinTickPos[$i]); ++$j; } } function _doAutoTickPos($aScale) { $maj_step_abs = $aScale->scale_factor*$this->major_step; $min_step_abs = $aScale->scale_factor*$this->minor_step; if( $min_step_abs==0 || $maj_step_abs==0 ) { JpGraphError::RaiseL(25068);//("A plot has an illegal scale. This could for example be that you are trying to use text autoscaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only '-' or 'x')"); } // We need to make this an int since comparing it below // with the result from round() can give wrong result, such that // (40 < 40) == TRUE !!! $limit = (int)$aScale->scale_abs[1]; if( $aScale->textscale ) { // This can only be true for a X-scale (horizontal) // Define ticks for a text scale. This is slightly different from a // normal linear type of scale since the position might be adjusted // and the labels start at on $label = (float)$aScale->GetMinVal()+$this->text_label_start+$this->label_offset; $start_abs=$aScale->scale_factor*$this->text_label_start; $nbrmajticks=ceil(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; $x = $aScale->scale_abs[0]+$start_abs+$this->xlabel_offset*$min_step_abs; for( $i=0; $label <= $aScale->GetMaxVal()+$this->label_offset; ++$i ) { // Apply format to label $this->maj_ticks_label[$i]=$this->_doLabelFormat($label,$i,$nbrmajticks); $label+=$this->major_step; // The x-position of the tick marks can be different from the labels. // Note that we record the tick position (not the label) so that the grid // happen upon tick marks and not labels. $xtick=$aScale->scale_abs[0]+$start_abs+$this->xtick_offset*$min_step_abs+$i*$maj_step_abs; $this->maj_ticks_pos[$i]=$xtick; $this->maj_ticklabels_pos[$i] = round($x); $x += $maj_step_abs; } } else { $label = $aScale->GetMinVal(); $abs_pos = $aScale->scale_abs[0]; $j=0; $i=0; $step = round($maj_step_abs/$min_step_abs); if( $aScale->type == "x" ) { // For a normal linear type of scale the major ticks will always be multiples // of the minor ticks. In order to avoid any rounding issues the major ticks are // defined as every "step" minor ticks and not calculated separately $nbrmajticks=ceil(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; while( round($abs_pos) <= $limit ) { $this->ticks_pos[] = round($abs_pos); $this->ticks_label[] = $label; if( $i % $step == 0 && $j < $nbrmajticks ) { $this->maj_ticks_pos[$j] = round($abs_pos); $this->maj_ticklabels_pos[$j] = round($abs_pos); $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks); ++$j; } ++$i; $abs_pos += $min_step_abs; $label+=$this->minor_step; } } elseif( $aScale->type == "y" ) { $nbrmajticks=floor(($aScale->GetMaxVal()-$aScale->GetMinVal())/$this->major_step)+1; while( round($abs_pos) >= $limit ) { $this->ticks_pos[$i] = round($abs_pos); $this->ticks_label[$i]=$label; if( $i % $step == 0 && $j < $nbrmajticks) { $this->maj_ticks_pos[$j] = round($abs_pos); $this->maj_ticklabels_pos[$j] = round($abs_pos); $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks); ++$j; } ++$i; $abs_pos += $min_step_abs; $label += $this->minor_step; } } } } function _doLabelFormat($aVal,$aIdx,$aNbrTicks) { // If precision hasn't been specified set it to a sensible value if( $this->precision==-1 ) { $t = log10($this->minor_step); if( $t > 0 ) $precision = 0; else $precision = -floor($t); } else $precision = $this->precision; if( $this->label_formfunc != '' ) { $f=$this->label_formfunc; $l = call_user_func($f,$aVal); } elseif( $this->label_formatstr != '' || $this->label_dateformatstr != '' ) { if( $this->label_usedateformat ) { $l = date($this->label_formatstr,$aVal); } else { if( $this->label_dateformatstr !== '' ) $l = date($this->label_dateformatstr,$aVal); else $l = sprintf($this->label_formatstr,$aVal); } } else { $l = sprintf('%01.'.$precision.'f',round($aVal,$precision)); } if( ($this->supress_zerolabel && $l==0) || ($this->supress_first && $aIdx==0) || ($this->supress_last && $aIdx==$aNbrTicks-1) ) { $l=''; } return $l; } // Stroke ticks on either X or Y axis function _StrokeTicks(&$aImg,$aScale,$aPos) { $hor = $aScale->type == 'x'; $aImg->SetLineWeight($this->weight); // We need to make this an int since comparing it below // with the result from round() can give wrong result, such that // (40 < 40) == TRUE !!! $limit = (int)$aScale->scale_abs[1]; // A text scale doesn't have any minor ticks if( !$aScale->textscale ) { // Stroke minor ticks $yu = $aPos - $this->direction*$this->GetMinTickAbsSize(); $xr = $aPos + $this->direction*$this->GetMinTickAbsSize(); $n = count($this->ticks_pos); for($i=0; $i < $n; ++$i ) { if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { if( $this->mincolor!="" ) $aImg->PushColor($this->mincolor); if( $hor ) { //if( $this->ticks_pos[$i] <= $limit ) $aImg->Line($this->ticks_pos[$i],$aPos,$this->ticks_pos[$i],$yu); } else { //if( $this->ticks_pos[$i] >= $limit ) $aImg->Line($aPos,$this->ticks_pos[$i],$xr,$this->ticks_pos[$i]); } if( $this->mincolor!="" ) $aImg->PopColor(); } } } // Stroke major ticks $yu = $aPos - $this->direction*$this->GetMajTickAbsSize(); $xr = $aPos + $this->direction*$this->GetMajTickAbsSize(); $nbrmajticks=ceil(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; $n = count($this->maj_ticks_pos); for($i=0; $i < $n ; ++$i ) { if(!($this->xtick_offset > 0 && $i==$nbrmajticks-1) && !$this->supress_tickmarks) { if( $this->majcolor!="" ) $aImg->PushColor($this->majcolor); if( $hor ) { //if( $this->maj_ticks_pos[$i] <= $limit ) $aImg->Line($this->maj_ticks_pos[$i],$aPos,$this->maj_ticks_pos[$i],$yu); } else { //if( $this->maj_ticks_pos[$i] >= $limit ) $aImg->Line($aPos,$this->maj_ticks_pos[$i],$xr,$this->maj_ticks_pos[$i]); } if( $this->majcolor!="" ) $aImg->PopColor(); } } } // Draw linear ticks function Stroke(&$aImg,$aScale,$aPos) { if( $this->iManualTickPos != NULL ) $this->_doManualTickPos($aScale); else $this->_doAutoTickPos($aScale); $this->_StrokeTicks($aImg,$aScale,$aPos, $aScale->type == 'x' ); } //--------------- // PRIVATE METHODS // Spoecify the offset of the displayed tick mark with the tick "space" // Legal values for $o is [0,1] used to adjust where the tick marks and label // should be positioned within the major tick-size // $lo specifies the label offset and $to specifies the tick offset // this comes in handy for example in bar graphs where we wont no offset for the // tick but have the labels displayed halfway under the bars. function SetXLabelOffset($aLabelOff,$aTickOff=-1) { $this->xlabel_offset=$aLabelOff; if( $aTickOff==-1 ) // Same as label offset $this->xtick_offset=$aLabelOff; else $this->xtick_offset=$aTickOff; if( $aLabelOff>0 ) $this->SupressLast(); // The last tick wont fit } // Which tick label should we start with? function SetTextLabelStart($aTextLabelOff) { $this->text_label_start=$aTextLabelOff; } } // Class //=================================================== // CLASS LinearScale // Description: Handle linear scaling between screen and world //=================================================== class LinearScale { var $scale=array(0,0); var $scale_abs=array(0,0); var $scale_factor; // Scale factor between world and screen var $world_size; // Plot area size in world coordinates var $world_abs_size; // Plot area size in pixels var $off; // Offset between image edge and plot area var $type; // is this x or y scale ? var $ticks=null; // Store ticks var $text_scale_off = 0; var $autoscale_min=false; // Forced minimum value, auto determine max var $autoscale_max=false; // Forced maximum value, auto determine min var $gracetop=0,$gracebottom=0; var $intscale=false; // Restrict autoscale to integers var $textscale=false; // Just a flag to let the Plot class find out if // we are a textscale or not. This is a cludge since // this ionformatyion is availabale in Graph::axtype but // we don't have access to the graph object in the Plots // stroke method. So we let graph store the status here // when the linear scale is created. A real cludge... var $auto_ticks=false; // When using manual scale should the ticks be automatically set? var $name = 'lin'; //--------------- // CONSTRUCTOR function LinearScale($aMin=0,$aMax=0,$aType="y") { assert($aType=="x" || $aType=="y" ); assert($aMin<=$aMax); $this->type=$aType; $this->scale=array($aMin,$aMax); $this->world_size=$aMax-$aMin; $this->ticks = new LinearTicks(); } //--------------- // PUBLIC METHODS // Check if scale is set or if we should autoscale // We should do this is either scale or ticks has not been set function IsSpecified() { if( $this->GetMinVal()==$this->GetMaxVal() ) { // Scale not set return false; } return true; } // Set the minimum data value when the autoscaling is used. // Usefull if you want a fix minimum (like 0) but have an // automatic maximum function SetAutoMin($aMin) { $this->autoscale_min=$aMin; } // Set the minimum data value when the autoscaling is used. // Usefull if you want a fix minimum (like 0) but have an // automatic maximum function SetAutoMax($aMax) { $this->autoscale_max=$aMax; } // If the user manually specifies a scale should the ticks // still be set automatically? function SetAutoTicks($aFlag=true) { $this->auto_ticks = $aFlag; } // Specify scale "grace" value (top and bottom) function SetGrace($aGraceTop,$aGraceBottom=0) { if( $aGraceTop<0 || $aGraceBottom < 0 ) JpGraphError::RaiseL(25069);//(" Grace must be larger then 0"); $this->gracetop=$aGraceTop; $this->gracebottom=$aGraceBottom; } // Get the minimum value in the scale function GetMinVal() { return $this->scale[0]; } // get maximum value for scale function GetMaxVal() { return $this->scale[1]; } // Specify a new min/max value for sclae function Update(&$aImg,$aMin,$aMax) { $this->scale=array($aMin,$aMax); $this->world_size=$aMax-$aMin; $this->InitConstants($aImg); } // Translate between world and screen function Translate($aCoord) { if( !is_numeric($aCoord) ) { if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.'); return 0; } else { return $this->off + ($aCoord - $this->scale[0])*$this->scale_factor; } } // Relative translate (don't include offset) usefull when we just want // to know the relative position (in pixels) on the axis function RelTranslate($aCoord) { if( !is_numeric($aCoord) ) { if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.'); return 0; } else { return ($aCoord - $this->scale[0]) * $this->scale_factor; } } // Restrict autoscaling to only use integers function SetIntScale($aIntScale=true) { $this->intscale=$aIntScale; } // Calculate an integer autoscale function IntAutoScale(&$img,$min,$max,$maxsteps,$majend=true) { // Make sure limits are integers $min=floor($min); $max=ceil($max); if( abs($min-$max)==0 ) { --$min; ++$max; } $maxsteps = floor($maxsteps); $gracetop=round(($this->gracetop/100.0)*abs($max-$min)); $gracebottom=round(($this->gracebottom/100.0)*abs($max-$min)); if( is_numeric($this->autoscale_min) ) { $min = ceil($this->autoscale_min); if( $min >= $max ) { JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); } } if( is_numeric($this->autoscale_max) ) { $max = ceil($this->autoscale_max); if( $min >= $max ) { JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); } } if( abs($min-$max ) == 0 ) { ++$max; --$min; } $min -= $gracebottom; $max += $gracetop; // First get tickmarks as multiples of 1, 10, ... if( $majend ) { list($num1steps,$adj1min,$adj1max,$maj1step) = $this->IntCalcTicks($maxsteps,$min,$max,1); } else { $adj1min = $min; $adj1max = $max; list($num1steps,$maj1step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,1); } if( abs($min-$max) > 2 ) { // Then get tick marks as 2:s 2, 20, ... if( $majend ) { list($num2steps,$adj2min,$adj2max,$maj2step) = $this->IntCalcTicks($maxsteps,$min,$max,5); } else { $adj2min = $min; $adj2max = $max; list($num2steps,$maj2step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,5); } } else { $num2steps = 10000; // Dummy high value so we don't choose this } if( abs($min-$max) > 5 ) { // Then get tickmarks as 5:s 5, 50, 500, ... if( $majend ) { list($num5steps,$adj5min,$adj5max,$maj5step) = $this->IntCalcTicks($maxsteps,$min,$max,2); } else { $adj5min = $min; $adj5max = $max; list($num5steps,$maj5step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,2); } } else { $num5steps = 10000; // Dummy high value so we don't choose this } // Check to see whichof 1:s, 2:s or 5:s fit better with // the requested number of major ticks $match1=abs($num1steps-$maxsteps); $match2=abs($num2steps-$maxsteps); if( !empty($maj5step) && $maj5step > 1 ) $match5=abs($num5steps-$maxsteps); else $match5=10000; // Dummy high value // Compare these three values and see which is the closest match // We use a 0.6 weight to gravitate towards multiple of 5:s if( $match1 < $match2 ) { if( $match1 < $match5 ) $r=1; else $r=3; } else { if( $match2 < $match5 ) $r=2; else $r=3; } // Minsteps are always the same as maxsteps for integer scale switch( $r ) { case 1: $this->ticks->Set($maj1step,$maj1step); $this->Update($img,$adj1min,$adj1max); break; case 2: $this->ticks->Set($maj2step,$maj2step); $this->Update($img,$adj2min,$adj2max); break; case 3: $this->ticks->Set($maj5step,$maj5step); $this->Update($img,$adj5min,$adj5max); break; default: JpGraphError::RaiseL(25073,$r);//('Internal error. Integer scale algorithm comparison out of bound (r=$r)'); } } // Calculate autoscale. Used if user hasn't given a scale and ticks // $maxsteps is the maximum number of major tickmarks allowed. function AutoScale(&$img,$min,$max,$maxsteps,$majend=true) { if( $this->intscale ) { $this->IntAutoScale($img,$min,$max,$maxsteps,$majend); return; } if( abs($min-$max) < 0.00001 ) { // We need some difference to be able to autoscale // make it 5% above and 5% below value if( $min==0 && $max==0 ) { // Special case $min=-1; $max=1; } else { $delta = (abs($max)+abs($min))*0.005; $min -= $delta; $max += $delta; } } $gracetop=($this->gracetop/100.0)*abs($max-$min); $gracebottom=($this->gracebottom/100.0)*abs($max-$min); if( is_numeric($this->autoscale_min) ) { $min = $this->autoscale_min; if( $min >= $max ) { JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); } if( abs($min-$max ) < 0.00001 ) $max *= 1.2; } if( is_numeric($this->autoscale_max) ) { $max = $this->autoscale_max; if( $min >= $max ) { JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); } if( abs($min-$max ) < 0.00001 ) $min *= 0.8; } $min -= $gracebottom; $max += $gracetop; // First get tickmarks as multiples of 0.1, 1, 10, ... if( $majend ) { list($num1steps,$adj1min,$adj1max,$min1step,$maj1step) = $this->CalcTicks($maxsteps,$min,$max,1,2); } else { $adj1min=$min; $adj1max=$max; list($num1steps,$min1step,$maj1step) = $this->CalcTicksFreeze($maxsteps,$min,$max,1,2,false); } // Then get tick marks as 2:s 0.2, 2, 20, ... if( $majend ) { list($num2steps,$adj2min,$adj2max,$min2step,$maj2step) = $this->CalcTicks($maxsteps,$min,$max,5,2); } else { $adj2min=$min; $adj2max=$max; list($num2steps,$min2step,$maj2step) = $this->CalcTicksFreeze($maxsteps,$min,$max,5,2,false); } // Then get tickmarks as 5:s 0.05, 0.5, 5, 50, ... if( $majend ) { list($num5steps,$adj5min,$adj5max,$min5step,$maj5step) = $this->CalcTicks($maxsteps,$min,$max,2,5); } else { $adj5min=$min; $adj5max=$max; list($num5steps,$min5step,$maj5step) = $this->CalcTicksFreeze($maxsteps,$min,$max,2,5,false); } // Check to see whichof 1:s, 2:s or 5:s fit better with // the requested number of major ticks $match1=abs($num1steps-$maxsteps); $match2=abs($num2steps-$maxsteps); $match5=abs($num5steps-$maxsteps); // Compare these three values and see which is the closest match // We use a 0.8 weight to gravitate towards multiple of 5:s $r=$this->MatchMin3($match1,$match2,$match5,0.8); switch( $r ) { case 1: $this->Update($img,$adj1min,$adj1max); $this->ticks->Set($maj1step,$min1step); break; case 2: $this->Update($img,$adj2min,$adj2max); $this->ticks->Set($maj2step,$min2step); break; case 3: $this->Update($img,$adj5min,$adj5max); $this->ticks->Set($maj5step,$min5step); break; } } //--------------- // PRIVATE METHODS // This method recalculates all constants that are depending on the // margins in the image. If the margins in the image are changed // this method should be called for every scale that is registred with // that image. Should really be installed as an observer of that image. function InitConstants(&$img) { if( $this->type=="x" ) { $this->world_abs_size=$img->width - $img->left_margin - $img->right_margin; $this->off=$img->left_margin; $this->scale_factor = 0; if( $this->world_size > 0 ) $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); } else { // y scale $this->world_abs_size=$img->height - $img->top_margin - $img->bottom_margin; $this->off=$img->top_margin+$this->world_abs_size; $this->scale_factor = 0; if( $this->world_size > 0 ) { $this->scale_factor=-$this->world_abs_size/($this->world_size*1.0); } } $size = $this->world_size * $this->scale_factor; $this->scale_abs=array($this->off,$this->off + $size); } // Initialize the conversion constants for this scale // This tries to pre-calculate as much as possible to speed up the // actual conversion (with Translate()) later on // $start =scale start in absolute pixels (for x-scale this is an y-position // and for an y-scale this is an x-position // $len =absolute length in pixels of scale function SetConstants($aStart,$aLen) { $this->world_abs_size=$aLen; $this->off=$aStart; if( $this->world_size<=0 ) { // This should never ever happen !! JpGraphError::RaiseL(25074); //("You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is ".$this->world_size." [for ".$this->type." scale]
Please report Bug #01 to jpgraph@aditus.nu and include the script that gave this error. This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail."); } // scale_factor = number of pixels per world unit $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); // scale_abs = start and end points of scale in absolute pixels $this->scale_abs=array($this->off,$this->off+$this->world_size*$this->scale_factor); } // Calculate number of ticks steps with a specific division // $a is the divisor of 10**x to generate the first maj tick intervall // $a=1, $b=2 give major ticks with multiple of 10, ...,0.1,1,10,... // $a=5, $b=2 give major ticks with multiple of 2:s ...,0.2,2,20,... // $a=2, $b=5 give major ticks with multiple of 5:s ...,0.5,5,50,... // We return a vector of // [$numsteps,$adjmin,$adjmax,$minstep,$majstep] // If $majend==true then the first and last marks on the axis will be major // labeled tick marks otherwise it will be adjusted to the closest min tick mark function CalcTicks($maxsteps,$min,$max,$a,$b,$majend=true) { $diff=$max-$min; if( $diff==0 ) $ld=0; else $ld=floor(log10($diff)); // Gravitate min towards zero if we are close if( $min>0 && $min < pow(10,$ld) ) $min=0; //$majstep=pow(10,$ld-1)/$a; $majstep=pow(10,$ld)/$a; $minstep=$majstep/$b; $adjmax=ceil($max/$minstep)*$minstep; $adjmin=floor($min/$minstep)*$minstep; $adjdiff = $adjmax-$adjmin; $numsteps=$adjdiff/$majstep; while( $numsteps>$maxsteps ) { $majstep=pow(10,$ld)/$a; $numsteps=$adjdiff/$majstep; ++$ld; } $minstep=$majstep/$b; $adjmin=floor($min/$minstep)*$minstep; $adjdiff = $adjmax-$adjmin; if( $majend ) { $adjmin = floor($min/$majstep)*$majstep; $adjdiff = $adjmax-$adjmin; $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; } else $adjmax=ceil($max/$minstep)*$minstep; return array($numsteps,$adjmin,$adjmax,$minstep,$majstep); } function CalcTicksFreeze($maxsteps,$min,$max,$a,$b) { // Same as CalcTicks but don't adjust min/max values $diff=$max-$min; if( $diff==0 ) $ld=0; else $ld=floor(log10($diff)); //$majstep=pow(10,$ld-1)/$a; $majstep=pow(10,$ld)/$a; $minstep=$majstep/$b; $numsteps=floor($diff/$majstep); while( $numsteps > $maxsteps ) { $majstep=pow(10,$ld)/$a; $numsteps=floor($diff/$majstep); ++$ld; } $minstep=$majstep/$b; return array($numsteps,$minstep,$majstep); } function IntCalcTicks($maxsteps,$min,$max,$a,$majend=true) { $diff=$max-$min; if( $diff==0 ) JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.'); else $ld=floor(log10($diff)); // Gravitate min towards zero if we are close if( $min>0 && $min < pow(10,$ld) ) $min=0; if( $ld == 0 ) $ld=1; if( $a == 1 ) $majstep = 1; else $majstep=pow(10,$ld)/$a; $adjmax=ceil($max/$majstep)*$majstep; $adjmin=floor($min/$majstep)*$majstep; $adjdiff = $adjmax-$adjmin; $numsteps=$adjdiff/$majstep; while( $numsteps>$maxsteps ) { $majstep=pow(10,$ld)/$a; $numsteps=$adjdiff/$majstep; ++$ld; } $adjmin=floor($min/$majstep)*$majstep; $adjdiff = $adjmax-$adjmin; if( $majend ) { $adjmin = floor($min/$majstep)*$majstep; $adjdiff = $adjmax-$adjmin; $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; } else $adjmax=ceil($max/$majstep)*$majstep; return array($numsteps,$adjmin,$adjmax,$majstep); } function IntCalcTicksFreeze($maxsteps,$min,$max,$a) { // Same as IntCalcTick but don't change min/max values $diff=$max-$min; if( $diff==0 ) JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.'); else $ld=floor(log10($diff)); if( $ld == 0 ) $ld=1; if( $a == 1 ) $majstep = 1; else $majstep=pow(10,$ld)/$a; $numsteps=floor($diff/$majstep); while( $numsteps > $maxsteps ) { $majstep=pow(10,$ld)/$a; $numsteps=floor($diff/$majstep); ++$ld; } return array($numsteps,$majstep); } // Determine the minimum of three values witha weight for last value function MatchMin3($a,$b,$c,$weight) { if( $a < $b ) { if( $a < ($c*$weight) ) return 1; // $a smallest else return 3; // $c smallest } elseif( $b < ($c*$weight) ) return 2; // $b smallest return 3; // $c smallest } } // Class //=================================================== // CLASS RGB // Description: Color definitions as RGB triples //=================================================== class RGB { var $rgb_table; var $img; function RGB(&$aImg) { $this->img = &$aImg; // Conversion array between color names and RGB $this->rgb_table = array( "aqua"=> array(0,255,255), "lime"=> array(0,255,0), "teal"=> array(0,128,128), "whitesmoke"=>array(245,245,245), "gainsboro"=>array(220,220,220), "oldlace"=>array(253,245,230), "linen"=>array(250,240,230), "antiquewhite"=>array(250,235,215), "papayawhip"=>array(255,239,213), "blanchedalmond"=>array(255,235,205), "bisque"=>array(255,228,196), "peachpuff"=>array(255,218,185), "navajowhite"=>array(255,222,173), "moccasin"=>array(255,228,181), "cornsilk"=>array(255,248,220), "ivory"=>array(255,255,240), "lemonchiffon"=>array(255,250,205), "seashell"=>array(255,245,238), "mintcream"=>array(245,255,250), "azure"=>array(240,255,255), "aliceblue"=>array(240,248,255), "lavender"=>array(230,230,250), "lavenderblush"=>array(255,240,245), "mistyrose"=>array(255,228,225), "white"=>array(255,255,255), "black"=>array(0,0,0), "darkslategray"=>array(47,79,79), "dimgray"=>array(105,105,105), "slategray"=>array(112,128,144), "lightslategray"=>array(119,136,153), "gray"=>array(190,190,190), "lightgray"=>array(211,211,211), "midnightblue"=>array(25,25,112), "navy"=>array(0,0,128), "cornflowerblue"=>array(100,149,237), "darkslateblue"=>array(72,61,139), "slateblue"=>array(106,90,205), "mediumslateblue"=>array(123,104,238), "lightslateblue"=>array(132,112,255), "mediumblue"=>array(0,0,205), "royalblue"=>array(65,105,225), "blue"=>array(0,0,255), "dodgerblue"=>array(30,144,255), "deepskyblue"=>array(0,191,255), "skyblue"=>array(135,206,235), "lightskyblue"=>array(135,206,250), "steelblue"=>array(70,130,180), "lightred"=>array(211,167,168), "lightsteelblue"=>array(176,196,222), "lightblue"=>array(173,216,230), "powderblue"=>array(176,224,230), "paleturquoise"=>array(175,238,238), "darkturquoise"=>array(0,206,209), "mediumturquoise"=>array(72,209,204), "turquoise"=>array(64,224,208), "cyan"=>array(0,255,255), "lightcyan"=>array(224,255,255), "cadetblue"=>array(95,158,160), "mediumaquamarine"=>array(102,205,170), "aquamarine"=>array(127,255,212), "darkgreen"=>array(0,100,0), "darkolivegreen"=>array(85,107,47), "darkseagreen"=>array(143,188,143), "seagreen"=>array(46,139,87), "mediumseagreen"=>array(60,179,113), "lightseagreen"=>array(32,178,170), "palegreen"=>array(152,251,152), "springgreen"=>array(0,255,127), "lawngreen"=>array(124,252,0), "green"=>array(0,255,0), "chartreuse"=>array(127,255,0), "mediumspringgreen"=>array(0,250,154), "greenyellow"=>array(173,255,47), "limegreen"=>array(50,205,50), "yellowgreen"=>array(154,205,50), "forestgreen"=>array(34,139,34), "olivedrab"=>array(107,142,35), "darkkhaki"=>array(189,183,107), "khaki"=>array(240,230,140), "palegoldenrod"=>array(238,232,170), "lightgoldenrodyellow"=>array(250,250,210), "lightyellow"=>array(255,255,200), "yellow"=>array(255,255,0), "gold"=>array(255,215,0), "lightgoldenrod"=>array(238,221,130), "goldenrod"=>array(218,165,32), "darkgoldenrod"=>array(184,134,11), "rosybrown"=>array(188,143,143), "indianred"=>array(205,92,92), "saddlebrown"=>array(139,69,19), "sienna"=>array(160,82,45), "peru"=>array(205,133,63), "burlywood"=>array(222,184,135), "beige"=>array(245,245,220), "wheat"=>array(245,222,179), "sandybrown"=>array(244,164,96), "tan"=>array(210,180,140), "chocolate"=>array(210,105,30), "firebrick"=>array(178,34,34), "brown"=>array(165,42,42), "darksalmon"=>array(233,150,122), "salmon"=>array(250,128,114), "lightsalmon"=>array(255,160,122), "orange"=>array(255,165,0), "darkorange"=>array(255,140,0), "coral"=>array(255,127,80), "lightcoral"=>array(240,128,128), "tomato"=>array(255,99,71), "orangered"=>array(255,69,0), "red"=>array(255,0,0), "hotpink"=>array(255,105,180), "deeppink"=>array(255,20,147), "pink"=>array(255,192,203), "lightpink"=>array(255,182,193), "palevioletred"=>array(219,112,147), "maroon"=>array(176,48,96), "mediumvioletred"=>array(199,21,133), "violetred"=>array(208,32,144), "magenta"=>array(255,0,255), "violet"=>array(238,130,238), "plum"=>array(221,160,221), "orchid"=>array(218,112,214), "mediumorchid"=>array(186,85,211), "darkorchid"=>array(153,50,204), "darkviolet"=>array(148,0,211), "blueviolet"=>array(138,43,226), "purple"=>array(160,32,240), "mediumpurple"=>array(147,112,219), "thistle"=>array(216,191,216), "snow1"=>array(255,250,250), "snow2"=>array(238,233,233), "snow3"=>array(205,201,201), "snow4"=>array(139,137,137), "seashell1"=>array(255,245,238), "seashell2"=>array(238,229,222), "seashell3"=>array(205,197,191), "seashell4"=>array(139,134,130), "AntiqueWhite1"=>array(255,239,219), "AntiqueWhite2"=>array(238,223,204), "AntiqueWhite3"=>array(205,192,176), "AntiqueWhite4"=>array(139,131,120), "bisque1"=>array(255,228,196), "bisque2"=>array(238,213,183), "bisque3"=>array(205,183,158), "bisque4"=>array(139,125,107), "peachPuff1"=>array(255,218,185), "peachpuff2"=>array(238,203,173), "peachpuff3"=>array(205,175,149), "peachpuff4"=>array(139,119,101), "navajowhite1"=>array(255,222,173), "navajowhite2"=>array(238,207,161), "navajowhite3"=>array(205,179,139), "navajowhite4"=>array(139,121,94), "lemonchiffon1"=>array(255,250,205), "lemonchiffon2"=>array(238,233,191), "lemonchiffon3"=>array(205,201,165), "lemonchiffon4"=>array(139,137,112), "ivory1"=>array(255,255,240), "ivory2"=>array(238,238,224), "ivory3"=>array(205,205,193), "ivory4"=>array(139,139,131), "honeydew"=>array(193,205,193), "lavenderblush1"=>array(255,240,245), "lavenderblush2"=>array(238,224,229), "lavenderblush3"=>array(205,193,197), "lavenderblush4"=>array(139,131,134), "mistyrose1"=>array(255,228,225), "mistyrose2"=>array(238,213,210), "mistyrose3"=>array(205,183,181), "mistyrose4"=>array(139,125,123), "azure1"=>array(240,255,255), "azure2"=>array(224,238,238), "azure3"=>array(193,205,205), "azure4"=>array(131,139,139), "slateblue1"=>array(131,111,255), "slateblue2"=>array(122,103,238), "slateblue3"=>array(105,89,205), "slateblue4"=>array(71,60,139), "royalblue1"=>array(72,118,255), "royalblue2"=>array(67,110,238), "royalblue3"=>array(58,95,205), "royalblue4"=>array(39,64,139), "dodgerblue1"=>array(30,144,255), "dodgerblue2"=>array(28,134,238), "dodgerblue3"=>array(24,116,205), "dodgerblue4"=>array(16,78,139), "steelblue1"=>array(99,184,255), "steelblue2"=>array(92,172,238), "steelblue3"=>array(79,148,205), "steelblue4"=>array(54,100,139), "deepskyblue1"=>array(0,191,255), "deepskyblue2"=>array(0,178,238), "deepskyblue3"=>array(0,154,205), "deepskyblue4"=>array(0,104,139), "skyblue1"=>array(135,206,255), "skyblue2"=>array(126,192,238), "skyblue3"=>array(108,166,205), "skyblue4"=>array(74,112,139), "lightskyblue1"=>array(176,226,255), "lightskyblue2"=>array(164,211,238), "lightskyblue3"=>array(141,182,205), "lightskyblue4"=>array(96,123,139), "slategray1"=>array(198,226,255), "slategray2"=>array(185,211,238), "slategray3"=>array(159,182,205), "slategray4"=>array(108,123,139), "lightsteelblue1"=>array(202,225,255), "lightsteelblue2"=>array(188,210,238), "lightsteelblue3"=>array(162,181,205), "lightsteelblue4"=>array(110,123,139), "lightblue1"=>array(191,239,255), "lightblue2"=>array(178,223,238), "lightblue3"=>array(154,192,205), "lightblue4"=>array(104,131,139), "lightcyan1"=>array(224,255,255), "lightcyan2"=>array(209,238,238), "lightcyan3"=>array(180,205,205), "lightcyan4"=>array(122,139,139), "paleturquoise1"=>array(187,255,255), "paleturquoise2"=>array(174,238,238), "paleturquoise3"=>array(150,205,205), "paleturquoise4"=>array(102,139,139), "cadetblue1"=>array(152,245,255), "cadetblue2"=>array(142,229,238), "cadetblue3"=>array(122,197,205), "cadetblue4"=>array(83,134,139), "turquoise1"=>array(0,245,255), "turquoise2"=>array(0,229,238), "turquoise3"=>array(0,197,205), "turquoise4"=>array(0,134,139), "cyan1"=>array(0,255,255), "cyan2"=>array(0,238,238), "cyan3"=>array(0,205,205), "cyan4"=>array(0,139,139), "darkslategray1"=>array(151,255,255), "darkslategray2"=>array(141,238,238), "darkslategray3"=>array(121,205,205), "darkslategray4"=>array(82,139,139), "aquamarine1"=>array(127,255,212), "aquamarine2"=>array(118,238,198), "aquamarine3"=>array(102,205,170), "aquamarine4"=>array(69,139,116), "darkseagreen1"=>array(193,255,193), "darkseagreen2"=>array(180,238,180), "darkseagreen3"=>array(155,205,155), "darkseagreen4"=>array(105,139,105), "seagreen1"=>array(84,255,159), "seagreen2"=>array(78,238,148), "seagreen3"=>array(67,205,128), "seagreen4"=>array(46,139,87), "palegreen1"=>array(154,255,154), "palegreen2"=>array(144,238,144), "palegreen3"=>array(124,205,124), "palegreen4"=>array(84,139,84), "springgreen1"=>array(0,255,127), "springgreen2"=>array(0,238,118), "springgreen3"=>array(0,205,102), "springgreen4"=>array(0,139,69), "chartreuse1"=>array(127,255,0), "chartreuse2"=>array(118,238,0), "chartreuse3"=>array(102,205,0), "chartreuse4"=>array(69,139,0), "olivedrab1"=>array(192,255,62), "olivedrab2"=>array(179,238,58), "olivedrab3"=>array(154,205,50), "olivedrab4"=>array(105,139,34), "darkolivegreen1"=>array(202,255,112), "darkolivegreen2"=>array(188,238,104), "darkolivegreen3"=>array(162,205,90), "darkolivegreen4"=>array(110,139,61), "khaki1"=>array(255,246,143), "khaki2"=>array(238,230,133), "khaki3"=>array(205,198,115), "khaki4"=>array(139,134,78), "lightgoldenrod1"=>array(255,236,139), "lightgoldenrod2"=>array(238,220,130), "lightgoldenrod3"=>array(205,190,112), "lightgoldenrod4"=>array(139,129,76), "yellow1"=>array(255,255,0), "yellow2"=>array(238,238,0), "yellow3"=>array(205,205,0), "yellow4"=>array(139,139,0), "gold1"=>array(255,215,0), "gold2"=>array(238,201,0), "gold3"=>array(205,173,0), "gold4"=>array(139,117,0), "goldenrod1"=>array(255,193,37), "goldenrod2"=>array(238,180,34), "goldenrod3"=>array(205,155,29), "goldenrod4"=>array(139,105,20), "darkgoldenrod1"=>array(255,185,15), "darkgoldenrod2"=>array(238,173,14), "darkgoldenrod3"=>array(205,149,12), "darkgoldenrod4"=>array(139,101,8), "rosybrown1"=>array(255,193,193), "rosybrown2"=>array(238,180,180), "rosybrown3"=>array(205,155,155), "rosybrown4"=>array(139,105,105), "indianred1"=>array(255,106,106), "indianred2"=>array(238,99,99), "indianred3"=>array(205,85,85), "indianred4"=>array(139,58,58), "sienna1"=>array(255,130,71), "sienna2"=>array(238,121,66), "sienna3"=>array(205,104,57), "sienna4"=>array(139,71,38), "burlywood1"=>array(255,211,155), "burlywood2"=>array(238,197,145), "burlywood3"=>array(205,170,125), "burlywood4"=>array(139,115,85), "wheat1"=>array(255,231,186), "wheat2"=>array(238,216,174), "wheat3"=>array(205,186,150), "wheat4"=>array(139,126,102), "tan1"=>array(255,165,79), "tan2"=>array(238,154,73), "tan3"=>array(205,133,63), "tan4"=>array(139,90,43), "chocolate1"=>array(255,127,36), "chocolate2"=>array(238,118,33), "chocolate3"=>array(205,102,29), "chocolate4"=>array(139,69,19), "firebrick1"=>array(255,48,48), "firebrick2"=>array(238,44,44), "firebrick3"=>array(205,38,38), "firebrick4"=>array(139,26,26), "brown1"=>array(255,64,64), "brown2"=>array(238,59,59), "brown3"=>array(205,51,51), "brown4"=>array(139,35,35), "salmon1"=>array(255,140,105), "salmon2"=>array(238,130,98), "salmon3"=>array(205,112,84), "salmon4"=>array(139,76,57), "lightsalmon1"=>array(255,160,122), "lightsalmon2"=>array(238,149,114), "lightsalmon3"=>array(205,129,98), "lightsalmon4"=>array(139,87,66), "orange1"=>array(255,165,0), "orange2"=>array(238,154,0), "orange3"=>array(205,133,0), "orange4"=>array(139,90,0), "darkorange1"=>array(255,127,0), "darkorange2"=>array(238,118,0), "darkorange3"=>array(205,102,0), "darkorange4"=>array(139,69,0), "coral1"=>array(255,114,86), "coral2"=>array(238,106,80), "coral3"=>array(205,91,69), "coral4"=>array(139,62,47), "tomato1"=>array(255,99,71), "tomato2"=>array(238,92,66), "tomato3"=>array(205,79,57), "tomato4"=>array(139,54,38), "orangered1"=>array(255,69,0), "orangered2"=>array(238,64,0), "orangered3"=>array(205,55,0), "orangered4"=>array(139,37,0), "deeppink1"=>array(255,20,147), "deeppink2"=>array(238,18,137), "deeppink3"=>array(205,16,118), "deeppink4"=>array(139,10,80), "hotpink1"=>array(255,110,180), "hotpink2"=>array(238,106,167), "hotpink3"=>array(205,96,144), "hotpink4"=>array(139,58,98), "pink1"=>array(255,181,197), "pink2"=>array(238,169,184), "pink3"=>array(205,145,158), "pink4"=>array(139,99,108), "lightpink1"=>array(255,174,185), "lightpink2"=>array(238,162,173), "lightpink3"=>array(205,140,149), "lightpink4"=>array(139,95,101), "palevioletred1"=>array(255,130,171), "palevioletred2"=>array(238,121,159), "palevioletred3"=>array(205,104,137), "palevioletred4"=>array(139,71,93), "maroon1"=>array(255,52,179), "maroon2"=>array(238,48,167), "maroon3"=>array(205,41,144), "maroon4"=>array(139,28,98), "violetred1"=>array(255,62,150), "violetred2"=>array(238,58,140), "violetred3"=>array(205,50,120), "violetred4"=>array(139,34,82), "magenta1"=>array(255,0,255), "magenta2"=>array(238,0,238), "magenta3"=>array(205,0,205), "magenta4"=>array(139,0,139), "mediumred"=>array(140,34,34), "orchid1"=>array(255,131,250), "orchid2"=>array(238,122,233), "orchid3"=>array(205,105,201), "orchid4"=>array(139,71,137), "plum1"=>array(255,187,255), "plum2"=>array(238,174,238), "plum3"=>array(205,150,205), "plum4"=>array(139,102,139), "mediumorchid1"=>array(224,102,255), "mediumorchid2"=>array(209,95,238), "mediumorchid3"=>array(180,82,205), "mediumorchid4"=>array(122,55,139), "darkorchid1"=>array(191,62,255), "darkorchid2"=>array(178,58,238), "darkorchid3"=>array(154,50,205), "darkorchid4"=>array(104,34,139), "purple1"=>array(155,48,255), "purple2"=>array(145,44,238), "purple3"=>array(125,38,205), "purple4"=>array(85,26,139), "mediumpurple1"=>array(171,130,255), "mediumpurple2"=>array(159,121,238), "mediumpurple3"=>array(137,104,205), "mediumpurple4"=>array(93,71,139), "thistle1"=>array(255,225,255), "thistle2"=>array(238,210,238), "thistle3"=>array(205,181,205), "thistle4"=>array(139,123,139), "gray1"=>array(10,10,10), "gray2"=>array(40,40,30), "gray3"=>array(70,70,70), "gray4"=>array(100,100,100), "gray5"=>array(130,130,130), "gray6"=>array(160,160,160), "gray7"=>array(190,190,190), "gray8"=>array(210,210,210), "gray9"=>array(240,240,240), "darkgray"=>array(100,100,100), "darkblue"=>array(0,0,139), "darkcyan"=>array(0,139,139), "darkmagenta"=>array(139,0,139), "darkred"=>array(139,0,0), "silver"=>array(192, 192, 192), "eggplant"=>array(144,176,168), "lightgreen"=>array(144,238,144)); } //---------------- // PUBLIC METHODS // Colors can be specified as either // 1. #xxxxxx HTML style // 2. "colorname" as a named color // 3. array(r,g,b) RGB triple // This function translates this to a native RGB format and returns an // RGB triple. function Color($aColor) { if (is_string($aColor)) { // Strip of any alpha factor $pos = strpos($aColor,'@'); if( $pos === false ) { $alpha = 0; } else { $pos2 = strpos($aColor,':'); if( $pos2===false ) $pos2 = $pos-1; // Sentinel if( $pos > $pos2 ) { $alpha = substr($aColor,$pos+1); $aColor = substr($aColor,0,$pos); } else { $alpha = substr($aColor,$pos+1,$pos2-$pos-1); $aColor = substr($aColor,0,$pos).substr($aColor,$pos2); } } // Extract potential adjustment figure at end of color // specification $pos = strpos($aColor,":"); if( $pos === false ) { $adj = 1.0; } else { $adj = 0.0 + substr($aColor,$pos+1); $aColor = substr($aColor,0,$pos); } if( $adj < 0 ) JpGraphError::RaiseL(25077);//('Adjustment factor for color must be > 0'); if (substr($aColor, 0, 1) == "#") { $r = hexdec(substr($aColor, 1, 2)); $g = hexdec(substr($aColor, 3, 2)); $b = hexdec(substr($aColor, 5, 2)); } else { if(!isset($this->rgb_table[$aColor]) ) JpGraphError::RaiseL(25078,$aColor);//(" Unknown color: $aColor"); $tmp=$this->rgb_table[$aColor]; $r = $tmp[0]; $g = $tmp[1]; $b = $tmp[2]; } // Scale adj so that an adj=2 always // makes the color 100% white (i.e. 255,255,255. // and adj=1 neutral and adj=0 black. if( $adj > 1 ) { $m = ($adj-1.0)*(255-min(255,min($r,min($g,$b)))); return array(min(255,$r+$m), min(255,$g+$m), min(255,$b+$m),$alpha); } elseif( $adj < 1 ) { $m = ($adj-1.0)*max(255,max($r,max($g,$b))); return array(max(0,$r+$m), max(0,$g+$m), max(0,$b+$m),$alpha); } else { return array($r,$g,$b,$alpha); } } elseif( is_array($aColor) ) { if( count($aColor)==3 ) { $aColor[3]=0; return $aColor; } else return $aColor; } else JpGraphError::RaiseL(25079,$aColor,count($aColor));//(" Unknown color specification: $aColor , size=".count($aColor)); } // Compare two colors // return true if equal function Equal($aCol1,$aCol2) { $c1 = $this->Color($aCol1); $c2 = $this->Color($aCol2); if( $c1[0]==$c2[0] && $c1[1]==$c2[1] && $c1[2]==$c2[2] ) return true; else return false; } // Allocate a new color in the current image // Return new color index, -1 if no more colors could be allocated function Allocate($aColor,$aAlpha=0.0) { list ($r, $g, $b, $a) = $this->color($aColor); // If alpha is specified in the color string then this // takes precedence over the second argument if( $a > 0 ) $aAlpha = $a; if( $GLOBALS['gd2'] ) { if( $aAlpha < 0 || $aAlpha > 1 ) { JpGraphError::RaiseL(25080);//('Alpha parameter for color must be between 0.0 and 1.0'); } return imagecolorresolvealpha($this->img, $r, $g, $b, round($aAlpha * 127)); } else { $index = imagecolorexact($this->img, $r, $g, $b); if ($index == -1) { $index = imagecolorallocate($this->img, $r, $g, $b); if( USE_APPROX_COLORS && $index == -1 ) $index = imagecolorresolve($this->img, $r, $g, $b); } return $index; } } } // Class //=================================================== // CLASS Image // Description: Wrapper class with some goodies to form the // Interface to low level image drawing routines. //=================================================== class Image { var $img_format; var $expired=true; var $img=null; var $left_margin=30,$right_margin=20,$top_margin=20,$bottom_margin=30; var $plotwidth=0,$plotheight=0; var $rgb=null; var $current_color,$current_color_name; var $lastx=0, $lasty=0; var $width=0, $height=0; var $line_weight=1; var $line_style=1; // Default line style is solid var $obs_list=array(); var $font_size=12,$font_family=FF_FONT1, $font_style=FS_NORMAL; var $font_file=''; var $text_halign="left",$text_valign="bottom"; var $ttf=null; var $use_anti_aliasing=false; var $quality=null; var $colorstack=array(),$colorstackidx=0; var $canvascolor = 'white' ; var $langconv = null ; //--------------- // CONSTRUCTOR function Image($aWidth,$aHeight,$aFormat=DEFAULT_GFORMAT) { $this->CreateImgCanvas($aWidth,$aHeight); $this->SetAutoMargin(); if( !$this->SetImgFormat($aFormat) ) { JpGraphError::RaiseL(25081,$aFormat);//("JpGraph: Selected graphic format is either not supported or unknown [$aFormat]"); } $this->ttf = new TTF(); $this->langconv = new LanguageConv(); } // Should we use anti-aliasing. Note: This really slows down graphics! function SetAntiAliasing() { $this->use_anti_aliasing=true; } function CreateRawCanvas($aWidth=0,$aHeight=0) { if( $aWidth <= 1 || $aHeight <= 1 ) { JpGraphError::RaiseL(25082,$aWidth,$aHeight);//("Illegal sizes specified for width or height when creating an image, (width=$aWidth, height=$aHeight)"); } if( @$GLOBALS['gd2']==true && USE_TRUECOLOR ) { $this->img = @imagecreatetruecolor($aWidth, $aHeight); if( $this->img < 1 ) { JpGraphError::RaiseL(25126); //die("Can't create truecolor image. Check that you really have GD2 library installed."); } $this->SetAlphaBlending(); } else { $this->img = @imagecreate($aWidth, $aHeight); if( $this->img < 1 ) { JpGraphError::RaiseL(25126); //die("JpGraph Error: Can't create image. Check that you really have the GD library installed."); } } if( $this->rgb != null ) $this->rgb->img = $this->img ; else $this->rgb = new RGB($this->img); } function CloneCanvasH() { $oldimage = $this->img; $this->CreateRawCanvas($this->width,$this->height); imagecopy($this->img,$oldimage,0,0,0,0,$this->width,$this->height); return $oldimage; } function CreateImgCanvas($aWidth=0,$aHeight=0) { $old = array($this->img,$this->width,$this->height); $aWidth = round($aWidth); $aHeight = round($aHeight); $this->width=$aWidth; $this->height=$aHeight; if( $aWidth==0 || $aHeight==0 ) { // We will set the final size later. // Note: The size must be specified before any other // img routines that stroke anything are called. $this->img = null; $this->rgb = null; return $old; } $this->CreateRawCanvas($aWidth,$aHeight); // Set canvas color (will also be the background color for a // a pallett image $this->SetColor($this->canvascolor); $this->FilledRectangle(0,0,$aWidth,$aHeight); return $old ; } function CopyCanvasH($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY,$aWidth,$aHeight,$aw=-1,$ah=-1) { if( $aw === -1 ) { $aw = $aWidth; $ah = $aHeight; $f = 'imagecopyresized'; } else { $f = $GLOBALS['copyfunc'] ; } $f($aToHdl,$aFromHdl, $aToX,$aToY,$aFromX,$aFromY, $aWidth,$aHeight,$aw,$ah); } function Copy($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1) { $this->CopyCanvasH($this->img,$fromImg,$toX,$toY,$fromX,$fromY, $toWidth,$toHeight,$fromWidth,$fromHeight); } function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) { if( $aMix == 100 ) { $this->CopyCanvasH($this->img,$fromImg, $toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight); } else { if( ($fromWidth != -1 && ($fromWidth != $toWidth)) || ($fromHeight != -1 && ($fromHeight != $fromHeight)) ) { // Create a new canvas that will hold the re-scaled original from image if( $toWidth <= 1 || $toHeight <= 1 ) { JpGraphError::RaiseL(25083);//('Illegal image size when copying image. Size for copied to image is 1 pixel or less.'); } if( @$GLOBALS['gd2']==true && USE_TRUECOLOR ) { $tmpimg = @imagecreatetruecolor($toWidth, $toHeight); } else { $tmpimg = @imagecreate($toWidth, $toHeight); } if( $tmpimg < 1 ) { JpGraphError::RaiseL(25084);//('Failed to create temporary GD canvas. Out of memory ?'); } $this->CopyCanvasH($tmpimg,$fromImg,0,0,0,0, $toWidth,$toHeight,$fromWidth,$fromHeight); $fromImg = $tmpimg; } imagecopymerge($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$aMix); } } function GetWidth($aImg=null) { if( $aImg === null ) $aImg = $this->img; return imagesx($aImg); } function GetHeight($aImg=null) { if( $aImg === null ) $aImg = $this->img; return imagesy($aImg); } function CreateFromString($aStr) { $img = imagecreatefromstring($aStr); if( $img === false ) { JpGraphError::RaiseL(25085);//('An image can not be created from the supplied string. It is either in a format not supported or the string is representing an corrupt image.'); } return $img; } function SetCanvasH($aHdl) { $this->img = $aHdl; $this->rgb->img = $aHdl; } function SetCanvasColor($aColor) { $this->canvascolor = $aColor ; } function SetAlphaBlending($aFlg=true) { if( $GLOBALS['gd2'] ) ImageAlphaBlending($this->img,$aFlg); else JpGraphError::RaiseL(25086);//('You only seem to have GD 1.x installed. To enable Alphablending requires GD 2.x or higher. Please install GD or make sure the constant USE_GD2 is specified correctly to reflect your installation. By default it tries to autodetect what version of GD you have installed. On some very rare occasions it may falsely detect GD2 where only GD1 is installed. You must then set USE_GD2 to false.'); } function SetAutoMargin() { GLOBAL $gJpgBrandTiming; $min_bm=10; /* if( $gJpgBrandTiming ) $min_bm=15; */ $lm = min(40,$this->width/7); $rm = min(20,$this->width/10); $tm = max(20,$this->height/7); $bm = max($min_bm,$this->height/7); $this->SetMargin($lm,$rm,$tm,$bm); } //--------------- // PUBLIC METHODS function SetFont($family,$style=FS_NORMAL,$size=10) { $this->font_family=$family; $this->font_style=$style; $this->font_size=$size; $this->font_file=''; if( ($this->font_family==FF_FONT1 || $this->font_family==FF_FONT2) && $this->font_style==FS_BOLD ){ ++$this->font_family; } if( $this->font_family > FF_FONT2+1 ) { // A TTF font so get the font file // Check that this PHP has support for TTF fonts if( !function_exists('imagettfbbox') ) { JpGraphError::RaiseL(25087);//('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.'); exit(); } $this->font_file = $this->ttf->File($this->font_family,$this->font_style); } } // Get the specific height for a text string function GetTextHeight($txt="",$angle=0) { $tmp = split("\n",$txt); $n = count($tmp); $m=0; for($i=0; $i< $n; ++$i) $m = max($m,strlen($tmp[$i])); if( $this->font_family <= FF_FONT2+1 ) { if( $angle==0 ) { $h = imagefontheight($this->font_family); if( $h === false ) { JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); } return $n*$h; } else { $w = @imagefontwidth($this->font_family); if( $w === false ) { JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); } return $m*$w; } } else { $bbox = $this->GetTTFBBox($txt,$angle); return $bbox[1]-$bbox[5]; } } // Estimate font height function GetFontHeight($angle=0) { $txt = "XOMg"; return $this->GetTextHeight($txt,$angle); } // Approximate font width with width of letter "O" function GetFontWidth($angle=0) { $txt = 'O'; return $this->GetTextWidth($txt,$angle); } // Get actual width of text in absolute pixels function GetTextWidth($txt,$angle=0) { $tmp = split("\n",$txt); $n = count($tmp); if( $this->font_family <= FF_FONT2+1 ) { $m=0; for($i=0; $i < $n; ++$i) { $l=strlen($tmp[$i]); if( $l > $m ) { $m = $l; } } if( $angle==0 ) { $w = @imagefontwidth($this->font_family); if( $w === false ) { JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); } return $m*$w; } else { // 90 degrees internal so height becomes width $h = @imagefontheight($this->font_family); if( $h === false ) { JpGraphError::RaiseL(25089);//('You have a misconfigured GD font support. The call to imagefontheight() fails.'); } return $n*$h; } } else { // For TTF fonts we must walk through a lines and find the // widest one which we use as the width of the multi-line // paragraph $m=0; for( $i=0; $i < $n; ++$i ) { $bbox = $this->GetTTFBBox($tmp[$i],$angle); $mm = $bbox[2] - $bbox[0]; if( $mm > $m ) $m = $mm; } return $m; } } // Draw text with a box around it function StrokeBoxedText($x,$y,$txt,$dir=0,$fcolor="white",$bcolor="black", $shadowcolor=false,$paragraph_align="left", $xmarg=6,$ymarg=4,$cornerradius=0,$dropwidth=3) { if( !is_numeric($dir) ) { if( $dir=="h" ) $dir=0; elseif( $dir=="v" ) $dir=90; else JpGraphError::RaiseL(25090,$dir);//(" Unknown direction specified in call to StrokeBoxedText() [$dir]"); } if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { $width=$this->GetTextWidth($txt,$dir) ; $height=$this->GetTextHeight($txt,$dir) ; } else { $width=$this->GetBBoxWidth($txt,$dir) ; $height=$this->GetBBoxHeight($txt,$dir) ; } $height += 2*$ymarg; $width += 2*$xmarg; if( $this->text_halign=="right" ) $x -= $width; elseif( $this->text_halign=="center" ) $x -= $width/2; if( $this->text_valign=="bottom" ) $y -= $height; elseif( $this->text_valign=="center" ) $y -= $height/2; if( $shadowcolor ) { $this->PushColor($shadowcolor); $this->FilledRoundedRectangle($x-$xmarg+$dropwidth,$y-$ymarg+$dropwidth, $x+$width+$dropwidth,$y+$height-$ymarg+$dropwidth, $cornerradius); $this->PopColor(); $this->PushColor($fcolor); $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg, $x+$width,$y+$height-$ymarg, $cornerradius); $this->PopColor(); $this->PushColor($bcolor); $this->RoundedRectangle($x-$xmarg,$y-$ymarg, $x+$width,$y+$height-$ymarg,$cornerradius); $this->PopColor(); } else { if( $fcolor ) { $oc=$this->current_color; $this->SetColor($fcolor); $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius); $this->current_color=$oc; } if( $bcolor ) { $oc=$this->current_color; $this->SetColor($bcolor); $this->RoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius); $this->current_color=$oc; } } $h=$this->text_halign; $v=$this->text_valign; $this->SetTextAlign("left","top"); $this->StrokeText($x, $y, $txt, $dir, $paragraph_align); $bb = array($x-$xmarg,$y+$height-$ymarg,$x+$width,$y+$height-$ymarg, $x+$width,$y-$ymarg,$x-$xmarg,$y-$ymarg); $this->SetTextAlign($h,$v); return $bb; } // Set text alignment function SetTextAlign($halign,$valign="bottom") { $this->text_halign=$halign; $this->text_valign=$valign; } function _StrokeBuiltinFont($x,$y,$txt,$dir=0,$paragraph_align="left",&$aBoundingBox,$aDebug=false) { if( is_numeric($dir) && $dir!=90 && $dir!=0) JpGraphError::RaiseL(25091);//(" Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead."); $h=$this->GetTextHeight($txt); $fh=$this->GetFontHeight(); $w=$this->GetTextWidth($txt); if( $this->text_halign=="right") $x -= $dir==0 ? $w : $h; elseif( $this->text_halign=="center" ) { // For center we subtract 1 pixel since this makes the middle // be prefectly in the middle $x -= $dir==0 ? $w/2-1 : $h/2; } if( $this->text_valign=="top" ) $y += $dir==0 ? $h : $w; elseif( $this->text_valign=="center" ) $y += $dir==0 ? $h/2 : $w/2; if( $dir==90 ) { imagestringup($this->img,$this->font_family,$x,$y,$txt,$this->current_color); $aBoundingBox = array(round($x),round($y),round($x),round($y-$w),round($x+$h),round($y-$w),round($x+$h),round($y)); if( $aDebug ) { // Draw bounding box $this->PushColor('green'); $this->Polygon($aBoundingBox,true); $this->PopColor(); } } else { if( ereg("\n",$txt) ) { $tmp = split("\n",$txt); for($i=0; $i < count($tmp); ++$i) { $w1 = $this->GetTextWidth($tmp[$i]); if( $paragraph_align=="left" ) { imagestring($this->img,$this->font_family,$x,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); } elseif( $paragraph_align=="right" ) { imagestring($this->img,$this->font_family,$x+($w-$w1), $y-$h+1+$i*$fh,$tmp[$i],$this->current_color); } else { imagestring($this->img,$this->font_family,$x+$w/2-$w1/2, $y-$h+1+$i*$fh,$tmp[$i],$this->current_color); } } } else { //Put the text imagestring($this->img,$this->font_family,$x,$y-$h+1,$txt,$this->current_color); } if( $aDebug ) { // Draw the bounding rectangle and the bounding box $p1 = array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y)); // Draw bounding box $this->PushColor('green'); $this->Polygon($p1,true); $this->PopColor(); } $aBoundingBox=array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y)); } } function AddTxtCR($aTxt) { // If the user has just specified a '\n' // instead of '\n\t' we have to add '\r' since // the width will be too muchy otherwise since when // we print we stroke the individually lines by hand. $e = explode("\n",$aTxt); $n = count($e); for($i=0; $i<$n; ++$i) { $e[$i]=str_replace("\r","",$e[$i]); } return implode("\n\r",$e); } function GetTTFBBox($aTxt,$aAngle=0) { $bbox = @ImageTTFBBox($this->font_size,$aAngle,$this->font_file,$aTxt); if( $bbox === false ) { JpGraphError::RaiseL(25092,$this->font_file); //("There is either a configuration problem with TrueType or a problem reading font file (".$this->font_file."). Make sure file exists and is in a readable place for the HTTP process. (If 'basedir' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try uppgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library."); } return $bbox; } function GetBBoxTTF($aTxt,$aAngle=0) { // Normalize the bounding box to become a minimum // enscribing rectangle $aTxt = $this->AddTxtCR($aTxt); if( !is_readable($this->font_file) ) { JpGraphError::RaiseL(25093,$this->font_file); //('Can not read font file ('.$this->font_file.') in call to Image::GetBBoxTTF. Please make sure that you have set a font before calling this method and that the font is installed in the TTF directory.'); } $bbox = $this->GetTTFBBox($aTxt,$aAngle); if( $aAngle==0 ) return $bbox; if( $aAngle >= 0 ) { if( $aAngle <= 90 ) { //<=0 $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1], $bbox[2],$bbox[5],$bbox[6],$bbox[5]); } elseif( $aAngle <= 180 ) { //<= 2 $bbox = array($bbox[4],$bbox[7],$bbox[0],$bbox[7], $bbox[0],$bbox[3],$bbox[4],$bbox[3]); } elseif( $aAngle <= 270 ) { //<= 3 $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5], $bbox[6],$bbox[1],$bbox[2],$bbox[1]); } else { $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], $bbox[4],$bbox[7],$bbox[0],$bbox[7]); } } elseif( $aAngle < 0 ) { if( $aAngle <= -270 ) { // <= -3 $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1], $bbox[2],$bbox[5],$bbox[6],$bbox[5]); } elseif( $aAngle <= -180 ) { // <= -2 $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], $bbox[4],$bbox[7],$bbox[0],$bbox[7]); } elseif( $aAngle <= -90 ) { // <= -1 $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5], $bbox[6],$bbox[1],$bbox[2],$bbox[1]); } else { $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], $bbox[4],$bbox[7],$bbox[0],$bbox[7]); } } return $bbox; } function GetBBoxHeight($aTxt,$aAngle=0) { $box = $this->GetBBoxTTF($aTxt,$aAngle); return $box[1]-$box[7]+1; } function GetBBoxWidth($aTxt,$aAngle=0) { $box = $this->GetBBoxTTF($aTxt,$aAngle); return $box[2]-$box[0]+1; } function _StrokeTTF($x,$y,$txt,$dir=0,$paragraph_align="left",&$aBoundingBox,$debug=false) { // Setupo default inter line margin for paragraphs to // 25% of the font height. $ConstLineSpacing = 0.25 ; // Remember the anchor point before adjustment if( $debug ) { $ox=$x; $oy=$y; } if( !ereg("\n",$txt) || ($dir>0 && ereg("\n",$txt)) ) { // Format a single line $txt = $this->AddTxtCR($txt); $bbox=$this->GetBBoxTTF($txt,$dir); // Align x,y ot lower left corner of bbox $x -= $bbox[0]; $y -= $bbox[1]; // Note to self: "topanchor" is deprecated after we changed the // bopunding box stuff. if( $this->text_halign=="right" || $this->text_halign=="topanchor" ) $x -= $bbox[2]-$bbox[0]; elseif( $this->text_halign=="center" ) $x -= ($bbox[2]-$bbox[0])/2; if( $this->text_valign=="top" ) $y += abs($bbox[5])+$bbox[1]; elseif( $this->text_valign=="center" ) $y -= ($bbox[5]-$bbox[1])/2; ImageTTFText ($this->img, $this->font_size, $dir, $x, $y, $this->current_color,$this->font_file,$txt); // Calculate and return the co-ordinates for the bounding box $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$txt); $p1 = array(); for($i=0; $i < 4; ++$i) { $p1[] = round($box[$i*2]+$x); $p1[] = round($box[$i*2+1]+$y); } $aBoundingBox = $p1; // Debugging code to highlight the bonding box and bounding rectangle // For text at 0 degrees the bounding box and bounding rectangle are the // same if( $debug ) { // Draw the bounding rectangle and the bounding box $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$txt); $p = array(); $p1 = array(); for($i=0; $i < 4; ++$i) { $p[] = $bbox[$i*2]+$x; $p[] = $bbox[$i*2+1]+$y; $p1[] = $box[$i*2]+$x; $p1[] = $box[$i*2+1]+$y; } // Draw bounding box $this->PushColor('green'); $this->Polygon($p1,true); $this->PopColor(); // Draw bounding rectangle $this->PushColor('darkgreen'); $this->Polygon($p,true); $this->PopColor(); // Draw a cross at the anchor point $this->PushColor('red'); $this->Line($ox-15,$oy,$ox+15,$oy); $this->Line($ox,$oy-15,$ox,$oy+15); $this->PopColor(); } } else { // Format a text paragraph $fh=$this->GetFontHeight(); // Line margin is 25% of font height $linemargin=round($fh*$ConstLineSpacing); $fh += $linemargin; $w=$this->GetTextWidth($txt); $y -= $linemargin/2; $tmp = split("\n",$txt); $nl = count($tmp); $h = $nl * $fh; if( $this->text_halign=="right") $x -= $dir==0 ? $w : $h; elseif( $this->text_halign=="center" ) { $x -= $dir==0 ? $w/2 : $h/2; } if( $this->text_valign=="top" ) $y += $dir==0 ? $h : $w; elseif( $this->text_valign=="center" ) $y += $dir==0 ? $h/2 : $w/2; // Here comes a tricky bit. // Since we have to give the position for the string at the // baseline this means thaht text will move slightly up // and down depending on any of it's character descend below // the baseline, for example a 'g'. To adjust the Y-position // we therefore adjust the text with the baseline Y-offset // as used for the current font and size. This will keep the // baseline at a fixed positoned disregarding the actual // characters in the string. $standardbox = $this->GetTTFBBox('Gg',$dir); $yadj = $standardbox[1]; $xadj = $standardbox[0]; $aBoundingBox = array(); for($i=0; $i < $nl; ++$i) { $wl = $this->GetTextWidth($tmp[$i]); $bbox = $this->GetTTFBBox($tmp[$i],$dir); if( $paragraph_align=="left" ) { $xl = $x; } elseif( $paragraph_align=="right" ) { $xl = $x + ($w-$wl); } else { // Center $xl = $x + $w/2 - $wl/2 ; } $xl -= $bbox[0]; $yl = $y - $yadj; $xl = $xl - $xadj; ImageTTFText ($this->img, $this->font_size, $dir, $xl, $yl-($h-$fh)+$fh*$i, $this->current_color,$this->font_file,$tmp[$i]); if( $debug ) { // Draw the bounding rectangle around each line $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$tmp[$i]); $p = array(); for($j=0; $j < 4; ++$j) { $p[] = $bbox[$j*2]+$xl; $p[] = $bbox[$j*2+1]+$yl-($h-$fh)+$fh*$i; } // Draw bounding rectangle $this->PushColor('darkgreen'); $this->Polygon($p,true); $this->PopColor(); } } // Get the bounding box $bbox = $this->GetBBoxTTF($txt,$dir); for($j=0; $j < 4; ++$j) { $bbox[$j*2]+= round($x); $bbox[$j*2+1]+= round($y - ($h-$fh) - $yadj); } $aBoundingBox = $bbox; if( $debug ) { // Draw a cross at the anchor point $this->PushColor('red'); $this->Line($ox-25,$oy,$ox+25,$oy); $this->Line($ox,$oy-25,$ox,$oy+25); $this->PopColor(); } } } function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left",$debug=false) { $x = round($x); $y = round($y); // Do special language encoding $txt = $this->langconv->Convert($txt,$this->font_family); if( !is_numeric($dir) ) JpGraphError::RaiseL(25094);//(" Direction for text most be given as an angle between 0 and 90."); if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { $this->_StrokeBuiltinFont($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug); } elseif($this->font_family >= _FF_FIRST && $this->font_family <= _FF_LAST) { $this->_StrokeTTF($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug); } else JpGraphError::RaiseL(25095);//(" Unknown font font family specification. "); return $boundingbox; } function SetMargin($lm,$rm,$tm,$bm) { $this->left_margin=$lm; $this->right_margin=$rm; $this->top_margin=$tm; $this->bottom_margin=$bm; $this->plotwidth=$this->width - $this->left_margin-$this->right_margin ; $this->plotheight=$this->height - $this->top_margin-$this->bottom_margin ; if( $this->width > 0 && $this->height > 0 ) { if( $this->plotwidth < 0 || $this->plotheight < 0 ) JpGraphError::raise("Too small plot area. ($lm,$rm,$tm,$bm : $this->plotwidth x $this->plotheight). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins."); } } function SetTransparent($color) { imagecolortransparent ($this->img,$this->rgb->allocate($color)); } function SetColor($color,$aAlpha=0) { $this->current_color_name = $color; $this->current_color=$this->rgb->allocate($color,$aAlpha); if( $this->current_color == -1 ) { $tc=imagecolorstotal($this->img); JpGraphError::RaiseL(25096); //("Can't allocate any more colors. Image has already allocated maximum of $tc colors. This might happen if you have anti-aliasing turned on together with a background image or perhaps gradient fill since this requires many, many colors. Try to turn off anti-aliasing. If there is still a problem try downgrading the quality of the background image to use a smaller pallete to leave some entries for your graphs. You should try to limit the number of colors in your background image to 64. If there is still problem set the constant DEFINE(\"USE_APPROX_COLORS\",true); in jpgraph.php This will use approximative colors when the palette is full. Unfortunately there is not much JpGraph can do about this since the palette size is a limitation of current graphic format and what the underlying GD library suppports."); } return $this->current_color; } function PushColor($color) { if( $color != "" ) { $this->colorstack[$this->colorstackidx]=$this->current_color_name; $this->colorstack[$this->colorstackidx+1]=$this->current_color; $this->colorstackidx+=2; $this->SetColor($color); } else { JpGraphError::RaiseL(25097);//("Color specified as empty string in PushColor()."); } } function PopColor() { if($this->colorstackidx<1) JpGraphError::RaiseL(25098);//(" Negative Color stack index. Unmatched call to PopColor()"); $this->current_color=$this->colorstack[--$this->colorstackidx]; $this->current_color_name=$this->colorstack[--$this->colorstackidx]; } // Why this duplication? Because this way we can call this method // for any image and not only the current objsct function AdjSat($sat) { if( $GLOBALS['gd2'] && USE_TRUECOLOR ) return; $this->_AdjSat($this->img,$sat); } function _AdjSat($img,$sat) { $nbr = imagecolorstotal ($img); for( $i=0; $i<$nbr; ++$i ) { $colarr = imagecolorsforindex ($img,$i); $rgb[0]=$colarr["red"]; $rgb[1]=$colarr["green"]; $rgb[2]=$colarr["blue"]; $rgb = $this->AdjRGBSat($rgb,$sat); imagecolorset ($img, $i, $rgb[0], $rgb[1], $rgb[2]); } } function AdjBrightContrast($bright,$contr=0) { if( $GLOBALS['gd2'] && USE_TRUECOLOR ) return; $this->_AdjBrightContrast($this->img,$bright,$contr); } function _AdjBrightContrast($img,$bright,$contr=0) { if( $bright < -1 || $bright > 1 || $contr < -1 || $contr > 1 ) JpGraphError::RaiseL(25099);//(" Parameters for brightness and Contrast out of range [-1,1]"); $nbr = imagecolorstotal ($img); for( $i=0; $i<$nbr; ++$i ) { $colarr = imagecolorsforindex ($img,$i); $r = $this->AdjRGBBrightContrast($colarr["red"],$bright,$contr); $g = $this->AdjRGBBrightContrast($colarr["green"],$bright,$contr); $b = $this->AdjRGBBrightContrast($colarr["blue"],$bright,$contr); imagecolorset ($img, $i, $r, $g, $b); } } // Private helper function for adj sat // Adjust saturation for RGB array $u. $sat is a value between -1 and 1 // Note: Due to GD inability to handle true color the RGB values are only between // 8 bit. This makes saturation quite sensitive for small increases in parameter sat. // // Tip: To get a grayscale picture set sat=-100, values <-100 changes the colors // to it's complement. // // Implementation note: The saturation is implemented directly in the RGB space // by adjusting the perpendicular distance between the RGB point and the "grey" // line (1,1,1). Setting $sat>0 moves the point away from the line along the perp. // distance and a negative value moves the point closer to the line. // The values are truncated when the color point hits the bounding box along the // RGB axis. // DISCLAIMER: I'm not 100% sure this is he correct way to implement a color // saturation function in RGB space. However, it looks ok and has the expected effect. function AdjRGBSat($rgb,$sat) { // TODO: Should be moved to the RGB class // Grey vector $v=array(1,1,1); // Dot product $dot = $rgb[0]*$v[0]+$rgb[1]*$v[1]+$rgb[2]*$v[2]; // Normalize dot product $normdot = $dot/3; // dot/|v|^2 // Direction vector between $u and its projection onto $v for($i=0; $i<3; ++$i) $r[$i] = $rgb[$i] - $normdot*$v[$i]; // Adjustment factor so that sat==1 sets the highest RGB value to 255 if( $sat > 0 ) { $m=0; for( $i=0; $i<3; ++$i) { if( sign($r[$i]) == 1 && $r[$i]>0) $m=max($m,(255-$rgb[$i])/$r[$i]); } $tadj=$m; } else $tadj=1; $tadj = $tadj*$sat; for($i=0; $i<3; ++$i) { $un[$i] = round($rgb[$i] + $tadj*$r[$i]); if( $un[$i]<0 ) $un[$i]=0; // Truncate color when they reach 0 if( $un[$i]>255 ) $un[$i]=255;// Avoid potential rounding error } return $un; } // Private helper function for AdjBrightContrast function AdjRGBBrightContrast($rgb,$bright,$contr) { // TODO: Should be moved to the RGB class // First handle contrast, i.e change the dynamic range around grey if( $contr <= 0 ) { // Decrease contrast $adj = abs($rgb-128) * (-$contr); if( $rgb < 128 ) $rgb += $adj; else $rgb -= $adj; } else { // $contr > 0 // Increase contrast if( $rgb < 128 ) $rgb = $rgb - ($rgb * $contr); else $rgb = $rgb + ((255-$rgb) * $contr); } // Add (or remove) various amount of white $rgb += $bright*255; $rgb=min($rgb,255); $rgb=max($rgb,0); return $rgb; } function SetLineWeight($weight) { $this->line_weight = $weight; } function SetStartPoint($x,$y) { $this->lastx=round($x); $this->lasty=round($y); } function Arc($cx,$cy,$w,$h,$s,$e) { // GD Arc doesn't like negative angles while( $s < 0) $s += 360; while( $e < 0) $e += 360; imagearc($this->img,round($cx),round($cy),round($w),round($h), $s,$e,$this->current_color); } function FilledArc($xc,$yc,$w,$h,$s,$e,$style="") { if( $GLOBALS['gd2'] ) { while( $s < 0 ) $s += 360; while( $e < 0 ) $e += 360; if( $style=="" ) $style=IMG_ARC_PIE; imagefilledarc($this->img,round($xc),round($yc),round($w),round($h), round($s),round($e),$this->current_color,$style); return; } // In GD 1.x we have to do it ourself interesting enough there is surprisingly // little difference in time between doing it PHP and using the optimised GD // library (roughly ~20%) I had expected it to be at least 100% slower doing it // manually with a polygon approximation in PHP..... $fillcolor = $this->current_color_name; $w /= 2; // We use radius in our calculations instead $h /= 2; // Setup the angles so we have the same conventions as the builtin // FilledArc() which is a little bit strange if you ask me.... $s = 360-$s; $e = 360-$e; if( $e > $s ) { $e = $e - 360; $da = $s - $e; } $da = $s-$e; // We use radians $s *= M_PI/180; $e *= M_PI/180; $da *= M_PI/180; // Calculate a polygon approximation $p[0] = $xc; $p[1] = $yc; // Heuristic on how many polygons we need to make the // arc look good $numsteps = round(8 * abs($da) * ($w+$h)*($w+$h)/1500); if( $numsteps == 0 ) return; if( $numsteps < 7 ) $numsteps=7; $delta = abs($da)/$numsteps; $pa=array(); $a = $s; for($i=1; $i<=$numsteps; ++$i ) { $p[2*$i] = round($xc + $w*cos($a)); $p[2*$i+1] = round($yc - $h*sin($a)); //$a = $s + $i*$delta; $a -= $delta; $pa[2*($i-1)] = $p[2*$i]; $pa[2*($i-1)+1] = $p[2*$i+1]; } // Get the last point at the exact ending angle to avoid // any rounding errors. $p[2*$i] = round($xc + $w*cos($e)); $p[2*$i+1] = round($yc - $h*sin($e)); $pa[2*($i-1)] = $p[2*$i]; $pa[2*($i-1)+1] = $p[2*$i+1]; $i++; $p[2*$i] = $xc; $p[2*$i+1] = $yc; if( $fillcolor != "" ) { $this->PushColor($fillcolor); imagefilledpolygon($this->img,$p,count($p)/2,$this->current_color); $this->PopColor(); } } function FilledCakeSlice($cx,$cy,$w,$h,$s,$e) { $this->CakeSlice($cx,$cy,$w,$h,$s,$e,$this->current_color_name); } function CakeSlice($xc,$yc,$w,$h,$s,$e,$fillcolor="",$arccolor="") { $s = round($s); $e = round($e); $w = round($w); $h = round($h); $xc = round($xc); $yc = round($yc); $this->PushColor($fillcolor); $this->FilledArc($xc,$yc,2*$w,2*$h,$s,$e); $this->PopColor(); if( $arccolor != "" ) { $this->PushColor($arccolor); // We add 2 pixels to make the Arc() better aligned with the filled arc. if( $GLOBALS['gd2'] ) { imagefilledarc($this->img,$xc,$yc,2*$w,2*$h,$s,$e,$this->current_color,IMG_ARC_NOFILL | IMG_ARC_EDGED ) ; } else { $this->Arc($xc,$yc,2*$w+2,2*$h+2,$s,$e); $xx = $w * cos(2*M_PI - $s*M_PI/180) + $xc; $yy = $yc - $h * sin(2*M_PI - $s*M_PI/180); $this->Line($xc,$yc,$xx,$yy); $xx = $w * cos(2*M_PI - $e*M_PI/180) + $xc; $yy = $yc - $h * sin(2*M_PI - $e*M_PI/180); $this->Line($xc,$yc,$xx,$yy); } $this->PopColor(); } } function Ellipse($xc,$yc,$w,$h) { $this->Arc($xc,$yc,$w,$h,0,360); } // Breseham circle gives visually better result then using GD // built in arc(). It takes some more time but gives better // accuracy. function BresenhamCircle($xc,$yc,$r) { $d = 3-2*$r; $x = 0; $y = $r; while($x<=$y) { $this->Point($xc+$x,$yc+$y); $this->Point($xc+$x,$yc-$y); $this->Point($xc-$x,$yc+$y); $this->Point($xc-$x,$yc-$y); $this->Point($xc+$y,$yc+$x); $this->Point($xc+$y,$yc-$x); $this->Point($xc-$y,$yc+$x); $this->Point($xc-$y,$yc-$x); if( $d<0 ) $d += 4*$x+6; else { $d += 4*($x-$y)+10; --$y; } ++$x; } } function Circle($xc,$yc,$r) { if( USE_BRESENHAM ) $this->BresenhamCircle($xc,$yc,$r); else { /* // Some experimental code snippet to see if we can get a decent // result doing a trig-circle // Create an approximated circle with 0.05 rad resolution $end = 2*M_PI; $l = $r/10; if( $l < 3 ) $l=3; $step_size = 2*M_PI/(2*$r*M_PI/$l); $pts = array(); $pts[] = $r + $xc; $pts[] = $yc; for( $a=$step_size; $a <= $end; $a += $step_size ) { $pts[] = round($xc + $r*cos($a)); $pts[] = round($yc - $r*sin($a)); } imagepolygon($this->img,$pts,count($pts)/2,$this->current_color); */ $this->Arc($xc,$yc,$r*2,$r*2,0,360); // For some reason imageellipse() isn't in GD 2.0.1, PHP 4.1.1 //imageellipse($this->img,$xc,$yc,$r,$r,$this->current_color); } } function FilledCircle($xc,$yc,$r) { if( $GLOBALS['gd2'] ) { imagefilledellipse($this->img,round($xc),round($yc), 2*$r,2*$r,$this->current_color); } else { for( $i=1; $i < 2*$r; $i += 2 ) { // To avoid moire patterns we have to draw some // 1 extra "skewed" filled circles $this->Arc($xc,$yc,$i,$i,0,360); $this->Arc($xc,$yc,$i+1,$i,0,360); $this->Arc($xc,$yc,$i+1,$i+1,0,360); } } } // Linear Color InterPolation function lip($f,$t,$p) { $p = round($p,1); $r = $f[0] + ($t[0]-$f[0])*$p; $g = $f[1] + ($t[1]-$f[1])*$p; $b = $f[2] + ($t[2]-$f[2])*$p; return array($r,$g,$b); } // Anti-aliased line. // Note that this is roughly 8 times slower then a normal line! function WuLine($x1,$y1,$x2,$y2) { // Get foreground line color $lc = imagecolorsforindex($this->img,$this->current_color); $lc = array($lc["red"],$lc["green"],$lc["blue"]); $dx = $x2-$x1; $dy = $y2-$y1; if( abs($dx) > abs($dy) ) { if( $dx<0 ) { $dx = -$dx;$dy = -$dy; $tmp=$x2;$x2=$x1;$x1=$tmp; $tmp=$y2;$y2=$y1;$y1=$tmp; } $x=$x1<<16; $y=$y1<<16; $yinc = ($dy*65535)/$dx; while( ($x >> 16) < $x2 ) { $bc = @imagecolorsforindex($this->img,imagecolorat($this->img,$x>>16,$y>>16)); if( $bc <= 0 ) { JpGraphError::RaiseL(25100);//('Problem with color palette and your GD setup. Please disable anti-aliasing or use GD2 with true-color. If you have GD2 library installed please make sure that you have set the USE_GD2 constant to true and that truecolor is enabled.'); } $bc=array($bc["red"],$bc["green"],$bc["blue"]); $this->SetColor($this->lip($lc,$bc,($y & 0xFFFF)/65535)); imagesetpixel($this->img,$x>>16,$y>>16,$this->current_color); $this->SetColor($this->lip($lc,$bc,(~$y & 0xFFFF)/65535)); imagesetpixel($this->img,$x>>16,($y>>16)+1,$this->current_color); $x += 65536; $y += $yinc; } } else { if( $dy<0 ) { $dx = -$dx;$dy = -$dy; $tmp=$x2;$x2=$x1;$x1=$tmp; $tmp=$y2;$y2=$y1;$y1=$tmp; } $x=$x1<<16; $y=$y1<<16; $xinc = ($dx*65535)/$dy; while( ($y >> 16) < $y2 ) { $bc = @imagecolorsforindex($this->img,imagecolorat($this->img,$x>>16,$y>>16)); if( $bc <= 0 ) { JpGraphError::RaiseL(25100);//('Problem with color palette and your GD setup. Please disable anti-aliasing or use GD2 with true-color. If you have GD2 library installed please make sure that you have set the USE_GD2 constant to true and truecolor is enabled.'); } $bc=array($bc["red"],$bc["green"],$bc["blue"]); $this->SetColor($this->lip($lc,$bc,($x & 0xFFFF)/65535)); imagesetpixel($this->img,$x>>16,$y>>16,$this->current_color); $this->SetColor($this->lip($lc,$bc,(~$x & 0xFFFF)/65535)); imagesetpixel($this->img,($x>>16)+1,$y>>16,$this->current_color); $y += 65536; $x += $xinc; } } $this->SetColor($lc); imagesetpixel($this->img,$x2,$y2,$this->current_color); imagesetpixel($this->img,$x1,$y1,$this->current_color); } // Set line style dashed, dotted etc function SetLineStyle($s) { if( is_numeric($s) ) { if( $s<1 || $s>4 ) JpGraphError::RaiseL(25101,$s);//(" Illegal numeric argument to SetLineStyle(): ($s)"); } elseif( is_string($s) ) { if( $s == "solid" ) $s=1; elseif( $s == "dotted" ) $s=2; elseif( $s == "dashed" ) $s=3; elseif( $s == "longdashed" ) $s=4; else JpGraphError::RaiseL(25102,$s);//(" Illegal string argument to SetLineStyle(): $s"); } else JpGraphError::RaiseL(25103,$s);//(" Illegal argument to SetLineStyle $s"); $this->line_style=$s; } // Same as Line but take the line_style into account function StyleLine($x1,$y1,$x2,$y2) { switch( $this->line_style ) { case 1:// Solid $this->Line($x1,$y1,$x2,$y2); break; case 2: // Dotted $this->DashedLine($x1,$y1,$x2,$y2,1,6); break; case 3: // Dashed $this->DashedLine($x1,$y1,$x2,$y2,2,4); break; case 4: // Longdashes $this->DashedLine($x1,$y1,$x2,$y2,8,6); break; default: JpGraphError::RaiseL(25104,$this->line_style);//(" Unknown line style: $this->line_style "); break; } } function Line($x1,$y1,$x2,$y2) { $x1 = round($x1); $x2 = round($x2); $y1 = round($y1); $y2 = round($y2); if( $this->line_weight==0 ) return; if( $this->use_anti_aliasing ) { $dx = $x2-$x1; $dy = $y2-$y1; // Vertical, Horizontal or 45 lines don't need anti-aliasing if( $dx!=0 && $dy!=0 && $dx!=$dy ) { $this->WuLine($x1,$y1,$x2,$y2); return; } } if( $this->line_weight==1 ) { imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); } elseif( $x1==$x2 ) { // Special case for vertical lines imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); $w1=floor($this->line_weight/2); $w2=floor(($this->line_weight-1)/2); for($i=1; $i<=$w1; ++$i) imageline($this->img,$x1+$i,$y1,$x2+$i,$y2,$this->current_color); for($i=1; $i<=$w2; ++$i) imageline($this->img,$x1-$i,$y1,$x2-$i,$y2,$this->current_color); } elseif( $y1==$y2 ) { // Special case for horizontal lines imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); $w1=floor($this->line_weight/2); $w2=floor(($this->line_weight-1)/2); for($i=1; $i<=$w1; ++$i) imageline($this->img,$x1,$y1+$i,$x2,$y2+$i,$this->current_color); for($i=1; $i<=$w2; ++$i) imageline($this->img,$x1,$y1-$i,$x2,$y2-$i,$this->current_color); } else { // General case with a line at an angle $a = atan2($y1-$y2,$x2-$x1); // Now establish some offsets from the center. This gets a little // bit involved since we are dealing with integer functions and we // want the apperance to be as smooth as possible and never be thicker // then the specified width. // We do the trig stuff to make sure that the endpoints of the line // are perpendicular to the line itself. $dx=(sin($a)*$this->line_weight/2); $dy=(cos($a)*$this->line_weight/2); $pnts = array($x2+$dx,$y2+$dy,$x2-$dx,$y2-$dy,$x1-$dx,$y1-$dy,$x1+$dx,$y1+$dy); imagefilledpolygon($this->img,$pnts,count($pnts)/2,$this->current_color); } $this->lastx=$x2; $this->lasty=$y2; } function Polygon($p,$closed=FALSE,$fast=FALSE) { if( $this->line_weight==0 ) return; $n=count($p); $oldx = $p[0]; $oldy = $p[1]; if( $fast ) { for( $i=2; $i < $n; $i+=2 ) { imageline($this->img,$oldx,$oldy,$p[$i],$p[$i+1],$this->current_color); $oldx = $p[$i]; $oldy = $p[$i+1]; } if( $closed ) { imageline($this->img,$p[$n*2-2],$p[$n*2-1],$p[0],$p[1],$this->current_color); } } else { for( $i=2; $i < $n; $i+=2 ) { $this->StyleLine($oldx,$oldy,$p[$i],$p[$i+1]); $oldx = $p[$i]; $oldy = $p[$i+1]; } } if( $closed ) $this->Line($oldx,$oldy,$p[0],$p[1]); } function FilledPolygon($pts) { $n=count($pts); if( $n == 0 ) { JpGraphError::RaiseL(25105);//('NULL data specified for a filled polygon. Check that your data is not NULL.'); } for($i=0; $i < $n; ++$i) $pts[$i] = round($pts[$i]); imagefilledpolygon($this->img,$pts,count($pts)/2,$this->current_color); } function Rectangle($xl,$yu,$xr,$yl) { $this->Polygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl,$xl,$yu)); } function FilledRectangle($xl,$yu,$xr,$yl) { $this->FilledPolygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl)); } function FilledRectangle2($xl,$yu,$xr,$yl,$color1,$color2,$style=1) { // Fill a rectangle with lines of two colors if( $style===1 ) { // Horizontal stripe if( $yl < $yu ) { $t = $yl; $yl=$yu; $yu=$t; } for( $y=$yu; $y <= $yl; ++$y) { $this->SetColor($color1); $this->Line($xl,$y,$xr,$y); ++$y; $this->SetColor($color2); $this->Line($xl,$y,$xr,$y); } } else { if( $xl < $xl ) { $t = $xl; $xl=$xr; $xr=$t; } for( $x=$xl; $x <= $xr; ++$x) { $this->SetColor($color1); $this->Line($x,$yu,$x,$yl); ++$x; $this->SetColor($color2); $this->Line($x,$yu,$x,$yl); } } } function ShadowRectangle($xl,$yu,$xr,$yl,$fcolor=false,$shadow_width=3,$shadow_color=array(102,102,102)) { // This is complicated by the fact that we must also handle the case where // the reactangle has no fill color $this->PushColor($shadow_color); $this->FilledRectangle($xr-$shadow_width,$yu+$shadow_width,$xr,$yl-$shadow_width-1); $this->FilledRectangle($xl+$shadow_width,$yl-$shadow_width,$xr,$yl); //$this->FilledRectangle($xl+$shadow_width,$yu+$shadow_width,$xr,$yl); $this->PopColor(); if( $fcolor==false ) $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); else { $this->PushColor($fcolor); $this->FilledRectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); $this->PopColor(); $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); } } function FilledRoundedRectangle($xt,$yt,$xr,$yl,$r=5) { if( $r==0 ) { $this->FilledRectangle($xt,$yt,$xr,$yl); return; } // To avoid overlapping fillings (which will look strange // when alphablending is enabled) we have no choice but // to fill the five distinct areas one by one. // Center square $this->FilledRectangle($xt+$r,$yt+$r,$xr-$r,$yl-$r); // Top band $this->FilledRectangle($xt+$r,$yt,$xr-$r,$yt+$r-1); // Bottom band $this->FilledRectangle($xt+$r,$yl-$r+1,$xr-$r,$yl); // Left band $this->FilledRectangle($xt,$yt+$r+1,$xt+$r-1,$yl-$r); // Right band $this->FilledRectangle($xr-$r+1,$yt+$r,$xr,$yl-$r); // Topleft & Topright arc $this->FilledArc($xt+$r,$yt+$r,$r*2,$r*2,180,270); $this->FilledArc($xr-$r,$yt+$r,$r*2,$r*2,270,360); // Bottomleft & Bottom right arc $this->FilledArc($xt+$r,$yl-$r,$r*2,$r*2,90,180); $this->FilledArc($xr-$r,$yl-$r,$r*2,$r*2,0,90); } function RoundedRectangle($xt,$yt,$xr,$yl,$r=5) { if( $r==0 ) { $this->Rectangle($xt,$yt,$xr,$yl); return; } // Top & Bottom line $this->Line($xt+$r,$yt,$xr-$r,$yt); $this->Line($xt+$r,$yl,$xr-$r,$yl); // Left & Right line $this->Line($xt,$yt+$r,$xt,$yl-$r); $this->Line($xr,$yt+$r,$xr,$yl-$r); // Topleft & Topright arc $this->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); $this->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); // Bottomleft & Bottomright arc $this->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); $this->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); } function FilledBevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='darkgray@0.4') { $this->FilledRectangle($x1,$y1,$x2,$y2); $this->Bevel($x1,$y1,$x2,$y2,$depth,$color1,$color2); } function Bevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='black@0.5') { $this->PushColor($color1); for( $i=0; $i < $depth; ++$i ) { $this->Line($x1+$i,$y1+$i,$x1+$i,$y2-$i); $this->Line($x1+$i,$y1+$i,$x2-$i,$y1+$i); } $this->PopColor(); $this->PushColor($color2); for( $i=0; $i < $depth; ++$i ) { $this->Line($x1+$i,$y2-$i,$x2-$i,$y2-$i); $this->Line($x2-$i,$y1+$i,$x2-$i,$y2-$i-1); } $this->PopColor(); } function StyleLineTo($x,$y) { $this->StyleLine($this->lastx,$this->lasty,$x,$y); $this->lastx=$x; $this->lasty=$y; } function LineTo($x,$y) { $this->Line($this->lastx,$this->lasty,$x,$y); $this->lastx=$x; $this->lasty=$y; } function Point($x,$y) { imagesetpixel($this->img,round($x),round($y),$this->current_color); } function Fill($x,$y) { imagefill($this->img,round($x),round($y),$this->current_color); } function FillToBorder($x,$y,$aBordColor) { $bc = $this->rgb->allocate($aBordColor); if( $bc == -1 ) { JpGraphError::RaiseL(25106);//('Image::FillToBorder : Can not allocate more colors'); exit(); } imagefilltoborder($this->img,round($x),round($y),$bc,$this->current_color); } function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) { $x1 = round($x1); $x2 = round($x2); $y1 = round($y1); $y2 = round($y2); // Code based on, but not identical to, work by Ariel Garza and James Pine $line_length = ceil (sqrt(pow(($x2 - $x1),2) + pow(($y2 - $y1),2)) ); $dx = ($line_length) ? ($x2 - $x1) / $line_length : 0; $dy = ($line_length) ? ($y2 - $y1) / $line_length : 0; $lastx = $x1; $lasty = $y1; $xmax = max($x1,$x2); $xmin = min($x1,$x2); $ymax = max($y1,$y2); $ymin = min($y1,$y2); for ($i = 0; $i < $line_length; $i += ($dash_length + $dash_space)) { $x = ($dash_length * $dx) + $lastx; $y = ($dash_length * $dy) + $lasty; // The last section might overshoot so we must take a computational hit // and check this. if( $x>$xmax ) $x=$xmax; if( $y>$ymax ) $y=$ymax; if( $x<$xmin ) $x=$xmin; if( $y<$ymin ) $y=$ymin; $this->Line($lastx,$lasty,$x,$y); $lastx = $x + ($dash_space * $dx); $lasty = $y + ($dash_space * $dy); } } function SetExpired($aFlg=true) { $this->expired = $aFlg; } // Generate image header function Headers() { // In case we are running from the command line with the client version of // PHP we can't send any headers. $sapi = php_sapi_name(); if( $sapi == 'cli' ) return; if( headers_sent($file,$lineno) ) { $file=basename($file); $t = new ErrMsgText(); $msg = $t->Get(10,$file,$lineno); die($msg); } if ($this->expired) { header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); header("Cache-Control: no-cache, must-revalidate"); header("Pragma: no-cache"); } header("Content-type: image/$this->img_format"); } // Adjust image quality for formats that allow this function SetQuality($q) { $this->quality = $q; } // Stream image to browser or to file function Stream($aFile="") { $func="image".$this->img_format; if( $this->img_format=="jpeg" && $this->quality != null ) { $res = @$func($this->img,$aFile,$this->quality); } else { if( $aFile != "" ) { $res = @$func($this->img,$aFile); if( !$res ) JpGraphError::RaiseL(25107,$aFile);//("Can't write to file '$aFile'. Check that the process running PHP has enough permission."); } else { $res = @$func($this->img); if( !$res ) JpGraphError::RaiseL(25108);//("Can't stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP."); } } } // Clear resource tide up by image function Destroy() { imagedestroy($this->img); } // Specify image format. Note depending on your installation // of PHP not all formats may be supported. function SetImgFormat($aFormat,$aQuality=75) { $this->quality = $aQuality; $aFormat = strtolower($aFormat); $tst = true; $supported = imagetypes(); if( $aFormat=="auto" ) { if( $supported & IMG_PNG ) $this->img_format="png"; elseif( $supported & IMG_JPG ) $this->img_format="jpeg"; elseif( $supported & IMG_GIF ) $this->img_format="gif"; else JpGraphError::RaiseL(25109);//("Your PHP (and GD-lib) installation does not appear to support any known graphic formats. You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images you must get the JPEG library. Please see the PHP docs for details."); return true; } else { if( $aFormat=="jpeg" || $aFormat=="png" || $aFormat=="gif" ) { if( $aFormat=="jpeg" && !($supported & IMG_JPG) ) $tst=false; elseif( $aFormat=="png" && !($supported & IMG_PNG) ) $tst=false; elseif( $aFormat=="gif" && !($supported & IMG_GIF) ) $tst=false; else { $this->img_format=$aFormat; return true; } } else $tst=false; if( !$tst ) JpGraphError::RaiseL(25110,$aFormat);//(" Your PHP installation does not support the chosen graphic format: $aFormat"); } } } // CLASS //=================================================== // CLASS RotImage // Description: Exactly as Image but draws the image at // a specified angle around a specified rotation point. //=================================================== class RotImage extends Image { var $m=array(); var $a=0; var $dx=0,$dy=0,$transx=0,$transy=0; function RotImage($aWidth,$aHeight,$a=0,$aFormat=DEFAULT_GFORMAT) { $this->Image($aWidth,$aHeight,$aFormat); $this->dx=$this->left_margin+$this->plotwidth/2; $this->dy=$this->top_margin+$this->plotheight/2; $this->SetAngle($a); } function SetCenter($dx,$dy) { $old_dx = $this->dx; $old_dy = $this->dy; $this->dx=$dx; $this->dy=$dy; $this->SetAngle($this->a); return array($old_dx,$old_dy); } function SetTranslation($dx,$dy) { $old = array($this->transx,$this->transy); $this->transx = $dx; $this->transy = $dy; return $old; } function UpdateRotMatrice() { $a = $this->a; $a *= M_PI/180; $sa=sin($a); $ca=cos($a); // Create the rotation matrix $this->m[0][0] = $ca; $this->m[0][1] = -$sa; $this->m[0][2] = $this->dx*(1-$ca) + $sa*$this->dy ; $this->m[1][0] = $sa; $this->m[1][1] = $ca; $this->m[1][2] = $this->dy*(1-$ca) - $sa*$this->dx ; } function SetAngle($a) { $tmp = $this->a; $this->a = $a; $this->UpdateRotMatrice(); return $tmp; } function Circle($xc,$yc,$r) { // Circle get's rotated through the Arc() call // made in the parent class parent::Circle($xc,$yc,$r); } function FilledCircle($xc,$yc,$r) { // If we use GD1 then Image::FilledCircle will use a // call to Arc so it will get rotated through the Arc // call. if( $GLOBALS['gd2'] ) { list($xc,$yc) = $this->Rotate($xc,$yc); } parent::FilledCircle($xc,$yc,$r); } function Arc($xc,$yc,$w,$h,$s,$e) { list($xc,$yc) = $this->Rotate($xc,$yc); $s += $this->a; $e += $this->a; parent::Arc($xc,$yc,$w,$h,$s,$e); } function FilledArc($xc,$yc,$w,$h,$s,$e) { list($xc,$yc) = $this->Rotate($xc,$yc); $s += $this->a; $e += $this->a; parent::FilledArc($xc,$yc,$w,$h,$s,$e); } function SetMargin($lm,$rm,$tm,$bm) { parent::SetMargin($lm,$rm,$tm,$bm); $this->dx=$this->left_margin+$this->plotwidth/2; $this->dy=$this->top_margin+$this->plotheight/2; $this->UpdateRotMatrice(); } function Rotate($x,$y) { // Optimization. Ignore rotation if Angle==0 || ANgle==360 if( $this->a == 0 || $this->a == 360 ) { return array($x + $this->transx, $y + $this->transy ); } else { $x1=round($this->m[0][0]*$x + $this->m[0][1]*$y,1) + $this->m[0][2] + $this->transx; $y1=round($this->m[1][0]*$x + $this->m[1][1]*$y,1) + $this->m[1][2] + $this->transy; return array($x1,$y1); } } function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) { list($toX,$toY) = $this->Rotate($toX,$toY); parent::CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight,$aMix); } function ArrRotate($pnts) { $n = count($pnts)-1; for($i=0; $i < $n; $i+=2) { list ($x,$y) = $this->Rotate($pnts[$i],$pnts[$i+1]); $pnts[$i] = $x; $pnts[$i+1] = $y; } return $pnts; } function Line($x1,$y1,$x2,$y2) { list($x1,$y1) = $this->Rotate($x1,$y1); list($x2,$y2) = $this->Rotate($x2,$y2); parent::Line($x1,$y1,$x2,$y2); } function Rectangle($x1,$y1,$x2,$y2) { // Rectangle uses Line() so it will be rotated through that call parent::Rectangle($x1,$y1,$x2,$y2); } function FilledRectangle($x1,$y1,$x2,$y2) { if( $y1==$y2 || $x1==$x2 ) $this->Line($x1,$y1,$x2,$y2); else $this->FilledPolygon(array($x1,$y1,$x2,$y1,$x2,$y2,$x1,$y2)); } function Polygon($pnts,$closed=FALSE,$fast=false) { //Polygon uses Line() so it will be rotated through that call parent::Polygon($pnts,$closed,$fast); } function FilledPolygon($pnts) { parent::FilledPolygon($this->ArrRotate($pnts)); } function Point($x,$y) { list($xp,$yp) = $this->Rotate($x,$y); parent::Point($xp,$yp); } function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left",$debug=false) { list($xp,$yp) = $this->Rotate($x,$y); return parent::StrokeText($xp,$yp,$txt,$dir,$paragraph_align,$debug); } } //=================================================== // CLASS ImgStreamCache // Description: Handle caching of graphs to files //=================================================== class ImgStreamCache { var $cache_dir; var $img=null; var $timeout=0; // Infinite timeout //--------------- // CONSTRUCTOR function ImgStreamCache(&$aImg, $aCacheDir=CACHE_DIR) { $this->img = &$aImg; $this->cache_dir = $aCacheDir; } //--------------- // PUBLIC METHODS // Specify a timeout (in minutes) for the file. If the file is older then the // timeout value it will be overwritten with a newer version. // If timeout is set to 0 this is the same as infinite large timeout and if // timeout is set to -1 this is the same as infinite small timeout function SetTimeout($aTimeout) { $this->timeout=$aTimeout; } // Output image to browser and also write it to the cache function PutAndStream(&$aImage,$aCacheFileName,$aInline,$aStrokeFileName) { // Some debugging code to brand the image with numbe of colors // used GLOBAL $gJpgBrandTiming; if( $gJpgBrandTiming ) { global $tim; $t=$tim->Pop()/1000.0; $c=$aImage->SetColor("black"); $t=sprintf(BRAND_TIME_FORMAT,round($t,3)); imagestring($this->img->img,2,5,$this->img->height-20,$t,$c); } // Check if we should stroke the image to an arbitrary file if( _FORCE_IMGTOFILE ) { $aStrokeFileName = _FORCE_IMGDIR.GenImgName(); } if( $aStrokeFileName!="" ) { if( $aStrokeFileName == "auto" ) $aStrokeFileName = GenImgName(); if( file_exists($aStrokeFileName) ) { // Delete the old file if( !@unlink($aStrokeFileName) ) JpGraphError::RaiseL(25111,$aStrokeFileName);//(" Can't delete cached image $aStrokeFileName. Permission problem?"); } $aImage->Stream($aStrokeFileName); return; } if( $aCacheFileName != "" && USE_CACHE) { $aCacheFileName = $this->cache_dir . $aCacheFileName; if( file_exists($aCacheFileName) ) { if( !$aInline ) { // If we are generating image off-line (just writing to the cache) // and the file exists and is still valid (no timeout) // then do nothing, just return. $diff=time()-filemtime($aCacheFileName); if( $diff < 0 ) JpGraphError::RaiseL(25112,$aCacheFileName);//(" Cached imagefile ($aCacheFileName) has file date in the future!!"); if( $this->timeout>0 && ($diff <= $this->timeout*60) ) return; } if( !@unlink($aCacheFileName) ) JpGraphError::RaiseL(25113,$aStrokeFileName);//(" Can't delete cached image $aStrokeFileName. Permission problem?"); $aImage->Stream($aCacheFileName); } else { $this->MakeDirs(dirname($aCacheFileName)); if( !is_writeable(dirname($aCacheFileName)) ) { JpGraphError::RaiseL(25114,$aCacheFileName);//('PHP has not enough permissions to write to the cache file '.$aCacheFileName.'. Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.'); } $aImage->Stream($aCacheFileName); } $res=true; // Set group to specified if( CACHE_FILE_GROUP != "" ) $res = @chgrp($aCacheFileName,CACHE_FILE_GROUP); if( CACHE_FILE_MOD != "" ) $res = @chmod($aCacheFileName,CACHE_FILE_MOD); if( !$res ) JpGraphError::RaiseL(25115,$aStrokeFileName);//(" Can't set permission for cached image $aStrokeFileName. Permission problem?"); $aImage->Destroy(); if( $aInline ) { if ($fh = @fopen($aCacheFileName, "rb") ) { $this->img->Headers(); fpassthru($fh); return; } else JpGraphError::RaiseL(25116,$aFile);//(" Cant open file from cache [$aFile]"); } } elseif( $aInline ) { $this->img->Headers(); $aImage->Stream(); return; } } // Check if a given image is in cache and in that case // pass it directly on to web browser. Return false if the // image file doesn't exist or exists but is to old function GetAndStream($aCacheFileName) { $aCacheFileName = $this->cache_dir.$aCacheFileName; if ( USE_CACHE && file_exists($aCacheFileName) && $this->timeout>=0 ) { $diff=time()-filemtime($aCacheFileName); if( $this->timeout>0 && ($diff > $this->timeout*60) ) { return false; } else { if ($fh = @fopen($aCacheFileName, "rb")) { $this->img->Headers(); fpassthru($fh); return true; } else JpGraphError::RaiseL(25117,$aCacheFileName);//(" Can't open cached image \"$aCacheFileName\" for reading."); } } return false; } //--------------- // PRIVATE METHODS // Create all necessary directories in a path function MakeDirs($aFile) { $dirs = array(); while ( !(file_exists($aFile)) ) { $dirs[] = $aFile; $aFile = dirname($aFile); } for ($i = sizeof($dirs)-1; $i>=0; $i--) { if(! @mkdir($dirs[$i],0777) ) JpGraphError::RaiseL(25118,$aFile);//(" Can't create directory $aFile. Make sure PHP has write permission to this directory."); // We also specify mode here after we have changed group. // This is necessary if Apache user doesn't belong the // default group and hence can't specify group permission // in the previous mkdir() call if( CACHE_FILE_GROUP != "" ) { $res=true; $res =@chgrp($dirs[$i],CACHE_FILE_GROUP); $res &= @chmod($dirs[$i],0777); if( !$res ) JpGraphError::RaiseL(25119,$aFile);//(" Can't set permissions for $aFile. Permission problems?"); } } return true; } } // CLASS Cache //=================================================== // CLASS Legend // Description: Responsible for drawing the box containing // all the legend text for the graph //=================================================== DEFINE('_DEFAULT_LPM_SIZE',8); class Legend { var $color=array(0,0,0); // Default fram color var $fill_color=array(235,235,235); // Default fill color var $shadow=true; // Shadow around legend "box" var $shadow_color='gray'; var $txtcol=array(); var $mark_abs_hsize=_DEFAULT_LPM_SIZE, $mark_abs_vsize=_DEFAULT_LPM_SIZE; var $xmargin=5,$ymargin=3,$shadow_width=2; var $xlmargin=2, $ylmargin=''; var $xpos=0.05, $ypos=0.15, $xabspos=-1, $yabspos=-1; var $halign="right", $valign="top"; var $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12; var $font_color='black'; var $hide=false,$layout_n=1; var $weight=1,$frameweight=1; var $csimareas=''; var $reverse = false ; //--------------- // CONSTRUCTOR function Legend() { // Empty } //--------------- // PUBLIC METHODS function Hide($aHide=true) { $this->hide=$aHide; } function SetHColMargin($aXMarg) { $this->xmargin = $aXMarg; } function SetVColMargin($aSpacing) { $this->ymargin = $aSpacing ; } function SetLeftMargin($aXMarg) { $this->xlmargin = $aXMarg; } // Synonym function SetLineSpacing($aSpacing) { $this->ymargin = $aSpacing ; } function SetShadow($aShow='gray',$aWidth=2) { if( is_string($aShow) ) { $this->shadow_color = $aShow; $this->shadow=true; } else $this->shadow=$aShow; $this->shadow_width=$aWidth; } function SetMarkAbsSize($aSize) { $this->mark_abs_vsize = $aSize ; $this->mark_abs_hsize = $aSize ; } function SetMarkAbsVSize($aSize) { $this->mark_abs_vsize = $aSize ; } function SetMarkAbsHSize($aSize) { $this->mark_abs_hsize = $aSize ; } function SetLineWeight($aWeight) { $this->weight = $aWeight; } function SetFrameWeight($aWeight) { $this->frameweight = $aWeight; } function SetLayout($aDirection=LEGEND_VERT) { $this->layout_n = $aDirection==LEGEND_VERT ? 1 : 99 ; } function SetColumns($aCols) { $this->layout_n = $aCols ; } function SetReverse($f=true) { $this->reverse = $f ; } // Set color on frame around box function SetColor($aFontColor,$aColor='black') { $this->font_color=$aFontColor; $this->color=$aColor; } function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { $this->font_family = $aFamily; $this->font_style = $aStyle; $this->font_size = $aSize; } function SetPos($aX,$aY,$aHAlign="right",$aVAlign="top") { $this->Pos($aX,$aY,$aHAlign,$aVAlign); } function SetAbsPos($aX,$aY,$aHAlign="right",$aVAlign="top") { $this->xabspos=$aX; $this->yabspos=$aY; $this->halign=$aHAlign; $this->valign=$aVAlign; } function Pos($aX,$aY,$aHAlign="right",$aVAlign="top") { if( !($aX<1 && $aY<1) ) JpGraphError::RaiseL(25120);//(" Position for legend must be given as percentage in range 0-1"); $this->xpos=$aX; $this->ypos=$aY; $this->halign=$aHAlign; $this->valign=$aVAlign; } function SetFillColor($aColor) { $this->fill_color=$aColor; } function Add($aTxt,$aColor,$aPlotmark="",$aLinestyle=0,$csimtarget="",$csimalt="") { $this->txtcol[]=array($aTxt,$aColor,$aPlotmark,$aLinestyle,$csimtarget,$csimalt); } function GetCSIMAreas() { return $this->csimareas; } function Stroke(&$aImg) { // Constant $fillBoxFrameWeight=1; if( $this->hide ) return; $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); if( $this->reverse ) { $this->txtcol = array_reverse($this->txtcol); } $n=count($this->txtcol); if( $n == 0 ) return; // Find out the max width and height of each column to be able // to size the legend box. $numcolumns = ($n > $this->layout_n ? $this->layout_n : $n); for( $i=0; $i < $numcolumns; ++$i ) { $colwidth[$i] = $aImg->GetTextWidth($this->txtcol[$i][0]) + 2*$this->xmargin + 2*$this->mark_abs_hsize; $colheight[$i] = 0; } // Find our maximum height in each row $rows = 0 ; $rowheight[0] = 0; for( $i=0; $i < $n; ++$i ) { $h = max($this->mark_abs_vsize,$aImg->GetTextHeight($this->txtcol[$i][0]))+$this->ymargin; if( $i % $numcolumns == 0 ) { $rows++; $rowheight[$rows-1] = 0; } $rowheight[$rows-1] = max($rowheight[$rows-1],$h); } $abs_height = 0; for( $i=0; $i < $rows; ++$i ) { $abs_height += $rowheight[$i] ; } // Make sure that the height is at least as high as mark size + ymargin $abs_height = max($abs_height,$this->mark_abs_vsize); // We add 3 extra pixels height to compensate for the difficult in // calculating font height $abs_height += $this->ymargin+3; // Find out the maximum width in each column for( $i=$numcolumns; $i < $n; ++$i ) { $colwidth[$i % $numcolumns] = max( $aImg->GetTextWidth($this->txtcol[$i][0])+2*$this->xmargin+2*$this->mark_abs_hsize,$colwidth[$i % $numcolumns]); } // Get the total width $mtw = 0; for( $i=0; $i < $numcolumns; ++$i ) { $mtw += $colwidth[$i] ; } // Find out maximum width we need for legend box $abs_width = $mtw+$this->xlmargin; if( $this->xabspos === -1 && $this->yabspos === -1 ) { $this->xabspos = $this->xpos*$aImg->width ; $this->yabspos = $this->ypos*$aImg->height ; } // Positioning of the legend box if( $this->halign=="left" ) $xp = $this->xabspos; elseif( $this->halign=="center" ) $xp = $this->xabspos - $abs_width/2; else $xp = $aImg->width - $this->xabspos - $abs_width; $yp=$this->yabspos; if( $this->valign=="center" ) $yp-=$abs_height/2; elseif( $this->valign=="bottom" ) $yp-=$abs_height; // Stroke legend box $aImg->SetColor($this->color); $aImg->SetLineWeight($this->frameweight); $aImg->SetLineStyle('solid'); if( $this->shadow ) $aImg->ShadowRectangle($xp,$yp,$xp+$abs_width+$this->shadow_width, $yp+$abs_height+$this->shadow_width, $this->fill_color,$this->shadow_width,$this->shadow_color); else { $aImg->SetColor($this->fill_color); $aImg->FilledRectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height); $aImg->SetColor($this->color); $aImg->Rectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height); } // x1,y1 is the position for the legend mark $x1=$xp+$this->mark_abs_hsize+$this->xlmargin; $y1=$yp + $this->ymargin; $f2 = round($aImg->GetTextHeight('X')/2); $grad = new Gradient($aImg); $patternFactory = null; // Now stroke each legend in turn // Each plot has added the following information to the legend // p[0] = Legend text // p[1] = Color, // p[2] = For markers a reference to the PlotMark object // p[3] = For lines the line style, for gradient the negative gradient style // p[4] = CSIM target // p[5] = CSIM Alt text $i = 1 ; $row = 0; foreach($this->txtcol as $p) { // STROKE DEBUG BOX if( _JPG_DEBUG ) { $aImg->SetLineWeight(1); $aImg->SetColor('red'); $aImg->SetLineStyle('solid'); $aImg->Rectangle($xp,$y1,$xp+$abs_width,$y1+$rowheight[$row]); } $aImg->SetLineWeight($this->weight); $x1 = round($x1); $y1=round($y1); if ( $p[2] != "" && $p[2]->GetType() > -1 ) { // Make a plot mark legend $aImg->SetColor($p[1]); if( is_string($p[3]) || $p[3]>0 ) { $aImg->SetLineStyle($p[3]); $aImg->StyleLine($x1-$this->mark_abs_hsize,$y1+$f2,$x1+$this->mark_abs_hsize,$y1+$f2); } // Stroke a mark with the standard size // (As long as it is not an image mark ) if( $p[2]->GetType() != MARK_IMG ) { $p[2]->iFormatCallback = ''; // Since size for circles is specified as the radius // this means that we must half the size to make the total // width behave as the other marks if( $p[2]->GetType() == MARK_FILLEDCIRCLE || $p[2]->GetType() == MARK_CIRCLE ) { $p[2]->SetSize(min($this->mark_abs_vsize,$this->mark_abs_hsize)/2); $p[2]->Stroke($aImg,$x1,$y1+$f2); } else { $p[2]->SetSize(min($this->mark_abs_vsize,$this->mark_abs_hsize)); $p[2]->Stroke($aImg,$x1,$y1+$f2); } } } elseif ( $p[2] != "" && (is_string($p[3]) || $p[3]>0 ) ) { // Draw a styled line $aImg->SetColor($p[1]); $aImg->SetLineStyle($p[3]); $aImg->StyleLine($x1-1,$y1+$f2,$x1+$this->mark_abs_hsize,$y1+$f2); $aImg->StyleLine($x1-1,$y1+$f2+1,$x1+$this->mark_abs_hsize,$y1+$f2+1); } else { // Draw a colored box $color = $p[1] ; // We make boxes slightly larger to better show $boxsize = min($this->mark_abs_vsize,$this->mark_abs_hsize) + 2 ; $ym = round($y1 + $f2 - $boxsize/2); // We either need to plot a gradient or a // pattern. To differentiate we use a kludge. // Patterns have a p[3] value of < -100 if( $p[3] < -100 ) { // p[1][0] == iPattern, p[1][1] == iPatternColor, p[1][2] == iPatternDensity if( $patternFactory == null ) { $patternFactory = new RectPatternFactory(); } $prect = $patternFactory->Create($p[1][0],$p[1][1],1); $prect->SetBackground($p[1][3]); $prect->SetDensity($p[1][2]+1); $prect->SetPos(new Rectangle($x1,$ym,$boxsize,$boxsize)); $prect->Stroke($aImg); $prect=null; } else { if( is_array($color) && count($color)==2 ) { // The client want a gradient color $grad->FilledRectangle($x1,$ym, $x1+$boxsize,$ym+$boxsize, $color[0],$color[1],-$p[3]); } else { $aImg->SetColor($p[1]); $aImg->FilledRectangle($x1,$ym,$x1+$boxsize,$ym+$boxsize); } $aImg->SetColor($this->color); $aImg->SetLineWeight($fillBoxFrameWeight); $aImg->Rectangle($x1,$ym,$x1+$boxsize,$ym+$boxsize); } } $aImg->SetColor($this->font_color); $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); $aImg->SetTextAlign("left","top"); $aImg->StrokeText(round($x1+$this->mark_abs_hsize+$this->xmargin),$y1,$p[0]); // Add CSIM for Legend if defined if( $p[4] != "" ) { $xe = $x1 + $this->xmargin+$this->mark_abs_hsize+$aImg->GetTextWidth($p[0]); $ye = $y1 + max($this->mark_abs_vsize,$aImg->GetTextHeight($p[0])); $coords = "$x1,$y1,$xe,$y1,$xe,$ye,$x1,$ye"; if( ! empty($p[4]) ) { $this->csimareas .= "csimareas .= " title=\"$tmp\""; } $this->csimareas .= " alt=\"\" />\n"; } } if( $i >= $this->layout_n ) { $x1 = $xp+$this->mark_abs_hsize+$this->xlmargin; $y1 += $rowheight[$row++]; $i = 1; } else { $x1 += $colwidth[($i-1) % $numcolumns] ; ++$i; } } } } // Class //=================================================== // CLASS DisplayValue // Description: Used to print data values at data points //=================================================== class DisplayValue { var $show=false,$format="%.1f",$negformat=""; var $iFormCallback=''; var $angle=0; var $ff=FF_FONT1,$fs=FS_NORMAL,$fsize=10; var $color="navy",$negcolor=""; var $margin=5,$valign="",$halign="center"; var $iHideZero=false; function Show($aFlag=true) { $this->show=$aFlag; } function SetColor($aColor,$aNegcolor="") { $this->color = $aColor; $this->negcolor = $aNegcolor; } function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) { $this->ff=$aFontFamily; $this->fs=$aFontStyle; $this->fsize=$aFontSize; } function SetMargin($aMargin) { $this->margin = $aMargin; } function SetAngle($aAngle) { $this->angle = $aAngle; } function SetAlign($aHAlign,$aVAlign='') { $this->halign = $aHAlign; $this->valign = $aVAlign; } function SetFormat($aFormat,$aNegFormat="") { $this->format= $aFormat; $this->negformat= $aNegFormat; } function SetFormatCallback($aFunc) { $this->iFormCallback = $aFunc; } function HideZero($aFlag=true) { $this->iHideZero=$aFlag; } function Stroke($img,$aVal,$x,$y) { if( $this->show ) { if( $this->negformat=="" ) $this->negformat=$this->format; if( $this->negcolor=="" ) $this->negcolor=$this->color; if( $aVal===NULL || (is_string($aVal) && ($aVal=="" || $aVal=="-" || $aVal=="x" ) ) ) return; if( is_numeric($aVal) && $aVal==0 && $this->iHideZero ) { return; } // Since the value is used in different cirumstances we need to check what // kind of formatting we shall use. For example, to display values in a line // graph we simply display the formatted value, but in the case where the user // has already specified a text string we don't fo anything. if( $this->iFormCallback != '' ) { $f = $this->iFormCallback; $sval = call_user_func($f,$aVal); } elseif( is_numeric($aVal) ) { if( $aVal >= 0 ) $sval=sprintf($this->format,$aVal); else $sval=sprintf($this->negformat,$aVal); } else $sval=$aVal; $y = $y-sign($aVal)*$this->margin; $txt = new Text($sval,$x,$y); $txt->SetFont($this->ff,$this->fs,$this->fsize); if( $this->valign == "" ) { if( $aVal >= 0 ) $valign = "bottom"; else $valign = "top"; } else $valign = $this->valign; $txt->Align($this->halign,$valign); $txt->SetOrientation($this->angle); if( $aVal > 0 ) $txt->SetColor($this->color); else $txt->SetColor($this->negcolor); $txt->Stroke($img); } } } //=================================================== // CLASS Plot // Description: Abstract base class for all concrete plot classes //=================================================== class Plot { var $line_weight=1; var $coords=array(); var $legend='',$hidelegend=false; var $csimtargets=array(); // Array of targets for CSIM var $csimareas=""; // Resultant CSIM area tags var $csimalts=null; // ALT:s for corresponding target var $color="black"; var $numpoints=0; var $weight=1; var $value; var $center=false; var $legendcsimtarget=''; var $legendcsimalt=''; //--------------- // CONSTRUCTOR function Plot(&$aDatay,$aDatax=false) { $this->numpoints = count($aDatay); if( $this->numpoints==0 ) JpGraphError::RaiseL(25121);//("Empty input data array specified for plot. Must have at least one data point."); $this->coords[0]=$aDatay; if( is_array($aDatax) ) $this->coords[1]=$aDatax; $this->value = new DisplayValue(); } //--------------- // PUBLIC METHODS // Stroke the plot // "virtual" function which must be implemented by // the subclasses function Stroke(&$aImg,&$aXScale,&$aYScale) { JpGraphError::RaiseL(25122);//("JpGraph: Stroke() must be implemented by concrete subclass to class Plot"); } function HideLegend($f=true) { $this->hidelegend = $f; } function DoLegend(&$graph) { if( !$this->hidelegend ) $this->Legend($graph); } function StrokeDataValue($img,$aVal,$x,$y) { $this->value->Stroke($img,$aVal,$x,$y); } // Set href targets for CSIM function SetCSIMTargets($aTargets,$aAlts=null) { $this->csimtargets=$aTargets; $this->csimalts=$aAlts; } // Get all created areas function GetCSIMareas() { return $this->csimareas; } // "Virtual" function which gets called before any scale // or axis are stroked used to do any plot specific adjustment function PreStrokeAdjust(&$aGraph) { if( substr($aGraph->axtype,0,4) == "text" && (isset($this->coords[1])) ) JpGraphError::RaiseL(25123);//("JpGraph: You can't use a text X-scale with specified X-coords. Use a \"int\" or \"lin\" scale instead."); return true; } // Get minimum values in plot function Min() { if( isset($this->coords[1]) ) $x=$this->coords[1]; else $x=""; if( $x != "" && count($x) > 0 ) $xm=min($x); else $xm=0; $y=$this->coords[0]; $cnt = count($y); if( $cnt > 0 ) { /* if( ! isset($y[0]) ) { JpGraphError('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)'); } */ //$ym = $y[0]; $i=0; while( $i<$cnt && !is_numeric($ym=$y[$i]) ) $i++; while( $i < $cnt) { if( is_numeric($y[$i]) ) $ym=min($ym,$y[$i]); ++$i; } } else $ym=""; return array($xm,$ym); } // Get maximum value in plot function Max() { if( isset($this->coords[1]) ) $x=$this->coords[1]; else $x=""; if( $x!="" && count($x) > 0 ) $xm=max($x); else { $xm = $this->numpoints-1; } $y=$this->coords[0]; if( count($y) > 0 ) { /* if( !isset($y[0]) ) { JpGraphError::Raise('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)'); //$y[0] = 0; // Change in 1.5.1 Don't treat this as an error any more. Just silently convert to 0 // Change in 1.17 Treat his as an error again !! This is the right way to do !! } */ $cnt = count($y); $i=0; while( $i<$cnt && !is_numeric($ym=$y[$i]) ) $i++; while( $i < $cnt ) { if( is_numeric($y[$i]) ) $ym=max($ym,$y[$i]); ++$i; } } else $ym=""; return array($xm,$ym); } function SetColor($aColor) { $this->color=$aColor; } function SetLegend($aLegend,$aCSIM="",$aCSIMAlt="") { $this->legend = $aLegend; $this->legendcsimtarget = $aCSIM; $this->legendcsimalt = $aCSIMAlt; } function SetWeight($aWeight) { $this->weight=$aWeight; } function SetLineWeight($aWeight=1) { $this->line_weight=$aWeight; } function SetCenter($aCenter=true) { $this->center = $aCenter; } // This method gets called by Graph class to plot anything that should go // into the margin after the margin color has been set. function StrokeMargin(&$aImg) { return true; } // Framework function the chance for each plot class to set a legend function Legend(&$aGraph) { if( $this->legend != "" ) $aGraph->legend->Add($this->legend,$this->color,"",0,$this->legendcsimtarget,$this->legendcsimalt); } } // Class //=================================================== // CLASS PlotLine // Description: // Data container class to hold properties for a static // line that is drawn directly in the plot area. // Usefull to add static borders inside a plot to show // for example set-values //=================================================== class PlotLine { var $weight=1; var $color="black"; var $direction=-1; var $scaleposition; //--------------- // CONSTRUCTOR function PlotLine($aDir=HORIZONTAL,$aPos=0,$aColor="black",$aWeight=1) { $this->direction = $aDir; $this->color=$aColor; $this->weight=$aWeight; $this->scaleposition=$aPos; } //--------------- // PUBLIC METHODS function SetPosition($aScalePosition) { $this->scaleposition=$aScalePosition; } function SetDirection($aDir) { $this->direction = $aDir; } function SetColor($aColor) { $this->color=$aColor; } function SetWeight($aWeight) { $this->weight=$aWeight; } function PreStrokeAdjust($aGraph) { // Nothing to do } function Stroke(&$aImg,&$aXScale,&$aYScale) { $aImg->SetColor($this->color); $aImg->SetLineWeight($this->weight); if( $this->direction == VERTICAL ) { $ymin_abs=$aYScale->Translate($aYScale->GetMinVal()); $ymax_abs=$aYScale->Translate($aYScale->GetMaxVal()); $xpos_abs=$aXScale->Translate($this->scaleposition); $aImg->Line($xpos_abs, $ymin_abs, $xpos_abs, $ymax_abs); } elseif( $this->direction == HORIZONTAL ) { $xmin_abs=$aXScale->Translate($aXScale->GetMinVal()); $xmax_abs=$aXScale->Translate($aXScale->GetMaxVal()); $ypos_abs=$aYScale->Translate($this->scaleposition); $aImg->Line($xmin_abs, $ypos_abs, $xmax_abs, $ypos_abs); } else JpGraphError::RaiseL(25125);//(" Illegal direction for static line"); } } // ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_antispam-digits.php ================================================ digits['6'][0]= 645 ; $this->digits['6'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAEBAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwMC'. 'BAQEBwAAAAAAAAABAgMEAAURBiESIjFRBxMUQRUWMmFTYnGRkrHC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFhEBAQEAAAAA'. 'AAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDslwiR3oDku8ONttsAvDiVyMcO/ET7ke5/aoOz6k1Vr5htNjW7a7M1yO3NTQU9JUDu'. 'GgrlSn8xyf6p4gXaHJvNps9/mKZtSkGdMjRwpfqAFBLLACRlZUrJONsI2717No1lbZ10kx7XGnRpKWQ/6GVGMfzEJ5VFIVtsOH6e'. 'wyKVhYsia0y22pLThSkJK1uniVgdThOM0ol+StIUhpopIyCFq3H8aUVCwnG3PGe4Rp6fLXJtMdyM0ojcIWvIz3HFnAPfrWTXb6GN'. 'WaLXDwZjVz8pKEfhuIUFg/bAz9sVJ61nt61mxJFslLtq7e5yPqiBT4UDklKw4MDpt+u+9bFiu9riXNu83R+fcr6tohuQ5HQhmK37'. 'paaC8DruScmg6X8KkjZEhbaB9KEyFYSOw26Uqd+e7Qerl5z74DY/1SomP//Z' ; //========================================================== // d2-small.jpg //========================================================== $this->digits['2'][0]= 606 ; $this->digits['2'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEQMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAFAAQHAv/EACsQAAEDBAEC'. 'BAYDAAAAAAAAAAIBAwQABQYRIRIxQVFhcQcTFSJSU5GU0f/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/xAAZEQACAwEAAAAAAAAA'. 'AAAAAAAAARESUUH/2gAMAwEAAhEDEQA/AOqXm/Q8dxmOL4PPSnCSNFixx6nXnkXgRT3Te17JWbGsveueSyLZdbPItNxOKLzTLjou'. 'gYCSoSoY8ISKSbFeUrzkdlnTL1YshskiErkQnFEZaF8kkdBBVdjyi6RNL5+9F486eS/ECVkcBtDt1vZcho5viS8ZCp9C9tAIAm/F'. 'VoPRU+HRtJ5JVRP1kP0PfwP+1VKrHBMliXG4Nw8VgE4xGkuqk2S1wTUNEVdIvgpL9iL6KtNxY7WOwo9tt0RCitj0sR2uCbFPPzH1'. '7+6rRuSRcljMBMsUy2tky045KOawZk5xtEFBJEROO3hx61kh2rPCIX3MhsyC4QmfTbC6lH8dq5212qwkiG5H6Y/9R2qm+ofxqqsL'. 'DLZ6f//Z' ; //========================================================== // d9-small.jpg //========================================================== $this->digits['9'][0]= 680 ; $this->digits['9'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwP/xAArEAABAwMD'. 'AgYBBQAAAAAAAAABAgMEBQYRABIhE1EUIjEzQUIHMlJhcdH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAYEQEAAwEAAAAAAAAA'. 'AAAAAAAAAREhQf/aAAwDAQACEQMRAD8AkK7brF6X7XpMeGoKhFMLEeT4ZUheEhanF4OcZ2pTgDykk92bZpdCsi7aezLjxkIPUZiV'. 'RSCy8hah7EkZ27yM7V+iscal5bE22Lon1qNDmSKROd8Sl+Ix1lMOlIS4HGgQpbStoUCnlJz8HmsXtW3Lst2rmBAelLMRRekOwnYz'. 'Edls9QKKnOVLyk7UgcbzzrdBthqEJJwZbAI4x1U/7o1TaFa9lG36aXaZTy54VrcXUgrzsGdx+T30aNydweqVw1GS87T6Lb86Q4ha'. 'my/IAYjZBx+snKk99oOQMf1AViE65SY348hzFy6hPKnqtKz7DC1lbqyPrvJKUJ7H+M6Wrt3InP7o1brFNp4bCDGhxGAsqz69VSiQ'. 'ORwBxrrQ7itm1ac7Hp0WoGTIc3PSn0pccdcP2WorycfA1RaRHjxosZqOyhtDTSAhCf2gDAGjVHTd9sKSCumynFEZK1tIJUe58/ro'. '1V1//9k=' ; //========================================================== // d5-small.jpg //========================================================== $this->digits['5'][0]= 632 ; $this->digits['5'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgIFBwT/xAAoEAABAwME'. 'AQQCAwAAAAAAAAABAgMEBQYRABIhIkEUMVFhBxNCgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/EABcRAQEBAQAAAAAAAAAAAAAA'. 'AAABEUH/2gAMAwEAAhEDEQA/ANGvW4YVOeiRX5b4mv5Sin05IdlupPKdo/j2SO3+6TbPNQvOsTVz33KRT4csR3YUF7Dsh5OSFvug'. 'kqG4FPBxnjxpvvi4KZb1pTpU+QwxUi2Y7ZIAefUk5ATxnB9/gbtL/wCH1UpuhPUlZlMVaQ0mS8zJjqZOPfc2TwpIUonI9tw40R1r'. 'WNGq/wBdJR1XT3lqHBUnGCfkfWjRWs1ve249erQqQYjOtN1FqPUpCXQ4WIzQSsJwT0UpRwQPG0nzqyuNHobjsl9kBuWqoOoXtT1/'. 'WppZcA8lKRj64HxqU+3KpAr6plElRVKef3S4E0K9O8pLXVzKcqSsJAB9wSAca6bSoNXeuA1+5pEV+SGFNU1iKVFqI0Vdx2AJUeoz'. '8DGlTDwG3CAf3q/pI0ah6MDhLz6U+EpXwPoaNMU//9k=' ; //========================================================== // d1-small.jpg //========================================================== $this->digits['1'][0]= 646 ; $this->digits['1'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEwMBIgACEQEDEQH/xAAZAAADAAMAAAAAAAAAAAAAAAAABQYCBAf/xAApEAACAQMD'. 'AwQBBQAAAAAAAAABAgMEBREABiESMUEHEyJRkSNCYXGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAA'. 'AAAAAAEREv/aAAwDAQACEQMRAD8A6jdd4WLbstILnc4Uq0VoWpkJknb6IjXLHJUePOlez923fcW4r1SxWlqC2UbdKirQif3Xw3yA'. 'OFAGT09/kO3OmV3a20MFRf6lIYPcpy7yRRAzgxjIy2M8YwcdiBzpX6d22VNvUlTXsFkuwkrKqNSfnK7F8OTzwrAY+l5zoxKskudN'. 'EgQPUT9PBkWF3DH+1GPxo1mLnRoAqF2VRgGOFmX/AAgY/GjRUP6hVMFv2FuFqUvUGrpDFJMBnpdyF5bsAQew7Hxzp6LZNT0yQ1DI'. 'wp0QCFBhD0jCsfLZHxbx5xxpTuvb1+v9PV7Ztk9roLPLCjmSSN3mX5ZwqjCgZX7PfWxDQb2in96pv9qq46aTE0bW4x9ceAWAYPwS'. 'PsYzoixgmheBGjIVcYCnjp/jHjHbRpe1JLn9OnopE/a0ykvjwDx47aNMXqP/2Q==' ; //========================================================== // d8-small.jpg //========================================================== $this->digits['8'][0]= 694 ; $this->digits['8'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AFQMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABgcEBf/EACsQAAEDAwMD'. 'AwMFAAAAAAAAAAECAwQFBhEAEiEUMVEHE0EVYYEiIzJCsf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/EABcRAQEBAQAAAAAAAAAA'. 'AAAAAAABERL/2gAMAwEAAhEDEQA/AKL6gVVUa0i1T5QjvTprUJMlxW4R9zgQXe/AH+kaWrntqlWjaq7gpcmotXAw82ht9yY4tch8'. 'uAFC0k7VBXPGMY51ruiaue+bThIj+7NbWqS+7HDxajFf6AlB/k44o8ZOABk4xkL0X0tZiojKrlRuGRJjugqldSlKGf6t7BuUQe3J'. '44xxxrA1a4KVJipLidri8uLHgqOcfjOPxo0o2hdDvS1CmV2Yl6fS5ioipIQR1CAlKkLKR2UUqAI8g6NRSwuuyHab6s1ufLI/Zai7'. 'UBJOxhTS0+6B32pWSFH4CidOdWU0ukLiN1BLr0zG5Sdm3GRvcPhIT858DvjXNrVsSLnm/VIdTXS6tTnFsxZTSN3jchaTwps+O/z9'. 'tcBVq3hIX0tYqlIiQHdy5CqRHKHXEjAOMgBKjnvyRk4xrQa7OiGt1K5biYZL8SoVEpjOqkFsONtJCNwASeCQrn7aNUKnQYtLp7EC'. 'EylmLHQltptPZKQOBo1FzH//2Q==' ; //========================================================== // d4-small.jpg //========================================================== $this->digits['4'][0]= 643 ; $this->digits['4'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABAYHAv/EAC0QAAIBAwQA'. 'BAMJAAAAAAAAAAECAwQFEQAGEiETFDFBUmGBByIjUVNxobHR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAIB/8QAGBEBAAMBAAAAAAAA'. 'AAAAAAAAAAERIVH/2gAMAwEAAhEDEQA/ANjM00Nxmt1xiWW31CZp5uJwoAAaOQ/n7qfcZHqO5my3q5XX7R6ijiqnNut9u4NyJ4yv'. 'JJyjYr8Xhrn5g599J7x3ulBNU7Zo7dXXXcLQ8kURYi4epYtkALjOePv1nUvbLvV7P3BZm3DR3eh88Kp7pVzBZI6iUhGWRRGWwE44'. 'HX3V+uiL1uHgt+vL/H+aNJQ3CSeCOaFqSaJ1DJKs/TqRkMOvQjvRorHE4pRDLNWLGlRHGUeYIORXs9e5B7OP31E0fmdyb/t0DJ4Q'. '27bfx3YZzPUIoAAz7IpOD6cuxq0uNumqLfVNDOqXBoZEjnZcqhIPXH4c46+WkdoWOltu3IDDLLLVVR83UVcuPEmmcZZ2/rHoAANG'. 'GI7KIY1ijoLeEQBVCwIoAHpgY6Hy0aZe7mJ2jeHLKcEhusj6aNKgzr//2Q==' ; //========================================================== // d7-small.jpg //========================================================== $this->digits['7'][0]= 658 ; $this->digits['7'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgEFBwT/xAAuEAABAwIE'. 'BAQGAwAAAAAAAAABAgMEBREABiExEhMiQSMyUXEHFBclVJFhk9L/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/8QAGREBAQEAAwAA'. 'AAAAAAAAAAAAAAEREiFR/9oADAMBAAIRAxEAPwDXq9mCjZeQ05VZ5ZST4bfEpa3VdglCbqUe+g9MZ5Uq7V8415WXoMSdQ6etgSps'. '19wpkCMDZKUpv0FZvbi1NzpYasMDLDUbMVXrtQdbeeU23xLWkj5RlLYK0J7anW9gbAjCzkOtsVSUJUdtc6dVZK51UeaFm4LKbhpC'. 'l7EhIFkDW974GbRI2XorUVls1OTdKAOqUpR0Hc3198GITQ6k+hLwrEpoODiDenRfW23bBicg78JXxPpD0mgVOW5PAivNNpahsPW5'. '8xxQaSVkboQnhsnYm5OHqDGp1IpsalMKjMsMIC3+XZKbJFth62/QOEfMOZqZXp9JcKZTcGmTky3meSi7xQklI81vMR+sXIz/AEgp'. 'Q0qPNu6ea8Q2jqtbp8+2w9h/OKORc/cpHjt1dDSHOtLZ4ekHW23bBjj+o9H/AB539aP94MG0+L//2Q==' ; //========================================================== // d3-small.jpg //========================================================== $this->digits['3'][0]= 662 ; $this->digits['3'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwL/xAArEAABBAED'. 'AwMDBQEAAAAAAAABAgMEBREABhIhMUEiMmETFZEHFkJDUdH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAYEQEBAQEBAAAAAAAA'. 'AAAAAAAAEQExQf/aAAwDAQACEQMRAD8A0vclruBdk3VVLLUNssGRJsZSCtqOjlgJAHvcOD6c4HnOdIbcttw1W5P29cFEhuawqTXS'. 'VsJjnCMBxKkJJx7goAde+ceJfdNxU0UNlyymyXHi6kxWUNl1S3EnkAEIHX2nv86qtTuZr9Q9+1VhRsOoYpYcgSVyAE/TdewkJxnK'. 'sBCjkdPGpnOtFMd3PqsXgfOAgD8Y0aX+11H9rDDjn8lr9yj5J+dGqsqxaw6Cc9cQZU4Sp7zTJsIrKlcUEKwhSin1JABI45GUjqOu'. 'lbOvjbc3Ts9ynjGCy445UuFLYRzbWgrT6fhSCQSMDke+pew2zYVly/d7YchNqkMJZnQpgV9J8IzwWFJyUrAJHYgjvpLbu37G5nR7'. 'vck5C3YRKYEOEVJZj8kjKypXqWvirjk9h+dB9i4faa89TDZUfKlIyT8k+To10a6KTkpcJ/0vL/7o0TS//9k=' ; } } class AntiSpam { var $iNumber=''; function AntiSpam($aNumber='') { $this->iNumber = $aNumber; } function Rand($aLen) { $d=''; for($i=0; $i < $aLen; ++$i) { $d .= rand(1,9); } $this->iNumber = $d; return $d; } function Stroke() { $n=strlen($this->iNumber); for($i=0; $i < $n; ++$i ) { if( !is_numeric($this->iNumber[$i]) || $this->iNumber[$i]==0 ) { return false; } } $dd = new HandDigits(); $n = strlen($this->iNumber); $img = @imagecreatetruecolor($n*$dd->iWidth, $dd->iHeight); if( $img < 1 ) { return false; } $start=0; for($i=0; $i < $n; ++$i ) { $size = $dd->digits[$this->iNumber[$i]][0]; $dimg = imagecreatefromstring(base64_decode($dd->digits[$this->iNumber[$i]][1])); imagecopy($img,$dimg,$start,0,0,0,imagesx($dimg), $dd->iHeight); $start += imagesx($dimg); } $resimg = @imagecreatetruecolor($start+4, $dd->iHeight+4); if( $resimg < 1 ) { return false; } imagecopy($resimg,$img,2,2,0,0,$start, $dd->iHeight); header("Content-type: image/jpeg"); imagejpeg($resimg); return true; } } ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_antispam.php ================================================ chars['j'][0]= 658 ; $this->chars['j'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUGBAf/xAAsEAACAQMDAwMBCQAAAAAAAAAB'. 'AgMEBREAEjEGIUEUUXGBBxMVIiNSYWKC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEC/8QAGhEAAwADAQAAAAAAAAAAAAAAAAECERIh'. 'Mv/aAAwDAQACEQMRAD8A6veK2st8zRWSyV1dUBfvHaGVI4hknsS7AFv4AyM57ayWbqeS+11xtT2etttwo4YqhEqnQs5bcAfyk4AZ'. 'SOeD441TKRTyingUBG4/ah8j684+dSFzh/BvtaslejMUu9DPQTDnLx4lQ/ONw1TGBm0jdRWqguEMghEisWilgDmNs4Ze+MEEEH40'. 'aUVFTa7JeLjRXu4GjhmnNbSfqFQVlA3rkckOjH/Q99Glmkl0C/Q06pvsvT9vttXHDF6T1KrWbs5gRgQJM+FDlQxPhjpF1XcVq+qe'. 'jEoKiOecXBqh2TDDYIXLKuP6549xk8auI6aJqV45oknWdNswkAIkGMYIxjGO2NR1F0LZY5qkWqkS1xrM0M8lMSJpY+TGrnJiQ577'. 'cEgeNHhi7D3qC3UN69M8tIakRhgrh9o748+eNGtcCiKjjpkQKlMTEg3ZwoxtHHtgfTRpYXArvp//2Q==' ; //========================================================== // lf-small.jpg //========================================================== $this->chars['f'][0]= 633 ; $this->chars['f'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQFBgcC/8QAKxAAAgEDAwMCBQUAAAAAAAAA'. 'AQIDBBEhAAUGEjFBEyIHFFFhoRUzYnGS/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQP/xAAaEQACAwEBAAAAAAAAAAAAAAAAAQIRMRIh'. '/9oADAMBAAIRAxEAPwDcnmLoIkiSYsouC3tA++O2lU9WkqVjJ+YdhZLsQI/4/YfQm50kZP0vbmaCSU0SRNIH6sghb9INs3t38dvp'. 'akUuz8x5DwdN5peS1jV1dSipSiVUigIcdQjQ26lIB/c6r3F86SZpE/zCFJaqsihQNhRgdj3Jyfxo0jDSbXHt9Oph9RAoV3qJGltY'. 'HDOxyb/nRpV0D3RXle21m48XraOk3IUSemUaV4g4Zc9ShcDtgff+tQfwvjq34Dtku7buamFqeJKemCCMxKFsEJU+/FrX8d76sEHG'. 'aNItzr4usVNdG3S0rmRYAVwEUmyjyQLZ11x7aF4zs9DQOyzml29I2cLa/pixIHi99DFCtU9dFuLIaijo9qiYPmR2mZmB9thgAHOD'. '4+mjUrURyrUNMZFEkkIOFuFAbsP9d/OjVIQ6Vh4tP//Z' ; //========================================================== // lb-small.jpg //========================================================== $this->chars['b'][0]= 645 ; $this->chars['b'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYCAwUH/8QAKxAAAQMDAwMDAwUAAAAAAAAA'. 'AQIDBAAFEQYSIRMxUSJBYQcVI2JxgqHw/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQL/xAAYEQEBAQEBAAAAAAAAAAAAAAAAATERYf/a'. 'AAwDAQACEQMRAD8A6H95mxNYwLXcX+pCuilSLXJ6YSplaUELjqxwe4IJ5PIPamJ2V0bPcS7+NxCX1cHggAnIP+xSd9RyzHh2m7FQ'. 'Q1CvMNQWTjCt+HFD+PB/Y1fI1PL1HFFt0zaGblFdJQ9cJjpZiqPJUlBAKnPcEpGB5NNRKdrOl1NlgiQol4R2w4Sc5VtGf7opZteo'. 'LhdorjUSM5FnQnlR50NeHQysYxtVxlJHIPgjtRRD3xkaghs6juumdHz4+Y7RVPnt59K2mk7W+fcKWsZ7djTXMkW+xMP3GRJjwIEN'. 'HTG/CWx5wPY8AADx2NYk3SL9wukvUjGobnBkORksIbjdMANozgEqSo8qJPGO/wAVO36IsjUmBIfZfuM7epZk3F9UhSSk5O0K9Kcq'. '8AcU3UzFuhUSBFud6nRXoz96mqmJZWg7m2dqUNhWBwdqQSP1UU5c/FFCn//Z' ; //========================================================== // d6-small.jpg //========================================================== $this->chars['6'][0]= 645 ; $this->chars['6'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAEBAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwMC'. 'BAQEBwAAAAAAAAABAgMEAAURBiESIjFRBxMUQRUWMmFTYnGRkrHC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFhEBAQEAAAAA'. 'AAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDslwiR3oDku8ONttsAvDiVyMcO/ET7ke5/aoOz6k1Vr5htNjW7a7M1yO3NTQU9JUDu'. 'GgrlSn8xyf6p4gXaHJvNps9/mKZtSkGdMjRwpfqAFBLLACRlZUrJONsI2717No1lbZ10kx7XGnRpKWQ/6GVGMfzEJ5VFIVtsOH6e'. 'wyKVhYsia0y22pLThSkJK1uniVgdThOM0ol+StIUhpopIyCFq3H8aUVCwnG3PGe4Rp6fLXJtMdyM0ojcIWvIz3HFnAPfrWTXb6GN'. 'WaLXDwZjVz8pKEfhuIUFg/bAz9sVJ61nt61mxJFslLtq7e5yPqiBT4UDklKw4MDpt+u+9bFiu9riXNu83R+fcr6tohuQ5HQhmK37'. 'paaC8DruScmg6X8KkjZEhbaB9KEyFYSOw26Uqd+e7Qerl5z74DY/1SomP//Z' ; //========================================================== // lx-small.jpg //========================================================== $this->chars['x'][0]= 650 ; $this->chars['x'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABMDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUHBgj/xAApEAABAwMDAwQCAwAAAAAAAAAB'. 'AgMEBQYRACFBBxIxFCJRgRNxkcHw/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAMAwEA'. 'AhEDEQA/AH9t3pKvO14UykVARa/HfAlxlDKXR24V2p3z7RlPwdtMep91uWdRGHWELjuTFFtLvcC4SNznnH+21O7ttiodOq1BvC0E'. 'p9I0lSX2kgqCSklK+5PKCMAng6zV2XRO6u3lSIURtbDRShltlZHa0tW7q/0MeTwnjxq1Jiw2xc9xTLbhSVU5iaXUFfqFFILgJOCd'. '9Gt3SXabR6REpkL8yo0RpLCFNx1qBCRjOQMHxo0pEr6o3um2LVYpMEpTVqg25lHn08dfcB9kEgfZ1LIFDuawqZRb7aQlLTzqglsg'. '9wQdveOEqBIB425xqhQuk8qo9UKlPrlRblw2ZBeCSVKW6CcoSrI2AGOT41SKzT4dYtmdS5bIXDZhNoWgbZJ94x8AYT/GkM03oNUc'. 'uKgwqtTZDTMOU0FttqRkoHggnPkEEHRrkJ6t1SlSHYUOc6zHaWrsbQrATk5/vRqK/9k=' ; //========================================================== // d2-small.jpg //========================================================== $this->chars['2'][0]= 606 ; $this->chars['2'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEQMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAFAAQHAv/EACsQAAEDBAEC'. 'BAYDAAAAAAAAAAIBAwQABQYRIRIxQVFhcQcTFSJSU5GU0f/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/xAAZEQACAwEAAAAAAAAA'. 'AAAAAAAAARESUUH/2gAMAwEAAhEDEQA/AOqXm/Q8dxmOL4PPSnCSNFixx6nXnkXgRT3Te17JWbGsveueSyLZdbPItNxOKLzTLjou'. 'gYCSoSoY8ISKSbFeUrzkdlnTL1YshskiErkQnFEZaF8kkdBBVdjyi6RNL5+9F486eS/ECVkcBtDt1vZcho5viS8ZCp9C9tAIAm/F'. 'VoPRU+HRtJ5JVRP1kP0PfwP+1VKrHBMliXG4Nw8VgE4xGkuqk2S1wTUNEVdIvgpL9iL6KtNxY7WOwo9tt0RCitj0sR2uCbFPPzH1'. '7+6rRuSRcljMBMsUy2tky045KOawZk5xtEFBJEROO3hx61kh2rPCIX3MhsyC4QmfTbC6lH8dq5212qwkiG5H6Y/9R2qm+ofxqqsL'. 'DLZ6f//Z' ; //========================================================== // lm-small.jpg //========================================================== $this->chars['m'][0]= 649 ; $this->chars['m'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAcDBAUCBv/EAC0QAAICAQMCBAMJAAAAAAAA'. 'AAECAwQRAAUSBiETMVFhB2KhFSIyQVJxgZHB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgED/8QAGREBAQEAAwAAAAAAAAAAAAAAAQAR'. 'EiEx/9oADAMBAAIRAxEAPwB0MI2lIdgI0Cly3kFXLEn2zx1FDdp7rbpbjUtRWKio3hyxOGQllJzkegX66rQ2qW87Zuk9S5FNVmru'. 'iywyBhjDKTkeXfSr+GRfYtq2KAO32b1BGxAZu0dyJ2DKPTxY1wPddVszycUq2Golq8jRWbcnJWwCVGMjz+VQP50atxMtm2ZUOY4l'. '4qfUnBP0x/Z0amy4jJm10Tt2yddWasFmfaRfdrlG3UcgArnxKzJ+Fu4DqCMkcgNem2DoWav8PLfTm+FPEkuSNTnqueS5bnHIv6CG'. 'LNjJwM99bm67NB1Ht89KSxNXnr2hNDbiUc47K4KyD2GQMfmMjUnS+7vuIktTqPCaaWCqAMMojPFyw8hyYMQBnAwNJHYGXPTsW9VN'. 'jg2zf50W9zk524GAEihuz+xbIOD82jW5TkjtRPZkTkJ+4VgDhQfuj/f3OjUxl1f/2Q==' ; //========================================================== // lt-small.jpg //========================================================== $this->chars['t'][0]= 648 ; $this->chars['t'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYH/8QAJxAAAQMDAgYDAQEAAAAAAAAA'. 'AQIDBAUGEQASEyExQVFhIjJxFSP/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAP/xAAZEQADAQEBAAAAAAAAAAAAAAAAAREhMUH/2gAM'. 'AwEAAhEDEQA/AO4BLEiEy7uG4IGxxs5IOOx76wd2XYidSp1HoD70240gcNNPbDyI6wQQpaz8E9MczkdhqtbsKYLieDk6WLKmZmmL'. 'Hk7AHVkbkLI+RQc7uRxgkfr1tx2rGu6VbToLVKkhU+kbugGf9WfaknCk5ycaX0zmaa+3JkqvW/CmzojsB9xoF6OoFK0r6HOcEDI0'. 'aefTuKX5ScMdC14HYq8n12zo1DEUcKTGg1Z+hyBwoPBVIiA/VQyOIgedhUCB4WMfXSV3UufVLcTUIqVf26K6mXDbPVRRzKT54iMg'. '+zjtq6mtsyJjclxpKlUhSXEbkgkqWnBx4+J5e/zU0pZemPvJJQzEPDfQOrwwFY9AZ5eeYPLV6FwhoFYZuigxpkJeIjqAeIoAk9wA'. 'D46EnuD+6Nc1smDNrTlRkxqtMo1vzKhIdYgU9YDqVpISrLhHxSSd21I0aYyqP//Z' ; //========================================================== // li-small.jpg //========================================================== $this->chars['i'][0]= 639 ; $this->chars['i'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABwAGBP/EACcQAAEEAQMEAgIDAAAAAAAAAAEC'. 'AwQRBQAGEiExQVEHExSBFWFx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgMB/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECMRH/2gAMAwEA'. 'AhEDEQA/AE7c+5M9BeRG29t1WUfKFFYW+GvrI7WD3B9g140YD5T36rcErDjbUR6dCBdejsKUpxITXI2FUrooCh70yvxzHyIlMvuK'. 'eVSH7IKEpJoKqu/ahddLryR/aMiO187bsmrWShhp1AZS2XHHrWhNJrzdf7f7GiVcHk3sptmHkJcJ2DIftS2FrKlJPXudWuLGYeQp'. 't2fmEIckqIZaaKuSGG0lQ4gduRoFRHQ9AOgs2lOJbk9aSUlpjGvAWeSVH2VKq/2dFPw3IjyJe8s281ct3I9UoHJXGiQkD2STrSZ7'. 'Yf8AOl7JTdw5eOCz0jw3+LbYCfA9nz71msb8KMxoTGTw+5srjsipAdDqFBQBIuiOl6KrdYyJMyTCshlw2G3Fr/HiNqNNAqJJUoGl'. 'KND+h47km1bZwsvCbYYjycxIyK1qDv2yEi0hQviK8atKDcy9j//Z' ; //========================================================== // lp-small.jpg //========================================================== $this->chars['p'][0]= 700 ; $this->chars['p'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAECBAUGB//EAC8QAAEDAwMCBAMJAAAAAAAA'. 'AAECAwQFESEABhIiMRMVUWEHFEEWIzIzcYGRocH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAgH/xAAcEQACAgIDAAAAAAAAAAAAAAAA'. 'AQIxAxESIUH/2gAMAwEAAhEDEQA/AOh703xG21DMeOyqoVNDjSzERiwU6Ep5qtZNycA97HTF13d33KWtmlt9xwkLl1NkXVxIuQgK'. 'wLj+hqBvel0qmbR8GnR22nJNZiLeeKr8nDIT1OLJucX+uPbWom7iocRpafOac5MX1ALltp/Cbi+cJH++utdh+WVNL3PNdNYpdWgx'. 'Y0qmLZSrwJJcQoOJ5XKlJFu4HbJOjVbt+V5nu7eopNRivqcdhK+bFnWwA1Y2AOcgjvj9dGlxy0g5y0xd+hNXoG24C4obizq3HZUh'. 'YHqtRHD06bG/8a0MbbG1mqekxaBSGmgkrcdcitlLfrckZIz7DUatbeFak0tyRLUwzT5vmiGm0cufEkFBJItfkD+59tKmiO12atFa'. 'eQukO3ejUxgENqTcfnE5WbkHiOnJ76N2IqI1DibabptS+zkZhtp90F2Y0S026EkAFK/qL46cXv65NVZDfxHmVCK4DE2/RX/lRFbA'. 'C5LwAyq2EtpHZI7mxPYDRqoctdESimz/2Q==' ; //========================================================== // le-small.jpg //========================================================== $this->chars['e'][0]= 700 ; $this->chars['e'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABgDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYEBQcB/8QAKhAAAQMCBAUEAwEAAAAAAAAA'. 'AgEDBAURAAYSIQciMTJBE0JRYRQVFoH/xAAXAQEBAQEAAAAAAAAAAAAAAAAAAgED/8QAGREAAwEBAQAAAAAAAAAAAAAAAAERAjFB'. '/9oADAMBAAIRAxEAPwDTszvhEYCoS80BTm2bCjQRwdAzVe2yopkpJtpRUVfjEIc4V2oMerByg5Ji30oMyS3GeMunK0upfnu09MdJ'. 'p2scTmWnnGfx6HThktgLfKj7xEOqyr7QBbL41LhBzpxbcOru0LKDLdSnOHoaltNqSC4qWL0x9xbJYum69caczSaHmGmTmpDUYn4l'. 'UiqjkynzAVtwV23Ud+X4Ibpa2DCPkjhfUaRO/p8yzpb+YHhUmhbev6ZEll1lvqK3jt2XrbBgp6HVwsK3THpfEubGSoOUyFMpbJmL'. 'Deh6SgOGKti57EuY6l62JMWdJy7k3hg1LkOozEbVm7suQSkTiKtkEfP1pH664Za/QItccgI4bseTHdNxiXHLQ8yVl7V32XyioqL5'. 'TGc1ng6eYs0idczXUZscBBABWgEhEtfKNuUezwPnBhEuj8X2M21z9BR6NUX211Kk/UKKAjuhkPhL7XVf8vtgw7UPJlEyrDWFSYLb'. 'LBNF6qrzG6t0spEu6+fpL7YMXhUndp//2Q==' ; //========================================================== // la-small.jpg //========================================================== $this->chars['a'][0]= 730 ; $this->chars['a'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABoDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwIFAQcCBwAAAAAAAAAB'. 'AgMEBREAEiExQQYHFBUiUXGBE2EyQkNSgpHh/8QAFwEBAQEBAAAAAAAAAAAAAAAAAAMBAv/EABkRAAMBAQEAAAAAAAAAAAAAAAAB'. 'IQIRMf/aAAwDAQACEQMRAD8AfdQ1pxjqZMSn0mRUZRYDaklJCE3OawO2ttTxY4hl07qFMVs1Ku02kpPnRGhsAqz8W9T9wDjozq6o'. 'Q1lDrcZLGVcmUoZg0obpufxK3Ftt9ccqB1GgBcmLSqtVEqOZcr6ARm/kbXHt7DEtc7WTJKTJqEWvRKfLqL9QplSjuPtGVYOJKBrm'. 't+U+n94WGStZzNypmRWqckUKTbixy6jAfxPxHtCgKqFNlU5huK6pLMndSlegG4J45N8aKmTMKQRBsCNMzwB+RbHWHGEAZlPZX2hx'. 'qZIC34ygZoYUbB50JSkFXFhZR9BrpheR4fIbQ6gvurJ7q02bIQTuAOAN8x40HAxRr3TrNRpBmSHVt1KMlTyJTCsqkKAPlSf28W+c'. 'UGaD1c9HSR1HFUh9tJU45EBcAtcC9+P9wqbg8IAto9o81yputrVGpiUkgHKkqUTZI32+cKm1z1tIUgPBBAKQ4UBQH3uL3xmXSXep'. 'HVDtXStE5K5jlPU7PF3Q41+okJFkjgC+3OuNSYiSzHaLtRcW4UDMpLYSCbakDW3thhum5p//2Q==' ; //========================================================== // d9-small.jpg //========================================================== $this->chars['9'][0]= 680 ; $this->chars['9'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwP/xAArEAABAwMD'. 'AgYBBQAAAAAAAAABAgMEBQYRABIhE1EUIjEzQUIHMlJhcdH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAYEQEAAwEAAAAAAAAA'. 'AAAAAAAAAREhQf/aAAwDAQACEQMRAD8AkK7brF6X7XpMeGoKhFMLEeT4ZUheEhanF4OcZ2pTgDykk92bZpdCsi7aezLjxkIPUZiV'. 'RSCy8hah7EkZ27yM7V+iscal5bE22Lon1qNDmSKROd8Sl+Ix1lMOlIS4HGgQpbStoUCnlJz8HmsXtW3Lst2rmBAelLMRRekOwnYz'. 'Edls9QKKnOVLyk7UgcbzzrdBthqEJJwZbAI4x1U/7o1TaFa9lG36aXaZTy54VrcXUgrzsGdx+T30aNydweqVw1GS87T6Lb86Q4ha'. 'my/IAYjZBx+snKk99oOQMf1AViE65SY348hzFy6hPKnqtKz7DC1lbqyPrvJKUJ7H+M6Wrt3InP7o1brFNp4bCDGhxGAsqz69VSiQ'. 'ORwBxrrQ7itm1ac7Hp0WoGTIc3PSn0pccdcP2WorycfA1RaRHjxosZqOyhtDTSAhCf2gDAGjVHTd9sKSCumynFEZK1tIJUe58/ro'. '1V1//9k=' ; //========================================================== // d5-small.jpg //========================================================== $this->chars['5'][0]= 632 ; $this->chars['5'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgIFBwT/xAAoEAABAwME'. 'AQQCAwAAAAAAAAABAgMEBQYRABIhIkEUMVFhBxNCgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/EABcRAQEBAQAAAAAAAAAAAAAA'. 'AAABEUH/2gAMAwEAAhEDEQA/ANGvW4YVOeiRX5b4mv5Sin05IdlupPKdo/j2SO3+6TbPNQvOsTVz33KRT4csR3YUF7Dsh5OSFvug'. 'kqG4FPBxnjxpvvi4KZb1pTpU+QwxUi2Y7ZIAefUk5ATxnB9/gbtL/wCH1UpuhPUlZlMVaQ0mS8zJjqZOPfc2TwpIUonI9tw40R1r'. 'WNGq/wBdJR1XT3lqHBUnGCfkfWjRWs1ve249erQqQYjOtN1FqPUpCXQ4WIzQSsJwT0UpRwQPG0nzqyuNHobjsl9kBuWqoOoXtT1/'. 'WppZcA8lKRj64HxqU+3KpAr6plElRVKef3S4E0K9O8pLXVzKcqSsJAB9wSAca6bSoNXeuA1+5pEV+SGFNU1iKVFqI0Vdx2AJUeoz'. '8DGlTDwG3CAf3q/pI0ah6MDhLz6U+EpXwPoaNMU//9k=' ; //========================================================== // d1-small.jpg //========================================================== $this->chars['1'][0]= 646 ; $this->chars['1'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEwMBIgACEQEDEQH/xAAZAAADAAMAAAAAAAAAAAAAAAAABQYCBAf/xAApEAACAQMD'. 'AwQBBQAAAAAAAAABAgMEBREABiESMUEHEyJRkSNCYXGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAA'. 'AAAAAAEREv/aAAwDAQACEQMRAD8A6jdd4WLbstILnc4Uq0VoWpkJknb6IjXLHJUePOlez923fcW4r1SxWlqC2UbdKirQif3Xw3yA'. 'OFAGT09/kO3OmV3a20MFRf6lIYPcpy7yRRAzgxjIy2M8YwcdiBzpX6d22VNvUlTXsFkuwkrKqNSfnK7F8OTzwrAY+l5zoxKskudN'. 'EgQPUT9PBkWF3DH+1GPxo1mLnRoAqF2VRgGOFmX/AAgY/GjRUP6hVMFv2FuFqUvUGrpDFJMBnpdyF5bsAQew7Hxzp6LZNT0yQ1DI'. 'wp0QCFBhD0jCsfLZHxbx5xxpTuvb1+v9PV7Ztk9roLPLCjmSSN3mX5ZwqjCgZX7PfWxDQb2in96pv9qq46aTE0bW4x9ceAWAYPwS'. 'PsYzoixgmheBGjIVcYCnjp/jHjHbRpe1JLn9OnopE/a0ykvjwDx47aNMXqP/2Q==' ; //========================================================== // ll-small.jpg //========================================================== $this->chars['l'][0]= 626 ; $this->chars['l'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYEBQf/xAArEAACAQIFAwIGAwAAAAAAAAAB'. 'AgMEEQAFBhIhFEFREzEHFSIyYcFxgZH/xAAXAQEAAwAAAAAAAAAAAAAAAAACAAED/8QAGhEAAwEAAwAAAAAAAAAAAAAAAAECMREh'. 'Qf/aAAwDAQACEQMRAD8A15Zfm1VURj1Fp5AqLKv3OARcL4W5Nzx+MLWjdRz5hqXU6TSb6OCr6WghiQbrJ91gOTy1yT5xZ55myZFk'. 'Gb5ozX6Ondm28XYqpQDwu7jEH4c5S2UaDy4xxrLmlUDWzk8XaQ3O49hbj+RiB85HNg8Ee3aqwIqhDuux7G/HHbvzgxEqaWOvy09R'. 'O0o3hjdQoUji20g+fY3wYSM6pJ4Ylr7V+Zz5PSaezHTlTRNWzxySSxt6q1MSkH6AOT2Fu3Aw7RfF/T9DEkLUeawuF2mKSgdWQj2/'. 'q3+fnDZDlqRZzQGaOGcpTOaeR1u8R+ncN3gj94so2jNWHeMNNKzorEX2qp9v3imNPoRE1zpjUtZ09HJmYq5lury0benZeTww23t3'. 'Ivgw+T0yRRyyxIqNfkLcA8jt7YMKcBWn/9k=' ; //========================================================== // ls-small.jpg //========================================================== $this->chars['s'][0]= 701 ; $this->chars['s'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAMCBAUGB//EACwQAAEEAQIFAgUFAAAAAAAA'. 'AAECAwQFEQAGEhMUITEiYQcjQVFxFRZCUoH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAgH/xAAZEQADAQEBAAAAAAAAAAAAAAAAAQIR'. 'EiH/2gAMAwEAAhEDEQA/APWZMhmFXSJU+SGmWFiQtAWMJQAnJUr8Z+w/OuQk71uZnMsqnbjy9s8st9UMCQ6kZJdZaIHEkZ/JHceN'. 'N3HtizuY1JLrG48yLBSC9UTFKQiY4nACir+wAOOMEe2rm2bTbzlqtE1MyBuZAPybpw85KSfDRJ4Cg+Pl/wC61hJeGjV31VuuKqwr'. 'LGU+whZZK+Rw+oYJAyj3GjS4dZFpZVkqPLktdfMXNcaU2kBC1BIITkdx6c599GlnvPAa3TL2vNvU76n0063acr3YSLCEjpUpUQtW'. 'Dhf14SMEnOc57aZ8Tegm7dbrEQGZt1PeTDgc1PEW3FeXAvyAkZVkeMDOm2G3f3O7Cl/qEuqkQg4lp6CRxraWfUlRUD24kZA741Ko'. '2k1HvlT3ri2sLOCgtsyJz6XEtBwZPAgJAGQMHUNPWKqWItsqh0UCFVyLeKhyLHQ2TMdHNVj+RKlAnJyfto1FW2ahgjrq6LYTFjjf'. 'lymUOLdWfJyoHA+gA7AAAaNPE3ysJdLT/9k=' ; //========================================================== // lh-small.jpg //========================================================== $this->chars['h'][0]= 677 ; $this->chars['h'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAIDBAUGB//EACwQAAIBAwMCBQIHAAAAAAAA'. 'AAECAwQFEQAGEiExExQiQVEVggcyU2GRocH/xAAXAQADAQAAAAAAAAAAAAAAAAAAAwQB/8QAGhEBAQEAAwEAAAAAAAAAAAAAAQAC'. 'AyEyMf/aAAwDAQACEQMRAD8A6DZb95q9bmpK6ieOCzNHJTxmE+NMhQ5fr1fLq3Ejvkak2e7ipiFsqb3R0m4qkPPJRiRXenU9VjKE'. '5JVcA9R7nWc3/BUbfoKTdO3VRXhpjbZ2D8Rwk6RyZH6chB+46m7i2hDYtgA2ePlV2VkuKysoLzzRnlIScZJZeeevvjtrX7LK2rp7'. 'tTwwJ9WjhILDrTKnIdMEDl2+P80aVdJZb1QW+vgqENLPH4sBCDLIwUgnOf4GjVvDnLgUk79T81voqjb8NnuUx8pVRCiEaYUSuynl'. 'jHU9mOfnOoOx6hqz8PrbNdfEkMUXg1LSM3rKOUywJ7YAJ1ZTWmSpvdvlaVTDSUzJAhH5ZJBgv0x2RSAPlz21WXqoet3ba9nuW8n4'. 'Jr6qTPqnUNxSM/f6mPvxA9zqJnExTbR+h0nkhVu1uE8j0UBRQ9PGxBKFjnkAScdsDp10a0lc7z0tI7Y5YYN+5GAf7GjVXF4Icj3f'. '/9k=' ; //========================================================== // ld-small.jpg //========================================================== $this->chars['d'][0]= 681 ; $this->chars['d'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFBgH/xAAsEAABAwMEAAQFBQAAAAAAAAAB'. 'AgMEBQYRABIhMQcTI0EUMlFhkRgicaGx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgEA/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECETH/'. '2gAMAwEAAhEDEQA/ALUhp6h3W/X63UlypbhCY0WMjLqGzwDtPCfv/WtealNpVInuVBBqCogcdbU36YUkAkJWVHG8YPXBxxzxqPcN'. 'YtWyWnIlUeW05VEOAvrCnnSkftK1H5lKJPHsMDoDUWq+KdrSbIqsalVsImiEtLUZ2MU71bcYJWkhZ/36ayLHhi/IXZVOmzKqp5uU'. '688hTyjuGVEFJKvoQesD86NL2jGZp1EoLDSmk+ZAQ8d7oPzp3YGesFWMfxo1YGvSzLsT9QExVX8phTlMaFOExAJIBGQjJwCcL+/e'. 'rd+W7GuO0Kw05CQ6+ww69Gfdb2kFIKk7DgEkjgnr86rXRa9HuyP8LV4SH0sIBbWFFDiFEgDaocgdkjo8ccay0qw7ut5nyrcviQqC'. 'slsRKo0HwlODkBRzxj2AGoXTtpzIdQ8MbffUChz4NCPRaClAo9Mn6c7T3o13wytmo0K05VIqkiPJbizFiMWs4CTgnIIHOST796NL'. 'Ia1JX//Z' ; //========================================================== // d8-small.jpg //========================================================== $this->chars['8'][0]= 694 ; $this->chars['8'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AFQMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABgcEBf/EACsQAAEDAwMD'. 'AwMFAAAAAAAAAAECAwQFBhEAEiEUMVEHE0EVYYEiIzJCsf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/EABcRAQEBAQAAAAAAAAAA'. 'AAAAAAABERL/2gAMAwEAAhEDEQA/AKL6gVVUa0i1T5QjvTprUJMlxW4R9zgQXe/AH+kaWrntqlWjaq7gpcmotXAw82ht9yY4tch8'. 'uAFC0k7VBXPGMY51ruiaue+bThIj+7NbWqS+7HDxajFf6AlB/k44o8ZOABk4xkL0X0tZiojKrlRuGRJjugqldSlKGf6t7BuUQe3J'. '44xxxrA1a4KVJipLidri8uLHgqOcfjOPxo0o2hdDvS1CmV2Yl6fS5ioipIQR1CAlKkLKR2UUqAI8g6NRSwuuyHab6s1ufLI/Zai7'. 'UBJOxhTS0+6B32pWSFH4CidOdWU0ukLiN1BLr0zG5Sdm3GRvcPhIT858DvjXNrVsSLnm/VIdTXS6tTnFsxZTSN3jchaTwps+O/z9'. 'tcBVq3hIX0tYqlIiQHdy5CqRHKHXEjAOMgBKjnvyRk4xrQa7OiGt1K5biYZL8SoVEpjOqkFsONtJCNwASeCQrn7aNUKnQYtLp7EC'. 'EylmLHQltptPZKQOBo1FzH//2Q==' ; //========================================================== // lz-small.jpg //========================================================== $this->chars['z'][0]= 690 ; $this->chars['z'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABgAHA//EACsQAAEDAwQBAwIHAAAAAAAAAAEC'. 'AwQFESEABhIxBxMiQVFxCCM0UmGRof/EABYBAQEBAAAAAAAAAAAAAAAAAAECAP/EABgRAAMBAQAAAAAAAAAAAAAAAAABEVEC/9oA'. 'DAMBAAIRAxEAPwBTWfLu1KXXZDbM4uewNvLajlwhaCbBAwDe5uehYd3xm6t6bi3jvulwqc7KgxXZZeYQLNLeF73WRg4HEdgfzrSa'. 'P45pNEkznITDc9ypLShtyWhJDJyXC2qxJHZvjoZOjyVv1v8AESt6FFS4ijxvTLbawEApSccrYHJf0+OtJMQ2rNXk7GZMufJgJjTH'. 'Un9M4qzxT7hyCiThIyRnPXWrRvyLElVBUF6vlhl0lwRYCFKcQhAtyWpVhyWTx+w++rUvp4EWjOvbniUOnVatcS43BYDbJSPZyIBw'. 'ejclIx+3Wa+J63T6DQanuGszI0eZVJJV60p0Jum5GEi6le7l0PjvSjyRsaTvJqI1BqhhR46ksuMrQVJcUSEoUbHNr/7o7C8L7eiz'. '4lLlyJk2cEqW+6V+m0AE9ISLnsj5+O9UhsFK92bZZqb9SRu9p2c4A0OCEqDbYAJSlJwAVZv3fBvbFrg/462btlhuS1RG5nL8pYkq'. 'KrnsKH06I/rVrQKkf//Z' ; //========================================================== // d4-small.jpg //========================================================== $this->chars['4'][0]= 643 ; $this->chars['4'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABAYHAv/EAC0QAAIBAwQA'. 'BAMJAAAAAAAAAAECAwQFEQAGEiETFDFBUmGBByIjUVNxobHR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAIB/8QAGBEBAAMBAAAAAAAA'. 'AAAAAAAAAAERIVH/2gAMAwEAAhEDEQA/ANjM00Nxmt1xiWW31CZp5uJwoAAaOQ/n7qfcZHqO5my3q5XX7R6ijiqnNut9u4NyJ4yv'. 'JJyjYr8Xhrn5g599J7x3ulBNU7Zo7dXXXcLQ8kURYi4epYtkALjOePv1nUvbLvV7P3BZm3DR3eh88Kp7pVzBZI6iUhGWRRGWwE44'. 'HX3V+uiL1uHgt+vL/H+aNJQ3CSeCOaFqSaJ1DJKs/TqRkMOvQjvRorHE4pRDLNWLGlRHGUeYIORXs9e5B7OP31E0fmdyb/t0DJ4Q'. '27bfx3YZzPUIoAAz7IpOD6cuxq0uNumqLfVNDOqXBoZEjnZcqhIPXH4c46+WkdoWOltu3IDDLLLVVR83UVcuPEmmcZZ2/rHoAANG'. 'GI7KIY1ijoLeEQBVCwIoAHpgY6Hy0aZe7mJ2jeHLKcEhusj6aNKgzr//2Q==' ; //========================================================== // lv-small.jpg //========================================================== $this->chars['v'][0]= 648 ; $this->chars['v'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYH/8QAKBAAAQQBAwMEAgMAAAAAAAAA'. 'AQIDBBEFAAYhEzFBEhQiYQdRFTKB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAAAAAAAAERIf/aAAwD'. 'AQACEQMRAD8A6Ngt1SZ4yrYgrecgTFsFJA9aGwAUrUaF2D2Avjzq6CIjiBPkB9bwQVIkIYIDae/wq+P9N+dY4SGMf+Txlev7KBmY'. 'PoadKRy4zxSgRxaTwO/x09u7KPYnasmHjlsyFZZXt4K23ezjvBpNGgLUrvXfVZyLLbWambiwEbKvvxYAkeotNlIJW2FEJWb7WBda'. 'NSQI0fHYyJjkrjKRDZQwnpQ1vgBIr+w8+a+9GocZr8iKkuY1eXhsKH8U8iZE9BHz6ZHUc48UfSPqzqH3kfeO9kTTDQYGGietpTaO'. 'shyW6AocpHNIrv8AvWzk9BUSdPdYS4BcRlomkhIV6KP0VE39V+tU2wdlRMHtZUB8NuTQ+51X27+Kr46ZPIAFV540D8zeLsJ5LMHa'. 'ubmMBCVJdjx0pRyLoWR4I8aNIQ8BvZMNtMTeUcsptKfc4tC1gAkCyFC+K0aJtf/Z' ; //========================================================== // lk-small.jpg //========================================================== $this->chars['k'][0]= 680 ; $this->chars['k'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAUGBAMH/8QALhAAAQMDAwIEBAcAAAAAAAAA'. 'AQIDBAUREgAGITFBEyIyYQcVUYEUIzNicZHx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEE/8QAGxEAAwACAwAAAAAAAAAAAAAAAAEC'. 'AxESMeH/2gAMAwEAAhEDEQA/APVK/V36dU6NSJDTT8esPLiqfK8S2cCoeTkKvZQ6jm2ldSqKqbu+OgMOvSX3m4UBrLnDlbqiefKl'. 'Nzz2x1m+IwNP27CkJQ7JkR6rCkMJbP5jp8S2CPfkgD6H+dJ6Ca0nerr+64rTNSqMYrg+C9mmOwhVpDfsuxSbi97DmybaoZeQ5jTl'. 'PEp18JTIfeW3kq3ly4H26aNZqvTWZsjFcZTsVtSg0G8Rio+vr2vb7g6NLPRnuXy8F+8kl+obUh4KXJdqSJJQnohlkZqJPYBXh3P+'. 'a4b5Hyp6k1bO7sOotPyXkj9NlwFl0ewstJA9ifrqkVSmET4csoS7UTHXFQ+6SQlskKUMb/tH9ddLVUmS7DqdBqD7U6OsqfS46jzl'. 'hQ5bXb1K9Scuybdxo2OTu92dwSZkWn0Sb8viQWyn8Qq5D6ifSLd0BIv7q0arTBRSKPToMZbi2GWylsvLK148Wue/XRrRjxOpT2R2'. 'k9aP/9k=' ; //========================================================== // lr-small.jpg //========================================================== $this->chars['r'][0]= 681 ; $this->chars['r'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAGgAAAgIDAAAAAAAAAAAAAAAAAAYCBQMEB//EAC4QAAICAQIFAgMJAQAAAAAA'. 'AAECAwQRBQYAEiExQQdRFGFxEyIyM0JSYoGC8P/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/EABcRAQEBAQAAAAAAAAAAAAAAAAAB'. 'EUH/2gAMAwEAAhEDEQA/AOs0ZdETU54Gt1INSmlPJEsyo7J+jlXPUYBPY9c+eE/dO9tY0a7ren6BVrW7VJTZtW5kZkjXkBSIKveQ'. 'gHp0AAJ4w+q2hVdT2Md0h46+saS4mr3EUK0gWTAB+vQj2PboeL/ZVOqmhaZVjkFmxdC6tctt3tM2G5/7bAx4C4+qxiWwd3prWzKe'. 'r3IBAth5OYxozKsgc8y4GTgnJB9uncdTi6tXq2140rRVM13JMEMAVAg7sMdBjJB/18uDgRO9R2Oo6FX2vShkFzURFUq1whIj+8DI'. '7EdAFjXv7MeNb0kuStsFEmIaajZaos2fy2Q4VGH7SGxn+Rzw9yMLOm/FzRhZazmOTkP4grYyD3B8j2PTyeFfZ+z7G3BeSS8lmprl'. '2K2qcnK0Z5S8gPjrgAY8cNEWmq7u23pEos6/Zji+Kd0rLLGWwseA3joeZj/w4OET1g0vlmrWV+ydFnkUxSgsvM4V+YYIwfHz6cHB'. 'ZeKZ1//Z' ; //========================================================== // lg-small.jpg //========================================================== $this->chars['g'][0]= 655 ; $this->chars['g'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQCBQYH/8QAJxAAAQQBAwQCAgMAAAAAAAAA'. 'AQIDBBEFAAYhBxIxQRNhcYEiQlH/xAAYAQACAwAAAAAAAAAAAAAAAAACAwABBP/EABkRAAMBAQEAAAAAAAAAAAAAAAABAhEhIv/a'. 'AAwDAQACEQMRAD8AayO4t6bq3hmMHtxyLi4OKeKH5jyASiiQCCQeTRNAeB61FrBb+jTGpLO+BMW24EFMhkhpQru8m7B/H70x09Yi'. 'q3nv/vLfwpnJ7UNkqSRbngf2ofWkpXV7brymC2malLfagurjW0aHk89xPJ9cX9aprURHWbYEaMHHEBfwpv8AnXPk+/8AdGqGJOxO'. '4YbOSxK4y4boIStUWysgkEmxY54r60aOI8oTV9MHtjJwunPUbO46WWo0HLlD8KY4goboFVoquOVEVwLT963WdnxYfT6ZJyz0JvHm'. 'KvtaSkW4tYNVSqKiTwB+fw5n9sY/cuOXCzDDcluyW3Ckd7V+0n0eNZTH9DdouFalHIOJBUhtDki0pNV3UALo81ehG6IdKjPZ6d47'. '4ywltanVJvuJI+RQs/sHRqy2r003JhsImEc/CUyhxRZBjKV2oJ8eRXNmufPnRo1WIz3DdNn/2Q==' ; //========================================================== // lc-small.jpg //========================================================== $this->chars['c'][0]= 629 ; $this->chars['c'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAUGBwID/8QALRAAAgICAQIEBAYDAAAAAAAA'. 'AQIDBAURACExBhIiQRMVUWEHMkJScYFykaH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAgP/xAAXEQEBAQEAAAAAAAAAAAAAAAAAATER'. '/9oADAMBAAIRAxEAPwDcoGkmiT4Q8kWvzuPU38D2/v8A1zwrCFayq1qTaFk2H7aJHt05MeMvENzC4upDWkjW9kJXiricAJCigvJN'. 'IB1IVQT5frrv24twPgunk6a288crbklUSJNNdnSTZ2STHHqOP/Eb17njdZtAoqwEvrEiGVyG117/AG6HhyV8H1sljMldoxXTksGC'. 'zV7M0oaWGQOVeGQ92I6EMR22D11w4LmEPjaOL51iL8ssc9Z69zHtZkYCGGeQK0ez2UEoU39wCeX1S/LLiEt+mPSbMLxsGVv2kEjR'. '305xkaEV/GTULMUT1LD/AAGh8gIZS2jv+vpybb8NMIb0dVLWYWgiiU0vmMphOj6V0TvQI3rfsON1E6dYjGtisa0F1mAWR2NhG0WZ'. '3Ls3TqNs5Hc9h23w49NWL9K+Q/VD5T/zhwPH/9k=' ; //========================================================== // d7-small.jpg //========================================================== $this->chars['7'][0]= 658 ; $this->chars['7'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgEFBwT/xAAuEAABAwIE'. 'BAQGAwAAAAAAAAABAgMEBREABiExEhMiQSMyUXEHFBclVJFhk9L/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/8QAGREBAQEAAwAA'. 'AAAAAAAAAAAAAAEREiFR/9oADAMBAAIRAxEAPwDXq9mCjZeQ05VZ5ZST4bfEpa3VdglCbqUe+g9MZ5Uq7V8415WXoMSdQ6etgSps'. '19wpkCMDZKUpv0FZvbi1NzpYasMDLDUbMVXrtQdbeeU23xLWkj5RlLYK0J7anW9gbAjCzkOtsVSUJUdtc6dVZK51UeaFm4LKbhpC'. 'l7EhIFkDW974GbRI2XorUVls1OTdKAOqUpR0Hc3198GITQ6k+hLwrEpoODiDenRfW23bBicg78JXxPpD0mgVOW5PAivNNpahsPW5'. '8xxQaSVkboQnhsnYm5OHqDGp1IpsalMKjMsMIC3+XZKbJFth62/QOEfMOZqZXp9JcKZTcGmTky3meSi7xQklI81vMR+sXIz/AEgp'. 'Q0qPNu6ea8Q2jqtbp8+2w9h/OKORc/cpHjt1dDSHOtLZ4ekHW23bBjj+o9H/AB539aP94MG0+L//2Q==' ; //========================================================== // ly-small.jpg //========================================================== $this->chars['y'][0]= 672 ; $this->chars['y'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQGBQf/xAArEAABAwMEAQIFBQAAAAAAAAAB'. 'AgMEBREhAAYSEzEHIhQkQVGxQmFxgaH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAQL/xAAeEQEAAgEEAwAAAAAAAAAAAAABABECAxIh'. 'MUGR8P/aAAwDAQACEQMRAD8Ar3tys07dVHohemz5dWQ7fk91MsA3IIRY8rkKFySceTqw3JVV0KhyKw+0C1CQp9aUOFSiAk4AIAvn'. '76xtz0ioVvbcJ6msx2JtOfZmw1PKI5LQcJNh7UqBKcn6+NRfqPu6s1fYc6GxSJsRfWDUVSGA22ygEckJWSexRNgOP0udXzDKOJ0I'. 'yo62mHm25Sy80l1Z4lSgpQvZRGLgWwPGjTjbchyLH+Ejx22EtJSgO8kki3kADA/nOjWjGzv73CyQZjUWNVp7bNSrj7qJDqflqUlQ'. 'DMds24l3HvcNr3Pi9gME6T9WWVsemdYWswwC2lPta4m5WMA3OdUExCmozUJD6g84ntMjrHIFBTdQz5yLDx/WDNytpwW6nAkViqVe'. 'uvmXdlme6n4dCwlRBKEgA2tj99QG7Ilncp5QqpU31PMsJ6x7A32f6SPxo0hPVCD45oVyKf0MtgeT97/nRrO7UOCFla3tn//Z' ; //========================================================== // d3-small.jpg //========================================================== $this->chars['3'][0]= 662 ; $this->chars['3'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwL/xAArEAABBAED'. 'AwMDBQEAAAAAAAABAgMEBREABhIhMUEiMmETFZEHFkJDUdH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAYEQEBAQEBAAAAAAAA'. 'AAAAAAAAEQExQf/aAAwDAQACEQMRAD8A0vclruBdk3VVLLUNssGRJsZSCtqOjlgJAHvcOD6c4HnOdIbcttw1W5P29cFEhuawqTXS'. 'VsJjnCMBxKkJJx7goAde+ceJfdNxU0UNlyymyXHi6kxWUNl1S3EnkAEIHX2nv86qtTuZr9Q9+1VhRsOoYpYcgSVyAE/TdewkJxnK'. 'sBCjkdPGpnOtFMd3PqsXgfOAgD8Y0aX+11H9rDDjn8lr9yj5J+dGqsqxaw6Cc9cQZU4Sp7zTJsIrKlcUEKwhSin1JABI45GUjqOu'. 'lbOvjbc3Ts9ynjGCy445UuFLYRzbWgrT6fhSCQSMDke+pew2zYVly/d7YchNqkMJZnQpgV9J8IzwWFJyUrAJHYgjvpLbu37G5nR7'. 'vck5C3YRKYEOEVJZj8kjKypXqWvirjk9h+dB9i4faa89TDZUfKlIyT8k+To10a6KTkpcJ/0vL/7o0TS//9k=' ; //========================================================== // ln-small.jpg //========================================================== $this->chars['n'][0]= 643 ; $this->chars['n'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGwAAAgEFAAAAAAAAAAAAAAAAAAYCAQMEBQf/xAAtEAACAQMCBAUCBwAAAAAA'. 'AAABAgMEBREAIQYSE0EHIjFRcWGRIzIzQoGCwf/EABYBAQEBAAAAAAAAAAAAAAAAAAMEAP/EABkRAQEBAQEBAAAAAAAAAAAAAAEA'. 'AhEhUf/aAAwDAQACEQMRAD8A6FR3p7v4oV9rlkMQsjL00RyOss0KkFxnDcrc2PbI1NOJKyTjW+W5OmKeA0UEJx5meRZS2/8AUfbS'. 'LVGS1+K16vCzfiR3GmoqqXGyxz06hWPsFlVMfOmq1iNvE69KjBYo3oJMZ3GKeYYPxg/fW+xzZX1FLQyxwSTcpWNceu4G3+aNSmpY'. 'qmQzzwh2k8yhv2r2H23/AJ0aoy+EWh7I1ntacR3PxDtEzhjWy0wkkIwYmanU5GO6sNh7rrU8AVdTceNbhDXxNHUQvS0tZ3DzwxVA'. 'fB7hj59/XJ08cPWaKj4gvlwSQiG7dCboqvLy9NOmQT9SM7ayJrBa6K5V91hjlWorp4JGUOAglRSiMMDb82/vgaBGTpVvtNUVtyJg'. '5+WNAh5ZCu/r2+dGrgq0pi0DhmlRsSSAfqMd+b6ZyNu3po1Rk1yNBe3/2Q==' ; //========================================================== // lu-small.jpg //========================================================== $this->chars['u'][0]= 671 ; $this->chars['u'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYDBAUH/8QAJRAAAQQBAwQDAQEAAAAAAAAA'. 'AQIDBBEFAAYhBxMxYRJBURSB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAD/8QAGhEBAQEAAwEAAAAAAAAAAAAAAQARITFBAv/aAAwD'. 'AQACEQMRAD8A6dLkQmJzu3WVtHIqjf0duKFNuBr5UTQ45F1R8/XI1PMmsYoJyjhS9iI7BKHeKjkXZVXqhyLHP+rrHeR1pZlx1W1M'. 'wTiW0ukkrS28nn5fV2SPPFfurHUKQhzYG7pLYKEfyBhaSOS7dG/YCki/uvWn3LPDOJrwa4kyEzOYeakqkpC3Hk0bNePQHgDRpchY'. 'leIZwzUWauKtuPctTSUlCAUmrBHIKuAPV/ujQsmHdm7hya43UbbD3ZVElOQJsdTS6IQaQUqBHCk8E2Pocgam6oYwObHy0Zm0oi45'. 'T1KBPdpV2f0pom/1Ws7cmPazu98Ltvcq3VzRHfehz8a4pirFEKRZo8eQT+eCdWYfS/b+WYnxpbuVcDRMdHcyTqg2fiAfiLoi+Rf+'. 'jT7Xc74HtOYnHyUOh8yWUvKeHhy0CiPVUAPoDRrm+OeznTva6lzsyMjCYbbaiNJjJSWElagD5tRpNUSALFeNGoOCH7Bv/9k=' ; //========================================================== // lw-small.jpg //========================================================== $this->chars['w'][0]= 673 ; $this->chars['w'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYDBAX/xAAtEAACAQMDAgMHBQAAAAAAAAAB'. 'AgMEBREABhIhMRMUQRUiIzJRYZEWNIGx0f/EABYBAQEBAAAAAAAAAAAAAAAAAAABA//EABoRAAICAwAAAAAAAAAAAAAAAAABERIh'. 'MVH/2gAMAwEAAhEDEQA/AHXbV13ZLu6t2/uaa1JijWopVp4XUTKSAXRyc+6ehBGeoPbTSlwpql0K3GneqpZViqUhI5JzGMEZJGeh'. 'GlXfaFILDf7FQzXC426rDLTojs8sLqVkXBGcfKf40twWbdWzZY75R0s90ul3jPtKjVMJDNn4DDp8iEhW+wJ1WZG2KWt3Lv26U1tv'. '92o7PaYkgYUbqVepYlmUBlIwqnB++O2jTDt/bBtth9jcpvEWNGqalZQryTlmeR8jPct6+mNGmRC4a1U13htzVFItB5nA/cyOUVfp'. '7oz/ALqitJulYJKuqvFsppHALLFb3cp9FBaXr+O51bq0q6i38KK5PDVAAxSzU6SIpz3Kjjn8jUFoS7uFmut1gq17xLFQ+DxOccj8'. 'Rsn+tVpiyJnqv09YfOXu5AycgZZQEhBZjgDBOOgwO/po0sttWHdNzqLruioa4UwmdaC3kYp4IwSvJlBHKQ4OSe3po0qxM6P/2Q==' ; //========================================================== // lq-small.jpg //========================================================== $this->chars['q'][0]= 671 ; $this->chars['q'][1]= '/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. 'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. 'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAcDBAUG/8QAKRAAAQQBBAICAQQDAAAAAAAA'. 'AQIDBBEFAAYSIQcxIlETCBQVgSNBYf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oADAMB'. 'AAIRAxEAPwDT3H5Qz+O3LN2vtrF/y86NYLzzVlAABJITQPv2a/17vXMboz3lDEYWPuafNx7CFrS03+2jpK2bs0CUkUa7pRvrUu63'. 'sr438yv7pLEo4XIK5Kcji0uJUkckm+uQUOVH6GsnyJv7A5vaJwuFdkONLmolgONFH4vioKRXYqyCADXvRMh0yspmZ4jyIEtDTK47'. 'aiA0lQUopBJBI/7X9aNT7amRo228e3a31iO3yUzCcdSPiKAIFdCho0TIswZ7GQlO/hlRxBooih1YXzAoKUkX0LPEBX110dJ7zbuv'. 'AORpO04cIpmxH23FSEIRwKuNnsdk0o31702XhFMKbuRUZJWP8LTQ6HBCuIB+iVWSR2BXuqK93/hDlvGzEphmG3Ml5JpDi1I7TzNA'. 'BYFlPafY+/7LBiv1CYDH4iFDOGySlMR22lFP4wCUpANfL11o1r4bxXlWMNEaE/bqlIbCFl/ANPK5Do/M0VDr2Rf3o0TX/9k=' ; } } class AntiSpam { var $iData=''; var $iDD=null; function AntiSpam($aData='') { $this->iData = $aData; $this->iDD = new HandDigits(); } function Set($aData) { $this->iData = $aData; } function Rand($aLen) { $d=''; for($i=0; $i < $aLen; ++$i) { if( rand(0,9) < 6 ) { // Digits $d .= chr( ord('1') + rand(0,8) ); } else { // Letters do { $offset = rand(0,25); } while ( $offset==14 ); $d .= chr( ord('a') + $offset ); } } $this->iData = $d; return $d; } function Stroke($aStrokeFileName="") { $n=strlen($this->iData); if( $n==0 ) { return false; } for($i=0; $i < $n; ++$i ) { if( $this->iData[$i]==='0' || strtolower($this->iData[$i])==='o') { return false; } } $img = @imagecreatetruecolor($n*$this->iDD->iWidth, $this->iDD->iHeight); if( $img < 1 ) { return false; } $start=0; for($i=0; $i < $n; ++$i ) { $dimg = imagecreatefromstring(base64_decode($this->iDD->chars[strtolower($this->iData[$i])][1])); imagecopy($img,$dimg,$start,0,0,0,imagesx($dimg), $this->iDD->iHeight); $start += imagesx($dimg); } $resimg = @imagecreatetruecolor($start+4, $this->iDD->iHeight+4); if( $resimg < 1 ) { return false; } imagecopy($resimg,$img,2,2,0,0,$start, $this->iDD->iHeight); if( $aStrokeFileName!="" ) { if( file_exists($aStrokeFileName) ) { if( !@unlink($aStrokeFileName) ) return false; } imagejpeg($resimg,$aStrokeFileName); return; } header("Content-type: image/jpeg"); $res=imagejpeg($resimg); return $res; } } ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_bar.php ================================================ Plot($datay,$datax); ++$this->numpoints; } //--------------- // PUBLIC METHODS // Set a drop shadow for the bar (or rather an "up-right" shadow) function SetShadow($color="black",$hsize=3,$vsize=3,$show=true) { $this->bar_shadow=$show; $this->bar_shadow_color=$color; $this->bar_shadow_vsize=$vsize; $this->bar_shadow_hsize=$hsize; // Adjust the value margin to compensate for shadow $this->value->margin += $vsize; } // DEPRECATED use SetYBase instead function SetYMin($aYStartValue) { //die("JpGraph Error: Deprecated function SetYMin. Use SetYBase() instead."); $this->ybase=$aYStartValue; } // Specify the base value for the bars function SetYBase($aYStartValue) { $this->ybase=$aYStartValue; } function Legend(&$graph) { if( $this->grad && $this->legend!="" && !$this->fill ) { $color=array($this->grad_fromcolor,$this->grad_tocolor); // In order to differentiate between gradients and cooors specified as an RGB triple $graph->legend->Add($this->legend,$color,"",-$this->grad_style, $this->legendcsimtarget,$this->legendcsimalt); } elseif( $this->legend!="" && ($this->iPattern > -1 || is_array($this->iPattern)) ) { if( is_array($this->iPattern) ) { $p1 = $this->iPattern[0]; $p2 = $this->iPatternColor[0]; $p3 = $this->iPatternDensity[0]; } else { $p1 = $this->iPattern; $p2 = $this->iPatternColor; $p3 = $this->iPatternDensity; } $color = array($p1,$p2,$p3,$this->fill_color); // A kludge: Too mark that we add a pattern we use a type value of < 100 $graph->legend->Add($this->legend,$color,"",-101, $this->legendcsimtarget,$this->legendcsimalt); } elseif( $this->fill_color && $this->legend!="" ) { if( is_array($this->fill_color) ) { $graph->legend->Add($this->legend,$this->fill_color[0],"",0, $this->legendcsimtarget,$this->legendcsimalt); } else { $graph->legend->Add($this->legend,$this->fill_color,"",0, $this->legendcsimtarget,$this->legendcsimalt); } } } // Gets called before any axis are stroked function PreStrokeAdjust(&$graph) { parent::PreStrokeAdjust($graph); // If we are using a log Y-scale we want the base to be at the // minimum Y-value unless the user have specifically set some other // value than the default. if( substr($graph->axtype,-3,3)=="log" && $this->ybase==0 ) $this->ybase = $graph->yaxis->scale->GetMinVal(); // For a "text" X-axis scale we will adjust the // display of the bars a little bit. if( substr($graph->axtype,0,3)=="tex" ) { // Position the ticks between the bars $graph->xaxis->scale->ticks->SetXLabelOffset(0.5,0); // Center the bars if( $this->abswidth > -1 ) { $graph->SetTextScaleAbsCenterOff($this->abswidth); } else { if( $this->align == "center" ) $graph->SetTextScaleOff(0.5-$this->width/2); elseif( $this->align == "right" ) $graph->SetTextScaleOff(1-$this->width); } } elseif( is_a($this,'AccBarPlot') || is_a($this,'GroupBarPlot') ) { // We only set an absolute width for linear and int scale // for text scale the width will be set to a fraction of // the majstep width. if( $this->abswidth == -1 ) { // Not set // set width to a visuable sensible default $this->abswidth = $graph->img->plotwidth/(2*count($this->coords[0])); } } } function Min() { $m = parent::Min(); if( $m[1] >= $this->ybase ) $m[1] = $this->ybase; return $m; } function Max() { $m = parent::Max(); if( $m[1] <= $this->ybase ) $m[1] = $this->ybase; return $m; } // Specify width as fractions of the major stepo size function SetWidth($aFractionWidth) { $this->width=$aFractionWidth; } // Specify width in absolute pixels. If specified this // overrides SetWidth() function SetAbsWidth($aWidth) { $this->abswidth=$aWidth; } function SetAlign($aAlign) { $this->align=$aAlign; } function SetNoFill() { $this->grad = false; $this->fill_color=false; $this->fill=false; } function SetFillColor($aColor) { $this->fill = true ; $this->fill_color=$aColor; } function SetFillGradient($from_color,$to_color,$style) { $this->grad=true; $this->grad_fromcolor=$from_color; $this->grad_tocolor=$to_color; $this->grad_style=$style; } function SetValuePos($aPos) { $this->valuepos = $aPos; } function SetPattern($aPattern, $aColor='black'){ if( is_array($aPattern) ) { $n = count($aPattern); $this->iPattern = array(); $this->iPatternDensity = array(); if( is_array($aColor) ) { $this->iPatternColor = array(); if( count($aColor) != $n ) { JpGraphError::RaiseL(2001);//('NUmber of colors is not the same as the number of patterns in BarPlot::SetPattern()'); } } else $this->iPatternColor = $aColor; for( $i=0; $i < $n; ++$i ) { $this->_SetPatternHelper($aPattern[$i], $this->iPattern[$i], $this->iPatternDensity[$i]); if( is_array($aColor) ) { $this->iPatternColor[$i] = $aColor[$i]; } } } else { $this->_SetPatternHelper($aPattern, $this->iPattern, $this->iPatternDensity); $this->iPatternColor = $aColor; } } function _SetPatternHelper($aPattern, &$aPatternValue, &$aDensity){ switch( $aPattern ) { case PATTERN_DIAG1: $aPatternValue= 1; $aDensity = 90; break; case PATTERN_DIAG2: $aPatternValue= 1; $aDensity = 75; break; case PATTERN_DIAG3: $aPatternValue= 2; $aDensity = 90; break; case PATTERN_DIAG4: $aPatternValue= 2; $aDensity = 75; break; case PATTERN_CROSS1: $aPatternValue= 8; $aDensity = 90; break; case PATTERN_CROSS2: $aPatternValue= 8; $aDensity = 78; break; case PATTERN_CROSS3: $aPatternValue= 8; $aDensity = 65; break; case PATTERN_CROSS4: $aPatternValue= 7; $aDensity = 90; break; case PATTERN_STRIPE1: $aPatternValue= 5; $aDensity = 95; break; case PATTERN_STRIPE2: $aPatternValue= 5; $aDensity = 85; break; default: JpGraphError::RaiseL(2002);//('Unknown pattern specified in call to BarPlot::SetPattern()'); } } function Stroke(&$img,&$xscale,&$yscale) { $numpoints = count($this->coords[0]); if( isset($this->coords[1]) ) { if( count($this->coords[1])!=$numpoints ) JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); //("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])."Number of Y-points:$numpoints"); else $exist_x = true; } else $exist_x = false; $numbars=count($this->coords[0]); // Use GetMinVal() instead of scale[0] directly since in the case // of log scale we get a correct value. Log scales will have negative // values for values < 1 while still not representing negative numbers. if( $yscale->GetMinVal() >= 0 ) $zp=$yscale->scale_abs[0]; else { $zp=$yscale->Translate(0); } if( $this->abswidth > -1 ) { $abswidth=$this->abswidth; } else $abswidth=round($this->width*$xscale->scale_factor,0); // Count potential pattern array to avoid doing the count for each iteration if( is_array($this->iPattern) ) { $np = count($this->iPattern); } for($i=0; $i < $numbars; ++$i) { // If value is NULL, or 0 then don't draw a bar at all if ($this->coords[0][$i] === null || $this->coords[0][$i] === '' || $this->coords[0][$i] === 0 ) continue; if( $exist_x ) $x=$this->coords[1][$i]; else $x=$i; $x=$xscale->Translate($x); // Comment Note: This confuses the positioning when using acc together with // grouped bars. Workaround for fixing #191 /* if( !$xscale->textscale ) { if($this->align=="center") $x -= $abswidth/2; elseif($this->align=="right") $x -= $abswidth; } */ // Stroke fill color and fill gradient $pts=array( $x,$zp, $x,$yscale->Translate($this->coords[0][$i]), $x+$abswidth,$yscale->Translate($this->coords[0][$i]), $x+$abswidth,$zp); if( $this->grad ) { $grad = new Gradient($img); $grad->FilledRectangle($pts[2],$pts[3], $pts[6],$pts[7], $this->grad_fromcolor,$this->grad_tocolor,$this->grad_style); } elseif( !empty($this->fill_color) ) { if(is_array($this->fill_color)) { $img->PushColor($this->fill_color[$i % count($this->fill_color)]); } else { $img->PushColor($this->fill_color); } $img->FilledPolygon($pts); $img->PopColor(); } // Remember value of this bar $val=$this->coords[0][$i]; if( !empty($val) && !is_numeric($val) ) { JpGraphError::RaiseL(2004,$i,$val); //('All values for a barplot must be numeric. You have specified value['.$i.'] == \''.$val.'\''); } // Determine the shadow if( $this->bar_shadow && $val != 0) { $ssh = $this->bar_shadow_hsize; $ssv = $this->bar_shadow_vsize; // Create points to create a "upper-right" shadow if( $val > 0 ) { $sp[0]=$pts[6]; $sp[1]=$pts[7]; $sp[2]=$pts[4]; $sp[3]=$pts[5]; $sp[4]=$pts[2]; $sp[5]=$pts[3]; $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; $sp[8]=$pts[4]+$ssh; $sp[9]=$pts[5]-$ssv; $sp[10]=$pts[6]+$ssh; $sp[11]=$pts[7]-$ssv; } elseif( $val < 0 ) { $sp[0]=$pts[4]; $sp[1]=$pts[5]; $sp[2]=$pts[6]; $sp[3]=$pts[7]; $sp[4]=$pts[0]; $sp[5]=$pts[1]; $sp[6]=$pts[0]+$ssh; $sp[7]=$pts[1]-$ssv; $sp[8]=$pts[6]+$ssh; $sp[9]=$pts[7]-$ssv; $sp[10]=$pts[4]+$ssh; $sp[11]=$pts[5]-$ssv; } if( is_array($this->bar_shadow_color) ) { $numcolors = count($this->bar_shadow_color); if( $numcolors == 0 ) { JpGraphError::RaiseL(2005);//('You have specified an empty array for shadow colors in the bar plot.'); } $img->PushColor($this->bar_shadow_color[$i % $numcolors]); } else { $img->PushColor($this->bar_shadow_color); } $img->FilledPolygon($sp); $img->PopColor(); } // Stroke the pattern if( is_array($this->iPattern) ) { $f = new RectPatternFactory(); if( is_array($this->iPatternColor) ) { $pcolor = $this->iPatternColor[$i % $np]; } else $pcolor = $this->iPatternColor; $prect = $f->Create($this->iPattern[$i % $np],$pcolor,1); $prect->SetDensity($this->iPatternDensity[$i % $np]); if( $val < 0 ) { $rx = $pts[0]; $ry = $pts[1]; } else { $rx = $pts[2]; $ry = $pts[3]; } $width = abs($pts[4]-$pts[0])+1; $height = abs($pts[1]-$pts[3])+1; $prect->SetPos(new Rectangle($rx,$ry,$width,$height)); $prect->Stroke($img); } else { if( $this->iPattern > -1 ) { $f = new RectPatternFactory(); $prect = $f->Create($this->iPattern,$this->iPatternColor,1); $prect->SetDensity($this->iPatternDensity); if( $val < 0 ) { $rx = $pts[0]; $ry = $pts[1]; } else { $rx = $pts[2]; $ry = $pts[3]; } $width = abs($pts[4]-$pts[0])+1; $height = abs($pts[1]-$pts[3])+1; $prect->SetPos(new Rectangle($rx,$ry,$width,$height)); $prect->Stroke($img); } } // Stroke the outline of the bar if( is_array($this->color) ) $img->SetColor($this->color[$i % count($this->color)]); else $img->SetColor($this->color); $pts[] = $pts[0]; $pts[] = $pts[1]; if( $this->weight > 0 ) { $img->SetLineWeight($this->weight); $img->Polygon($pts); } // Determine how to best position the values of the individual bars $x=$pts[2]+($pts[4]-$pts[2])/2; if( $this->valuepos=='top' ) { $y=$pts[3]; if( $img->a === 90 ) { if( $val < 0 ) $this->value->SetAlign('right','center'); else $this->value->SetAlign('left','center'); } $this->value->Stroke($img,$val,$x,$y); } elseif( $this->valuepos=='max' ) { $y=$pts[3]; if( $img->a === 90 ) { if( $val < 0 ) $this->value->SetAlign('left','center'); else $this->value->SetAlign('right','center'); } else { $this->value->SetAlign('center','top'); } $this->value->SetMargin(-3); $this->value->Stroke($img,$val,$x,$y); } elseif( $this->valuepos=='center' ) { $y = ($pts[3] + $pts[1])/2; $this->value->SetAlign('center','center'); $this->value->SetMargin(0); $this->value->Stroke($img,$val,$x,$y); } elseif( $this->valuepos=='bottom' || $this->valuepos=='min' ) { $y=$pts[1]; if( $img->a === 90 ) { if( $val < 0 ) $this->value->SetAlign('right','center'); else $this->value->SetAlign('left','center'); } $this->value->SetMargin(3); $this->value->Stroke($img,$val,$x,$y); } else { JpGraphError::RaiseL(2006,$this->valuepos); //('Unknown position for values on bars :'.$this->valuepos); } // Create the client side image map $rpts = $img->ArrRotate($pts); $csimcoord=round($rpts[0]).", ".round($rpts[1]); for( $j=1; $j < 4; ++$j){ $csimcoord .= ", ".round($rpts[2*$j]).", ".round($rpts[2*$j+1]); } if( !empty($this->csimtargets[$i]) ) { $this->csimareas .= 'csimareas .= " href=\"".$this->csimtargets[$i]."\""; $sval=''; if( !empty($this->csimalts[$i]) ) { $sval=sprintf($this->csimalts[$i],$this->coords[0][$i]); $this->csimareas .= " title=\"$sval\" "; } $this->csimareas .= " alt=\"$sval\" />\n"; } } return true; } } // Class //=================================================== // CLASS GroupBarPlot // Description: Produce grouped bar plots //=================================================== class GroupBarPlot extends BarPlot { var $plots; var $width=0.7; var $nbrplots=0; var $numpoints; //--------------- // CONSTRUCTOR function GroupBarPlot($plots) { $this->plots = $plots; $this->nbrplots = count($plots); if( $this->nbrplots < 1 ) { JpGraphError::RaiseL(2007);//('Cannot create GroupBarPlot from empty plot array.'); } for($i=0; $i < $this->nbrplots; ++$i ) { if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) { JpGraphError::RaiseL(2008,$i);//("Group bar plot element nbr $i is undefined or empty."); } } $this->numpoints = $plots[0]->numpoints; } //--------------- // PUBLIC METHODS function Legend(&$graph) { $n = count($this->plots); for($i=0; $i < $n; ++$i) { $c = get_class($this->plots[$i]); if( !is_a($this->plots[$i],'BarPlot') ) { JpGraphError::RaiseL(2009,$c);//('One of the objects submitted to GroupBar is not a BarPlot. Make sure that you create the Group Bar plot from an array of BarPlot or AccBarPlot objects. (Class = '.$c.')'); } $this->plots[$i]->DoLegend($graph); } } function Min() { list($xmin,$ymin) = $this->plots[0]->Min(); $n = count($this->plots); for($i=0; $i < $n; ++$i) { list($xm,$ym) = $this->plots[$i]->Min(); $xmin = max($xmin,$xm); $ymin = min($ymin,$ym); } return array($xmin,$ymin); } function Max() { list($xmax,$ymax) = $this->plots[0]->Max(); $n = count($this->plots); for($i=0; $i < $n; ++$i) { list($xm,$ym) = $this->plots[$i]->Max(); $xmax = max($xmax,$xm); $ymax = max($ymax,$ym); } return array($xmax,$ymax); } function GetCSIMareas() { $n = count($this->plots); $csimareas=''; for($i=0; $i < $n; ++$i) { $csimareas .= $this->plots[$i]->csimareas; } return $csimareas; } // Stroke all the bars next to each other function Stroke(&$img,&$xscale,&$yscale) { $tmp=$xscale->off; $n = count($this->plots); $subwidth = $this->width/$this->nbrplots ; for( $i=0; $i < $n; ++$i ) { $this->plots[$i]->ymin=$this->ybase; $this->plots[$i]->SetWidth($subwidth); // If the client have used SetTextTickInterval() then // major_step will be > 1 and the positioning will fail. // If we assume it is always one the positioning will work // fine with a text scale but this will not work with // arbitrary linear scale $xscale->off = $tmp+$i*round(/*$xscale->ticks->major_step* */ $xscale->scale_factor* $subwidth); $this->plots[$i]->Stroke($img,$xscale,$yscale); } $xscale->off=$tmp; } } // Class //=================================================== // CLASS AccBarPlot // Description: Produce accumulated bar plots //=================================================== class AccBarPlot extends BarPlot { var $plots=null,$nbrplots=0,$numpoints=0; //--------------- // CONSTRUCTOR function AccBarPlot($plots) { $this->plots = $plots; $this->nbrplots = count($plots); if( $this->nbrplots < 1 ) { JpGraphError::RaiseL(2010);//('Cannot create AccBarPlot from empty plot array.'); } for($i=0; $i < $this->nbrplots; ++$i ) { if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) { JpGraphError::RaiseL(2011,$i);//("Acc bar plot element nbr $i is undefined or empty."); } } $this->numpoints = $plots[0]->numpoints; $this->value = new DisplayValue(); } //--------------- // PUBLIC METHODS function Legend(&$graph) { $n = count($this->plots); for( $i=$n-1; $i >= 0; --$i ) { $c = get_class($this->plots[$i]); if( !is_a($this->plots[$i],'BarPlot') ) { JpGraphError::RaiseL(2012,$c);//('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects.(Class='.$c.')'); } $this->plots[$i]->DoLegend($graph); } } function Max() { list($xmax) = $this->plots[0]->Max(); $nmax=0; for($i=0; $i < count($this->plots); ++$i) { $n = count($this->plots[$i]->coords[0]); $nmax = max($nmax,$n); list($x) = $this->plots[$i]->Max(); $xmax = max($xmax,$x); } for( $i = 0; $i < $nmax; $i++ ) { // Get y-value for bar $i by adding the // individual bars from all the plots added. // It would be wrong to just add the // individual plots max y-value since that // would in most cases give to large y-value. $y=0; if( !isset($this->plots[0]->coords[0][$i]) ) { JpGraphError::RaiseL(2014); } if( $this->plots[0]->coords[0][$i] > 0 ) $y=$this->plots[0]->coords[0][$i]; for( $j = 1; $j < $this->nbrplots; $j++ ) { if( !isset($this->plots[$j]->coords[0][$i]) ) { JpGraphError::RaiseL(2014); } if( $this->plots[$j]->coords[0][$i] > 0 ) $y += $this->plots[$j]->coords[0][$i]; } $ymax[$i] = $y; } $ymax = max($ymax); // Bar always start at baseline if( $ymax <= $this->ybase ) $ymax = $this->ybase; return array($xmax,$ymax); } function Min() { $nmax=0; list($xmin,$ysetmin) = $this->plots[0]->Min(); for($i=0; $i < count($this->plots); ++$i) { $n = count($this->plots[$i]->coords[0]); $nmax = max($nmax,$n); list($x,$y) = $this->plots[$i]->Min(); $xmin = Min($xmin,$x); $ysetmin = Min($y,$ysetmin); } for( $i = 0; $i < $nmax; $i++ ) { // Get y-value for bar $i by adding the // individual bars from all the plots added. // It would be wrong to just add the // individual plots max y-value since that // would in most cases give to large y-value. $y=0; if( $this->plots[0]->coords[0][$i] < 0 ) $y=$this->plots[0]->coords[0][$i]; for( $j = 1; $j < $this->nbrplots; $j++ ) { if( $this->plots[$j]->coords[0][$i] < 0 ) $y += $this->plots[ $j ]->coords[0][$i]; } $ymin[$i] = $y; } $ymin = Min($ysetmin,Min($ymin)); // Bar always start at baseline if( $ymin >= $this->ybase ) $ymin = $this->ybase; return array($xmin,$ymin); } // Stroke acc bar plot function Stroke(&$img,&$xscale,&$yscale) { $pattern=NULL; $img->SetLineWeight($this->weight); for($i=0; $i < $this->numpoints-1; $i++) { $accy = 0; $accy_neg = 0; for($j=0; $j < $this->nbrplots; ++$j ) { $img->SetColor($this->plots[$j]->color); if ( $this->plots[$j]->coords[0][$i] >= 0) { $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy); $accyt=$yscale->Translate($accy); $accy+=$this->plots[$j]->coords[0][$i]; } else { //if ( $this->plots[$j]->coords[0][$i] < 0 || $accy_neg < 0 ) { $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg); $accyt=$yscale->Translate($accy_neg); $accy_neg+=$this->plots[$j]->coords[0][$i]; } $xt=$xscale->Translate($i); if( $this->abswidth > -1 ) $abswidth=$this->abswidth; else $abswidth=round($this->width*$xscale->scale_factor,0); $pts=array($xt,$accyt,$xt,$yt,$xt+$abswidth,$yt,$xt+$abswidth,$accyt); if( $this->bar_shadow ) { $ssh = $this->bar_shadow_hsize; $ssv = $this->bar_shadow_vsize; // We must also differ if we are a positive or negative bar. if( $j === 0 ) { // This gets extra complicated since we have to // see all plots to see if we are negative. It could // for example be that all plots are 0 until the very // last one. We therefore need to save the initial setup // for both the negative and positive case // In case the final bar is positive $sp[0]=$pts[6]+1; $sp[1]=$pts[7]; $sp[2]=$pts[6]+$ssh; $sp[3]=$pts[7]-$ssv; // In case the final bar is negative $nsp[0]=$pts[0]; $nsp[1]=$pts[1]; $nsp[2]=$pts[0]+$ssh; $nsp[3]=$pts[1]-$ssv; $nsp[4]=$pts[6]+$ssh; $nsp[5]=$pts[7]-$ssv; $nsp[10]=$pts[6]+1; $nsp[11]=$pts[7]; } if( $j === $this->nbrplots-1 ) { // If this is the last plot of the bar and // the total value is larger than 0 then we // add the shadow. if( is_array($this->bar_shadow_color) ) { $numcolors = count($this->bar_shadow_color); if( $numcolors == 0 ) { JpGraphError::RaiseL(2013);//('You have specified an empty array for shadow colors in the bar plot.'); } $img->PushColor($this->bar_shadow_color[$i % $numcolors]); } else { $img->PushColor($this->bar_shadow_color); } if( $accy > 0 ) { $sp[4]=$pts[4]+$ssh; $sp[5]=$pts[5]-$ssv; $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; $sp[8]=$pts[2]; $sp[9]=$pts[3]-1; $sp[10]=$pts[4]+1; $sp[11]=$pts[5]; $img->FilledPolygon($sp,4); } elseif( $accy_neg < 0 ) { $nsp[6]=$pts[4]+$ssh; $nsp[7]=$pts[5]-$ssv; $nsp[8]=$pts[4]+1; $nsp[9]=$pts[5]; $img->FilledPolygon($nsp,4); } $img->PopColor(); } } // If value is NULL or 0, then don't draw a bar at all if ($this->plots[$j]->coords[0][$i] == 0 ) continue; if( $this->plots[$j]->grad ) { $grad = new Gradient($img); $grad->FilledRectangle( $pts[2],$pts[3], $pts[6],$pts[7], $this->plots[$j]->grad_fromcolor, $this->plots[$j]->grad_tocolor, $this->plots[$j]->grad_style); } else { if (is_array($this->plots[$j]->fill_color) ) { $numcolors = count($this->plots[$j]->fill_color); $img->SetColor($this->plots[$j]->fill_color[$i % $numcolors]); } else { $img->SetColor($this->plots[$j]->fill_color); } $img->FilledPolygon($pts); $img->SetColor($this->plots[$j]->color); } // Stroke the pattern if( $this->plots[$j]->iPattern > -1 ) { if( $pattern===NULL ) $pattern = new RectPatternFactory(); $prect = $pattern->Create($this->plots[$j]->iPattern,$this->plots[$j]->iPatternColor,1); $prect->SetDensity($this->plots[$j]->iPatternDensity); if( $this->plots[$j]->coords[0][$i] < 0 ) { $rx = $pts[0]; $ry = $pts[1]; } else { $rx = $pts[2]; $ry = $pts[3]; } $width = abs($pts[4]-$pts[0])+1; $height = abs($pts[1]-$pts[3])+1; $prect->SetPos(new Rectangle($rx,$ry,$width,$height)); $prect->Stroke($img); } // CSIM array if( $i < count($this->plots[$j]->csimtargets) ) { // Create the client side image map $rpts = $img->ArrRotate($pts); $csimcoord=round($rpts[0]).", ".round($rpts[1]); for( $k=1; $k < 4; ++$k){ $csimcoord .= ", ".round($rpts[2*$k]).", ".round($rpts[2*$k+1]); } if( ! empty($this->plots[$j]->csimtargets[$i]) ) { $this->csimareas.= 'csimareas.= " href=\"".$this->plots[$j]->csimtargets[$i]."\""; if( !empty($this->plots[$j]->csimalts[$i]) ) { $sval=sprintf($this->plots[$j]->csimalts[$i],$this->plots[$j]->coords[0][$i]); $this->csimareas .= " title=\"$sval\" "; } $this->csimareas .= " alt=\"$sval\" />\n"; } } $pts[] = $pts[0]; $pts[] = $pts[1]; $img->Polygon($pts); } // Draw labels for each acc.bar $x=$pts[2]+($pts[4]-$pts[2])/2; if($this->bar_shadow) $x += $ssh; // First stroke the accumulated value for the entire bar // This value is always placed at the top/bottom of the bars if( $accy_neg < 0 ) { $y=$yscale->Translate($accy_neg); $this->value->Stroke($img,$accy_neg,$x,$y); } else { $y=$yscale->Translate($accy); $this->value->Stroke($img,$accy,$x,$y); } $accy = 0; $accy_neg = 0; for($j=0; $j < $this->nbrplots; ++$j ) { // We don't print 0 values in an accumulated bar plot if( $this->plots[$j]->coords[0][$i] == 0 ) continue; if ($this->plots[$j]->coords[0][$i] > 0) { $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy); $accyt=$yscale->Translate($accy); if( $this->plots[$j]->valuepos=='center' ) { $y = $accyt-($accyt-$yt)/2; } elseif( $this->plots[$j]->valuepos=='bottom' ) { $y = $accyt; } else { // top or max $y = $accyt-($accyt-$yt); } $accy+=$this->plots[$j]->coords[0][$i]; if( $this->plots[$j]->valuepos=='center' ) { $this->plots[$j]->value->SetAlign("center","center"); $this->plots[$j]->value->SetMargin(0); } elseif( $this->plots[$j]->valuepos=='bottom' ) { $this->plots[$j]->value->SetAlign('center','bottom'); $this->plots[$j]->value->SetMargin(2); } else { $this->plots[$j]->value->SetAlign('center','top'); $this->plots[$j]->value->SetMargin(1); } } else { $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg); $accyt=$yscale->Translate($accy_neg); $accy_neg+=$this->plots[$j]->coords[0][$i]; if( $this->plots[$j]->valuepos=='center' ) { $y = $accyt-($accyt-$yt)/2; } elseif( $this->plots[$j]->valuepos=='bottom' ) { $y = $accyt; } else { $y = $accyt-($accyt-$yt); } if( $this->plots[$j]->valuepos=='center' ) { $this->plots[$j]->value->SetAlign("center","center"); $this->plots[$j]->value->SetMargin(0); } elseif( $this->plots[$j]->valuepos=='bottom' ) { $this->plots[$j]->value->SetAlign('center',$j==0 ? 'bottom':'top'); $this->plots[$j]->value->SetMargin(-2); } else { $this->plots[$j]->value->SetAlign('center','bottom'); $this->plots[$j]->value->SetMargin(-1); } } $this->plots[$j]->value->Stroke($img,$this->plots[$j]->coords[0][$i],$x,$y); } } return true; } } // Class /* EOF */ ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_canvas.php ================================================ Graph($aWidth,$aHeight,$aCachedName,$timeout,$inline); } //--------------- // PUBLIC METHODS function InitFrame() { $this->StrokePlotArea(); } // Method description function Stroke($aStrokeFileName="") { if( $this->texts != null ) { for($i=0; $i < count($this->texts); ++$i) { $this->texts[$i]->Stroke($this->img); } } if( $this->iTables !== null ) { for($i=0; $i < count($this->iTables); ++$i) { $this->iTables[$i]->Stroke($this->img); } } $this->StrokeTitles(); // Should we do any final image transformation if( $this->iImgTrans ) { if( !class_exists('ImgTrans') ) { require_once('jpgraph_imgtrans.php'); } $tform = new ImgTrans($this->img->img); $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, $this->iImgTransDirection,$this->iImgTransHighQ, $this->iImgTransMinSize,$this->iImgTransFillColor, $this->iImgTransBorder); } // If the filename is given as the special _IMG_HANDLER // then the image handler is returned and the image is NOT // streamed back if( $aStrokeFileName == _IMG_HANDLER ) { return $this->img->img; } else { // Finally stream the generated picture $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); return true; } } } // Class /* EOF */ ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_canvtools.php ================================================ g = &$graph; $this->w = $graph->img->width; $this->h = $graph->img->height; $this->ixmin = $xmin; $this->ixmax = $xmax; $this->iymin = $ymin; $this->iymax = $ymax; } function Set($xmin=0,$xmax=10,$ymin=0,$ymax=10) { $this->ixmin = $xmin; $this->ixmax = $xmax; $this->iymin = $ymin; $this->iymax = $ymax; } function Translate($x,$y) { $xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w); $yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h); return array($xp,$yp); } function TranslateX($x) { $xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w); return $xp; } function TranslateY($y) { $yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h); return $yp; } } //=================================================== // CLASS Shape // Description: Methods to draw shapes on canvas //=================================================== class Shape { var $img,$scale; function Shape(&$aGraph,&$scale) { $this->img = &$aGraph->img; $this->img->SetColor('black'); $this->scale = &$scale; } function SetColor($aColor) { $this->img->SetColor($aColor); } function Line($x1,$y1,$x2,$y2) { list($x1,$y1) = $this->scale->Translate($x1,$y1); list($x2,$y2) = $this->scale->Translate($x2,$y2); $this->img->Line($x1,$y1,$x2,$y2); } function Polygon($p,$aClosed=false) { $n=count($p); for($i=0; $i < $n; $i+=2 ) { $p[$i] = $this->scale->TranslateX($p[$i]); $p[$i+1] = $this->scale->TranslateY($p[$i+1]); } $this->img->Polygon($p,$aClosed); } function FilledPolygon($p) { $n=count($p); for($i=0; $i < $n; $i+=2 ) { $p[$i] = $this->scale->TranslateX($p[$i]); $p[$i+1] = $this->scale->TranslateY($p[$i+1]); } $this->img->FilledPolygon($p); } // Draw a bezier curve with defining points in the $aPnts array // using $aSteps steps. // 0=x0, 1=y0 // 2=x1, 3=y1 // 4=x2, 5=y2 // 6=x3, 7=y3 function Bezier($p,$aSteps=40) { $x0 = $p[0]; $y0 = $p[1]; // Calculate coefficients $cx = 3*($p[2]-$p[0]); $bx = 3*($p[4]-$p[2])-$cx; $ax = $p[6]-$p[0]-$cx-$bx; $cy = 3*($p[3]-$p[1]); $by = 3*($p[5]-$p[3])-$cy; $ay = $p[7]-$p[1]-$cy-$by; // Step size $delta = 1.0/$aSteps; $x_old = $x0; $y_old = $y0; for($t=$delta; $t<=1.0; $t+=$delta) { $tt = $t*$t; $ttt=$tt*$t; $x = $ax*$ttt + $bx*$tt + $cx*$t + $x0; $y = $ay*$ttt + $by*$tt + $cy*$t + $y0; $this->Line($x_old,$y_old,$x,$y); $x_old = $x; $y_old = $y; } $this->Line($x_old,$y_old,$p[6],$p[7]); } function Rectangle($x1,$y1,$x2,$y2) { list($x1,$y1) = $this->scale->Translate($x1,$y1); list($x2,$y2) = $this->scale->Translate($x2,$y2); $this->img->Rectangle($x1,$y1,$x2,$y2); } function FilledRectangle($x1,$y1,$x2,$y2) { list($x1,$y1) = $this->scale->Translate($x1,$y1); list($x2,$y2) = $this->scale->Translate($x2,$y2); $this->img->FilledRectangle($x1,$y1,$x2,$y2); } function Circle($x1,$y1,$r) { list($x1,$y1) = $this->scale->Translate($x1,$y1); if( $r >= 0 ) $r = $this->scale->TranslateX($r); else $r = -$r; $this->img->Circle($x1,$y1,$r); } function FilledCircle($x1,$y1,$r) { list($x1,$y1) = $this->scale->Translate($x1,$y1); if( $r >= 0 ) $r = $this->scale->TranslateX($r); else $r = -$r; $this->img->FilledCircle($x1,$y1,$r); } function RoundedRectangle($x1,$y1,$x2,$y2,$r=null) { list($x1,$y1) = $this->scale->Translate($x1,$y1); list($x2,$y2) = $this->scale->Translate($x2,$y2); if( $r == null ) $r = 5; elseif( $r >= 0 ) $r = $this->scale->TranslateX($r); else $r = -$r; $this->img->RoundedRectangle($x1,$y1,$x2,$y2,$r); } function FilledRoundedRectangle($x1,$y1,$x2,$y2,$r=null) { list($x1,$y1) = $this->scale->Translate($x1,$y1); list($x2,$y2) = $this->scale->Translate($x2,$y2); if( $r == null ) $r = 5; elseif( $r > 0 ) $r = $this->scale->TranslateX($r); else $r = -$r; $this->img->FilledRoundedRectangle($x1,$y1,$x2,$y2,$r); } function ShadowRectangle($x1,$y1,$x2,$y2,$fcolor=false,$shadow_width=null,$shadow_color=array(102,102,102)) { list($x1,$y1) = $this->scale->Translate($x1,$y1); list($x2,$y2) = $this->scale->Translate($x2,$y2); if( $shadow_width == null ) $shadow_width=4; else $shadow_width=$this->scale->TranslateX($shadow_width); $this->img->ShadowRectangle($x1,$y1,$x2,$y2,$fcolor,$shadow_width,$shadow_color); } function SetTextAlign($halign,$valign="bottom") { $this->img->SetTextAlign($halign,$valign="bottom"); } function StrokeText($x1,$y1,$txt,$dir=0,$paragraph_align="left") { list($x1,$y1) = $this->scale->Translate($x1,$y1); $this->img->StrokeText($x1,$y1,$txt,$dir,$paragraph_align); } // A rounded rectangle where one of the corner has been moved "into" the // rectangle 'iw' width and 'ih' height. Corners: // 0=Top left, 1=top right, 2=bottom right, 3=bottom left function IndentedRectangle($xt,$yt,$w,$h,$iw=0,$ih=0,$aCorner=3,$aFillColor="",$r=4) { list($xt,$yt) = $this->scale->Translate($xt,$yt); list($w,$h) = $this->scale->Translate($w,$h); list($iw,$ih) = $this->scale->Translate($iw,$ih); $xr = $xt + $w - 0; $yl = $yt + $h - 0; switch( $aCorner ) { case 0: // Upper left // Bottom line, left & right arc $this->img->Line($xt+$r,$yl,$xr-$r,$yl); $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); // Right line, Top right arc $this->img->Line($xr,$yt+$r,$xr,$yl-$r); $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); // Top line, Top left arc $this->img->Line($xt+$iw+$r,$yt,$xr-$r,$yt); $this->img->Arc($xt+$iw+$r,$yt+$r,$r*2,$r*2,180,270); // Left line $this->img->Line($xt,$yt+$ih+$r,$xt,$yl-$r); // Indent horizontal, Lower left arc $this->img->Line($xt+$r,$yt+$ih,$xt+$iw-$r,$yt+$ih); $this->img->Arc($xt+$r,$yt+$ih+$r,$r*2,$r*2,180,270); // Indent vertical, Indent arc $this->img->Line($xt+$iw,$yt+$r,$xt+$iw,$yt+$ih-$r); $this->img->Arc($xt+$iw-$r,$yt+$ih-$r,$r*2,$r*2,0,90); if( $aFillColor != '' ) { $bc = $this->img->current_color_name; $this->img->PushColor($aFillColor); $this->img->FillToBorder($xr-$r,$yl-$r,$bc); $this->img->PopColor(); } break; case 1: // Upper right // Bottom line, left & right arc $this->img->Line($xt+$r,$yl,$xr-$r,$yl); $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); // Left line, Top left arc $this->img->Line($xt,$yt+$r,$xt,$yl-$r); $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); // Top line, Top right arc $this->img->Line($xt+$r,$yt,$xr-$iw-$r,$yt); $this->img->Arc($xr-$iw-$r,$yt+$r,$r*2,$r*2,270,360); // Right line $this->img->Line($xr,$yt+$ih+$r,$xr,$yl-$r); // Indent horizontal, Lower right arc $this->img->Line($xr-$iw+$r,$yt+$ih,$xr-$r,$yt+$ih); $this->img->Arc($xr-$r,$yt+$ih+$r,$r*2,$r*2,270,360); // Indent vertical, Indent arc $this->img->Line($xr-$iw,$yt+$r,$xr-$iw,$yt+$ih-$r); $this->img->Arc($xr-$iw+$r,$yt+$ih-$r,$r*2,$r*2,90,180); if( $aFillColor != '' ) { $bc = $this->img->current_color_name; $this->img->PushColor($aFillColor); $this->img->FillToBorder($xt+$r,$yl-$r,$bc); $this->img->PopColor(); } break; case 2: // Lower right // Top line, Top left & Top right arc $this->img->Line($xt+$r,$yt,$xr-$r,$yt); $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); // Left line, Bottom left arc $this->img->Line($xt,$yt+$r,$xt,$yl-$r); $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); // Bottom line, Bottom right arc $this->img->Line($xt+$r,$yl,$xr-$iw-$r,$yl); $this->img->Arc($xr-$iw-$r,$yl-$r,$r*2,$r*2,0,90); // Right line $this->img->Line($xr,$yt+$r,$xr,$yl-$ih-$r); // Indent horizontal, Lower right arc $this->img->Line($xr-$r,$yl-$ih,$xr-$iw+$r,$yl-$ih); $this->img->Arc($xr-$r,$yl-$ih-$r,$r*2,$r*2,0,90); // Indent vertical, Indent arc $this->img->Line($xr-$iw,$yl-$r,$xr-$iw,$yl-$ih+$r); $this->img->Arc($xr-$iw+$r,$yl-$ih+$r,$r*2,$r*2,180,270); if( $aFillColor != '' ) { $bc = $this->img->current_color_name; $this->img->PushColor($aFillColor); $this->img->FillToBorder($xt+$r,$yt+$r,$bc); $this->img->PopColor(); } break; case 3: // Lower left // Top line, Top left & Top right arc $this->img->Line($xt+$r,$yt,$xr-$r,$yt); $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); // Right line, Bottom right arc $this->img->Line($xr,$yt+$r,$xr,$yl-$r); $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); // Bottom line, Bottom left arc $this->img->Line($xt+$iw+$r,$yl,$xr-$r,$yl); $this->img->Arc($xt+$iw+$r,$yl-$r,$r*2,$r*2,90,180); // Left line $this->img->Line($xt,$yt+$r,$xt,$yl-$ih-$r); // Indent horizontal, Lower left arc $this->img->Line($xt+$r,$yl-$ih,$xt+$iw-$r,$yl-$ih); $this->img->Arc($xt+$r,$yl-$ih-$r,$r*2,$r*2,90,180); // Indent vertical, Indent arc $this->img->Line($xt+$iw,$yl-$ih+$r,$xt+$iw,$yl-$r); $this->img->Arc($xt+$iw-$r,$yl-$ih+$r,$r*2,$r*2,270,360); if( $aFillColor != '' ) { $bc = $this->img->current_color_name; $this->img->PushColor($aFillColor); $this->img->FillToBorder($xr-$r,$yt+$r,$bc); $this->img->PopColor(); } break; } } } //=================================================== // CLASS RectangleText // Description: Draws a text paragraph inside a // rounded, possible filled, rectangle. //=================================================== class CanvasRectangleText { var $ix,$iy,$iw,$ih,$ir=4; var $iTxt,$iColor='black',$iFillColor='',$iFontColor='black'; var $iParaAlign='center'; var $iAutoBoxMargin=5; var $iShadowWidth=3,$iShadowColor=''; function CanvasRectangleText($aTxt='',$xl=0,$yt=0,$w=0,$h=0) { $this->iTxt = new Text($aTxt); $this->ix = $xl; $this->iy = $yt; $this->iw = $w; $this->ih = $h; } function SetShadow($aColor='gray',$aWidth=3) { $this->iShadowColor = $aColor; $this->iShadowWidth = $aWidth; } function SetFont($FontFam,$aFontStyle,$aFontSize=12) { $this->iTxt->SetFont($FontFam,$aFontStyle,$aFontSize); } function SetTxt($aTxt) { $this->iTxt->Set($aTxt); } function ParagraphAlign($aParaAlign) { $this->iParaAlign = $aParaAlign; } function SetFillColor($aFillColor) { $this->iFillColor = $aFillColor; } function SetAutoMargin($aMargin) { $this->iAutoBoxMargin=$aMargin; } function SetColor($aColor) { $this->iColor = $aColor; } function SetFontColor($aColor) { $this->iFontColor = $aColor; } function SetPos($xl=0,$yt=0,$w=0,$h=0) { $this->ix = $xl; $this->iy = $yt; $this->iw = $w; $this->ih = $h; } function Pos($xl=0,$yt=0,$w=0,$h=0) { $this->ix = $xl; $this->iy = $yt; $this->iw = $w; $this->ih = $h; } function Set($aTxt,$xl,$yt,$w=0,$h=0) { $this->iTxt->Set($aTxt); $this->ix = $xl; $this->iy = $yt; $this->iw = $w; $this->ih = $h; } function SetCornerRadius($aRad=5) { $this->ir = $aRad; } function Stroke($aImg,$scale) { // If coordinates are specifed as negative this means we should // treat them as abolsute (pixels) coordinates if( $this->ix > 0 ) { $this->ix = $scale->TranslateX($this->ix) ; } else { $this->ix = -$this->ix; } if( $this->iy > 0 ) { $this->iy = $scale->TranslateY($this->iy) ; } else { $this->iy = -$this->iy; } list($this->iw,$this->ih) = $scale->Translate($this->iw,$this->ih) ; if( $this->iw == 0 ) $this->iw = round($this->iTxt->GetWidth($aImg) + $this->iAutoBoxMargin); if( $this->ih == 0 ) { $this->ih = round($this->iTxt->GetTextHeight($aImg) + $this->iAutoBoxMargin); } if( $this->iShadowColor != '' ) { $aImg->PushColor($this->iShadowColor); $aImg->FilledRoundedRectangle($this->ix+$this->iShadowWidth, $this->iy+$this->iShadowWidth, $this->ix+$this->iw-1+$this->iShadowWidth, $this->iy+$this->ih-1+$this->iShadowWidth, $this->ir); $aImg->PopColor(); } if( $this->iFillColor != '' ) { $aImg->PushColor($this->iFillColor); $aImg->FilledRoundedRectangle($this->ix,$this->iy, $this->ix+$this->iw-1, $this->iy+$this->ih-1, $this->ir); $aImg->PopColor(); } if( $this->iColor != '' ) { $aImg->PushColor($this->iColor); $aImg->RoundedRectangle($this->ix,$this->iy, $this->ix+$this->iw-1, $this->iy+$this->ih-1, $this->ir); $aImg->PopColor(); } $this->iTxt->Align('center','center'); $this->iTxt->ParagraphAlign($this->iParaAlign); $this->iTxt->SetColor($this->iFontColor); $this->iTxt->Stroke($aImg, $this->ix+$this->iw/2, $this->iy+$this->ih/2); return array($this->iw, $this->ih); } } ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_date.php ================================================ type=$aType; $this->scale=array($aMin,$aMax); $this->world_size=$aMax-$aMin; $this->ticks = new LinearTicks(); $this->intscale=true; } //------------------------------------------------------------------------------------------ // Utility Function AdjDate() // Description: Will round a given time stamp to an even year, month or day // argument. //------------------------------------------------------------------------------------------ function AdjDate($aTime,$aRound=0,$aYearType=false,$aMonthType=false,$aDayType=false) { $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); $h=0;$i=0;$s=0; if( $aYearType !== false ) { $yearAdj = array(0=>1, 1=>2, 2=>5); if( $aRound == 0 ) { $y = floor($y/$yearAdj[$aYearType])*$yearAdj[$aYearType]; } else { ++$y; $y = ceil($y/$yearAdj[$aYearType])*$yearAdj[$aYearType]; } $m=1;$d=1; } elseif( $aMonthType !== false ) { $monthAdj = array(0=>1, 1=>6); if( $aRound == 0 ) { $m = floor($m/$monthAdj[$aMonthType])*$monthAdj[$aMonthType]; $d=1; } else { ++$m; $m = ceil($m/$monthAdj[$aMonthType])*$monthAdj[$aMonthType]; $d=1; } } elseif( $aDayType !== false ) { if( $aDayType == 0 ) { if( $aRound == 1 ) { //++$d; $h=23;$i=59;$s=59; } } else { // Adjust to an even week boundary. $w = (int)date('w',$aTime); // Day of week 0=Sun, 6=Sat if( true ) { // Adjust to start on Mon if( $w==0 ) $w=6; else --$w; } if( $aRound == 0 ) { $d -= $w; } else { $d += (7-$w); $h=23;$i=59;$s=59; } } } return mktime($h,$i,$s,$m,$d,$y); } //------------------------------------------------------------------------------------------ // Wrapper for AdjDate that will round a timestamp to an even date rounding // it downwards. //------------------------------------------------------------------------------------------ function AdjStartDate($aTime,$aYearType=false,$aMonthType=false,$aDayType=false) { return $this->AdjDate($aTime,0,$aYearType,$aMonthType,$aDayType); } //------------------------------------------------------------------------------------------ // Wrapper for AdjDate that will round a timestamp to an even date rounding // it upwards //------------------------------------------------------------------------------------------ function AdjEndDate($aTime,$aYearType=false,$aMonthType=false,$aDayType=false) { return $this->AdjDate($aTime,1,$aYearType,$aMonthType,$aDayType); } //------------------------------------------------------------------------------------------ // Utility Function AdjTime() // Description: Will round a given time stamp to an even time according to // argument. //------------------------------------------------------------------------------------------ function AdjTime($aTime,$aRound=0,$aHourType=false,$aMinType=false,$aSecType=false) { $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); $h = (int)date('H',$aTime); $i = (int)date('i',$aTime); $s = (int)date('s',$aTime); if( $aHourType !== false ) { $aHourType %= 6; $hourAdj = array(0=>1, 1=>2, 2=>3, 3=>4, 4=>6, 5=>12); if( $aRound == 0 ) $h = floor($h/$hourAdj[$aHourType])*$hourAdj[$aHourType]; else { if( ($h % $hourAdj[$aHourType]==0) && ($i > 0 || $s > 0) ) { $h++; } $h = ceil($h/$hourAdj[$aHourType])*$hourAdj[$aHourType]; if( $h >= 24 ) { $aTime += 86400; $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); $h -= 24; } } $i=0;$s=0; } elseif( $aMinType !== false ) { $aMinType %= 5; $minAdj = array(0=>1, 1=>5, 2=>10, 3=>15, 4=>30); if( $aRound == 0 ) { $i = floor($i/$minAdj[$aMinType])*$minAdj[$aMinType]; } else { if( ($i % $minAdj[$aMinType]==0) && $s > 0 ) { $i++; } $i = ceil($i/$minAdj[$aMinType])*$minAdj[$aMinType]; if( $i >= 60) { $aTime += 3600; $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); $h = (int)date('H',$aTime); $i = 0; } } $s=0; } elseif( $aSecType !== false ) { $aSecType %= 5; $secAdj = array(0=>1, 1=>5, 2=>10, 3=>15, 4=>30); if( $aRound == 0 ) { $s = floor($s/$secAdj[$aSecType])*$secAdj[$aSecType]; } else { $s = ceil($s/$secAdj[$aSecType]*1.0)*$secAdj[$aSecType]; if( $s >= 60) { $s=0; $aTime += 60; $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); $h = (int)date('H',$aTime); $i = (int)date('i',$aTime); } } } return mktime($h,$i,$s,$m,$d,$y); } //------------------------------------------------------------------------------------------ // Wrapper for AdjTime that will round a timestamp to an even time rounding // it downwards. // Example: AdjStartTime(mktime(18,27,13,2,22,2005),false,2) => 18:20 //------------------------------------------------------------------------------------------ function AdjStartTime($aTime,$aHourType=false,$aMinType=false,$aSecType=false) { return $this->AdjTime($aTime,0,$aHourType,$aMinType,$aSecType); } //------------------------------------------------------------------------------------------ // Wrapper for AdjTime that will round a timestamp to an even time rounding // it upwards // Example: AdjEndTime(mktime(18,27,13,2,22,2005),false,2) => 18:30 //------------------------------------------------------------------------------------------ function AdjEndTime($aTime,$aHourType=false,$aMinType=false,$aSecType=false) { return $this->AdjTime($aTime,1,$aHourType,$aMinType,$aSecType); } //------------------------------------------------------------------------------------------ // DateAutoScale // Autoscale a date axis given start and end time // Returns an array ($start,$end,$major,$minor,$format) //------------------------------------------------------------------------------------------ function DoDateAutoScale($aStartTime,$aEndTime,$aDensity=0,$aAdjust=true) { // Format of array // array ( Decision point, array( array( Major-scale-step-array ), // array( Minor-scale-step-array ), // array( 0=date-adjust, 1=time-adjust, adjustment-alignment) ) // $scalePoints = array( /* Intervall larger than 10 years */ SECPERYEAR*10,array(array(SECPERYEAR*5,SECPERYEAR*2), array(SECPERYEAR), array(0,YEARADJ_1, 0,YEARADJ_1) ), /* Intervall larger than 2 years */ SECPERYEAR*2,array(array(SECPERYEAR),array(SECPERYEAR), array(0,YEARADJ_1) ), /* Intervall larger than 90 days (approx 3 month) */ SECPERDAY*90,array(array(SECPERDAY*30,SECPERDAY*14,SECPERDAY*7,SECPERDAY), array(SECPERDAY*5,SECPERDAY*7,SECPERDAY,SECPERDAY), array(0,MONTHADJ_1, 0,DAYADJ_WEEK, 0,DAYADJ_1, 0,DAYADJ_1)), /* Intervall larger than 30 days (approx 1 month) */ SECPERDAY*30,array(array(SECPERDAY*14,SECPERDAY*7,SECPERDAY*2, SECPERDAY), array(SECPERDAY,SECPERDAY.SECPERDAY,SECPERDAY), array(0,DAYADJ_WEEK, 0,DAYADJ_1, 0,DAYADJ_1, 0,DAYADJ_1)), /* Intervall larger than 7 days */ SECPERDAY*7,array(array(SECPERDAY,SECPERHOUR*12,SECPERHOUR*6,SECPERHOUR*2), array(SECPERHOUR*6,SECPERHOUR*3,SECPERHOUR,SECPERHOUR), array(0,DAYADJ_1, 1,HOURADJ_12, 1,HOURADJ_6, 1,HOURADJ_1)), /* Intervall larger than 1 day */ SECPERDAY,array(array(SECPERDAY,SECPERHOUR*12,SECPERHOUR*6,SECPERHOUR*2,SECPERHOUR), array(SECPERHOUR*6,SECPERHOUR*2,SECPERHOUR,SECPERHOUR,SECPERHOUR), array(1,HOURADJ_12, 1,HOURADJ_6, 1,HOURADJ_1, 1,HOURADJ_1)), /* Intervall larger than 12 hours */ SECPERHOUR*12,array(array(SECPERHOUR*2,SECPERHOUR,SECPERMIN*30,900,600), array(1800,1800,900,300,300), array(1,HOURADJ_1, 1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), /* Intervall larger than 2 hours */ SECPERHOUR*2,array(array(SECPERHOUR,SECPERMIN*30,900,600,300), array(1800,900,300,120,60), array(1,HOURADJ_1, 1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), /* Intervall larger than 1 hours */ SECPERHOUR,array(array(SECPERMIN*30,900,600,300),array(900,300,120,60), array(1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), /* Intervall larger than 30 min */ SECPERMIN*30,array(array(SECPERMIN*15,SECPERMIN*10,SECPERMIN*5,SECPERMIN), array(300,300,60,10), array(1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5, 1,MINADJ_1)), /* Intervall larger than 1 min */ SECPERMIN,array(array(SECPERMIN,15,10,5), array(15,5,2,1), array(1,MINADJ_1, 1,SECADJ_15, 1,SECADJ_10, 1,SECADJ_5)), /* Intervall larger than 10 sec */ 10,array(array(5,2), array(1,1), array(1,SECADJ_5, 1,SECADJ_1)), /* Intervall larger than 1 sec */ 1,array(array(1), array(1), array(1,SECADJ_1)), ); $ns = count($scalePoints); // Establish major and minor scale units for the date scale $diff = $aEndTime - $aStartTime; if( $diff < 1 ) return false; $done=false; $i=0; while( ! $done ) { if( $diff > $scalePoints[2*$i] ) { // Get major and minor scale for this intervall $scaleSteps = $scalePoints[2*$i+1]; $major = $scaleSteps[0][min($aDensity,count($scaleSteps[0])-1)]; // Try to find out which minor step looks best $minor = $scaleSteps[1][min($aDensity,count($scaleSteps[1])-1)]; if( $aAdjust ) { // Find out how we should align the start and end timestamps $idx = 2*min($aDensity,floor(count($scaleSteps[2])/2)-1); if( $scaleSteps[2][$idx] === 0 ) { // Use date adjustment $adj = $scaleSteps[2][$idx+1]; if( $adj >= 30 ) { $start = $this->AdjStartDate($aStartTime,$adj-30); $end = $this->AdjEndDate($aEndTime,$adj-30); } elseif( $adj >= 20 ) { $start = $this->AdjStartDate($aStartTime,false,$adj-20); $end = $this->AdjEndDate($aEndTime,false,$adj-20); } else { $start = $this->AdjStartDate($aStartTime,false,false,$adj); $end = $this->AdjEndDate($aEndTime,false,false,$adj); // We add 1 second for date adjustment to make sure we end on 00:00 the following day // This makes the final major tick be srawn when we step day-by-day instead of ending // on xx:59:59 which would not draw the final major tick $end++; } } else { // Use time adjustment $adj = $scaleSteps[2][$idx+1]; if( $adj >= 30 ) { $start = $this->AdjStartTime($aStartTime,$adj-30); $end = $this->AdjEndTime($aEndTime,$adj-30); } elseif( $adj >= 20 ) { $start = $this->AdjStartTime($aStartTime,false,$adj-20); $end = $this->AdjEndTime($aEndTime,false,$adj-20); } else { $start = $this->AdjStartTime($aStartTime,false,false,$adj); $end = $this->AdjEndTime($aEndTime,false,false,$adj); } } } // If the overall date span is larger than 1 day ten we show date $format = ''; if( ($end-$start) > SECPERDAY ) { $format = 'Y-m-d '; } // If the major step is less than 1 day we need to whow hours + min if( $major < SECPERDAY ) { $format .= 'H:i'; } // If the major step is less than 1 min we need to show sec if( $major < 60 ) { $format .= ':s'; } $done=true; } ++$i; } return array($start,$end,$major,$minor,$format); } // Overrides the automatic determined date format. Must be a valid date() format string function SetDateFormat($aFormat) { $this->date_format = $aFormat; } function SetDateAlign($aStartAlign,$aEndAlign=false) { if( $aEndAlign === false ) { $aEndAlign=$aStartAlign; } $this->iStartAlign = $aStartAlign; $this->iEndAlign = $aEndAlign; } function SetTimeAlign($aStartAlign,$aEndAlign=false) { if( $aEndAlign === false ) { $aEndAlign=$aStartAlign; } $this->iStartTimeAlign = $aStartAlign; $this->iEndTimeAlign = $aEndAlign; } function AutoScale(&$img,$aStartTime,$aEndTime,$aNumSteps) { if( $aStartTime == $aEndTime ) { // Special case when we only have one data point. // Create a small artifical intervall to do the autoscaling $aStartTime -= 10; $aEndTime += 10; } $done=false; $i=0; while( ! $done && $i < 5) { list($adjstart,$adjend,$maj,$min,$format) = $this->DoDateAutoScale($aStartTime,$aEndTime,$i); $n = floor(($adjend-$adjstart)/$maj); if( $n * 1.7 > $aNumSteps ) { $done=true; } $i++; } /* if( 0 ) { // DEBUG echo " Start =".date("Y-m-d H:i:s",$aStartTime)."
"; echo " End =".date("Y-m-d H:i:s",$aEndTime)."
"; echo "Adj Start =".date("Y-m-d H:i:s",$adjstart)."
"; echo "Adj End =".date("Y-m-d H:i:s",$adjend)."

"; echo "Major = $maj s, ".floor($maj/60)."min, ".floor($maj/3600)."h, ".floor($maj/86400)."day
"; echo "Min = $min s, ".floor($min/60)."min, ".floor($min/3600)."h, ".floor($min/86400)."day
"; echo "Format=$format

"; } */ if( $this->iStartTimeAlign !== false && $this->iStartAlign !== false ) { JpGraphError::RaiseL(3001); //('It is only possible to use either SetDateAlign() or SetTimeAlign() but not both'); } if( $this->iStartTimeAlign !== false ) { if( $this->iStartTimeAlign >= 30 ) { $adjstart = $this->AdjStartTime($aStartTime,$this->iStartTimeAlign-30); } elseif( $this->iStartTimeAlign >= 20 ) { $adjstart = $this->AdjStartTime($aStartTime,false,$this->iStartTimeAlign-20); } else { $adjstart = $this->AdjStartTime($aStartTime,false,false,$this->iStartTimeAlign); } } if( $this->iEndTimeAlign !== false ) { if( $this->iEndTimeAlign >= 30 ) { $adjend = $this->AdjEndTime($aEndTime,$this->iEndTimeAlign-30); } elseif( $this->iEndTimeAlign >= 20 ) { $adjend = $this->AdjEndTime($aEndTime,false,$this->iEndTimeAlign-20); } else { $adjend = $this->AdjEndTime($aEndTime,false,false,$this->iEndTimeAlign); } } if( $this->iStartAlign !== false ) { if( $this->iStartAlign >= 30 ) { $adjstart = $this->AdjStartDate($aStartTime,$this->iStartAlign-30); } elseif( $this->iStartAlign >= 20 ) { $adjstart = $this->AdjStartDate($aStartTime,false,$this->iStartAlign-20); } else { $adjstart = $this->AdjStartDate($aStartTime,false,false,$this->iStartAlign); } } if( $this->iEndAlign !== false ) { if( $this->iEndAlign >= 30 ) { $adjend = $this->AdjEndDate($aEndTime,$this->iEndAlign-30); } elseif( $this->iEndAlign >= 20 ) { $adjend = $this->AdjEndDate($aEndTime,false,$this->iEndAlign-20); } else { $adjend = $this->AdjEndDate($aEndTime,false,false,$this->iEndAlign); } } $this->Update($img,$adjstart,$adjend); if( ! $this->ticks->IsSpecified() ) $this->ticks->Set($maj,$min); if( $this->date_format == '' ) $this->ticks->SetLabelDateFormat($format); else $this->ticks->SetLabelDateFormat($this->date_format); } } ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_error.php ================================================ Plot($datay,$datax); $this->numpoints /= 2; } //--------------- // PUBLIC METHODS // Gets called before any axis are stroked function PreStrokeAdjust(&$graph) { if( $this->center ) { $a=0.5; $b=0.5; ++$this->numpoints; } else { $a=0; $b=0; } $graph->xaxis->scale->ticks->SetXLabelOffset($a); $graph->SetTextScaleOff($b); //$graph->xaxis->scale->ticks->SupressMinorTickMarks(); } // Method description function Stroke(&$img,&$xscale,&$yscale) { $numpoints=count($this->coords[0])/2; $img->SetColor($this->color); $img->SetLineWeight($this->weight); if( isset($this->coords[1]) ) { if( count($this->coords[1])!=$numpoints ) JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); //("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); else $exist_x = true; } else $exist_x = false; for( $i=0; $i<$numpoints; ++$i) { if( $exist_x ) $x=$this->coords[1][$i]; else $x=$i; if( !is_numeric($x) || !is_numeric($this->coords[0][$i*2]) || !is_numeric($this->coords[0][$i*2+1]) ) { continue; } $xt = $xscale->Translate($x); $yt1 = $yscale->Translate($this->coords[0][$i*2]); $yt2 = $yscale->Translate($this->coords[0][$i*2+1]); $img->Line($xt,$yt1,$xt,$yt2); $img->Line($xt-$this->errwidth,$yt1,$xt+$this->errwidth,$yt1); $img->Line($xt-$this->errwidth,$yt2,$xt+$this->errwidth,$yt2); } return true; } } // Class //=================================================== // CLASS ErrorLinePlot // Description: Combine a line and error plot // THIS IS A DEPRECATED PLOT TYPE JUST KEPT FOR // BACKWARD COMPATIBILITY //=================================================== class ErrorLinePlot extends ErrorPlot { var $line=null; //--------------- // CONSTRUCTOR function ErrorLinePlot(&$datay,$datax=false) { $this->ErrorPlot($datay,$datax); // Calculate line coordinates as the average of the error limits $n = count($datay); for($i=0; $i < $n; $i+=2 ) { $ly[]=($datay[$i]+$datay[$i+1])/2; } $this->line=new LinePlot($ly,$datax); } //--------------- // PUBLIC METHODS function Legend(&$graph) { if( $this->legend != "" ) $graph->legend->Add($this->legend,$this->color); $this->line->Legend($graph); } function Stroke(&$img,&$xscale,&$yscale) { parent::Stroke($img,$xscale,$yscale); $this->line->Stroke($img,$xscale,$yscale); } } // Class //=================================================== // CLASS LineErrorPlot // Description: Combine a line and error plot //=================================================== class LineErrorPlot extends ErrorPlot { var $line=null; //--------------- // CONSTRUCTOR // Data is (val, errdeltamin, errdeltamax) function LineErrorPlot(&$datay,$datax=false) { $ly=array(); $ey=array(); $n = count($datay); if( $n % 3 != 0 ) { JpGraphError::RaiseL(4002); //('Error in input data to LineErrorPlot. Number of data points must be a multiple of 3'); } for($i=0; $i < $n; $i+=3 ) { $ly[]=$datay[$i]; $ey[]=$datay[$i]+$datay[$i+1]; $ey[]=$datay[$i]+$datay[$i+2]; } $this->ErrorPlot($ey,$datax); $this->line=new LinePlot($ly,$datax); } //--------------- // PUBLIC METHODS function Legend(&$graph) { if( $this->legend != "" ) $graph->legend->Add($this->legend,$this->color); $this->line->Legend($graph); } function Stroke(&$img,&$xscale,&$yscale) { parent::Stroke($img,$xscale,$yscale); $this->line->Stroke($img,$xscale,$yscale); } } // Class /* EOF */ ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_flags.php ================================================ 'afgh', 'Republic of Angola' => 'agla', 'Republic of Albania' => 'alba', 'Alderney' => 'alde', 'Democratic and Popular Republic of Algeria' => 'alge', 'Territory of American Samoa' => 'amsa', 'Principality of Andorra' => 'andr', 'British Overseas Territory of Anguilla' => 'angu', 'Antarctica' => 'anta', 'Argentine Republic' => 'arge', 'League of Arab States' => 'arle', 'Republic of Armenia' => 'arme', 'Aruba' => 'arub', 'Commonwealth of Australia' => 'astl', 'Republic of Austria' => 'aust', 'Azerbaijani Republic' => 'azer', 'British Antarctic Territory' => 'bant', 'Kingdom of Belgium' => 'belg', 'British Overseas Territory of Bermuda' => 'berm', 'Commonwealth of the Bahamas' => 'bhms', 'Kingdom of Bahrain' => 'bhrn', 'Republic of Belarus' => 'blru', 'Republic of Bolivia' => 'blva', 'Belize' => 'blze', 'Republic of Benin' => 'bnin', 'Republic of Botswana' => 'bots', 'Federative Republic of Brazil' => 'braz', 'Barbados' => 'brbd', 'British Indian Ocean Territory' => 'brin', 'Brunei Darussalam' => 'brun', 'Republic of Burkina' => 'bufa', 'Republic of Bulgaria' => 'bulg', 'Republic of Burundi' => 'buru', 'Overseas Territory of the British Virgin Islands' => 'bvis', 'Central African Republic' => 'cafr', 'Kingdom of Cambodia' => 'camb', 'Republic of Cameroon' => 'came', 'Dominion of Canada' => 'cana', 'Caribbean Community' => 'cari', 'Republic of Cape Verde' => 'cave', 'Republic of Chad' => 'chad', 'Republic of Chile' => 'chil', 'Peoples Republic of China' => 'chin', 'Territory of Christmas Island' => 'chms', 'Commonwealth of Independent States' => 'cins', 'Cook Islands' => 'ckis', 'Republic of Colombia' => 'clmb', 'Territory of Cocos Islands' => 'cois', 'Commonwealth' => 'comn', 'Union of the Comoros' => 'como', 'Republic of the Congo' => 'cong', 'Republic of Costa Rica' => 'corc', 'Republic of Croatia' => 'croa', 'Republic of Cuba' => 'cuba', 'British Overseas Territory of the Cayman Islands' => 'cyis', 'Republic of Cyprus' => 'cypr', 'The Czech Republic' => 'czec', 'Kingdom of Denmark' => 'denm', 'Republic of Djibouti' => 'djib', 'Commonwealth of Dominica' => 'domn', 'Dominican Republic' => 'dore', 'Republic of Ecuador' => 'ecua', 'Arab Republic of Egypt' => 'egyp', 'Republic of El Salvador' => 'elsa', 'England' => 'engl', 'Republic of Equatorial Guinea' => 'eqgu', 'State of Eritrea' => 'erit', 'Republic of Estonia' => 'estn', 'Ethiopia' => 'ethp', 'European Union' => 'euun', 'British Overseas Territory of the Falkland Islands' => 'fais', 'International Federation of Vexillological Associations' => 'fiav', 'Republic of Fiji' => 'fiji', 'Republic of Finland' => 'finl', 'Territory of French Polynesia' => 'fpol', 'French Republic' => 'fran', 'Overseas Department of French Guiana' => 'frgu', 'Gabonese Republic' => 'gabn', 'Republic of the Gambia' => 'gamb', 'Republic of Georgia' => 'geor', 'Federal Republic of Germany' => 'germ', 'Republic of Ghana' => 'ghan', 'Gibraltar' => 'gibr', 'Hellenic Republic' => 'grec', 'State of Grenada' => 'gren', 'Overseas Department of Guadeloupe' => 'guad', 'Territory of Guam' => 'guam', 'Republic of Guatemala' => 'guat', 'The Bailiwick of Guernsey' => 'guer', 'Republic of Guinea' => 'guin', 'Republic of Haiti' => 'hait', 'Hong Kong Special Administrative Region' => 'hokn', 'Republic of Honduras' => 'hond', 'Republic of Hungary' => 'hung', 'Republic of Iceland' => 'icel', 'International Committee of the Red Cross' => 'icrc', 'Republic of India' => 'inda', 'Republic of Indonesia' => 'indn', 'Republic of Iraq' => 'iraq', 'Republic of Ireland' => 'irel', 'Organization of the Islamic Conference' => 'isco', 'Isle of Man' => 'isma', 'State of Israel' => 'isra', 'Italian Republic' => 'ital', 'Jamaica' => 'jama', 'Japan' => 'japa', 'The Bailiwick of Jersey' => 'jers', 'Hashemite Kingdom of Jordan' => 'jord', 'Republic of Kazakhstan' => 'kazk', 'Republic of Kenya' => 'keny', 'Republic of Kiribati' => 'kirb', 'State of Kuwait' => 'kuwa', 'Kyrgyz Republic' => 'kyrg', 'Republic of Latvia' => 'latv', 'Lebanese Republic' => 'leba', 'Kingdom of Lesotho' => 'lest', 'Republic of Liberia' => 'libe', 'Principality of Liechtenstein' => 'liec', 'Republic of Lithuania' => 'lith', 'Grand Duchy of Luxembourg' => 'luxe', 'Macao Special Administrative Region' => 'maca', 'Republic of Macedonia' => 'mace', 'Republic of Madagascar' => 'mada', 'Republic of the Marshall Islands' => 'mais', 'Republic of Mali' => 'mali', 'Federation of Malaysia' => 'mals', 'Republic of Malta' => 'malt', 'Republic of Malawi' => 'malw', 'Overseas Department of Martinique' => 'mart', 'Islamic Republic of Mauritania' => 'maur', 'Territorial Collectivity of Mayotte' => 'mayt', 'United Mexican States' => 'mexc', 'Federated States of Micronesia' => 'micr', 'Midway Islands' => 'miis', 'Republic of Moldova' => 'mold', 'Principality of Monaco' => 'mona', 'Republic of Mongolia' => 'mong', 'British Overseas Territory of Montserrat' => 'mont', 'Kingdom of Morocco' => 'morc', 'Republic of Mozambique' => 'moza', 'Republic of Mauritius' => 'mrts', 'Union of Myanmar' => 'myan', 'Republic of Namibia' => 'namb', 'North Atlantic Treaty Organization' => 'nato', 'Republic of Nauru' => 'naur', 'Turkish Republic of Northern Cyprus' => 'ncyp', 'Netherlands Antilles' => 'nean', 'Kingdom of Nepal' => 'nepa', 'Kingdom of the Netherlands' => 'neth', 'Territory of Norfolk Island' => 'nfis', 'Federal Republic of Nigeria' => 'ngra', 'Republic of Nicaragua' => 'nica', 'Republic of Niger' => 'nigr', 'Niue' => 'niue', 'Commonwealth of the Northern Mariana Islands' => 'nmar', 'Province of Northern Ireland' => 'noir', 'Nordic Council' => 'nord', 'Kingdom of Norway' => 'norw', 'Territory of New Caledonia and Dependencies' => 'nwca', 'New Zealand' => 'nwze', 'Organization of American States' => 'oast', 'Organization of African Unity' => 'oaun', 'International Olympic Committee' => 'olym', 'Sultanate of Oman' => 'oman', 'Islamic Republic of Pakistan' => 'paks', 'Republic of Palau' => 'pala', 'Independent State of Papua New Guinea' => 'pang', 'Republic of Paraguay' => 'para', 'Republic of Peru' => 'peru', 'Republic of the Philippines' => 'phil', 'British Overseas Territory of the Pitcairn Islands' => 'piis', 'Republic of Poland' => 'pola', 'Republic of Portugal' => 'port', 'Commonwealth of Puerto Rico' => 'purc', 'State of Qatar' => 'qata', 'Russian Federation' => 'russ', 'Republic of Rwanda' => 'rwan', 'Kingdom of Saudi Arabia' => 'saar', 'Republic of San Marino' => 'sama', 'Nordic Sami Conference' => 'sami', 'Sark' => 'sark', 'Scotland' => 'scot', 'Principality of Seborga' => 'sebo', 'Republic of Sierra Leone' => 'sile', 'Republic of Singapore' => 'sing', 'Republic of Korea' => 'skor', 'Republic of Slovenia' => 'slva', 'Somali Republic' => 'smla', 'Republic of Somaliland' => 'smld', 'Republic of South Africa' => 'soaf', 'Solomon Islands' => 'sois', 'Kingdom of Spain' => 'span', 'Secretariat of the Pacific Community' => 'spco', 'Democratic Socialist Republic of Sri Lanka' => 'srla', 'Saint Lucia' => 'stlu', 'Republic of the Sudan' => 'suda', 'Republic of Suriname' => 'surn', 'Slovak Republic' => 'svka', 'Kingdom of Sweden' => 'swdn', 'Swiss Confederation' => 'swit', 'Syrian Arab Republic' => 'syra', 'Kingdom of Swaziland' => 'szld', 'Republic of China' => 'taiw', 'Taiwan' => 'taiw', 'Republic of Tajikistan' => 'tajk', 'United Republic of Tanzania' => 'tanz', 'Kingdom of Thailand' => 'thal', 'Autonomous Region of Tibet' => 'tibe', 'Turkmenistan' => 'tkst', 'Togolese Republic' => 'togo', 'Tokelau' => 'toke', 'Kingdom of Tonga' => 'tong', 'Tristan da Cunha' => 'trdc', 'Tromelin' => 'tris', 'Republic of Tunisia' => 'tuns', 'Republic of Turkey' => 'turk', 'Tuvalu' => 'tuva', 'United Arab Emirates' => 'uaem', 'Republic of Uganda' => 'ugan', 'Ukraine' => 'ukrn', 'United Kingdom of Great Britain' => 'unkg', 'United Nations' => 'unna', 'United States of America' => 'unst', 'Oriental Republic of Uruguay' => 'urgy', 'Virgin Islands of the United States' => 'usvs', 'Republic of Uzbekistan' => 'uzbk', 'State of the Vatican City' => 'vacy', 'Republic of Vanuatu' => 'vant', 'Bolivarian Republic of Venezuela' => 'venz', 'Republic of Yemen' => 'yemn', 'Democratic Republic of Congo' => 'zare', 'Republic of Zimbabwe' => 'zbwe' ) ; var $iFlagCount = -1; var $iFlagSetMap = array( FLAGSIZE1 => 'flags_thumb35x35', FLAGSIZE2 => 'flags_thumb60x60', FLAGSIZE3 => 'flags_thumb100x100', FLAGSIZE4 => 'flags' ); var $iFlagData ; var $iOrdIdx=array(); function FlagImages($aSize=FLAGSIZE1) { switch($aSize) { case FLAGSIZE1 : case FLAGSIZE2 : case FLAGSIZE3 : case FLAGSIZE4 : $file = dirname(__FILE__).'/'.$this->iFlagSetMap[$aSize].'.dat'; $fp = fopen($file,'rb'); $rawdata = fread($fp,filesize($file)); $this->iFlagData = unserialize($rawdata); break; default: JpGraphError::RaiseL(5001,$aSize); //('Unknown flag size. ('.$aSize.')'); } $this->iFlagCount = count($this->iCountryNameMap); } function GetNum() { return $this->iFlagCount; } function GetImgByName($aName,&$outFullName) { $idx = $this->GetIdxByName($aName,$outFullName); return $this->GetImgByIdx($idx); } function GetImgByIdx($aIdx) { if( array_key_exists($aIdx,$this->iFlagData) ) { $d = $this->iFlagData[$aIdx][1]; return Image::CreateFromString($d); } else { JpGraphError::RaiseL(5002,$aIdx); //("Flag index \"$aIdx\" does not exist."); } } function GetIdxByOrdinal($aOrd,&$outFullName) { $aOrd--; $n = count($this->iOrdIdx); if( $n == 0 ) { reset($this->iCountryNameMap); $this->iOrdIdx=array(); $i=0; while( list($key,$val) = each($this->iCountryNameMap) ) { $this->iOrdIdx[$i++] = array($val,$key); } $tmp=$this->iOrdIdx[$aOrd]; $outFullName = $tmp[1]; return $tmp[0]; } elseif( $aOrd >= 0 && $aOrd < $n ) { $tmp=$this->iOrdIdx[$aOrd]; $outFullName = $tmp[1]; return $tmp[0]; } else { JpGraphError::RaiseL(5003,$aOrd); //('Invalid ordinal number specified for flag index.'); } } function GetIdxByName($aName,&$outFullName) { if( is_integer($aName) ) { $idx = $this->GetIdxByOrdinal($aName,$outFullName); return $idx; } $found=false; $aName = strtolower($aName); $nlen = strlen($aName); reset($this->iCountryNameMap); // Start by trying to match exact index name while( list($key,$val) = each($this->iCountryNameMap) ) { if( $nlen == strlen($val) && $val == $aName ) { $found=true; break; } } if( !$found ) { reset($this->iCountryNameMap); // If the exact index doesn't work try a (partial) full name while( list($key,$val) = each($this->iCountryNameMap) ) { if( strpos(strtolower($key), $aName) !== false ) { $found=true; break; } } } if( $found ) { $outFullName = $key; return $val; } else { JpGraphError::RaiseL(5004,$aName); //("The (partial) country name \"$aName\" does not have a cooresponding flag image. The flag may still exist but under another name, e.g. insted of \"usa\" try \"united states\"."); } } } ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_gantt.php ================================================ vgrid = new LineProperty(); } function Hide($aF=true) { $this->iShow=!$aF; } function Show($aF=true) { $this->iShow=$aF; } // Specify font function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { $this->iFFamily = $aFFamily; $this->iFStyle = $aFStyle; $this->iFSize = $aFSize; } function SetStyle($aStyle) { $this->iStyle = $aStyle; } function SetColumnMargin($aLeft,$aRight) { $this->iLeftColMargin = $aLeft; $this->iRightColMargin = $aRight; } function SetFontColor($aFontColor) { $this->iFontColor = $aFontColor; } function SetColor($aColor) { $this->iColor = $aColor; } function SetBackgroundColor($aColor) { $this->iBackgroundColor = $aColor; } function SetColTitles($aTitles,$aWidth=null) { $this->iTitles = $aTitles; $this->iWidth = $aWidth; } function SetMinColWidth($aWidths) { $n = min(count($this->iTitles),count($aWidths)); for($i=0; $i < $n; ++$i ) { if( !empty($aWidths[$i]) ) { if( empty($this->iWidth[$i]) ) { $this->iWidth[$i] = $aWidths[$i]; } else { $this->iWidth[$i] = max($this->iWidth[$i],$aWidths[$i]); } } } } function GetWidth(&$aImg) { $txt = new TextProperty(); $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); $n = count($this->iTitles) ; $rm=$this->iRightColMargin; $w = 0; for($h=0, $i=0; $i < $n; ++$i ) { $w += $this->iLeftColMargin; $txt->Set($this->iTitles[$i]); if( !empty($this->iWidth[$i]) ) { $w1 = max($txt->GetWidth($aImg)+$rm,$this->iWidth[$i]); } else { $w1 = $txt->GetWidth($aImg)+$rm; } $this->iWidth[$i] = $w1; $w += $w1; $h = max($h,$txt->GetHeight($aImg)); } $this->iHeight = $h+$this->iTopHeaderMargin; $txt=''; return $w; } function GetColStart(&$aImg,&$ioStart,$aAddLeftMargin=false) { $n = count($this->iTitles) ; $adj = $aAddLeftMargin ? $this->iLeftColMargin : 0; $ioStart=array($aImg->left_margin+$adj); for( $i=1; $i < $n; ++$i ) { $ioStart[$i] = $ioStart[$i-1]+$this->iLeftColMargin+$this->iWidth[$i-1]; } } // Adjust headers left, right or centered function SetHeaderAlign($aAlign) { $this->iHeaderAlign=$aAlign; } function Stroke(&$aImg,$aXLeft,$aYTop,$aXRight,$aYBottom,$aUseTextHeight=false) { if( !$this->iShow ) return; $txt = new TextProperty(); $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); $txt->SetColor($this->iFontColor); $txt->SetAlign($this->iHeaderAlign,'top'); $n=count($this->iTitles); if( $n == 0 ) return; $x = $aXLeft; $h = $this->iHeight; $yTop = $aUseTextHeight ? $aYBottom-$h-$this->iTopColMargin-$this->iBottomColMargin : $aYTop ; if( $h < 0 ) { JpGraphError::RaiseL(6001); //('Internal error. Height for ActivityTitles is < 0'); } $aImg->SetLineWeight(1); // Set background color $aImg->SetColor($this->iBackgroundColor); $aImg->FilledRectangle($aXLeft,$yTop,$aXRight,$aYBottom-1); if( $this->iStyle == 1 ) { // Make a 3D effect $aImg->SetColor('white'); $aImg->Line($aXLeft,$yTop+1, $aXRight,$yTop+1); } for($i=0; $i < $n; ++$i ) { if( $this->iStyle == 1 ) { // Make a 3D effect $aImg->SetColor('white'); $aImg->Line($x+1,$yTop,$x+1,$aYBottom); } $x += $this->iLeftColMargin; $txt->Set($this->iTitles[$i]); // Adjust the text anchor position according to the choosen alignment $xp = $x; if( $this->iHeaderAlign == 'center' ) { $xp = (($x-$this->iLeftColMargin)+($x+$this->iWidth[$i]))/2; } elseif( $this->iHeaderAlign == 'right' ) { $xp = $x +$this->iWidth[$i]-$this->iRightColMargin; } $txt->Stroke($aImg,$xp,$yTop+$this->iTopHeaderMargin); $x += $this->iWidth[$i]; if( $i < $n-1 ) { $aImg->SetColor($this->iColor); $aImg->Line($x,$yTop,$x,$aYBottom); } } $aImg->SetColor($this->iColor); $aImg->Line($aXLeft,$yTop, $aXRight,$yTop); // Stroke vertical column dividers $cols=array(); $this->GetColStart($aImg,$cols); $n=count($cols); for( $i=1; $i < $n; ++$i ) { $this->vgrid->Stroke($aImg,$cols[$i],$aYBottom,$cols[$i], $aImg->height - $aImg->bottom_margin); } } } //=================================================== // CLASS GanttGraph // Description: Main class to handle gantt graphs //=================================================== class GanttGraph extends Graph { var $scale; // Public accessible var $iObj=array(); // Gantt objects var $iLabelHMarginFactor=0.2; // 10% margin on each side of the labels var $iLabelVMarginFactor=0.4; // 40% margin on top and bottom of label var $iLayout=GANTT_FROMTOP; // Could also be GANTT_EVEN var $iSimpleFont = FF_FONT1,$iSimpleFontSize=11; var $iSimpleStyle=GANTT_RDIAG,$iSimpleColor='yellow',$iSimpleBkgColor='red'; var $iSimpleProgressBkgColor='gray',$iSimpleProgressColor='darkgreen'; var $iSimpleProgressStyle=GANTT_SOLID; var $hgrid=null; //--------------- // CONSTRUCTOR // Create a new gantt graph function GanttGraph($aWidth=0,$aHeight=0,$aCachedName="",$aTimeOut=0,$aInline=true) { // Backward compatibility if( $aWidth == -1 ) $aWidth=0; if( $aHeight == -1 ) $aHeight=0; if( $aWidth< 0 || $aHeight < 0 ) { JpgraphError::RaiseL(6002); //("You can't specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension."); } Graph::Graph($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline); $this->scale = new GanttScale($this->img); // Default margins $this->img->SetMargin(15,17,25,15); $this->hgrid = new HorizontalGridLine(); $this->scale->ShowHeaders(GANTT_HWEEK|GANTT_HDAY); $this->SetBox(); } //--------------- // PUBLIC METHODS // function SetSimpleFont($aFont,$aSize) { $this->iSimpleFont = $aFont; $this->iSimpleFontSize = $aSize; } function SetSimpleStyle($aBand,$aColor,$aBkgColor) { $this->iSimpleStyle = $aBand; $this->iSimpleColor = $aColor; $this->iSimpleBkgColor = $aBkgColor; } // A utility function to help create basic Gantt charts function CreateSimple($data,$constrains=array(),$progress=array()) { $num = count($data); for( $i=0; $i < $num; ++$i) { switch( $data[$i][1] ) { case ACTYPE_GROUP: // Create a slightly smaller height bar since the // "wings" at the end will make it look taller $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',8); $a->title->SetFont($this->iSimpleFont,FS_BOLD,$this->iSimpleFontSize); $a->rightMark->Show(); $a->rightMark->SetType(MARK_RIGHTTRIANGLE); $a->rightMark->SetWidth(8); $a->rightMark->SetColor('black'); $a->rightMark->SetFillColor('black'); $a->leftMark->Show(); $a->leftMark->SetType(MARK_LEFTTRIANGLE); $a->leftMark->SetWidth(8); $a->leftMark->SetColor('black'); $a->leftMark->SetFillColor('black'); $a->SetPattern(BAND_SOLID,'black'); $csimpos = 6; break; case ACTYPE_NORMAL: $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',10); $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); $a->SetPattern($this->iSimpleStyle,$this->iSimpleColor); $a->SetFillColor($this->iSimpleBkgColor); // Check if this activity should have a constrain line $n = count($constrains); for( $j=0; $j < $n; ++$j ) { if( empty($constrains[$j]) || (count($constrains[$j]) != 3) ) { JpGraphError::RaiseL(6003,$j); //("Invalid format for Constrain parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)"); } if( $constrains[$j][0]==$data[$i][0] ) { $a->SetConstrain($constrains[$j][1],$constrains[$j][2],'black',ARROW_S2,ARROWT_SOLID); } } // Check if this activity have a progress bar $n = count($progress); for( $j=0; $j < $n; ++$j ) { if( empty($progress[$j]) || (count($progress[$j]) != 2) ) { JpGraphError::RaiseL(6004,$j); //("Invalid format for Progress parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)"); } if( $progress[$j][0]==$data[$i][0] ) { $a->progress->Set($progress[$j][1]); $a->progress->SetHeight(0.5); $a->progress->SetPattern($this->iSimpleProgressStyle, $this->iSimpleProgressColor); $a->progress->SetFillColor($this->iSimpleProgressBkgColor); //$a->progress->SetPattern($progress[$j][2],$progress[$j][3]); break; } } $csimpos = 6; break; case ACTYPE_MILESTONE: $a = new MileStone($data[$i][0],$data[$i][2],$data[$i][3]); $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); $a->caption->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); $csimpos = 5; break; default: die('Unknown activity type'); break; } // Setup caption $a->caption->Set($data[$i][$csimpos-1]); // Check if this activity should have a CSIM target? if( !empty($data[$i][$csimpos]) ) { $a->SetCSIMTarget($data[$i][$csimpos]); $a->SetCSIMAlt($data[$i][$csimpos+1]); } if( !empty($data[$i][$csimpos+2]) ) { $a->title->SetCSIMTarget($data[$i][$csimpos+2]); $a->title->SetCSIMAlt($data[$i][$csimpos+3]); } $this->Add($a); } } // Set what headers should be shown function ShowHeaders($aFlg) { $this->scale->ShowHeaders($aFlg); } // Specify the fraction of the font height that should be added // as vertical margin function SetLabelVMarginFactor($aVal) { $this->iLabelVMarginFactor = $aVal; } // Synonym to the method above function SetVMarginFactor($aVal) { $this->iLabelVMarginFactor = $aVal; } // Add a new Gantt object function Add($aObject) { if( is_array($aObject) && count($aObject) > 0 ) { $cl = $aObject[0]; if( is_a($cl,'IconPlot') ) { $this->AddIcon($aObject); } else { $n = count($aObject); for($i=0; $i < $n; ++$i) $this->iObj[] = $aObject[$i]; } } else { if( is_a($aObject,'IconPlot') ) { $this->AddIcon($aObject); } else { $this->iObj[] = $aObject; } } } // Override inherit method from Graph and give a warning message function SetScale() { JpGraphError::RaiseL(6005); //("SetScale() is not meaningfull with Gantt charts."); } // Specify the date range for Gantt graphs (if this is not set it will be // automtically determined from the input data) function SetDateRange($aStart,$aEnd) { // Adjust the start and end so that the indicate the // beginning and end of respective start and end days if( strpos($aStart,':') === false ) $aStart = date('Y-m-d 00:00',strtotime($aStart)); if( strpos($aEnd,':') === false ) $aEnd = date('Y-m-d 23:59',strtotime($aEnd)); $this->scale->SetRange($aStart,$aEnd); } // Get the maximum width of the activity titles columns for the bars // The name is lightly misleading since we from now on can have // multiple columns in the label section. When this was first written // it only supported a single label, hence the name. function GetMaxLabelWidth() { $m=50; if( $this->iObj != null ) { $marg = $this->scale->actinfo->iLeftColMargin+$this->scale->actinfo->iRightColMargin; $m = $this->iObj[0]->title->GetWidth($this->img)+$marg; $n = count($this->iObj); for($i=1; $i < $n; ++$i) { if( !empty($this->iObj[$i]->title) ) { if( $this->iObj[$i]->title->HasTabs() ) { list($tot,$w) = $this->iObj[$i]->title->GetWidth($this->img,true); $m=max($m,$tot); } else $m=max($m,$this->iObj[$i]->title->GetWidth($this->img)); } } } return $m; } // Get the maximum height of the titles for the bars function GetMaxLabelHeight() { $m=0; if( $this->iObj != null ) { $m = $this->iObj[0]->title->GetHeight($this->img); $n = count($this->iObj); for($i=1; $i < $n; ++$i) { if( !empty($this->iObj[$i]->title) ) { $m=max($m,$this->iObj[$i]->title->GetHeight($this->img)); } } } return $m; } function GetMaxBarAbsHeight() { $m=0; if( $this->iObj != null ) { $m = $this->iObj[0]->GetAbsHeight($this->img); $n = count($this->iObj); for($i=1; $i < $n; ++$i) { $m=max($m,$this->iObj[$i]->GetAbsHeight($this->img)); } } return $m; } // Get the maximum used line number (vertical position) for bars function GetBarMaxLineNumber() { $m=0; if( $this->iObj != null ) { $m = $this->iObj[0]->GetLineNbr(); $n = count($this->iObj); for($i=1; $i < $n; ++$i) { $m=max($m,$this->iObj[$i]->GetLineNbr()); } } return $m; } // Get the minumum and maximum used dates for all bars function GetBarMinMax() { $start = 0 ; $n = count($this->iObj); while( $start < $n && $this->iObj[$start]->GetMaxDate() === false ) ++$start; if( $start >= $n ) { JpgraphError::RaiseL(6006); //('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]'); } $max=$this->scale->NormalizeDate($this->iObj[$start]->GetMaxDate()); $min=$this->scale->NormalizeDate($this->iObj[$start]->GetMinDate()); for($i=$start+1; $i < $n; ++$i) { $rmax = $this->scale->NormalizeDate($this->iObj[$i]->GetMaxDate()); if( $rmax != false ) $max=Max($max,$rmax); $rmin = $this->scale->NormalizeDate($this->iObj[$i]->GetMinDate()); if( $rmin != false ) $min=Min($min,$rmin); } $minDate = date("Y-m-d",$min); $min = strtotime($minDate); $maxDate = date("Y-m-d 23:59",$max); $max = strtotime($maxDate); return array($min,$max); } // Create a new auto sized canvas if the user hasn't specified a size // The size is determined by what scale the user has choosen and hence // the minimum width needed to display the headers. Some margins are // also added to make it better looking. function AutoSize() { if( $this->img->img == null ) { // The predefined left, right, top, bottom margins. // Note that the top margin might incease depending on // the title. $lm = $this->img->left_margin; $rm = $this->img->right_margin; $rm += 2 ; $tm = $this->img->top_margin; $bm = $this->img->bottom_margin; $bm += 1; if( BRAND_TIMING ) $bm += 10; // First find out the height $n=$this->GetBarMaxLineNumber()+1; $m=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); $height=$n*((1+$this->iLabelVMarginFactor)*$m); // Add the height of the scale titles $h=$this->scale->GetHeaderHeight(); $height += $h; // Calculate the top margin needed for title and subtitle if( $this->title->t != "" ) { $tm += $this->title->GetFontHeight($this->img); } if( $this->subtitle->t != "" ) { $tm += $this->subtitle->GetFontHeight($this->img); } // ...and then take the bottom and top plot margins into account $height += $tm + $bm + $this->scale->iTopPlotMargin + $this->scale->iBottomPlotMargin; // Now find the minimum width for the chart required // If day scale or smaller is shown then we use the day font width // as the base size unit. // If only weeks or above is displayed we use a modified unit to // get a smaller image. if( $this->scale->IsDisplayHour() || $this->scale->IsDisplayMinute() ) { // Add 2 pixel margin on each side $fw=$this->scale->day->GetFontWidth($this->img)+4; } elseif( $this->scale->IsDisplayWeek() ) { $fw = 8; } elseif( $this->scale->IsDisplayMonth() ) { $fw = 4; } else { $fw = 2; } $nd=$this->scale->GetNumberOfDays(); if( $this->scale->IsDisplayDay() ) { // If the days are displayed we also need to figure out // how much space each day's title will require. switch( $this->scale->day->iStyle ) { case DAYSTYLE_LONG : $txt = "Monday"; break; case DAYSTYLE_LONGDAYDATE1 : $txt = "Monday 23 Jun"; break; case DAYSTYLE_LONGDAYDATE2 : $txt = "Monday 23 Jun 2003"; break; case DAYSTYLE_SHORT : $txt = "Mon"; break; case DAYSTYLE_SHORTDAYDATE1 : $txt = "Mon 23/6"; break; case DAYSTYLE_SHORTDAYDATE2 : $txt = "Mon 23 Jun"; break; case DAYSTYLE_SHORTDAYDATE3 : $txt = "Mon 23"; break; case DAYSTYLE_SHORTDATE1 : $txt = "23/6"; break; case DAYSTYLE_SHORTDATE2 : $txt = "23 Jun"; break; case DAYSTYLE_SHORTDATE3 : $txt = "Mon 23"; break; case DAYSTYLE_SHORTDATE4 : $txt = "88"; break; case DAYSTYLE_CUSTOM : $txt = date($this->scale->day->iLabelFormStr, strtotime('2003-12-20 18:00')); break; case DAYSTYLE_ONELETTER : default: $txt = "M"; break; } $fw = $this->scale->day->GetStrWidth($this->img,$txt)+6; } // If we have hours enabled we must make sure that each day has enough // space to fit the number of hours to be displayed. if( $this->scale->IsDisplayHour() ) { // Depending on what format the user has choose we need different amount // of space. We therefore create a typical string for the choosen format // and determine the length of that string. switch( $this->scale->hour->iStyle ) { case HOURSTYLE_HMAMPM: $txt = '12:00pm'; break; case HOURSTYLE_H24: // 13 $txt = '24'; break; case HOURSTYLE_HAMPM: $txt = '12pm'; break; case HOURSTYLE_CUSTOM: $txt = date($this->scale->hour->iLabelFormStr,strtotime('2003-12-20 18:00')); break; case HOURSTYLE_HM24: default: $txt = '24:00'; break; } $hfw = $this->scale->hour->GetStrWidth($this->img,$txt)+6; $mw = $hfw; if( $this->scale->IsDisplayMinute() ) { // Depending on what format the user has choose we need different amount // of space. We therefore create a typical string for the choosen format // and determine the length of that string. switch( $this->scale->minute->iStyle ) { case HOURSTYLE_CUSTOM: $txt2 = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55')); break; case MINUTESTYLE_MM: default: $txt2 = '15'; break; } $mfw = $this->scale->minute->GetStrWidth($this->img,$txt2)+6; $n2 = ceil(60 / $this->scale->minute->GetIntervall() ); $mw = $n2 * $mfw; } $hfw = $hfw < $mw ? $mw : $hfw ; $n = ceil(24*60 / $this->scale->TimeToMinutes($this->scale->hour->GetIntervall()) ); $hw = $n * $hfw; $fw = $fw < $hw ? $hw : $fw ; } // We need to repeat this code block here as well. // THIS iS NOT A MISTAKE ! // We really need it since we need to adjust for minutes both in the case // where hour scale is shown and when it is not shown. if( $this->scale->IsDisplayMinute() ) { // Depending on what format the user has choose we need different amount // of space. We therefore create a typical string for the choosen format // and determine the length of that string. switch( $this->scale->minute->iStyle ) { case HOURSTYLE_CUSTOM: $txt = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55')); break; case MINUTESTYLE_MM: default: $txt = '15'; break; } $mfw = $this->scale->minute->GetStrWidth($this->img,$txt)+6; $n = ceil(60 / $this->scale->TimeToMinutes($this->scale->minute->GetIntervall()) ); $mw = $n * $mfw; $fw = $fw < $mw ? $mw : $fw ; } // If we display week we must make sure that 7*$fw is enough // to fit up to 10 characters of the week font (if the week is enabled) if( $this->scale->IsDisplayWeek() ) { // Depending on what format the user has choose we need different amount // of space $fsw = strlen($this->scale->week->iLabelFormStr); if( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { $fsw += 8; } elseif( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) { $fsw += 7; } else { $fsw += 4; } $ww = $fsw*$this->scale->week->GetFontWidth($this->img); if( 7*$fw < $ww ) { $fw = ceil($ww/7); } } if( !$this->scale->IsDisplayDay() && !$this->scale->IsDisplayHour() && !( ($this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR) && $this->scale->IsDisplayWeek() ) ) { // If we don't display the individual days we can shrink the // scale a little bit. This is a little bit pragmatic at the // moment and should be re-written to take into account // a) What scales exactly are shown and // b) what format do they use so we know how wide we need to // make each scale text space at minimum. $fw /= 2; if( !$this->scale->IsDisplayWeek() ) { $fw /= 1.8; } } // Has the user specified a width or do we need to // determine it? if( $this->img->width <= 0 ) { // Now determine the width for the activity titles column // Firdst find out the maximum width of each object column $cw = $this->GetMaxActInfoColWidth() ; $this->scale->actinfo->SetMinColWidth($cw); $titlewidth = max(max($this->GetMaxLabelWidth(), $this->scale->tableTitle->GetWidth($this->img)), $this->scale->actinfo->GetWidth($this->img)); // Add the width of the vertivcal divider line $titlewidth += $this->scale->divider->iWeight*2; // Now get the total width taking // titlewidth, left and rigt margin, dayfont size // into account $width = $titlewidth + $nd*$fw + $lm+$rm; } else $width = $this->img->width; $width = round($width); $height = round($height); if( $width > MAX_GANTTIMG_SIZE_W || $height > MAX_GANTTIMG_SIZE_H ) { JpgraphError::RaiseL(6007,$width,$height); //("Sanity check for automatic Gantt chart size failed. Either the width (=$width) or height (=$height) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities."); } $this->img->CreateImgCanvas($width,$height); $this->img->SetMargin($lm,$rm,$tm,$bm); } } // Return an array width the maximum width for each activity // column. This is used when we autosize the columns where we need // to find out the maximum width of each column. In order to do that we // must walk through all the objects, sigh... function GetMaxActInfoColWidth() { $n = count($this->iObj); if( $n == 0 ) return; $w = array(); $m = $this->scale->actinfo->iLeftColMargin + $this->scale->actinfo->iRightColMargin; for( $i=0; $i < $n; ++$i ) { $tmp = $this->iObj[$i]->title->GetColWidth($this->img,$m); $nn = count($tmp); for( $j=0; $j < $nn; ++$j ) { if( empty($w[$j]) ) $w[$j] = $tmp[$j]; else $w[$j] = max($w[$j],$tmp[$j]); } } return $w; } // Stroke the gantt chart function Stroke($aStrokeFileName="") { // If the filename is the predefined value = '_csim_special_' // we assume that the call to stroke only needs to do enough // to correctly generate the CSIM maps. // We use this variable to skip things we don't strictly need // to do to generate the image map to improve performance // a best we can. Therefor you will see a lot of tests !$_csim in the // code below. $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); // Should we autoscale dates? if( !$this->scale->IsRangeSet() ) { list($min,$max) = $this->GetBarMinMax(); $this->scale->SetRange($min,$max); } $this->scale->AdjustStartEndDay(); // Check if we should autoscale the image $this->AutoSize(); // Should we start from the top or just spread the bars out even over the // available height $this->scale->SetVertLayout($this->iLayout); if( $this->iLayout == GANTT_FROMTOP ) { $maxheight=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); $this->scale->SetVertSpacing($maxheight*(1+$this->iLabelVMarginFactor)); } // If it hasn't been set find out the maximum line number if( $this->scale->iVertLines == -1 ) $this->scale->iVertLines = $this->GetBarMaxLineNumber()+1; $maxwidth=max($this->scale->actinfo->GetWidth($this->img), max($this->GetMaxLabelWidth(), $this->scale->tableTitle->GetWidth($this->img))); $this->scale->SetLabelWidth($maxwidth+$this->scale->divider->iWeight);//*(1+$this->iLabelHMarginFactor)); if( !$_csim ) { $this->StrokePlotArea(); if( $this->iIconDepth == DEPTH_BACK ) { $this->StrokeIcons(); } } $this->scale->Stroke(); if( !$_csim ) { // Due to a minor off by 1 bug we need to temporarily adjust the margin $this->img->right_margin--; $this->StrokePlotBox(); $this->img->right_margin++; } // Stroke Grid line $this->hgrid->Stroke($this->img,$this->scale); $n = count($this->iObj); for($i=0; $i < $n; ++$i) { //$this->iObj[$i]->SetLabelLeftMargin(round($maxwidth*$this->iLabelHMarginFactor/2)); $this->iObj[$i]->Stroke($this->img,$this->scale); } $this->StrokeTitles(); if( !$_csim ) { $this->StrokeConstrains(); $this->footer->Stroke($this->img); if( $this->iIconDepth == DEPTH_FRONT) { $this->StrokeIcons(); } // Should we do any final image transformation if( $this->iImgTrans ) { if( !class_exists('ImgTrans') ) { require_once('jpgraph_imgtrans.php'); } $tform = new ImgTrans($this->img->img); $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, $this->iImgTransDirection,$this->iImgTransHighQ, $this->iImgTransMinSize,$this->iImgTransFillColor, $this->iImgTransBorder); } // If the filename is given as the special "__handle" // then the image handler is returned and the image is NOT // streamed back if( $aStrokeFileName == _IMG_HANDLER ) { return $this->img->img; } else { // Finally stream the generated picture $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, $aStrokeFileName); } } } function StrokeConstrains() { $n = count($this->iObj); // Stroke all constrains for($i=0; $i < $n; ++$i) { // Some gantt objects may not have constraints associated with them // for example we can add IconPlots which doesn't have this property. if( empty($this->iObj[$i]->constraints) ) continue; $numConstrains = count($this->iObj[$i]->constraints); for( $k = 0; $k < $numConstrains; $k++ ) { $vpos = $this->iObj[$i]->constraints[$k]->iConstrainRow; if( $vpos >= 0 ) { $c1 = $this->iObj[$i]->iConstrainPos; // Find out which object is on the target row $targetobj = -1; for( $j=0; $j < $n && $targetobj == -1; ++$j ) { if( $this->iObj[$j]->iVPos == $vpos ) { $targetobj = $j; } } if( $targetobj == -1 ) { JpGraphError::RaiseL(6008,$this->iObj[$i]->iVPos,$vpos); //('You have specifed a constrain from row='.$this->iObj[$i]->iVPos.' to row='.$vpos.' which does not have any activity.'); } $c2 = $this->iObj[$targetobj]->iConstrainPos; if( count($c1) == 4 && count($c2 ) == 4) { switch( $this->iObj[$i]->constraints[$k]->iConstrainType ) { case CONSTRAIN_ENDSTART: if( $c1[1] < $c2[1] ) { $link = new GanttLink($c1[2],$c1[3],$c2[0],$c2[1]); } else { $link = new GanttLink($c1[2],$c1[1],$c2[0],$c2[3]); } $link->SetPath(3); break; case CONSTRAIN_STARTEND: if( $c1[1] < $c2[1] ) { $link = new GanttLink($c1[0],$c1[3],$c2[2],$c2[1]); } else { $link = new GanttLink($c1[0],$c1[1],$c2[2],$c2[3]); } $link->SetPath(0); break; case CONSTRAIN_ENDEND: if( $c1[1] < $c2[1] ) { $link = new GanttLink($c1[2],$c1[3],$c2[2],$c2[1]); } else { $link = new GanttLink($c1[2],$c1[1],$c2[2],$c2[3]); } $link->SetPath(1); break; case CONSTRAIN_STARTSTART: if( $c1[1] < $c2[1] ) { $link = new GanttLink($c1[0],$c1[3],$c2[0],$c2[1]); } else { $link = new GanttLink($c1[0],$c1[1],$c2[0],$c2[3]); } $link->SetPath(3); break; default: JpGraphError::RaiseL(6009,$this->iObj[$i]->iVPos,$vpos); //('Unknown constrain type specified from row='.$this->iObj[$i]->iVPos.' to row='.$vpos); break; } $link->SetColor($this->iObj[$i]->constraints[$k]->iConstrainColor); $link->SetArrow($this->iObj[$i]->constraints[$k]->iConstrainArrowSize, $this->iObj[$i]->constraints[$k]->iConstrainArrowType); $link->Stroke($this->img); } } } } } function GetCSIMAreas() { if( !$this->iHasStroked ) $this->Stroke(_CSIM_SPECIALFILE); $csim = $this->title->GetCSIMAreas(); $csim .= $this->subtitle->GetCSIMAreas(); $csim .= $this->subsubtitle->GetCSIMAreas(); $n = count($this->iObj); for( $i=$n-1; $i >= 0; --$i ) $csim .= $this->iObj[$i]->GetCSIMArea(); return $csim; } } //=================================================== // CLASS PredefIcons // Description: Predefined icons for use with Gantt charts //=================================================== DEFINE('GICON_WARNINGRED',0); DEFINE('GICON_TEXT',1); DEFINE('GICON_ENDCONS',2); DEFINE('GICON_MAIL',3); DEFINE('GICON_STARTCONS',4); DEFINE('GICON_CALC',5); DEFINE('GICON_MAGNIFIER',6); DEFINE('GICON_LOCK',7); DEFINE('GICON_STOP',8); DEFINE('GICON_WARNINGYELLOW',9); DEFINE('GICON_FOLDEROPEN',10); DEFINE('GICON_FOLDER',11); DEFINE('GICON_TEXTIMPORTANT',12); class PredefIcons { var $iBuiltinIcon = null; var $iLen = -1 ; function GetLen() { return $this->iLen ; } function GetImg($aIdx) { if( $aIdx < 0 || $aIdx >= $this->iLen ) { JpGraphError::RaiseL(6010,$aIdx); //('Illegal icon index for Gantt builtin icon ['.$aIdx.']'); } return Image::CreateFromString(base64_decode($this->iBuiltinIcon[$aIdx][1])); } function PredefIcons() { //========================================================== // warning.png //========================================================== $this->iBuiltinIcon[0][0]= 1043 ; $this->iBuiltinIcon[0][1]= 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. 'B3RJTUUH0wgKFSgilWPhUQAAA6BJREFUeNrtl91rHFUYh5/3zMx+Z5JNUoOamCZNaqTZ6IWIkqRiQWmi1IDetHfeiCiltgXBP8AL'. '0SIUxf/AvfRSBS9EKILFFqyIH9CEmFZtPqrBJLs7c+b1YneT3WTTbNsUFPLCcAbmzPt73o9zzgzs2Z793231UOdv3w9k9Z2uzOdA'. '5+2+79yNeL7Hl7hw7oeixRMZ6PJM26W18DNAm/Vh7lR8fqh97NmMF11es1iFpMATqdirwMNA/J4DpIzkr5YsAF1PO6gIMYHRdPwl'. 'oO2elmB+qH3sm7XozbkgYvy8SzYnZPtcblyM6I+5z3jQ+0vJfgpEu56BfI9vUkbyi2HZd1QJoeWRiAjBd4SDCW8SSAOy6wBHMzF7'. 'YdV2A+ROuvRPLfHoiSU0EMY/cDAIhxJeGngKaN1VgHyPL7NBxI1K9P4QxBzw3K1zJ/zkG8B9uwaQ7/HNsRZv9kohBGD0o7JqMYS/'. '/ynPidQw/LrBiPBcS/yFCT95DvB2BWAy4575PaQbQKW+tPd3GCItu2odKI++YxiKu0d26oWmAD7paZU/rLz37VqIijD2YbnzNBBE'. 'IBHf8K8qjL7vYhCGErEU8CTg3xXAeMp96GrJEqkyXkm9Bhui1xfsunjdGhcYLq+IzjsGmBt5YH/cmJkFq6gIqlon3u4LxdKGuCIo'. 'Qu41g0E41po+2R33Xt5uz9kRIB2UTle7PnfKrROP1HD4sRjZlq0lzhwoZ6rDNeTi3nEg1si/7FT7kYQbXS6E5E65tA5uRF9tutq0'. 'K/VwAF+/FbIYWt6+tjQM/AqUms7A4Wy6d7YSfSNxgMmzi0ycWWworio4QJvj4LpuL5BqugTnXzzqJsJwurrlNhJXFaavW67NRw3F'. 'q+aJcCQVe9fzvJGmAY7/dPH0gi0f64OveGxa+usCuQMeZ0+kt8BVrX+qPO9Bzx0MgqBvs+a2PfDdYIf+WAjXU1ub4tqNaPPzRs8A'. 'blrli+WVn79cXn0cWKl+tGx7HLc7pu3CSmnfitL+l1UihAhwjFkPQev4K/fSABjBM8JCaFuurJU+rgW41SroA8aNMVNAFtgHJCsn'. 'XGy/58QVxAC9MccJtZ5kIzNlW440WrJ2ea4YPA9cAooA7i0A/gS+iqLoOpB1HOegqrYB3UBmJrAtQAJwpwPr1Ry92wVlgZsiYlW1'. 'uX1gU36dymgqYxJIJJNJT1W9QqHgNwFQBGYqo94OwHZQUuPD7ACglSvc+5n5T9m/wfJJX4U9qzEAAAAASUVORK5CYII=' ; //========================================================== // edit.png //========================================================== $this->iBuiltinIcon[1][0]= 959 ; $this->iBuiltinIcon[1][1]= 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAFgAWABY9j+ZuwAAAAlwSFlz'. 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDAwbIEXOA6AAAAM8SURBVHicpdRPaBxlHMbx76ZvsmOTmm1dsEqQSIIsEmGVBAQjivEQ'. 'PAUJngpWsAWlBw8egpQepKwplN4ULEG9CjkEyUFKlSJrWTG0IU51pCsdYW2ncUPjdtp9Z+f3vuNhu8nKbmhaf5cZeGc+PO8zf1Lc'. 'm0KhkACICCKCMeaBjiLC0tLSnjNvPmuOHRpH0TZTU1M8zBi9wakzn7OFTs5sw8YYACYmJrre7HkeuVyu69qPF77hlT1XmZ0eQ03O'. 'wOLJTvhBx1rLz18VmJ0eY+jVd2FxDkKXnvYLHgb97OgLzE4ON9Hzc1B1QaQzsed5O0Lta3Ec89OnR5h5McfQ+Mw2qgQUnfBOPbZ3'. 'bK3l+xOvMT0+3ERLp5FNF6UEjcL32+DdVmGt5WLhDYYPZrbRqreFumXwql0S3w9tnDvLWD5PZigPpdOwuYpSCo3C8wU3UHxQdHbf'. 'cZIkNM6dxcnlUM4k1eUFMlUPpUADbpkttFarHe6oYqeOr6yt4RzMQHYUcUsQVtGicHDwKprViuLDkkOtVnsHCHZVRVy/zcj1i5Af'. 'h8AjdIts+hUcGcYPK3iBtKM3gD/uAzf/AdY2mmmVgy6X8YNNKmGIvyloPcB8SUin07RQ4EZHFdsdG0wkJEnEaHAJxvKEpSLeaokV'. 'r4zWmhUZYLlY4b1D03y5eIEWCtS7vsciAgiIxkQRabWOrlQor66y4pUphoJb1jiO4uO5o0S3q6RSqVbiOmC7VCEgAhLSaDQ48dH7'. 'vD46REY0iysegSjKQciRt99ib7qXwX0O+pG4teM6YKHLB9JMq4mTmF9/+AKA4wvLZByH7OgYL7+UY2qvw/7Bfg5kHiXjJFyv3CGO'. 'Y1rof+BW4t/XLiPG0DCGr79d4XzRxRnIMn98huXSTYyJ6et1UNYQhRvcinpJq86H3wGPPPM0iBDd+QffD1g4eZjLvuG7S1Wef26E'. 'J7L7eSx7gAHVg7V3MSbi6m/r93baBd6qQjerAJg/9Ql/XrvG0ON1+vv7GH3qSfY5fahUnSTpwZgIEQesaVXRPbHRG/xyJSAxMYlp'. 'EOm71HUINiY7mGb95l/8jZCyQmJjMDGJjUmsdCROtZ0n/P/Z8v4Fs2MTUUf7vYoAAAAASUVORK5CYII=' ; //========================================================== // endconstrain.png //========================================================== $this->iBuiltinIcon[2][0]= 666 ; $this->iBuiltinIcon[2][1]= 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ALEREILkh0+eQAAAIXSURBVHictZU9aFNRFMd/N81HX77aptJUWmp1LHRpIcWhg5sIDlUQ'. 'LAXB4t7RRUpwEhy7iQ46CCIoSHcl0CFaoVARU2MFMYktadLXJNok7x2HtCExvuYFmnO4w/3gx+Gc/z1HKRTdMEdXqHbB/sgc/sic'. 'nDoYAI8XwDa8o1RMLT+2hAsigtTvbIGVqhX46szUifBGswUeCPgAGB7QeLk0X4Ork+HOxo1VgSqGASjMqkn8W4r4vVtEgI/RRQEL'. 'vaoGD85cl5V3nySR/S1mxWxab7f35PnntNyMJeRr9kCMqiHTy09EoeToLwggx6ymiMOD/VwcD7Oa/MHkcIiQx026WGYto5P/U+ZZ'. '7gD0QwDuT5z9N3LrVPi0Xs543eQPKkRzaS54eviJIp4tMFQFMllAWN2qcRZHBnixNM8NYD162xq8u7ePSQ+GX2Pjwxc2dB2cLtB8'. '7GgamCb0anBYBeChMtl8855CarclxU1gvViiUK4w2OMkNDnGeJ8bt9fH90yOnOkCwLFTwhzykhvtYzOWoBBbY//R3dbaNTYhf2RO'. 'QpeuUMzv188MlwuHy0H13HnE48UzMcL0WAtUHX8OxZHoG1URiFw7rnLLCswuSPD1ulze/iWjT2PSf+dBXRFtVVGIvzqph0pQL7VE'. 'avXYaXXxPwsnt0imdttCocMmZBdK7YU9D8wuNOW0nXc6QWzPsSa5naZ1beb9BbGB6dxGtMnXAAAAAElFTkSuQmCC' ; //========================================================== // mail.png //========================================================== $this->iBuiltinIcon[3][0]= 1122 ; $this->iBuiltinIcon[3][1]= 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AJHAMfFvL9OU8AAAPfSURBVHictZRdaBRXFMd/987H7tbNx8aYtGCrEexDsOBDaKHFxirb'. 'h0qhsiY0ykppKq1osI99C4H2WSiFFMHWUhXBrjRi0uCmtSEUGgP1QWqhWjGkoW7M1kTX3WRn5p4+TJJNGolQ6IXDnDtz+N0z/3PP'. 'UWBIpdpYa23b9g09PZ2kUrOrvmUyGVKp1Ao/mUyi56YnVgWfO/P1CihAd/dJMpmaNROIRq8BkM1m0bH6TasC3j6QXgFdXI+DR6PR'. 'JX/Pno8B+KLnMKqlpUU8z8MYs2RBEDzWf9J+0RcRbMdxGBsbw/fmCXwPMUEYID4iAVp8wIRmDIHMo4yHSIBSASKC+CWE0C/PF9jU'. '3B6Cp+4M07C5FUtKGNvGwQJctPgIsgD2wRhEIqAMGB+UQYkHJgYYZD7P1HwVlmWhHcfhyk83KeRGUW4t6CgoG5SNUS4KBWgQDUov'. '7AGlwYASBVqH0Bk49dXpCviVV3dw/tI1Bvr7kMIIlh0NYUpjlF0BAYvcxSXmEVLKceHSCJm+PnbueBHbtkNwTXUNBzo6aGpq4sSZ'. 'GwT5H7BsF6Wdf1GWHQAoM0upeI9PT1yioS7B7tdaSdSuw7KsUGMAy7HYsmUztTW1nMwM0txssX1rlHjjS5jy/Uq2YkK/eJuLl6/z'. 'x+1xkslW6mrixGIODx8EFSlEBC0+tmXT0NhA2763iEUjnLv4C8XpUbSbAB1mKkGJ3J83Od77HW5EszvZSqK2iljMIeJaRGNuJePF'. '6mspY7BJ1DXwQnCd2fxGRq5OUCz8xt72dyhMZcn++Cu3xu9SKhdp2b4ZHWnAtTSxmIWlhcIjlksR3lNBYzlxZsb7+f7ne+xtSzOd'. 'u83szH1OnThOPp/n+a0beeP1l4mvq+PU2Qyd+5PY1RuwlAqLYFaBfbTbyPSdfgaH77A//QF4f1O/vpr6RJyq+C5Kc/M8FbFxXItY'. 'xOHDrvfo/fxLDnbsJBp5BowBReVWYAzabeTh5ABDw7cWoNNL3YYYNtSv57lnn6Z+Qx01VeuIuBa2DV1HD3H63BAPZu4u1WGpeLHq'. 'Rh7+NcjA0O+0p4+CNwXigwnbWlQQdpuEpli+n+PIkcOc//YKuckJJFh2K2anrjFw+QZt6S6kPImIF/b+cqAJD1LihWAxC61twBTo'. 'fPcQF/oGsVW5ovHQlavs2/8+uYnRVSOUgHAmmAClBIOBwKC0gPjhIRgEIX2wg7NnwpZW3d3d4vs+vu8TBMGK51rvPM9b8hdteZxd'. 'LBbVR8feJDs0Rlv6GFKeXJ21rNRXESxMPR+CBUl0nN7PjtO+dye7Up/8v1I88bf/ixT/AO1/hZsqW+C6AAAAAElFTkSuQmCC' ; //========================================================== // startconstrain.png //========================================================== $this->iBuiltinIcon[4][0]= 725 ; $this->iBuiltinIcon[4][1]= 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. 'AAALDgAACw4BQL7hQQAAAAd0SU1FB9ALEREICJp5fBkAAAJSSURBVHic3dS9a1NRGMfx77kxtS+xqS9FG6p1ER3qVJpBQUUc3CRU'. 'BwURVLB1EAuKIP0THJQiiNRJBK3iJl18AyeltRZa0bbaJMbUNmlNSm5e7s25j0NqpSSmyag/OMM9POdzDuflwn8djz8gClVRrVEV'. 'ur4Bl1FTNSzLrSS6vbml0jUUwSXj8Qfk3PkLtLW2AeBIybmrgz3+gFzpucjlE4f4btuFTuWuCF5XDr3a3UPf6cM8GQvxzbsRAJdh'. 'ScfxSywml5j7mVypN0eGEJ0tebIre+zxB6Tv7jPReS2hREpOvpmUXU+H5eC913JnNCSRVE60pUVbWoZjprR39Yq70bdqj4pW7PEH'. '5FpvL9e79jOTTHM7ssDL6CJZ08LbvAGnrpZg2mI2Z/MlZfN8IkxuSwu4V9+WIrj7zFlOHfXzKrLIi2SGh5ECKjnNVNxkQEc55vOw'. 'rb6O8JLFdHyJ+ayFElUeHvjwkfteL/V7fKTSkFvIQE4DoLI2Mz/muTkTApcBKIwaN8pwIUrKw+ajWwDknAO0d/r4zFaMuRS63sWm'. 'RoOdm+vRIriUYjKexrQV+t1o0YEVwfZSVJmD/dIABJuO0LG3lRFx0GOfiAELE9OgCrfU0XnIp5FwGLEy5WEAOxlR5uN+ARhP7GN3'. '5w7Gv4bQI2+xpt4jjv2nWBmIlcExE2vDAHYioszBZXw6CPE4ADoWVHmd/tuwlZR9eXYyoszBfpiNQqaAOU5+TXRN+DeeenADPT9b'. 'EVgKVsutKPl0TGWGhwofoquaoKK4apsq/tH/e/kFwBMXLgAEKK4AAAAASUVORK5CYII=' ; //========================================================== // calc.png //========================================================== $this->iBuiltinIcon[5][0]= 589 ; $this->iBuiltinIcon[5][1]= 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAA4AIwBbgMF12wAAAAlwSFlz'. 'AAALEQAACxEBf2RfkQAAAAd0SU1FB9AHBxQeFsqn0wQAAAHKSURBVHicnZWff+RAGIef3U/gcOEgUAgUCgcLhYXCwsHBQeGgUDgs'. 'FgMHB4VA/4Bg4XChWFgIFIqBwkJhsRAYeOGF+TQHmWSTTbKd9pU37/x45jvfTDITXEynAbdWKVQB0NazcVm0alcL4rJaRVzm+w/e'. '3iwAkzbYRcnnYgI04GCvsxxSPabYaEdt2Ra6D0atcvvvDmyrMWBX1zPq2ircP/Tk98DiJtjV/fim6ziOCL6dDHZNhxQ3arIMsox4'. 'vejleL2Ay9+jaw6A+4OSICG2cacGKhsGxg+CxeqAQS0Y7BYJvowq7iGMOhXHEfzpvpQkA9bLKgOgWKt+4Lo1mM9hs9m17QNsJ70P'. 'Fjc/O52joogoX8MZKiBiAFxd9Z1vcj9wfSpUlDRNMcYQxzFpmnJ0FPH8nDe1MQaWSz9woQpWSZKEojDkeaWoKAyr1tlu+s48wfVx'. 'u7n5i7jthmGIiEGcT+36PP+gFeJrxWLhb0UA/lb4ggGs1T0rZs0zwM/ZjNfilcIY5tutPxgOW3F6dUX464LrKILLiw+A7WErrl+2'. 'rABG1EL/BilZP8DjU2uR4U+2E49P1Z8QJmNXUzl24A9GBT0IruCfi86d9x+D12RGzt+pNAAAAABJRU5ErkJggg==' ; //========================================================== // mag.png //========================================================== $this->iBuiltinIcon[6][0]= 1415 ; $this->iBuiltinIcon[6][1]= 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. 'AAALDAAACwwBP0AiyAAAAAd0SU1FB9ALDxEWDY6Ul+UAAAUESURBVHicdZVrbFRFGIafsyyF0nalV1R6WiggaAptlzsr1OgEogmC'. '0IgoBAsBgkIrBAPEhBj/AP6xRTCUFEwRI4jcgsitXMrFCJptJWvBNpXYbbXtbtttt6e7e86ec/yxadlCfZPJZDIz73zzzjfvR2VL'. 'F7U+hf0HD2JduIzTFy6SlJRkPtkcDgdCCE65OxFC8NPV6wghyM7OptankJ2dzbSC5QghEEIgCSHog9PpNAF27dlN6miZuPgElB4/'. 'nmY3O7ZtByA1NVUCkGWZweD1eklJScESTbqxuIjrd+/x6uIl5M19hSy7nfGOeUxf+g7VjU1sKi7C4/GYsiyz7tAJAD4/cRaA1tZW'. 'AHIPnECUVGD1+/3U19ebG4uLeHf1akamjsIwoVnVCOvQEdLoVILYYmMo3PIxSBJflpSaDX5FAmju1QAYv/8k/s8+wLVxOU0jR2LZ'. '8sMFAApWrCApbRRDrRZirBYSLBKaoRPQw3SFernf2sav7T0Ubt4KwL4FMwF4Vu8FoHBCKgCzDhwHwLIhZ7y5a89u4m2JhA0wTdDC'. 'OrphEjJMNElCHxKDEjaobmvlfo/Krj27CQQCJsCGJW8C0KXqAMxMiosQA8hZWcTFx9OsaniDKh1qmG7VoFsL0x0K06kbeAMhWpRe'. '/KpG+gwHAKUnz7Dz3BUMw6DK18nuw99wt0Nh6VdHI8RJicmETQgFg7SFwjSrGv+oKp6ghldV6dZ0ugJBlF6FmCESQ2w2AIqXLsan'. 'BrFYLJTnTCBrdBqveeopWZiPFaBHUegJhegMqGgxEkHDwB/UaQ9rdIV06v0+TD2EEQjQFtAY0dsNgNvt5sialQAIIXh7wQKuVf6J'. 'gTsSccPDWlQstClBGjr9eHpVWvUQncEwdYEedF8noQ4vmYmpZMTH0nTvDn25vLbrNmu7bvfnsYEbAMnhcPDgwQPzUo2LJusw/mhp'. 'QwlHNO0KBAnoIfxtrcQMT2De1Mm891wyUzNlUlJSpIyMDBobGzlzr5rFM/Koq6vrP8ASGxsLwPmKcvIShjPGZiPOakE3VFB8hHwd'. 'vJAxhrk5L7Ly+RQuH/sWgPdXrwFg/6HDFBUsIj09nehfbAWwPWOT9n5RYhqGwarNWxkRM5TRCfF4U1PQsDDJFk9uYhwXvzvKjm3b'. 'KSsro3DJInNW5RXp7u2bAKSlpeH1esnPz6eqqgqLpmmcr3Fht9ulfaV7mZk1Bs+lM6T1djM9fhg5egDPpTNMy5TZsW07kydPYdWM'. 'aXx96ixOp9O8cfUa80srmDpjOgAulytiQqZpMnvObLbt/JTtHxXj9/tRVdU0DGOAufRpevPDTeac0hJyc3NxOOawfv161lVWS6eX'. 'z+9/UOCxu1VWVvaTRGv16NFfjB2bNeAQp9NpTpmSM4DcbrdL0WsGDKLRR+52uwe1yP8jb2lpYfikyY9t80n03UCWZeaXVjw1f+zs'. 'Oen+/d+pqanhzp2fKSsrw+l0mi6XiyPl5ZGITdN8fAVJwjRNJEmi1qfw1kw7siyTnJxMe3s71dXV3GpoZO64DG41NPJylvxU5D/e'. 'qJKsfWQD9IkaZ2RmUvr9aV4aGYcQgjfO3aWoYBF5eXm4ewIsu/CbdPz1aWb0/p1bNoOrQxlUiuiaFo3c3FyEEOx9+C9CCD6paaTW'. 'p/TXyYkTJ0Xe59jf7QOyAKDWp/QXxcFQ61P4pT3ShBBcvnUHIQTjxmX19/8BCeVg+/GPpskAAAAASUVORK5CYII=' ; //========================================================== // lock.png //========================================================== $this->iBuiltinIcon[7][0]= 963 ; $this->iBuiltinIcon[7][1]= 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. 'AAALCwAACwsBbQSEtwAAAAd0SU1FB9AKAw0XDmwMOwIAAANASURBVHic7ZXfS1t3GMY/3+PprI7aisvo2YU6h6ATA8JW4rrlsF4U'. 'qiAsF9mhl0N2cYTRy9G/wptAYWPD9iJtRy5asDe7cYFmyjaXOLaMImOrmkRrjL9yTmIS3120JybWQgfb3R74wuc8Lzw858vLOUpE'. 'OK6pqSm2trbY39+nu7tbPHYch7m5OcLhMIA67kWj0aMQEWk6tm17rNm2LSIie3t7ksvlJJ1OSyqVkls3Z8SyLMnlcqTTaVKpFLdu'. 'zmBZVj1HeY2VUti2TSQSQSml2bZdi0QirK2tMT09zerqKtlslqGhISYnJ4nHv2N+foFsNquOe9FotLlxOBwmk8lgWRbhcFgymYxY'. 'liUi0mqaJoAuIi2macrdO7fFsizx3to0Te7euV1vrXtXEgqFmJmZYWVlhXK5LB4/U9kwDL784kYV0A3DYHd3m4sXRymXywKoRi8U'. 'Ch01DgQCJBIJLMsiEAhIIpHw2uLz+eqtYrEYIqKZpimxWEyCwaCMjY01zYPBIJpXqVQqsby8TLVabWKA/v5+RkZGMAyDrq4ulFKH'. 'HsfjcWZnZ+ns7KTRqwcnk0mKxSKFQqGJlVKtruuSTCYB6O3trW9UI/v9/iZPB/j8s2HOnX0FgHfeXpeffnzK+fWf+fijvhLs0PtG'. 'D/n1OJ9+MsrlSwb3733DwMCAt1EyPj6uACYmJp56168NU6nUqFSE9nZdPE7+WqC/r4NKTagcCJVqDaUUB5VDAA4Pa9x7sMLlSwan'. 'WjRmv13D7/erpaWlo604qOp88OF7LC48rPNosMq5Th+Dgxd4/XyA1rbzADi7j8jnf2P++wdcvSr8MJ/i8eomAKlUqn41OsDAQDeD'. 'g++yuPCwzm/2vU8+n2a7sMFfj79mp7BBuVzioFSiXHJx3SKuW2Rzy0Up9dxnQVvODALQerqNRn4ZKe0Mvtc6TpzpmqbxalcY9Ato'. '2v06t515C73YQftZB9GLnDrt4LoujuPgOA4Ui+C6yOpXJwZrJ7r/gv4P/u+D9W7fLxTz+1ScQxrZ3atRLaVxdjbY2d184R6/sLHe'. 'opHP7/Do90Ua+WWUyezzZHObP/7cfX54/dowE1d66s8TV3oE+Mfn+L/zb4XmHPjRG9YjAAAAAElFTkSuQmCC' ; //========================================================== // stop.png //========================================================== $this->iBuiltinIcon[8][0]= 889 ; $this->iBuiltinIcon[8][1]= 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9AJDwEvNyD6M/0AAAL2SURBVHic1ZTLaxVnGIefb2bO5OScHJN4oWrFNqcUJYoUEgU3/Qf6'. 'F7gwCkIrvdBLUtqqiLhSg9bgBduFSHZdiG5ctkJ3xRDbUFwUmghNzBDanPGMkzOX79LFJGPMOSd204U/+Bbzvd/78F4H/ieJdoad'. 'pZKxRFszAI/DcP0HazXY22v+HB01kee1PA/v3zfnjx4xgGnHcNZe7OvuNj+cOEF1ZATv5nUA4jhBSgmADCVWo8Ge2Of9wb18P/G7'. 'oUXmYi30zqlTVEdGWLh1g2D6MYlKkXGE0Vl8aa2GEB149+4xXSzyoOIw/mimiZV/DPb25pFOj13A9gOMEChhUEqhVYqWKUk9QAUp'. 'sT/P4s8PmKlUmNhQaIJbkDVqBbpw6wZ2zUc4Nm+ePku5p4eOrgpueQOFUoVCVxcD4+N07dpF9+5tVJeWGPBjhvr7WF1zC8ASgtcP'. 'H8a7eZ1odh4sh50nzwCw9ZNh3M4Stutiu0X2nB/LyjZ6lcIbVTpdQU/jWVPzLADM8+ZGBRdtC7wrF/O7bR99iu26VL86iU4SAH4b'. 'Po5d6AQhstMSvGyI4wS5FJBKSRwnzF8byx/u+PjzzMF1mfryQ1K/jnCahqp1xEopjFLoNEFJSRJHzF799gWHqa+/QKcSUXBI609f'. 'Al5W4teQSiHDOipNUKnMI13RvnOXAIEKQixvGWya98SC560MFwPiqEG86JM8q79Q06lvhnOndy5/B6GPCUOMUu3BQgg8z0M3GmBZ'. 'iGJn3v2VmsqnfzNx7FDueODuj8ROCFpjtG5TCmOYv32bJ09msP0ISydMfnAUgF8/O45RAA6WTPjlvXcB+Gn7FuRf/zAnNX6x3ARe'. 'PSdmqL+P/YHkwMGDOGWDZTlQcNBRhPEComgB/YeHfq2InF1kLlXUOkpMbio1bd7aATRD/X0M1lPeSlM2vt2X1XBZjZnpLG2tmZO6'. 'LbQVOIcP+HG2UauH3xgwBqOz9Cc3l1tC24Fz+MvUDroeGNb5if9H/1dM/wLPCYMw9fryKgAAAABJRU5ErkJggg==' ; //========================================================== // error.png //========================================================== $this->iBuiltinIcon[9][0]= 541 ; $this->iBuiltinIcon[9][1]= 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaVBMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'. 'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpYiYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'. 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTCAkUMSj9wWSOAAABLUlEQVR4'. '2s2U3ZKCMAxGjfzJanFAXFkUle/9H9JUKA1gKTN7Yy6YMjl+kNPK5rlZVSuxf1ZRnlZxFYAm93NnIKvR+MEHUgqBXx93wZGIUrSe'. 'h+ctEgbpiMo3iQ4kioHCGxir/ZYUbr7AgPXs9bX0BCYM8vN/cPe8oQYzom3tVsSBMVHEoOJ5dm5F1RsIe9CtqGgRacCAkUvRtevT'. 'e2pd6vOWF+gCuc/brcuhyARakBU9FgK5bUBWdHEH8tHpDsZnRTZQGzdLVvQ3CzyYZiTAmSIODEwzFCAdJopuvbpeZDisJ4pKEcjD'. 'ijWPJhU1MjCo9dkYfiUVjQNTDKY6CVbR6A0niUSZjRwFanR0l9i/TyvGnFdqwStq5axMfDbyBksld/FUumvxS/Bd9VyJvQDWiiMx'. 'iOsCHgAAAABJRU5ErkJggg==' ; //========================================================== // openfolder.png //========================================================== $this->iBuiltinIcon[10][0]= 2040 ; $this->iBuiltinIcon[10][1]= 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEANAAtwClFht71AAAAAlwSFlz'. 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDQ4RIXMeaLcAAAd1SURBVHicxZd7jBXVHcc/58zcvTNzH8vusqw8FsTsKiCUUh5WBZXG'. 'GkOptmqwNWsWLKXFGlEpzZI0AWNKSy0WhDS22gJKtWlTsSRqzYIuLGB2WVvDIwQMZQMsy2OFfdzde+/OnHP6x907vJaFpjb9JZM5'. 'c85Mfp/f9/s7Jxn4P4e41gtSyp78WGvtfdEAcqDFYUOH9HS0NhGk9tPb/ilSyp789UUB2AMuqhQy3Uzm7HGkE6W3dTNZMRI3EcWO'. 'jf9ClLmWBT3dzW8jUsevWHCG3UpWl+IkHSxnbDh/Mcz12NevBcuWXTmf6TjnXvJ88gDmVB3pw3+nt3UzHa1NqMzBS2zqPLGFjtMN'. 'ZNr3XdW+qyqwZcFk76HX/tHWfuQvyO4W7qhaHwL8efkMRlRUpPv7rqD0RrJ+FgAjLy1a20OIxZJEEuNCRfIApj+om4bGM3u2/sYU'. '9J41d8973f3Dhg1pISTV1dXXBRNJxPGFCzhou+DCQrScZOkktNaeDZjamgeZ9MgiYmVDccvHhjAzJw0NTh8/alyZMaVJicp0iTHj'. 'JpgNv38tjWUhhGROdbUL9W5/MH5XCkjlcibi+KIop5LVHLKEu8A/f4r286doa9pGrGwYAAsfqbbH3b8MgO/Nqgy6WvdbbXHMkEFJ'. '4xUOMVEvaTZu3BgmvF4Yk4hz9rO/Ulr5cE9owae/rcGxohSOuiWkC2IjcIqKyPZm+OmCH7GhoZEF077EEzVVweAbJ+riEeO0Ey8y'. 'UubqOHn0AOgMwvf59txnBrSp9dgxKmf/+kIP1NY8SFk0jh5ajmNHAWg5b2E5EexojGHjbiVRMoRMNs0LC+Yz46vTuH3enN7BI8fr'. 'qFdo0BoVZNC9aVSQ4fNjBzEmQJiARxb+/AqYPMAVB5FsPU5v37g9OxgLhe14ZM5/ju052E6MNZvf5pmHHuLmmWOkEysxUtpGAtme'. 'dtHTflJkezqQto3jFRnLssyf1jydxiiM7zNnye/c3ZsqLu2BN5fcMfzrv/hby1tPzmRUoihcTJ87CwQI2yLtDcIqsIjYUf51qBlf'. 'OnScOSrdQUOMURkiXsLUzJnvbGhoBGDHH5cGyZLhOpYoNl5hqYnYEXOu5fDl9eYAHntx98n8hFHZcPHUuTSxSASAeK/CGIOxJJ0f'. 'bOGNPU280dgkq6Y2yu8vfjCIlwwzr+/ZQ/PHO0gOLuO5qsftDQ2NbN+4OCgqG6WTxWVaq6zpF+DiSHWnicdylp3r6aZTWthIOrNp'. 'ktHcvBu0sHX1Sm6ozB3B42d90zZA9bQp7PvgPSzXZfnqX/HS4DKKK2+x69Y/HURs26iBAN5ccsfw7774UcumF37C6f07KSt2OHji'. 'DEUJD0tISjyPrrSPlAKvN0JP/U4O1NfjuhG2rvklN1SOpfXwftpbTqAyKRrff5fb7rs9V1R7m4wlz2ihA3HpmXflUWyOH2umpLiY'. 'ui3v8M+6bWzfsRNbSgqkxaCkiy0simMuEWEhpcRzIhQWOIAh6tiAwS4owInFiTou5dOnMnl2NR++ujBwXEc9terD6M43nrj6LgAB'. 'QnDPA9/irtkP8JRS7Hr/3T6YekDQ1pEiEXOwpUVJzCVlZZFS4mZtkpEo9ChAkDp/jtLMBACy6S4RiQghLyv5cgBRPnKUOX6smUGF'. 'hSil0MYw9d77mPy1e5mnFE3batm3czvb6nYgEJztSFGU9LCRlMRdUjIH0+lnEMIwPNXD3NumoVJnrMCJaiciMUZfvQnz4QcBSvV1'. 'vjE5GK358t0zmXDnDB79saLpo20c+aSRD+t25JTp7GZQwsEWFiVxl6hlUf/WO9z32CxmL1rOe6u/I2KuwGhzLQCB7/sYY9Bah3el'. 'FKbvrrVm4vS7GH/7ncx+chEHGz7myCeNbPtoO0JI2jq78WIRLGkzsqs7V5SfFV5EovXACoiqqsfNpk2vo5VCWtYFBfoU0VoTBAFa'. 'a7TRaK2p+MoURk+cxMzq+Rzbv49DDbuo27UTW9h0dedssPxuK+kIfN8XxhgDYPVXf2Fh4XKtFIl4AiklAlBKAYRKKK36wHIweTCt'. 'NfHiEkaOn8j0+7/BmDFjaT30GbHywSxcuZkpFfFg+m1jjZ/NmnVvNfRvwd69e8WBA/uNFAIh4JVXXmHsmDHE4vEQQgjQ2lxQIm9N'. 'nz35q3BEOZOHzaG2thaA4mRU+L29It+IV21CpbRQfeMFC35gRB/M2rVrubnyZmLxWJhECBEmz/eHyo/7lMlH3LFFujsthNFCCGOu'. '+WNyeUgpjSVzMKtWraKyshLPdcPEeYWCIEBdpIxSivr6eta8vI7d6+cGnhdV06pe1QP+F/QXWmuRL+jZZ58LlVmxYgUVFRV4rhtu'. '4TzMxXAA6XRaRAtsYUkx8I/JtSJQOlSwpmZpCLN8+fPcdNNoHMfB9/0QJgRoP295TlR7UVv8xxZcHMuWIZ9/Hn35vG3JEGZpzVJG'. 'jx5N1IlitKahsZE1L69j69qHgx+urFX/lQL9JYdLlfnZihUhzOLFi8N3Ml1dthOxVH/f/8/CtqSJ2JaJ2JZ59J7RPsC/AViJsQS/'. 'dBntAAAAAElFTkSuQmCC' ; //========================================================== // folder.png //========================================================== $this->iBuiltinIcon[11][0]= 1824 ; $this->iBuiltinIcon[11][1]= 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. 'AAALEAAACxABrSO9dQAAAAd0SU1FB9ECAQgFFyd9cRUAAAadSURBVHiczdhvbBP3Hcfx9/2xfefEOA5JoCNNnIT8AdtZmYBETJsI'. '6+jQOlQihT1AYgytqzZpD1atfyYqlT1h0lRpT7aRJ4NQpRvZGELVuo5Ua9jEJDIETQsNQyPBsUJMWGPnj//e+e72wNg4xElMR6ed'. 'ZNln3933dZ/f93f6yfB/sgmrHdDV1WXlPg8NDZUDScD8LFFFEZZlWYZhWMFg0Orq6sq/gDJAfFy1iiZy9OjrVnj4JzQ1rMWqfxm/'. '309jYyNtbW0kEgnu3bvH4cOH88c/jqSKQl4/XGkd+eVtAN46up1LH92ktqYS++ZX8Pv9NDQ0sGnTJlKpFOFwmO7u7vy5IyMjeVRd'. 'XV1+WEOh0IrY4pDnq6wXX/sTiCJaMkFZdRNqxefoe7VtCSqXVDqdZnZ2ltraWkzTpKqqijt3JpFlG7dvj7NzZ1f++qFQyA3EClHL'. 'Ql743nFkhxPDtJAd5eTaYSVUfX09lZWVlJWVIUnSg7sVQMBCUcu4ceMGe/bsIRQK1QAzOcyykIM9P0KyudAyCWyqG8nhwqa4SkLt'. '3r0bVVVxu924XC40TUOWZUQxe97CwgIdHR2LMHIxSCaVInVvFElxE0vMY1Pd2NUKJMWNTXHlUfF//4vETJCelwbpFm3MjP2dt37x'. 'AlN+PzU1NViWRSwW4+7du3g8HjweD4qi5EFAJzAExIpCANbooxhplfB0FJvTg6xWIqsVRVF6MopkU3FXPcnkJxGU0VEAdF2noqKC'. 'W3/8DpnqLjzep2lubsblcjE8PExHR8fboVDID9xYFpLBDpJF0jDQIncQpWlkm31FlFLtp9PfyuW/vYQj1kPSuRW/38+lj27S2Q7v'. '/aWXUBVUffVNtm3blivVCEwsC5Eyc5iiApEpDEAXMqQdldhSiWVQHjJagud+8Fuexck/zv+K82dfoSbSCsDe75/km+4GVPd6+l5t'. '4zJHcqVUYN2yEEtZQDCSJCueRAYsPY49HsFIZVG6p25JUumFafT4DKJN4amtT7Nz38sk5+5A70HMtEYyMkFiZhxzjQ/poXrLQrRU'. 'DFGEeFpAlkQkm4pRiCpIKodKzk0T/2QMh+piPjxKZPwiSkUtu/b9mNnJEWS7E8nhAmvpM60oJDkXJxqNozxRRUxPIesispBBlsXV'. 'UaKEFo8gzoaJhz8s2lOmrpUG+WBhJ9/60g+Z+fDXTAXfxllRjl1VkO0OFATsYhYliiK21ZKKhhHnFveUqSdKgwAEOp7F2v51vvw8'. 'XH7/N1wd/BlTweuUV65BdtgfoLTSkipsdD3tRi0VYpommUwGwzDwdT5HYEc3giAwcvH3jLz3BlPB67jWeZBEKYsSBWwpHZtNKo4q'. 'aHTDsJeeiGEYWJaFZVmYpommaRiGQdPnv0bb1m8gSRL/vPIOV979aR4lmAJ2p4qCgCxksNuKJ6VNpx4NYhgGpmkuQhmGQTqdxjAM'. 'qr2d7HtxEEEQuH1tkKvvvkF44tqDnrIcKJKAPf1g+LAUElq8dIiu60sApmnm93Pfzc7OYhgGrie+wFe++ztcLhcT1wf54PzPCU9c'. 'w7XWjWS3IdsdOAUBWZAxrRJnTQ6SG5bce2FCpmkughmGQSqVYm5uDtnj44sH38TtdhP6+Dwf//V4ttHXrkGURZJaic8RgHQ6jWma'. 'SJKUL5RLKNfIOczDKF3XSSaTRCIRhLJWntp3nGfWrSMxc5OLf3iNP4+68T9Ub9nF76lTpxgfHycajZJKpdA0LZ9GbjYV7hcDWZaF'. 'pmnMz88Ti8UYunSLmu1HFi2aVkxkaGjINTY2ttDb24vX6+XQoUNs3ryZ8vJyIDu1BUFYkkxhgxeiWlpaOHPmDE1NTdTX1xe98eWG'. 'JnF/9dQZCoXUYDA4AOD1ejlw4ACtra2Ul5fniwmCkEcUJiUIAoFAgL6+Pnw+H21tbfT39z8SxCS7hHsfWH9/8dL4MKqnp4eWlhac'. 'TmcekEvMNE2am5s5ceIEgUCA9vZ2Tp48ic/nY3j4UsmQHCYOjJHtpeBKqL1799Lc3IzT6UTXdRobGxkYGKC9vZ3W1tZ8Ko86NJ8a'. 'tXHjRo4dO8bp06fZsmULGzZsoL+/n0AggNfr5ezZs/8VpGTU5OSkc//+/acBfD4f1dXV7Nq1i4aGBs6dO4fP5+Pq1SuPBbIiyjTN'. 'RUnV1dUNXLhwAa/Xy44dO4jFYgBEo9FFF1r134BPuYlk16LrAYXsAlmtq6sbKDwoFAp9m+ykuP5ZQVZF3f8tCdwCov8LyHIoAANI'. 'AXf/A1TI0XCDh7OWAAAAAElFTkSuQmCC' ; //========================================================== // file_important.png //========================================================== $this->iBuiltinIcon[12][0]= 1785 ; $this->iBuiltinIcon[12][1]= 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ECDAcjDeD3lKsAAAZ2SURBVHicrZhPaFzHHcc/897s7lutJCsr2VHsOHWMk0MPbsBUrcnF'. 'OFRdSo6FNhdB6SGHlpDmYtJCDyoxyKe6EBxKQkt7KKL0T6ABo0NbciqigtC6PhWKI2NFqqxdSd7V2/dmftPDvPd212t55dCBYfbN'. 'zpvfZ77z+/1mdhUjytWrV93Hf/24eD5z9gwiMlDjOKbb7dLtdhER2u02u7u73Lp1CxEZBw4AeZwdNQqkMd9wbziFGINJUt6rRbz5'. '1ptUq1XK5TJBEAAUMHt7e+zu7gKwvLzMysoKwAng/uNg9CgQgFKlgg1DUJ67Vqtx6tQpZmdniaIIpRTOOZRSdDoddnZ2aLfbLC8v'. 's7S0xJUrV7ZGwQSj1PhhfRodVdDlMrpc5vup5Z2fvMPdu3fZ29vDWjvwztjYGPV6nVqtRqVS4dKlSywtLQFsAdOH2XwsCEApg3jl'. 'w98Rak2gvYjNZpNms0mSJDjnHgkDMDc3dySYQ0Ea8w139YUX0OUKulzyg7UmCEO+l1huvHuDra0t9vf3h1TJYSqVypFhHquIrlQI'. 'S5qv/uIDAC7/4bcEQYAKvK+0Wq1DVQGIoog7d+4cCeaRII35hrt+8SsEOkRlUaEyR0UpFIrXHxyMVKVUKnHv3r0jwRwaNelBjBjL'. 'Sz/7KYuLiwAsLi7y4z/9kY9e+TpkCuSqjI+Po7XuAWeKXLt2DWNMUZMkwRjDhQsXWFtbK6JpCCT3jfQgxomPtPX19YHWicM5x3c2'. '73Pj3Ru8/aO3mZqaolKpoHVvyuvXr/Ppnf/Q7uzz380NPtu4y/qnG+ztd1hfX2dtbQ3gIvDnRyqSxl1UoPjyz98D4PTp0wPtq39Z'. '4fdzLxegrVaLVqvF5OQkYRgWqpRKJZ77wvNsbW1RG5tgfKLOTH2G7Z1twqBQrgrMDvhInjfSOCY5iIv+hYWFgRZArEWsZWF941Bf'. 'SdMUgMnJCWpjVU4cn+HUyePM1Gc4+fRUPkzBI5w1jbukcczLv/5l0XfmzJmBFuCba38r/CRXpT+CrDUoZ0jjB4RYonJAOYRobJKT'. 'z5zgqfqxAbsFSH6mpHFM2qdGXh4VnoViD6mSJF2cTQeqDqBaKVHWmonJCWpZjhkC6anR5WsffTgwaHV1FaUUq6urA/2v3f5k4LnV'. 'arG9tUn3oI2YBCcWHYAxMVYs1qZEZY2SFB2aYZDGfMN9d7uJiWPSeFiNo5Rclc3NTXZbO6RpF7EJVixYA9agwwDnUiqlEPdQ3imi'. 'Jo27BGHIt/7x9yEjc3Nzh27Na7c/4TdffKl4bja3ae5MUIu0T/HOEIaOpJt4gwoSsVTK4SBIY77hFtY3ABBjBiZ90rKwvsH77/+K'. 't37wOhO1iPpTk4SBw1mLsz6CnKQ4l3qV+kE+t9XHlNZOk+bUJLVIE1VCcIJWQmJ6qjj30NbcXLkZMt8YPig+Z3n1G5fZ39/j/vY2'. '9ckqZT2Ochbn0p4qNkU/dDfUADdXbh4HXgRO4zNdEU0XL1784PLly5w9e7Z4SazFOfGrEotDcOKrcoJPmrYIXf/Zop3QNd1skuGt'. 'cUAb2MgAxvHZTgFUq1Wmp6eZnZ0F8JlTjDduDThBnDeECEoJtbGIp6enqEblzCcEZ1PECU4yVRiOGgd0gc+AB0CZvkv1sWPHOHfu'. 'HOfPn8da41cpkkltEBEPJhYnBkTQJcdYVKGkgRxCfBsq5xXNgAa2Bn+hjTOgHEKBP8pzRUxykIH4ifLJRTJAl+UMBJzPHQ6bfe/f'. 'cWIzPxlUpD+zugzIZtVk1d8znBAqRxgoQuVQgSJQ3h9C5QhDRYgjUILCAzlnEdsHYTKfMTEBcP7F54YUGVmc2GLlIn6ve6v0ahSt'. '8X25TzjJ+rIx1grKpQPWR4LkGVVsMgghvS0qjPdvm5OeceOTWA5Evo2mFzkjQfL7hZPUy5yvvF/uPFQL3+nbDmsLCEmT3sTmCTNr'. 'rogT6yFsOix3ftw7OwQhkvSU6CuinhCk0+kAkFoBazEEICHaHHiPVmU0gnUp4EAc1mYrF0EBVpwPi34VrBkwPxKk3W5ju/e5/c+d'. 'bGUHIAIuydTIE5zfc5Wr4lJcahHnHTP3CVGm78DrgY38N+DEibp7dmYKdAQmBh1hjEFjis+9CTWYGK21H6PxPyOI0DobYwzZF/z7'. '7jadTvJtYG0kCD7lfwl49ijgT1gc0AH+dZSJA/xB+Mz/GSIvFoj/B7H1mAd8CO/zAAAAAElFTkSuQmCC' ; $this->iLen = count($this->iBuiltinIcon); } } //=================================================== // Global cache for builtin images //=================================================== $_gPredefIcons = new PredefIcons(); //=================================================== // CLASS IconImage // Description: Holds properties for an icon image //=================================================== class IconImage { var $iGDImage=null; var $iWidth,$iHeight; var $ixalign='left',$iyalign='center'; var $iScale=1.0; function IconImage($aIcon,$aScale=1) { GLOBAL $_gPredefIcons ; if( is_string($aIcon) ) { $this->iGDImage = Graph::LoadBkgImage('',$aIcon); } elseif( is_integer($aIcon) ) { // Builtin image $this->iGDImage = $_gPredefIcons->GetImg($aIcon); } else { JpGraphError::RaiseL(6011); //('Argument to IconImage must be string or integer'); } $this->iScale = $aScale; $this->iWidth = Image::GetWidth($this->iGDImage); $this->iHeight = Image::GetHeight($this->iGDImage); } function GetWidth() { return round($this->iScale*$this->iWidth); } function GetHeight() { return round($this->iScale*$this->iHeight); } function SetAlign($aX='left',$aY='center') { $this->ixalign = $aX; $this->iyalign = $aY; } function Stroke(&$aImg,$x,$y) { if( $this->ixalign == 'right' ) { $x -= $this->iWidth; } elseif( $this->ixalign == 'center' ) { $x -= round($this->iWidth/2*$this->iScale); } if( $this->iyalign == 'bottom' ) { $y -= $this->iHeight; } elseif( $this->iyalign == 'center' ) { $y -= round($this->iHeight/2*$this->iScale); } $aImg->Copy($this->iGDImage, $x,$y,0,0, round($this->iWidth*$this->iScale),round($this->iHeight*$this->iScale), $this->iWidth,$this->iHeight); } } //=================================================== // CLASS TextProperty // Description: Holds properties for a text //=================================================== class TextProperty { var $iFFamily=FF_FONT1,$iFStyle=FS_NORMAL,$iFSize=10; var $iColor="black"; var $iShow=true; var $iText=""; var $iHAlign="left",$iVAlign="bottom"; var $csimtarget='',$csimalt=''; //--------------- // CONSTRUCTOR function TextProperty($aTxt='') { $this->iText = $aTxt; } //--------------- // PUBLIC METHODS function Set($aTxt) { $this->iText = $aTxt; } function SetCSIMTarget($aTarget,$aAltText='') { if( is_string($aTarget) ) $aTarget = array($aTarget); $this->csimtarget=$aTarget; if( is_string($aAltText) ) $aAltText = array($aAltText); $this->csimalt=$aAltText; } function SetCSIMAlt($aAltText) { if( is_string($aAltText) ) $aAltText = array($aAltText); $this->csimalt=$aAltText; } // Set text color function SetColor($aColor) { $this->iColor = $aColor; } function HasTabs() { if( is_string($this->iText) ) { return substr_count($this->iText,"\t") > 0; } elseif( is_array($this->iText) ) { return false; } } // Get number of tabs in string function GetNbrTabs() { if( is_string($this->iText) ) { return substr_count($this->iText,"\t") ; } else{ return 0; } } // Set alignment function Align($aHAlign,$aVAlign="bottom") { $this->iHAlign=$aHAlign; $this->iVAlign=$aVAlign; } // Synonym function SetAlign($aHAlign,$aVAlign="bottom") { $this->iHAlign=$aHAlign; $this->iVAlign=$aVAlign; } // Specify font function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { $this->iFFamily = $aFFamily; $this->iFStyle = $aFStyle; $this->iFSize = $aFSize; } function IsColumns() { return is_array($this->iText) ; } // Get width of text. If text contains several columns separated by // tabs then return both the total width as well as an array with a // width for each column. function GetWidth(&$aImg,$aUseTabs=false,$aTabExtraMargin=1.1) { $extra_margin=4; $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); if( is_string($this->iText) ) { if( strlen($this->iText) == 0 ) return 0; $tmp = split("\t",$this->iText); if( count($tmp) <= 1 || !$aUseTabs ) { return $aImg->GetTextWidth($this->iText)+2*$extra_margin; } else { $tot=0; $n = count($tmp); for($i=0; $i < $n; ++$i) { $res[$i] = $aImg->GetTextWidth($tmp[$i]); $tot += $res[$i]*$aTabExtraMargin; } return array(round($tot),$res); } } elseif( is_object($this->iText) ) { // A single icon return $this->iText->GetWidth()+2*$extra_margin; } elseif( is_array($this->iText) ) { // Must be an array of texts. In this case we return the sum of the // length + a fixed margin of 4 pixels on each text string $n = count($this->iText); for( $i=0, $w=0; $i < $n; ++$i ) { $tmp = $this->iText[$i]; if( is_string($tmp) ) { $w += $aImg->GetTextWidth($tmp)+$extra_margin; } else { if( is_object($tmp) === false ) { JpGraphError::RaiseL(6012); } $w += $tmp->GetWidth()+$extra_margin; } } return $w; } else { JpGraphError::RaiseL(6012); } } // for the case where we have multiple columns this function returns the width of each // column individually. If there is no columns just return the width of the single // column as an array of one function GetColWidth(&$aImg,$aMargin=0) { $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); if( is_array($this->iText) ) { $n = count($this->iText); for( $i=0, $w=array(); $i < $n; ++$i ) { $tmp = $this->iText[$i]; if( is_string($tmp) ) { $w[$i] = $aImg->GetTextWidth($this->iText[$i])+$aMargin; } else { if( is_object($tmp) === false ) { JpGraphError::RaiseL(6012); } $w[$i] = $tmp->GetWidth()+$aMargin; } } return $w; } else { return array($this->GetWidth($aImg)); } } // Get total height of text function GetHeight(&$aImg) { $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); return $aImg->GetFontHeight(); } // Unhide/hide the text function Show($aShow=true) { $this->iShow=$aShow; } // Stroke text at (x,y) coordinates. If the text contains tabs then the // x parameter should be an array of positions to be used for each successive // tab mark. If no array is supplied then the tabs will be ignored. function Stroke(&$aImg,$aX,$aY) { if( $this->iShow ) { $aImg->SetColor($this->iColor); $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); $aImg->SetTextAlign($this->iHAlign,$this->iVAlign); if( $this->GetNbrTabs() <= 1 ) { if( is_string($this->iText) ) { // Get rid of any "\t" characters and stroke string if( is_array($aX) ) $aX=$aX[0]; if( is_array($aY) ) $aY=$aY[0]; $aImg->StrokeText($aX,$aY,str_replace("\t"," ",$this->iText)); } else { $n = count($this->iText); $ax = is_array($aX) ; $ay = is_array($aY) ; if( $ax && $ay ) { // Nothing; both are already arrays } elseif( $ax ) { $aY = array_fill(0,$n,$aY); } elseif( $ay ) { $aX = array_fill(0,$n,$aX); } else { $aX = array_fill(0,$n,$aX); $aY = array_fill(0,$n,$aY); } $n = min($n, count($aX) ) ; $n = min($n, count($aY) ) ; for($i=0; $i < $n; ++$i ) { $tmp = $this->iText[$i]; if( is_object($tmp) ) { $tmp->Stroke($aImg,$aX[$i],$aY[$i]); } else $aImg->StrokeText($aX[$i],$aY[$i],str_replace("\t"," ",$tmp)); } } } else { $tmp = split("\t",$this->iText); $n = min(count($tmp),count($aX)); for($i=0; $i < $n; ++$i) { $aImg->StrokeText($aX[$i],$aY,$tmp[$i]); } } } } } //=================================================== // CLASS HeaderProperty // Description: Data encapsulating class to hold property // for each type of the scale headers //=================================================== class HeaderProperty { var $iTitleVertMargin=3,$iFFamily=FF_FONT0,$iFStyle=FS_NORMAL,$iFSize=8; var $iFrameColor="black",$iFrameWeight=1; var $iShowLabels=true,$iShowGrid=true; var $iBackgroundColor="white"; var $iWeekendBackgroundColor="lightgray",$iSundayTextColor="red"; // these are only used with day scale var $iTextColor="black"; var $iLabelFormStr="%d"; var $grid,$iStyle=0; var $iIntervall = 1; //--------------- // CONSTRUCTOR function HeaderProperty() { $this->grid = new LineProperty(); } //--------------- // PUBLIC METHODS function Show($aShow=true) { $this->iShowLabels = $aShow; } function SetIntervall($aInt) { $this->iIntervall = $aInt; } function GetIntervall() { return $this->iIntervall ; } function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { $this->iFFamily = $aFFamily; $this->iFStyle = $aFStyle; $this->iFSize = $aFSize; } function SetFontColor($aColor) { $this->iTextColor = $aColor; } function GetFontHeight(&$aImg) { $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); return $aImg->GetFontHeight(); } function GetFontWidth(&$aImg) { $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); return $aImg->GetFontWidth(); } function GetStrWidth(&$aImg,$aStr) { $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); return $aImg->GetTextWidth($aStr); } function SetStyle($aStyle) { $this->iStyle = $aStyle; } function SetBackgroundColor($aColor) { $this->iBackgroundColor=$aColor; } function SetFrameWeight($aWeight) { $this->iFrameWeight=$aWeight; } function SetFrameColor($aColor) { $this->iFrameColor=$aColor; } // Only used by day scale function SetWeekendColor($aColor) { $this->iWeekendBackgroundColor=$aColor; } // Only used by day scale function SetSundayFontColor($aColor) { $this->iSundayTextColor=$aColor; } function SetTitleVertMargin($aMargin) { $this->iTitleVertMargin=$aMargin; } function SetLabelFormatString($aStr) { $this->iLabelFormStr=$aStr; } function SetFormatString($aStr) { $this->SetLabelFormatString($aStr); } } //=================================================== // CLASS GanttScale // Description: Responsible for calculating and showing // the scale in a gantt chart. This includes providing methods for // converting dates to position in the chart as well as stroking the // date headers (days, week, etc). //=================================================== class GanttScale { var $minute,$hour,$day,$week,$month,$year; var $divider,$dividerh,$tableTitle; var $iStartDate=-1,$iEndDate=-1; // Number of gantt bar position (n.b not necessariliy the same as the number of bars) // we could have on bar in position 1, and one bar in position 5 then there are two // bars but the number of bar positions is 5 var $iVertLines=-1; // The width of the labels (defaults to the widest of all labels) var $iLabelWidth; // Out image to stroke the scale to var $iImg; var $iTableHeaderBackgroundColor="white",$iTableHeaderFrameColor="black"; var $iTableHeaderFrameWeight=1; var $iAvailableHeight=-1,$iVertSpacing=-1,$iVertHeaderSize=-1; var $iDateLocale; var $iVertLayout=GANTT_EVEN; var $iTopPlotMargin=10,$iBottomPlotMargin=15; var $iUsePlotWeekendBackground=true; var $iWeekStart = 1; // Default to have weekends start on Monday var $actinfo; //--------------- // CONSTRUCTOR function GanttScale(&$aImg) { $this->iImg = &$aImg; $this->iDateLocale = new DateLocale(); $this->minute = new HeaderProperty(); $this->minute->SetIntervall(15); $this->minute->SetLabelFormatString('i'); $this->minute->SetFont(FF_FONT0); $this->minute->grid->SetColor("gray"); $this->hour = new HeaderProperty(); $this->hour->SetFont(FF_FONT0); $this->hour->SetIntervall(6); $this->hour->SetStyle(HOURSTYLE_HM24); $this->hour->SetLabelFormatString('H:i'); $this->hour->grid->SetColor("gray"); $this->day = new HeaderProperty(); $this->day->grid->SetColor("gray"); $this->day->SetLabelFormatString('l'); $this->week = new HeaderProperty(); $this->week->SetLabelFormatString("w%d"); $this->week->SetFont(FF_FONT1); $this->month = new HeaderProperty(); $this->month->SetFont(FF_FONT1,FS_BOLD); $this->year = new HeaderProperty(); $this->year->SetFont(FF_FONT1,FS_BOLD); $this->divider=new LineProperty(); $this->dividerh=new LineProperty(); $this->dividerh->SetWeight(2); $this->divider->SetWeight(6); $this->divider->SetColor('gray'); $this->divider->SetStyle('fancy'); $this->tableTitle=new TextProperty(); $this->tableTitle->Show(false); $this->actinfo = new GanttActivityInfo(); } //--------------- // PUBLIC METHODS // Specify what headers should be visible function ShowHeaders($aFlg) { $this->day->Show($aFlg & GANTT_HDAY); $this->week->Show($aFlg & GANTT_HWEEK); $this->month->Show($aFlg & GANTT_HMONTH); $this->year->Show($aFlg & GANTT_HYEAR); $this->hour->Show($aFlg & GANTT_HHOUR); $this->minute->Show($aFlg & GANTT_HMIN); // Make some default settings of gridlines whihc makes sense if( $aFlg & GANTT_HWEEK ) { $this->month->grid->Show(false); $this->year->grid->Show(false); } if( $aFlg & GANTT_HHOUR ) { $this->day->grid->SetColor("black"); } } // Should the weekend background stretch all the way down in the plotarea function UseWeekendBackground($aShow) { $this->iUsePlotWeekendBackground = $aShow; } // Have a range been specified? function IsRangeSet() { return $this->iStartDate!=-1 && $this->iEndDate!=-1; } // Should the layout be from top or even? function SetVertLayout($aLayout) { $this->iVertLayout = $aLayout; } // Which locale should be used? function SetDateLocale($aLocale) { $this->iDateLocale->Set($aLocale); } // Number of days we are showing function GetNumberOfDays() { return round(($this->iEndDate-$this->iStartDate)/SECPERDAY); } // The width of the actual plot area function GetPlotWidth() { $img=$this->iImg; return $img->width - $img->left_margin - $img->right_margin; } // Specify the width of the titles(labels) for the activities // (This is by default set to the minimum width enought for the // widest title) function SetLabelWidth($aLabelWidth) { $this->iLabelWidth=$aLabelWidth; } // Which day should the week start? // 0==Sun, 1==Monday, 2==Tuesday etc function SetWeekStart($aStartDay) { $this->iWeekStart = $aStartDay % 7; //Recalculate the startday since this will change the week start $this->SetRange($this->iStartDate,$this->iEndDate); } // Do we show min scale? function IsDisplayMinute() { return $this->minute->iShowLabels; } // Do we show day scale? function IsDisplayHour() { return $this->hour->iShowLabels; } // Do we show day scale? function IsDisplayDay() { return $this->day->iShowLabels; } // Do we show week scale? function IsDisplayWeek() { return $this->week->iShowLabels; } // Do we show month scale? function IsDisplayMonth() { return $this->month->iShowLabels; } // Do we show year scale? function IsDisplayYear() { return $this->year->iShowLabels; } // Specify spacing (in percent of bar height) between activity bars function SetVertSpacing($aSpacing) { $this->iVertSpacing = $aSpacing; } // Specify scale min and max date either as timestamp or as date strings // Always round to the nearest week boundary function SetRange($aMin,$aMax) { $this->iStartDate = $this->NormalizeDate($aMin); $this->iEndDate = $this->NormalizeDate($aMax); } // Adjust the start and end date so they fit to beginning/ending // of the week taking the specified week start day into account. function AdjustStartEndDay() { if( !($this->IsDisplayYear() ||$this->IsDisplayMonth() || $this->IsDisplayWeek()) ) { // Don't adjust return; } // Get day in week for start and ending date (Sun==0) $ds=strftime("%w",$this->iStartDate); $de=strftime("%w",$this->iEndDate); // We want to start on iWeekStart day. But first we subtract a week // if the startdate is "behind" the day the week start at. // This way we ensure that the given start date is always included // in the range. If we don't do this the nearest correct weekday in the week // to start at might be later than the start date. if( $ds < $this->iWeekStart ) $d = strtotime('-7 day',$this->iStartDate); else $d = $this->iStartDate; $adjdate = strtotime(($this->iWeekStart-$ds).' day',$d /*$this->iStartDate*/ ); $this->iStartDate = $adjdate; // We want to end on the last day of the week $preferredEndDay = ($this->iWeekStart+6)%7; if( $preferredEndDay != $de ) { // Solve equivalence eq: $de + x ~ $preferredDay (mod 7) $adj = (7+($preferredEndDay - $de)) % 7; $adjdate = strtotime("+$adj day",$this->iEndDate); $this->iEndDate = $adjdate; } } // Specify background for the table title area (upper left corner of the table) function SetTableTitleBackground($aColor) { $this->iTableHeaderBackgroundColor = $aColor; } /////////////////////////////////////// // PRIVATE Methods // Determine the height of all the scale headers combined function GetHeaderHeight() { $img=$this->iImg; $height=1; if( $this->minute->iShowLabels ) { $height += $this->minute->GetFontHeight($img); $height += $this->minute->iTitleVertMargin; } if( $this->hour->iShowLabels ) { $height += $this->hour->GetFontHeight($img); $height += $this->hour->iTitleVertMargin; } if( $this->day->iShowLabels ) { $height += $this->day->GetFontHeight($img); $height += $this->day->iTitleVertMargin; } if( $this->week->iShowLabels ) { $height += $this->week->GetFontHeight($img); $height += $this->week->iTitleVertMargin; } if( $this->month->iShowLabels ) { $height += $this->month->GetFontHeight($img); $height += $this->month->iTitleVertMargin; } if( $this->year->iShowLabels ) { $height += $this->year->GetFontHeight($img); $height += $this->year->iTitleVertMargin; } return $height; } // Get width (in pixels) for a single day function GetDayWidth() { return ($this->GetPlotWidth()-$this->iLabelWidth+1)/$this->GetNumberOfDays(); } // Get width (in pixels) for a single hour function GetHourWidth() { return $this->GetDayWidth() / 24 ; } function GetMinuteWidth() { return $this->GetHourWidth() / 60 ; } // Nuber of days in a year function GetNumDaysInYear($aYear) { if( $this->IsLeap($aYear) ) return 366; else return 365; } // Get week number function GetWeekNbr($aDate,$aSunStart=true) { // We can't use the internal strftime() since it gets the weeknumber // wrong since it doesn't follow ISO on all systems since this is // system linrary dependent. // Even worse is that this works differently if we are on a Windows // or UNIX box (it even differs between UNIX boxes how strftime() // is natively implemented) // // Credit to Nicolas Hoizey for this elegant // version of Week Nbr calculation. $day = $this->NormalizeDate($aDate) ; if( $aSunStart ) $day += 60*60*24; /*------------------------------------------------------------------------- According to ISO-8601 : "Week 01 of a year is per definition the first week that has the Thursday in this year, which is equivalent to the week that contains the fourth day of January. In other words, the first week of a new year is the week that has the majority of its days in the new year." Be carefull, with PHP, -3 % 7 = -3, instead of 4 !!! day of year = date("z", $day) + 1 offset to thursday = 3 - (date("w", $day) + 6) % 7 first thursday of year = 1 + (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $day)))) % 7 week number = (thursday's day of year - first thursday's day of year) / 7 + 1 ---------------------------------------------------------------------------*/ $thursday = $day + 60 * 60 * 24 * (3 - (date("w", $day) + 6) % 7); // take week's thursday $week = 1 + (date("z", $thursday) - (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $thursday)))) % 7) / 7; return $week; } // Is year a leap year? function IsLeap($aYear) { // Is the year a leap year? //$year = 0+date("Y",$aDate); if( $aYear % 4 == 0) if( !($aYear % 100 == 0) || ($aYear % 400 == 0) ) return true; return false; } // Get current year function GetYear($aDate) { return 0+Date("Y",$aDate); } // Return number of days in a year function GetNumDaysInMonth($aMonth,$aYear) { $days=array(31,28,31,30,31,30,31,31,30,31,30,31); $daysl=array(31,29,31,30,31,30,31,31,30,31,30,31); if( $this->IsLeap($aYear)) return $daysl[$aMonth]; else return $days[$aMonth]; } // Get day in month function GetMonthDayNbr($aDate) { return 0+strftime("%d",$aDate); } // Get day in year function GetYearDayNbr($aDate) { return 0+strftime("%j",$aDate); } // Get month number function GetMonthNbr($aDate) { return 0+strftime("%m",$aDate); } // Translate a date to screen coordinates (horizontal scale) function TranslateDate($aDate) { // // In order to handle the problem with Daylight savings time // the scale written with equal number of seconds per day beginning // with the start date. This means that we "cement" the state of // DST as it is in the start date. If later the scale includes the // switchover date (depends on the locale) we need to adjust back // if the date we try to translate has a different DST status since // we would otherwise be off by one hour. $aDate = $this->NormalizeDate($aDate); $tmp = localtime($aDate); $cloc = $tmp[8]; $tmp = localtime($this->iStartDate); $sloc = $tmp[8]; $offset = 0; if( $sloc != $cloc) { if( $sloc ) $offset = 3600; else $offset = -3600; } $img=$this->iImg; return ($aDate-$this->iStartDate-$offset)/SECPERDAY*$this->GetDayWidth()+$img->left_margin+$this->iLabelWidth;; } // Get screen coordinatesz for the vertical position for a bar function TranslateVertPos($aPos) { $img=$this->iImg; $ph=$this->iAvailableHeight; if( $aPos > $this->iVertLines ) JpGraphError::RaiseL(6015,$aPos); // 'Illegal vertical position %d' if( $this->iVertLayout == GANTT_EVEN ) { // Position the top bar at 1 vert spacing from the scale return round($img->top_margin + $this->iVertHeaderSize + ($aPos+1)*$this->iVertSpacing); } else { // position the top bar at 1/2 a vert spacing from the scale return round($img->top_margin + $this->iVertHeaderSize + $this->iTopPlotMargin + ($aPos+1)*$this->iVertSpacing); } } // What is the vertical spacing? function GetVertSpacing() { return $this->iVertSpacing; } // Convert a date to timestamp function NormalizeDate($aDate) { if( $aDate === false ) return false; if( is_string($aDate) ) { $t = strtotime($aDate); if( $t === FALSE || $t === -1 ) { JpGraphError::RaiseL(6016,$aDate); //("Date string ($aDate) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30"); } return $t; } elseif( is_int($aDate) || is_float($aDate) ) return $aDate; else JpGraphError::RaiseL(6017,$aDate); //Unknown date format in GanttScale ($aDate)."); } // Convert a time string to minutes function TimeToMinutes($aTimeString) { // Split in hours and minutes $pos=strpos($aTimeString,':'); $minint=60; if( $pos === false ) { $hourint = $aTimeString; $minint = 0; } else { $hourint = floor(substr($aTimeString,0,$pos)); $minint = floor(substr($aTimeString,$pos+1)); } $minint += 60 * $hourint; return $minint; } // Stroke the day scale (including gridlines) function StrokeMinutes($aYCoord,$getHeight=false) { $img=$this->iImg; $xt=$img->left_margin+$this->iLabelWidth; $yt=$aYCoord+$img->top_margin; if( $this->minute->iShowLabels ) { $img->SetFont($this->minute->iFFamily,$this->minute->iFStyle,$this->minute->iFSize); $yb = $yt + $img->GetFontHeight() + $this->minute->iTitleVertMargin + $this->minute->iFrameWeight; if( $getHeight ) { return $yb - $img->top_margin; } $xb = $img->width-$img->right_margin+1; $img->SetColor($this->minute->iBackgroundColor); $img->FilledRectangle($xt,$yt,$xb,$yb); $x = $xt; $img->SetTextAlign("center"); $day = date('w',$this->iStartDate); $minint = $this->minute->GetIntervall() ; if( 60 % $minint !== 0 ) { JpGraphError::RaiseL(6018,$minint); //'Intervall for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an intervall of '.$minint.' minutes.'); } $n = 60 / $minint; $datestamp = $this->iStartDate; $width = $this->GetHourWidth() / $n ; if( $width < 8 ) { // TO small width to draw minute scale JpGraphError::RaiseL(6019,$width); //('The available width ('.$width.') for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.'); } $nh = ceil(24*60 / $this->TimeToMinutes($this->hour->GetIntervall()) ); $nd = $this->GetNumberOfDays(); // Convert to intervall to seconds $minint *= 60; for($j=0; $j < $nd; ++$j, $day += 1, $day %= 7) { for( $k=0; $k < $nh; ++$k ) { for($i=0; $i < $n ;++$i, $x+=$width, $datestamp += $minint ) { if( $day==6 || $day==0 ) { $img->PushColor($this->day->iWeekendBackgroundColor); if( $this->iUsePlotWeekendBackground ) $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin); else $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight); $img->PopColor(); } if( $day==0 ) $img->SetColor($this->day->iSundayTextColor); else $img->SetColor($this->day->iTextColor); switch( $this->minute->iStyle ) { case MINUTESTYLE_CUSTOM: $txt = date($this->minute->iLabelFormStr,$datestamp); break; case MINUTESTYLE_MM: default: // 15 $txt = date('i',$datestamp); break; } $img->StrokeText(round($x+$width/2),round($yb-$this->minute->iTitleVertMargin),$txt); // FIXME: The rounding problem needs to be solved properly ... // // Fix a rounding problem the wrong way .. // If we also have hour scale then don't draw the firsta or last // gridline since that will be overwritten by the hour scale gridline if such exists. // However, due to the propagation of rounding of the 'x+=width' term in the loop // this might sometimes be one pixel of so we fix this by not drawing it. // The proper way to fix it would be to re-calculate the scale for each step and // not using the additive term. if( !(($i == $n || $i==0) && $this->hour->iShowLabels && $this->hour->grid->iShow) ) { $img->SetColor($this->minute->grid->iColor); $img->SetLineWeight($this->minute->grid->iWeight); $img->Line($x,$yt,$x,$yb); $this->minute->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); } } } } $img->SetColor($this->minute->iFrameColor); $img->SetLineWeight($this->minute->iFrameWeight); $img->Rectangle($xt,$yt,$xb,$yb); return $yb - $img->top_margin; } return $aYCoord; } // Stroke the day scale (including gridlines) function StrokeHours($aYCoord,$getHeight=false) { $img=$this->iImg; $xt=$img->left_margin+$this->iLabelWidth; $yt=$aYCoord+$img->top_margin; if( $this->hour->iShowLabels ) { $img->SetFont($this->hour->iFFamily,$this->hour->iFStyle,$this->hour->iFSize); $yb = $yt + $img->GetFontHeight() + $this->hour->iTitleVertMargin + $this->hour->iFrameWeight; if( $getHeight ) { return $yb - $img->top_margin; } $xb = $img->width-$img->right_margin+1; $img->SetColor($this->hour->iBackgroundColor); $img->FilledRectangle($xt,$yt,$xb,$yb); $x = $xt; $img->SetTextAlign("center"); $tmp = $this->hour->GetIntervall() ; $minint = $this->TimeToMinutes($tmp); if( 1440 % $minint !== 0 ) { JpGraphError::RaiseL(6020,$tmp); //('Intervall for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an intervall of '.$tmp); } $n = ceil(24*60 / $minint ); $datestamp = $this->iStartDate; $day = date('w',$this->iStartDate); $doback = !$this->minute->iShowLabels; $width = $this->GetDayWidth() / $n ; for($j=0; $j < $this->GetNumberOfDays(); ++$j, $day += 1,$day %= 7) { for($i=0; $i < $n ;++$i, $x+=$width) { if( $day==6 || $day==0 ) { $img->PushColor($this->day->iWeekendBackgroundColor); if( $this->iUsePlotWeekendBackground && $doback ) $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin); else $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight); $img->PopColor(); } if( $day==0 ) $img->SetColor($this->day->iSundayTextColor); else $img->SetColor($this->day->iTextColor); switch( $this->hour->iStyle ) { case HOURSTYLE_HMAMPM: // 1:35pm $txt = date('g:ia',$datestamp); break; case HOURSTYLE_H24: // 13 $txt = date('H',$datestamp); break; case HOURSTYLE_HAMPM: $txt = date('ga',$datestamp); break; case HOURSTYLE_CUSTOM: $txt = date($this->hour->iLabelFormStr,$datestamp); break; case HOURSTYLE_HM24: default: $txt = date('H:i',$datestamp); break; } $img->StrokeText(round($x+$width/2),round($yb-$this->hour->iTitleVertMargin),$txt); $img->SetColor($this->hour->grid->iColor); $img->SetLineWeight($this->hour->grid->iWeight); $img->Line($x,$yt,$x,$yb); $this->hour->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); //$datestamp += $minint*60 $datestamp = mktime(date('H',$datestamp),date('i',$datestamp)+$minint,0, date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp)); } } $img->SetColor($this->hour->iFrameColor); $img->SetLineWeight($this->hour->iFrameWeight); $img->Rectangle($xt,$yt,$xb,$yb); return $yb - $img->top_margin; } return $aYCoord; } // Stroke the day scale (including gridlines) function StrokeDays($aYCoord,$getHeight=false) { $img=$this->iImg; $daywidth=$this->GetDayWidth(); $xt=$img->left_margin+$this->iLabelWidth; $yt=$aYCoord+$img->top_margin; if( $this->day->iShowLabels ) { $img->SetFont($this->day->iFFamily,$this->day->iFStyle,$this->day->iFSize); $yb=$yt + $img->GetFontHeight() + $this->day->iTitleVertMargin + $this->day->iFrameWeight; if( $getHeight ) { return $yb - $img->top_margin; } $xb=$img->width-$img->right_margin+1; $img->SetColor($this->day->iBackgroundColor); $img->FilledRectangle($xt,$yt,$xb,$yb); $x = $xt; $img->SetTextAlign("center"); $day = date('w',$this->iStartDate); $datestamp = $this->iStartDate; $doback = !($this->hour->iShowLabels || $this->minute->iShowLabels); setlocale(LC_TIME,$this->iDateLocale->iLocale); for($i=0; $i < $this->GetNumberOfDays(); ++$i, $x+=$daywidth, $day += 1,$day %= 7) { if( $day==6 || $day==0 ) { $img->SetColor($this->day->iWeekendBackgroundColor); if( $this->iUsePlotWeekendBackground && $doback) $img->FilledRectangle($x,$yt+$this->day->iFrameWeight, $x+$daywidth,$img->height-$img->bottom_margin); else $img->FilledRectangle($x,$yt+$this->day->iFrameWeight, $x+$daywidth,$yb-$this->day->iFrameWeight); } $mn = strftime('%m',$datestamp); if( $mn[0]=='0' ) $mn = $mn[1]; switch( $this->day->iStyle ) { case DAYSTYLE_LONG: // "Monday" $txt = strftime('%A',$datestamp); break; case DAYSTYLE_SHORT: // "Mon" $txt = strftime('%a',$datestamp); break; case DAYSTYLE_SHORTDAYDATE1: // "Mon 23/6" $txt = strftime('%a %d/'.$mn,$datestamp); break; case DAYSTYLE_SHORTDAYDATE2: // "Mon 23 Jun" $txt = strftime('%a %d %b',$datestamp); break; case DAYSTYLE_SHORTDAYDATE3: // "Mon 23 Jun 2003" $txt = strftime('%a %d %b %Y',$datestamp); break; case DAYSTYLE_LONGDAYDATE1: // "Monday 23 Jun" $txt = strftime('%A %d %b',$datestamp); break; case DAYSTYLE_LONGDAYDATE2: // "Monday 23 Jun 2003" $txt = strftime('%A %d %b %Y',$datestamp); break; case DAYSTYLE_SHORTDATE1: // "23/6" $txt = strftime('%d/'.$mn,$datestamp); break; case DAYSTYLE_SHORTDATE2: // "23 Jun" $txt = strftime('%d %b',$datestamp); break; case DAYSTYLE_SHORTDATE3: // "Mon 23" $txt = strftime('%a %d',$datestamp); break; case DAYSTYLE_SHORTDATE4: // "23" $txt = strftime('%d',$datestamp); break; case DAYSTYLE_CUSTOM: // Custom format $txt = strftime($this->day->iLabelFormStr,$datestamp); break; case DAYSTYLE_ONELETTER: default: // "M" $txt = strftime('%A',$datestamp); $txt = strtoupper($txt[0]); break; } if( $day==0 ) $img->SetColor($this->day->iSundayTextColor); else $img->SetColor($this->day->iTextColor); $img->StrokeText(round($x+$daywidth/2+1), round($yb-$this->day->iTitleVertMargin),$txt); $img->SetColor($this->day->grid->iColor); $img->SetLineWeight($this->day->grid->iWeight); $img->Line($x,$yt,$x,$yb); $this->day->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); $datestamp = mktime(0,0,0,date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp)); //$datestamp += SECPERDAY; } $img->SetColor($this->day->iFrameColor); $img->SetLineWeight($this->day->iFrameWeight); $img->Rectangle($xt,$yt,$xb,$yb); return $yb - $img->top_margin; } return $aYCoord; } // Stroke week header and grid function StrokeWeeks($aYCoord,$getHeight=false) { if( $this->week->iShowLabels ) { $img=$this->iImg; $yt=$aYCoord+$img->top_margin; $img->SetFont($this->week->iFFamily,$this->week->iFStyle,$this->week->iFSize); $yb=$yt + $img->GetFontHeight() + $this->week->iTitleVertMargin + $this->week->iFrameWeight; if( $getHeight ) { return $yb - $img->top_margin; } $xt=$img->left_margin+$this->iLabelWidth; $weekwidth=$this->GetDayWidth()*7; $wdays=$this->iDateLocale->GetDayAbb(); $xb=$img->width-$img->right_margin+1; $week = $this->iStartDate; $weeknbr=$this->GetWeekNbr($week); $img->SetColor($this->week->iBackgroundColor); $img->FilledRectangle($xt,$yt,$xb,$yb); $img->SetColor($this->week->grid->iColor); $x = $xt; if( $this->week->iStyle==WEEKSTYLE_WNBR ) { $img->SetTextAlign("center"); $txtOffset = $weekwidth/2+1; } elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 || $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { $img->SetTextAlign("left"); $txtOffset = 3; } else JpGraphError::RaiseL(6021); //("Unknown formatting style for week."); for($i=0; $i<$this->GetNumberOfDays()/7; ++$i, $x+=$weekwidth) { $img->PushColor($this->week->iTextColor); if( $this->week->iStyle==WEEKSTYLE_WNBR ) $txt = sprintf($this->week->iLabelFormStr,$weeknbr); elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) $txt = date("j/n",$week); elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 || $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { $monthnbr = date("n",$week)-1; $shortmonth = $this->iDateLocale->GetShortMonthName($monthnbr); $txt = Date("j",$week)." ".$shortmonth; } if( $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { $w = sprintf($this->week->iLabelFormStr,$weeknbr); $txt .= ' '.$w; } $img->StrokeText(round($x+$txtOffset), round($yb-$this->week->iTitleVertMargin),$txt); $week = strtotime('+7 day',$week); $weeknbr = $this->GetWeekNbr($week); $img->PopColor(); $img->SetLineWeight($this->week->grid->iWeight); $img->Line($x,$yt,$x,$yb); $this->week->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); } $img->SetColor($this->week->iFrameColor); $img->SetLineWeight($this->week->iFrameWeight); $img->Rectangle($xt,$yt,$xb,$yb); return $yb-$img->top_margin; } return $aYCoord; } // Format the mont scale header string function GetMonthLabel($aMonthNbr,$year) { $sn = $this->iDateLocale->GetShortMonthName($aMonthNbr); $ln = $this->iDateLocale->GetLongMonthName($aMonthNbr); switch($this->month->iStyle) { case MONTHSTYLE_SHORTNAME: $m=$sn; break; case MONTHSTYLE_LONGNAME: $m=$ln; break; case MONTHSTYLE_SHORTNAMEYEAR2: $m=$sn." '".substr("".$year,2); break; case MONTHSTYLE_SHORTNAMEYEAR4: $m=$sn." ".$year; break; case MONTHSTYLE_LONGNAMEYEAR2: $m=$ln." '".substr("".$year,2); break; case MONTHSTYLE_LONGNAMEYEAR4: $m=$ln." ".$year; break; case MONTHSTYLE_FIRSTLETTER: $m=$sn[0]; break; } return $m; } // Stroke month scale and gridlines function StrokeMonths($aYCoord,$getHeight=false) { if( $this->month->iShowLabels ) { $img=$this->iImg; $img->SetFont($this->month->iFFamily,$this->month->iFStyle,$this->month->iFSize); $yt=$aYCoord+$img->top_margin; $yb=$yt + $img->GetFontHeight() + $this->month->iTitleVertMargin + $this->month->iFrameWeight; if( $getHeight ) { return $yb - $img->top_margin; } $monthnbr = $this->GetMonthNbr($this->iStartDate)-1; $xt=$img->left_margin+$this->iLabelWidth; $xb=$img->width-$img->right_margin+1; $img->SetColor($this->month->iBackgroundColor); $img->FilledRectangle($xt,$yt,$xb,$yb); $img->SetLineWeight($this->month->grid->iWeight); $img->SetColor($this->month->iTextColor); $year = 0+strftime("%Y",$this->iStartDate); $img->SetTextAlign("center"); if( $this->GetMonthNbr($this->iStartDate) == $this->GetMonthNbr($this->iEndDate) && $this->GetYear($this->iStartDate)==$this->GetYear($this->iEndDate) ) { $monthwidth=$this->GetDayWidth()*($this->GetMonthDayNbr($this->iEndDate) - $this->GetMonthDayNbr($this->iStartDate) + 1); } else { $monthwidth=$this->GetDayWidth()*($this->GetNumDaysInMonth($monthnbr,$year)-$this->GetMonthDayNbr($this->iStartDate)+1); } // Is it enough space to stroke the first month? $monthName = $this->GetMonthLabel($monthnbr,$year); if( $monthwidth >= 1.2*$img->GetTextWidth($monthName) ) { $img->SetColor($this->month->iTextColor); $img->StrokeText(round($xt+$monthwidth/2+1), round($yb-$this->month->iTitleVertMargin), $monthName); } $x = $xt + $monthwidth; while( $x < $xb ) { $img->SetColor($this->month->grid->iColor); $img->Line($x,$yt,$x,$yb); $this->month->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); $monthnbr++; if( $monthnbr==12 ) { $monthnbr=0; $year++; } $monthName = $this->GetMonthLabel($monthnbr,$year); $monthwidth=$this->GetDayWidth()*$this->GetNumDaysInMonth($monthnbr,$year); if( $x + $monthwidth < $xb ) $w = $monthwidth; else $w = $xb-$x; if( $w >= 1.2*$img->GetTextWidth($monthName) ) { $img->SetColor($this->month->iTextColor); $img->StrokeText(round($x+$w/2+1), round($yb-$this->month->iTitleVertMargin),$monthName); } $x += $monthwidth; } $img->SetColor($this->month->iFrameColor); $img->SetLineWeight($this->month->iFrameWeight); $img->Rectangle($xt,$yt,$xb,$yb); return $yb-$img->top_margin; } return $aYCoord; } // Stroke year scale and gridlines function StrokeYears($aYCoord,$getHeight=false) { if( $this->year->iShowLabels ) { $img=$this->iImg; $yt=$aYCoord+$img->top_margin; $img->SetFont($this->year->iFFamily,$this->year->iFStyle,$this->year->iFSize); $yb=$yt + $img->GetFontHeight() + $this->year->iTitleVertMargin + $this->year->iFrameWeight; if( $getHeight ) { return $yb - $img->top_margin; } $xb=$img->width-$img->right_margin+1; $xt=$img->left_margin+$this->iLabelWidth; $year = $this->GetYear($this->iStartDate); $img->SetColor($this->year->iBackgroundColor); $img->FilledRectangle($xt,$yt,$xb,$yb); $img->SetLineWeight($this->year->grid->iWeight); $img->SetTextAlign("center"); if( $year == $this->GetYear($this->iEndDate) ) $yearwidth=$this->GetDayWidth()*($this->GetYearDayNbr($this->iEndDate)-$this->GetYearDayNbr($this->iStartDate)+1); else $yearwidth=$this->GetDayWidth()*($this->GetNumDaysInYear($year)-$this->GetYearDayNbr($this->iStartDate)+1); // The space for a year must be at least 20% bigger than the actual text // so we allow 10% margin on each side if( $yearwidth >= 1.20*$img->GetTextWidth("".$year) ) { $img->SetColor($this->year->iTextColor); $img->StrokeText(round($xt+$yearwidth/2+1), round($yb-$this->year->iTitleVertMargin), $year); } $x = $xt + $yearwidth; while( $x < $xb ) { $img->SetColor($this->year->grid->iColor); $img->Line($x,$yt,$x,$yb); $this->year->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); $year += 1; $yearwidth=$this->GetDayWidth()*$this->GetNumDaysInYear($year); if( $x + $yearwidth < $xb ) $w = $yearwidth; else $w = $xb-$x; if( $w >= 1.2*$img->GetTextWidth("".$year) ) { $img->SetColor($this->year->iTextColor); $img->StrokeText(round($x+$w/2+1), round($yb-$this->year->iTitleVertMargin), $year); } $x += $yearwidth; } $img->SetColor($this->year->iFrameColor); $img->SetLineWeight($this->year->iFrameWeight); $img->Rectangle($xt,$yt,$xb,$yb); return $yb-$img->top_margin; } return $aYCoord; } // Stroke table title (upper left corner) function StrokeTableHeaders($aYBottom) { $img=$this->iImg; $xt=$img->left_margin; $yt=$img->top_margin; $xb=$xt+$this->iLabelWidth; $yb=$aYBottom+$img->top_margin; if( $this->tableTitle->iShow ) { $img->SetColor($this->iTableHeaderBackgroundColor); $img->FilledRectangle($xt,$yt,$xb,$yb); $this->tableTitle->Align("center","top"); $this->tableTitle->Stroke($img,$xt+($xb-$xt)/2+1,$yt+2); $img->SetColor($this->iTableHeaderFrameColor); $img->SetLineWeight($this->iTableHeaderFrameWeight); $img->Rectangle($xt,$yt,$xb,$yb); } $this->actinfo->Stroke($img,$xt,$yt,$xb,$yb,$this->tableTitle->iShow); // Draw the horizontal dividing line $this->dividerh->Stroke($img,$xt,$yb,$img->width-$img->right_margin,$yb); // Draw the vertical dividing line // We do the width "manually" since we want the line only to grow // to the left $fancy = $this->divider->iStyle == 'fancy' ; if( $fancy ) { $this->divider->iStyle = 'solid'; } $tmp = $this->divider->iWeight; $this->divider->iWeight=1; $y = $img->height-$img->bottom_margin; for($i=0; $i < $tmp; ++$i ) { $this->divider->Stroke($img,$xb-$i,$yt,$xb-$i,$y); } // Should we draw "fancy" divider if( $fancy ) { $img->SetLineWeight(1); $img->SetColor($this->iTableHeaderFrameColor); $img->Line($xb,$yt,$xb,$y); $img->Line($xb-$tmp+1,$yt,$xb-$tmp+1,$y); $img->SetColor('white'); $img->Line($xb-$tmp+2,$yt,$xb-$tmp+2,$y); } } // Main entry point to stroke scale function Stroke() { if( !$this->IsRangeSet() ) JpGraphError::RaiseL(6022); //("Gantt scale has not been specified."); $img=$this->iImg; // If minutes are displayed then hour interval must be 1 if( $this->IsDisplayMinute() && $this->hour->GetIntervall() > 1 ) { JpGraphError::RaiseL(6023); //('If you display both hour and minutes the hour intervall must be 1 (Otherwise it doesn\' make sense to display minutes).'); } // Stroke all headers. As argument we supply the offset from the // top which depends on any previous headers // First find out the height of each header $offy=$this->StrokeYears(0,true); $offm=$this->StrokeMonths($offy,true); $offw=$this->StrokeWeeks($offm,true); $offd=$this->StrokeDays($offw,true); $offh=$this->StrokeHours($offd,true); $offmin=$this->StrokeMinutes($offh,true); // ... then we can stroke them in the "backwards order to ensure that // the larger scale gridlines is stroked over the smaller scale gridline $this->StrokeMinutes($offh); $this->StrokeHours($offd); $this->StrokeDays($offw); $this->StrokeWeeks($offm); $this->StrokeMonths($offy); $this->StrokeYears(0); // Now when we now the oaverall size of the scale headers // we can stroke the overall table headers $this->StrokeTableHeaders($offmin); // Now we can calculate the correct scaling factor for each vertical position $this->iAvailableHeight = $img->height - $img->top_margin - $img->bottom_margin - $offd; $this->iVertHeaderSize = $offmin; if( $this->iVertSpacing == -1 ) $this->iVertSpacing = $this->iAvailableHeight / $this->iVertLines; } } //=================================================== // CLASS GanttConstraint // Just a structure to store all the values for a constraint //=================================================== class GanttConstraint { var $iConstrainType; var $iConstrainRow; var $iConstrainColor; var $iConstrainArrowSize; var $iConstrainArrowType; //--------------- // CONSTRUCTOR function GanttConstraint($aRow,$aType,$aColor,$aArrowSize,$aArrowType){ $this->iConstrainType = $aType; $this->iConstrainRow = $aRow; $this->iConstrainColor=$aColor; $this->iConstrainArrowSize=$aArrowSize; $this->iConstrainArrowType=$aArrowType; } } //=================================================== // CLASS GanttPlotObject // The common signature for a Gantt object //=================================================== class GanttPlotObject { var $iVPos=0; // Vertical position var $iLabelLeftMargin=2; // Title margin var $iStart=""; // Start date var $title,$caption; var $iCaptionMargin=5; var $csimarea='',$csimtarget='',$csimalt=''; var $constraints = array(); var $iConstrainPos=array(); function GanttPlotObject() { $this->title = new TextProperty(); $this->title->Align("left","center"); $this->caption = new TextProperty(); } function GetCSIMArea() { return $this->csimarea; } function SetCSIMTarget($aTarget,$aAlt='') { if( !is_string($aTarget) ) { $tv = substr(var_export($aTarget,true),0,40); JpGraphError::RaiseL(6024,$tv); //('CSIM Target must be specified as a string.'."\nStart of target is:\n$tv"); } if( !is_string($aAlt) ) { $tv = substr(var_export($aAlt,true),0,40); JpGraphError::RaiseL(6025,$tv); //('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv"); } $this->csimtarget=$aTarget; $this->csimalt=$aAlt; } function SetCSIMAlt($aAlt) { if( !is_string($aAlt) ) { $tv = substr(var_export($aAlt,true),0,40); JpGraphError::RaiseL(6025,$tv); //('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv"); } $this->csimalt=$aAlt; } function SetConstrain($aRow,$aType,$aColor='black',$aArrowSize=ARROW_S2,$aArrowType=ARROWT_SOLID) { $this->constraints[] = new GanttConstraint($aRow, $aType, $aColor, $aArrowSize, $aArrowType); } function SetConstrainPos($xt,$yt,$xb,$yb) { $this->iConstrainPos = array($xt,$yt,$xb,$yb); } /* function GetConstrain() { return array($this->iConstrainRow,$this->iConstrainType); } */ function GetMinDate() { return $this->iStart; } function GetMaxDate() { return $this->iStart; } function SetCaptionMargin($aMarg) { $this->iCaptionMargin=$aMarg; } function GetAbsHeight(&$aImg) { return 0; } function GetLineNbr() { return $this->iVPos; } function SetLabelLeftMargin($aOff) { $this->iLabelLeftMargin=$aOff; } function StrokeActInfo(&$aImg,$aScale,$aYPos) { $cols=array(); $aScale->actinfo->GetColStart($aImg,$cols,true); $this->title->Stroke($aImg,$cols,$aYPos); } } //=================================================== // CLASS Progress // Holds parameters for the progress indicator // displyed within a bar //=================================================== class Progress { var $iProgress=-1, $iColor="black", $iFillColor='black'; var $iPattern=GANTT_SOLID; var $iDensity=98, $iHeight=0.65; function Set($aProg) { if( $aProg < 0.0 || $aProg > 1.0 ) JpGraphError::RaiseL(6027); //("Progress value must in range [0, 1]"); $this->iProgress = $aProg; } function SetPattern($aPattern,$aColor="blue",$aDensity=98) { $this->iPattern = $aPattern; $this->iColor = $aColor; $this->iDensity = $aDensity; } function SetFillColor($aColor) { $this->iFillColor = $aColor; } function SetHeight($aHeight) { $this->iHeight = $aHeight; } } DEFINE('GANTT_HGRID1',0); DEFINE('GANTT_HGRID2',1); //=================================================== // CLASS HorizontalGridLine // Responsible for drawinf horizontal gridlines and filled alternatibg rows //=================================================== class HorizontalGridLine { var $iGraph=NULL; var $iRowColor1 = '', $iRowColor2 = ''; var $iShow=false; var $line=null; var $iStart=0; // 0=from left margin, 1=just along header function HorizontalGridLine() { $this->line = new LineProperty(); $this->line->SetColor('gray@0.4'); $this->line->SetStyle('dashed'); } function Show($aShow=true) { $this->iShow = $aShow; } function SetRowFillColor($aColor1,$aColor2='') { $this->iRowColor1 = $aColor1; $this->iRowColor2 = $aColor2; } function SetStart($aStart) { $this->iStart = $aStart; } function Stroke(&$aImg,$aScale) { if( ! $this->iShow ) return; // Get horizontal width of line /* $limst = $aScale->iStartDate; $limen = $aScale->iEndDate; $xt = round($aScale->TranslateDate($aScale->iStartDate)); $xb = round($aScale->TranslateDate($limen)); */ if( $this->iStart === 0 ) { $xt = $aImg->left_margin-1; } else { $xt = round($aScale->TranslateDate($aScale->iStartDate))+1; } $xb = $aImg->width-$aImg->right_margin; $yt = round($aScale->TranslateVertPos(0)); $yb = round($aScale->TranslateVertPos(1)); $height = $yb - $yt; // Loop around for all lines in the chart for($i=0; $i < $aScale->iVertLines; ++$i ) { $yb = $yt - $height; $this->line->Stroke($aImg,$xt,$yb,$xb,$yb); if( $this->iRowColor1 !== '' ) { if( $i % 2 == 0 ) { $aImg->PushColor($this->iRowColor1); $aImg->FilledRectangle($xt,$yt,$xb,$yb); $aImg->PopColor(); } elseif( $this->iRowColor2 !== '' ) { $aImg->PushColor($this->iRowColor2); $aImg->FilledRectangle($xt,$yt,$xb,$yb); $aImg->PopColor(); } } $yt = round($aScale->TranslateVertPos($i+1)); } $yb = $yt - $height; $this->line->Stroke($aImg,$xt,$yb,$xb,$yb); } } //=================================================== // CLASS GanttBar // Responsible for formatting individual gantt bars //=================================================== class GanttBar extends GanttPlotObject { var $iEnd; var $iHeightFactor=0.5; var $iFillColor="white",$iFrameColor="black"; var $iShadow=false,$iShadowColor="darkgray",$iShadowWidth=1,$iShadowFrame="black"; var $iPattern=GANTT_RDIAG,$iPatternColor="blue",$iPatternDensity=95; var $leftMark,$rightMark; var $progress; //--------------- // CONSTRUCTOR function GanttBar($aPos,$aLabel,$aStart,$aEnd,$aCaption="",$aHeightFactor=0.6) { parent::GanttPlotObject(); $this->iStart = $aStart; // Is the end date given as a date or as number of days added to start date? if( is_string($aEnd) ) { // If end date has been specified without a time we will asssume // end date is at the end of that date if( strpos($aEnd,':') === false ) $this->iEnd = strtotime($aEnd)+SECPERDAY-1; else $this->iEnd = $aEnd; } elseif(is_int($aEnd) || is_float($aEnd) ) $this->iEnd = strtotime($aStart)+round($aEnd*SECPERDAY); $this->iVPos = $aPos; $this->iHeightFactor = $aHeightFactor; $this->title->Set($aLabel); $this->caption = new TextProperty($aCaption); $this->caption->Align("left","center"); $this->leftMark =new PlotMark(); $this->leftMark->Hide(); $this->rightMark=new PlotMark(); $this->rightMark->Hide(); $this->progress = new Progress(); } //--------------- // PUBLIC METHODS function SetShadow($aShadow=true,$aColor="gray") { $this->iShadow=$aShadow; $this->iShadowColor=$aColor; } function GetMaxDate() { return $this->iEnd; } function SetHeight($aHeight) { $this->iHeightFactor = $aHeight; } function SetColor($aColor) { $this->iFrameColor = $aColor; } function SetFillColor($aColor) { $this->iFillColor = $aColor; } function GetAbsHeight(&$aImg) { if( is_int($this->iHeightFactor) || $this->leftMark->show || $this->rightMark->show ) { $m=-1; if( is_int($this->iHeightFactor) ) $m = $this->iHeightFactor; if( $this->leftMark->show ) $m = max($m,$this->leftMark->width*2); if( $this->rightMark->show ) $m = max($m,$this->rightMark->width*2); return $m; } else return -1; } function SetPattern($aPattern,$aColor="blue",$aDensity=95) { $this->iPattern = $aPattern; $this->iPatternColor = $aColor; $this->iPatternDensity = $aDensity; } function Stroke(&$aImg,$aScale) { $factory = new RectPatternFactory(); $prect = $factory->Create($this->iPattern,$this->iPatternColor); $prect->SetDensity($this->iPatternDensity); // If height factor is specified as a float between 0,1 then we take it as meaning // percetage of the scale width between horizontal line. // If it is an integer > 1 we take it to mean the absolute height in pixels if( $this->iHeightFactor > -0.0 && $this->iHeightFactor <= 1.1) $vs = $aScale->GetVertSpacing()*$this->iHeightFactor; elseif(is_int($this->iHeightFactor) && $this->iHeightFactor>2 && $this->iHeightFactor < 200 ) $vs = $this->iHeightFactor; else JpGraphError::RaiseL(6028,$this->iHeightFactor); //("Specified height (".$this->iHeightFactor.") for gantt bar is out of range."); // Clip date to min max dates to show $st = $aScale->NormalizeDate($this->iStart); $en = $aScale->NormalizeDate($this->iEnd); $limst = max($st,$aScale->iStartDate); $limen = min($en,$aScale->iEndDate); $xt = round($aScale->TranslateDate($limst)); $xb = round($aScale->TranslateDate($limen)); $yt = round($aScale->TranslateVertPos($this->iVPos)-$vs-($aScale->GetVertSpacing()/2-$vs/2)); $yb = round($aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2-$vs/2)); $middle = round($yt+($yb-$yt)/2); $this->StrokeActInfo($aImg,$aScale,$middle); // CSIM for title if( ! empty($this->title->csimtarget) ) { $colwidth = $this->title->GetColWidth($aImg); $colstarts=array(); $aScale->actinfo->GetColStart($aImg,$colstarts,true); $n = min(count($colwidth),count($this->title->csimtarget)); for( $i=0; $i < $n; ++$i ) { $title_xt = $colstarts[$i]; $title_xb = $title_xt + $colwidth[$i]; $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb"; $this->csimarea .= "title->csimtarget[$i]."\""; if( ! empty($this->title->csimalt[$i]) ) { $tmp = $this->title->csimalt[$i]; $this->csimarea .= " title=\"$tmp\""; } $this->csimarea .= " alt=\"$tmp\" />\n"; } } // Check if the bar is totally outside the current scale range if( $en < $aScale->iStartDate || $st > $aScale->iEndDate ) return; // Remember the positions for the bar $this->SetConstrainPos($xt,$yt,$xb,$yb); $prect->ShowFrame(false); $prect->SetBackground($this->iFillColor); if( $this->iShadow ) { $aImg->SetColor($this->iFrameColor); $aImg->ShadowRectangle($xt,$yt,$xb,$yb,$this->iFillColor,$this->iShadowWidth,$this->iShadowColor); $prect->SetPos(new Rectangle($xt+1,$yt+1,$xb-$xt-$this->iShadowWidth-2,$yb-$yt-$this->iShadowWidth-2)); $prect->Stroke($aImg); } else { $prect->SetPos(new Rectangle($xt,$yt,$xb-$xt+1,$yb-$yt+1)); $prect->Stroke($aImg); $aImg->SetColor($this->iFrameColor); $aImg->Rectangle($xt,$yt,$xb,$yb); } // CSIM for bar if( $this->csimtarget != '' ) { $coords = "$xt,$yt,$xb,$yt,$xb,$yb,$xt,$yb"; $this->csimarea .= "csimtarget."\""; if( $this->csimalt != '' ) { $tmp = $this->csimalt; $this->csimarea .= " title=\"$tmp\""; } $this->csimarea .= " alt=\"$tmp\" />\n"; } // Draw progress bar inside activity bar if( $this->progress->iProgress > 0 ) { $xtp = $aScale->TranslateDate($st); $xbp = $aScale->TranslateDate($en); $len = ($xbp-$xtp)*$this->progress->iProgress; $endpos = $xtp+$len; if( $endpos > $xt ) { $len -= ($xt-$xtp); // Make sure that the progess bar doesn't extend over the end date if( $xtp+$len-1 > $xb ) $len = $xb - $xtp + 1; if( $xtp < $xt ) $xtp = $xt; $prog = $factory->Create($this->progress->iPattern,$this->progress->iColor); $prog->SetDensity($this->progress->iDensity); $prog->SetBackground($this->progress->iFillColor); $barheight = ($yb-$yt+1); if( $this->iShadow ) $barheight -= $this->iShadowWidth; $progressheight = floor($barheight*$this->progress->iHeight); $marg = ceil(($barheight-$progressheight)/2); $pos = new Rectangle($xtp,$yt + $marg, $len,$barheight-2*$marg); $prog->SetPos($pos); $prog->Stroke($aImg); } } // We don't plot the end mark if the bar has been capped if( $limst == $st ) { $y = $middle; // We treat the RIGHT and LEFT triangle mark a little bi // special so that these marks are placed right under the // bar. if( $this->leftMark->GetType() == MARK_LEFTTRIANGLE ) { $y = $yb ; } $this->leftMark->Stroke($aImg,$xt,$y); } if( $limen == $en ) { $y = $middle; // We treat the RIGHT and LEFT triangle mark a little bi // special so that these marks are placed right under the // bar. if( $this->rightMark->GetType() == MARK_RIGHTTRIANGLE ) { $y = $yb ; } $this->rightMark->Stroke($aImg,$xb,$y); $margin = $this->iCaptionMargin; if( $this->rightMark->show ) $margin += $this->rightMark->GetWidth(); $this->caption->Stroke($aImg,$xb+$margin,$middle); } } } //=================================================== // CLASS MileStone // Responsible for formatting individual milestones //=================================================== class MileStone extends GanttPlotObject { var $mark; //--------------- // CONSTRUCTOR function MileStone($aVPos,$aLabel,$aDate,$aCaption="") { GanttPlotObject::GanttPlotObject(); $this->caption->Set($aCaption); $this->caption->Align("left","center"); $this->caption->SetFont(FF_FONT1,FS_BOLD); $this->title->Set($aLabel); $this->title->SetColor("darkred"); $this->mark = new PlotMark(); $this->mark->SetWidth(10); $this->mark->SetType(MARK_DIAMOND); $this->mark->SetColor("darkred"); $this->mark->SetFillColor("darkred"); $this->iVPos = $aVPos; $this->iStart = $aDate; } //--------------- // PUBLIC METHODS function GetAbsHeight(&$aImg) { return max($this->title->GetHeight($aImg),$this->mark->GetWidth()); } function Stroke(&$aImg,$aScale) { // Put the mark in the middle at the middle of the day $d = $aScale->NormalizeDate($this->iStart)+SECPERDAY/2; $x = $aScale->TranslateDate($d); $y = $aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2); $this->StrokeActInfo($aImg,$aScale,$y); // CSIM for title if( ! empty($this->title->csimtarget) ) { $yt = round($y - $this->title->GetHeight($aImg)/2); $yb = round($y + $this->title->GetHeight($aImg)/2); $colwidth = $this->title->GetColWidth($aImg); $colstarts=array(); $aScale->actinfo->GetColStart($aImg,$colstarts,true); $n = min(count($colwidth),count($this->title->csimtarget)); for( $i=0; $i < $n; ++$i ) { $title_xt = $colstarts[$i]; $title_xb = $title_xt + $colwidth[$i]; $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb"; $this->csimarea .= "title->csimtarget[$i]."\""; if( ! empty($this->title->csimalt[$i]) ) { $tmp = $this->title->csimalt[$i]; $this->csimarea .= " title=\"$tmp\""; } $this->csimarea .= " alt=\"$tmp\" />\n"; } } if( $d < $aScale->iStartDate || $d > $aScale->iEndDate ) return; // Remember the coordinates for any constrains linking to // this milestone $w = $this->mark->GetWidth()/2; $this->SetConstrainPos($x,round($y-$w),$x,round($y+$w)); // Setup CSIM if( $this->csimtarget != '' ) { $this->mark->SetCSIMTarget( $this->csimtarget ); $this->mark->SetCSIMAlt( $this->csimalt ); } $this->mark->Stroke($aImg,$x,$y); $this->caption->Stroke($aImg,$x+$this->mark->width/2+$this->iCaptionMargin,$y); $this->csimarea .= $this->mark->GetCSIMAreas(); } } //=================================================== // CLASS GanttVLine // Responsible for formatting individual milestones //=================================================== class TextPropertyBelow extends TextProperty { function TextPropertyBelow($aTxt='') { parent::TextProperty($aTxt); } function GetColWidth(&$aImg,$margin) { // Since we are not stroking the title in the columns // but rather under the graph we want this to return 0. return array(0); } } class GanttVLine extends GanttPlotObject { var $iLine,$title_margin=3; var $iDayOffset=1; // Defult to right edge of day //--------------- // CONSTRUCTOR function GanttVLine($aDate,$aTitle="",$aColor="black",$aWeight=3,$aStyle="dashed") { GanttPlotObject::GanttPlotObject(); $this->iLine = new LineProperty(); $this->iLine->SetColor($aColor); $this->iLine->SetWeight($aWeight); $this->iLine->SetStyle($aStyle); $this->iStart = $aDate; $this->title = new TextPropertyBelow(); $this->title->Set($aTitle); } //--------------- // PUBLIC METHODS function SetDayOffset($aOff=0.5) { if( $aOff < 0.0 || $aOff > 1.0 ) JpGraphError::RaiseL(6029); //("Offset for vertical line must be in range [0,1]"); $this->iDayOffset = $aOff; } function SetTitleMargin($aMarg) { $this->title_margin = $aMarg; } function Stroke(&$aImg,$aScale) { $d = $aScale->NormalizeDate($this->iStart); if( $d < $aScale->iStartDate || $d > $aScale->iEndDate ) return; if($this->iDayOffset != 0.0) $d += 24*60*60*$this->iDayOffset; $x = $aScale->TranslateDate($d); $y1 = $aScale->iVertHeaderSize+$aImg->top_margin; $y2 = $aImg->height - $aImg->bottom_margin; $this->iLine->Stroke($aImg,$x,$y1,$x,$y2); $this->title->Align("center","top"); $this->title->Stroke($aImg,$x,$y2+$this->title_margin); } } //=================================================== // CLASS LinkArrow // Handles the drawing of a an arrow //=================================================== class LinkArrow { var $ix,$iy; var $isizespec = array( array(2,3),array(3,5),array(3,8),array(6,15),array(8,22)); var $iDirection=ARROW_DOWN,$iType=ARROWT_SOLID,$iSize=ARROW_S2; var $iColor='black'; function LinkArrow($x,$y,$aDirection,$aType=ARROWT_SOLID,$aSize=ARROW_S2) { $this->iDirection = $aDirection; $this->iType = $aType; $this->iSize = $aSize; $this->ix = $x; $this->iy = $y; } function SetColor($aColor) { $this->iColor = $aColor; } function SetSize($aSize) { $this->iSize = $aSize; } function SetType($aType) { $this->iType = $aType; } function Stroke(&$aImg) { list($dx,$dy) = $this->isizespec[$this->iSize]; $x = $this->ix; $y = $this->iy; switch ( $this->iDirection ) { case ARROW_DOWN: $c = array($x,$y,$x-$dx,$y-$dy,$x+$dx,$y-$dy,$x,$y); break; case ARROW_UP: $c = array($x,$y,$x-$dx,$y+$dy,$x+$dx,$y+$dy,$x,$y); break; case ARROW_LEFT: $c = array($x,$y,$x+$dy,$y-$dx,$x+$dy,$y+$dx,$x,$y); break; case ARROW_RIGHT: $c = array($x,$y,$x-$dy,$y-$dx,$x-$dy,$y+$dx,$x,$y); break; default: JpGraphError::RaiseL(6030); //('Unknown arrow direction for link.'); die(); break; } $aImg->SetColor($this->iColor); switch( $this->iType ) { case ARROWT_SOLID: $aImg->FilledPolygon($c); break; case ARROWT_OPEN: $aImg->Polygon($c); break; default: JpGraphError::RaiseL(6031); //('Unknown arrow type for link.'); die(); break; } } } //=================================================== // CLASS GanttLink // Handles the drawing of a link line between 2 points //=================================================== class GanttLink { var $ix1,$ix2,$iy1,$iy2; var $iPathType=2,$iPathExtend=15; var $iColor='black',$iWeight=1; var $iArrowSize=ARROW_S2,$iArrowType=ARROWT_SOLID; function GanttLink($x1=0,$y1=0,$x2=0,$y2=0) { $this->ix1 = $x1; $this->ix2 = $x2; $this->iy1 = $y1; $this->iy2 = $y2; } function SetPos($x1,$y1,$x2,$y2) { $this->ix1 = $x1; $this->ix2 = $x2; $this->iy1 = $y1; $this->iy2 = $y2; } function SetPath($aPath) { $this->iPathType = $aPath; } function SetColor($aColor) { $this->iColor = $aColor; } function SetArrow($aSize,$aType=ARROWT_SOLID) { $this->iArrowSize = $aSize; $this->iArrowType = $aType; } function SetWeight($aWeight) { $this->iWeight = $aWeight; } function Stroke(&$aImg) { // The way the path for the arrow is constructed is partly based // on some heuristics. This is not an exact science but draws the // path in a way that, for me, makes esthetic sence. For example // if the start and end activities are very close we make a small // detour to endter the target horixontally. If there are more // space between axctivities then no suh detour is made and the // target is "hit" directly vertical. I have tried to keep this // simple. no doubt this could become almost infinitive complex // and have some real AI. Feel free to modify this. // This will no-doubt be tweaked as times go by. One design aim // is to avoid having the user choose what types of arrow // he wants. // The arrow is drawn between (x1,y1) to (x2,y2) $x1 = $this->ix1 ; $x2 = $this->ix2 ; $y1 = $this->iy1 ; $y2 = $this->iy2 ; // Depending on if the target is below or above we have to // handle thi different. if( $y2 > $y1 ) { $arrowtype = ARROW_DOWN; $midy = round(($y2-$y1)/2+$y1); if( $x2 > $x1 ) { switch ( $this->iPathType ) { case 0: $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); break; case 1: case 2: case 3: $c = array($x1,$y1,$x2,$y1,$x2,$y2); break; default: JpGraphError::RaiseL(6032,$this->iPathType); //('Internal error: Unknown path type (='.$this->iPathType .') specified for link.'); exit(1); break; } } else { switch ( $this->iPathType ) { case 0: case 1: $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); break; case 2: // Always extend out horizontally a bit from the first point // If we draw a link back in time (end to start) and the bars // are very close we also change the path so it comes in from // the left on the activity $c = array($x1,$y1,$x1+$this->iPathExtend,$y1, $x1+$this->iPathExtend,$midy, $x2,$midy,$x2,$y2); break; case 3: if( $y2-$midy < 6 ) { $c = array($x1,$y1,$x1,$midy, $x2-$this->iPathExtend,$midy, $x2-$this->iPathExtend,$y2, $x2,$y2); $arrowtype = ARROW_RIGHT; } else { $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); } break; default: JpGraphError::RaiseL(6032,$this->iPathType); //('Internal error: Unknown path type specified for link.'); exit(1); break; } } $arrow = new LinkArrow($x2,$y2,$arrowtype); } else { // Y2 < Y1 $arrowtype = ARROW_UP; $midy = round(($y1-$y2)/2+$y2); if( $x2 > $x1 ) { switch ( $this->iPathType ) { case 0: case 1: $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); break; case 3: if( $midy-$y2 < 8 ) { $arrowtype = ARROW_RIGHT; $c = array($x1,$y1,$x1,$y2,$x2,$y2); } else { $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); } break; default: JpGraphError::RaiseL(6032,$this->iPathType); //('Internal error: Unknown path type specified for link.'); break; } } else { switch ( $this->iPathType ) { case 0: case 1: $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); break; case 2: // Always extend out horizontally a bit from the first point $c = array($x1,$y1,$x1+$this->iPathExtend,$y1, $x1+$this->iPathExtend,$midy, $x2,$midy,$x2,$y2); break; case 3: if( $midy-$y2 < 16 ) { $arrowtype = ARROW_RIGHT; $c = array($x1,$y1,$x1,$midy,$x2-$this->iPathExtend,$midy, $x2-$this->iPathExtend,$y2, $x2,$y2); } else { $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); } break; default: JpGraphError::RaiseL(6032,$this->iPathType); //('Internal error: Unknown path type specified for link.'); break; } } $arrow = new LinkArrow($x2,$y2,$arrowtype); } $aImg->SetColor($this->iColor); $aImg->SetLineWeight($this->iWeight); $aImg->Polygon($c); $aImg->SetLineWeight(1); $arrow->SetColor($this->iColor); $arrow->SetSize($this->iArrowSize); $arrow->SetType($this->iArrowType); $arrow->Stroke($aImg); } } // ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_gb2312.php ================================================ 12288, 8482 => 12289, 8483 => 12290, 8484 => 12539, 8485 => 713, 8486 => 711, 8487 => 168, 8488 => 12291, 8489 => 12293, 8490 => 8213, 8491 => 65374, 8492 => 8214, 8493 => 8230, 8494 => 8216, 8495 => 8217, 8496 => 8220, 8497 => 8221, 8498 => 12308, 8499 => 12309, 8500 => 12296, 8501 => 12297, 8502 => 12298, 8503 => 12299, 8504 => 12300, 8505 => 12301, 8506 => 12302, 8507 => 12303, 8508 => 12310, 8509 => 12311, 8510 => 12304, 8511 => 12305, 8512 => 177, 8513 => 215, 8514 => 247, 8515 => 8758, 8516 => 8743, 8517 => 8744, 8518 => 8721, 8519 => 8719, 8520 => 8746, 8521 => 8745, 8522 => 8712, 8523 => 8759, 8524 => 8730, 8525 => 8869, 8526 => 8741, 8527 => 8736, 8528 => 8978, 8529 => 8857, 8530 => 8747, 8531 => 8750, 8532 => 8801, 8533 => 8780, 8534 => 8776, 8535 => 8765, 8536 => 8733, 8537 => 8800, 8538 => 8814, 8539 => 8815, 8540 => 8804, 8541 => 8805, 8542 => 8734, 8543 => 8757, 8544 => 8756, 8545 => 9794, 8546 => 9792, 8547 => 176, 8548 => 8242, 8549 => 8243, 8550 => 8451, 8551 => 65284, 8552 => 164, 8553 => 65504, 8554 => 65505, 8555 => 8240, 8556 => 167, 8557 => 8470, 8558 => 9734, 8559 => 9733, 8560 => 9675, 8561 => 9679, 8562 => 9678, 8563 => 9671, 8564 => 9670, 8565 => 9633, 8566 => 9632, 8567 => 9651, 8568 => 9650, 8569 => 8251, 8570 => 8594, 8571 => 8592, 8572 => 8593, 8573 => 8595, 8574 => 12307, 8753 => 9352, 8754 => 9353, 8755 => 9354, 8756 => 9355, 8757 => 9356, 8758 => 9357, 8759 => 9358, 8760 => 9359, 8761 => 9360, 8762 => 9361, 8763 => 9362, 8764 => 9363, 8765 => 9364, 8766 => 9365, 8767 => 9366, 8768 => 9367, 8769 => 9368, 8770 => 9369, 8771 => 9370, 8772 => 9371, 8773 => 9332, 8774 => 9333, 8775 => 9334, 8776 => 9335, 8777 => 9336, 8778 => 9337, 8779 => 9338, 8780 => 9339, 8781 => 9340, 8782 => 9341, 8783 => 9342, 8784 => 9343, 8785 => 9344, 8786 => 9345, 8787 => 9346, 8788 => 9347, 8789 => 9348, 8790 => 9349, 8791 => 9350, 8792 => 9351, 8793 => 9312, 8794 => 9313, 8795 => 9314, 8796 => 9315, 8797 => 9316, 8798 => 9317, 8799 => 9318, 8800 => 9319, 8801 => 9320, 8802 => 9321, 8805 => 12832, 8806 => 12833, 8807 => 12834, 8808 => 12835, 8809 => 12836, 8810 => 12837, 8811 => 12838, 8812 => 12839, 8813 => 12840, 8814 => 12841, 8817 => 8544, 8818 => 8545, 8819 => 8546, 8820 => 8547, 8821 => 8548, 8822 => 8549, 8823 => 8550, 8824 => 8551, 8825 => 8552, 8826 => 8553, 8827 => 8554, 8828 => 8555, 8993 => 65281, 8994 => 65282, 8995 => 65283, 8996 => 65509, 8997 => 65285, 8998 => 65286, 8999 => 65287, 9000 => 65288, 9001 => 65289, 9002 => 65290, 9003 => 65291, 9004 => 65292, 9005 => 65293, 9006 => 65294, 9007 => 65295, 9008 => 65296, 9009 => 65297, 9010 => 65298, 9011 => 65299, 9012 => 65300, 9013 => 65301, 9014 => 65302, 9015 => 65303, 9016 => 65304, 9017 => 65305, 9018 => 65306, 9019 => 65307, 9020 => 65308, 9021 => 65309, 9022 => 65310, 9023 => 65311, 9024 => 65312, 9025 => 65313, 9026 => 65314, 9027 => 65315, 9028 => 65316, 9029 => 65317, 9030 => 65318, 9031 => 65319, 9032 => 65320, 9033 => 65321, 9034 => 65322, 9035 => 65323, 9036 => 65324, 9037 => 65325, 9038 => 65326, 9039 => 65327, 9040 => 65328, 9041 => 65329, 9042 => 65330, 9043 => 65331, 9044 => 65332, 9045 => 65333, 9046 => 65334, 9047 => 65335, 9048 => 65336, 9049 => 65337, 9050 => 65338, 9051 => 65339, 9052 => 65340, 9053 => 65341, 9054 => 65342, 9055 => 65343, 9056 => 65344, 9057 => 65345, 9058 => 65346, 9059 => 65347, 9060 => 65348, 9061 => 65349, 9062 => 65350, 9063 => 65351, 9064 => 65352, 9065 => 65353, 9066 => 65354, 9067 => 65355, 9068 => 65356, 9069 => 65357, 9070 => 65358, 9071 => 65359, 9072 => 65360, 9073 => 65361, 9074 => 65362, 9075 => 65363, 9076 => 65364, 9077 => 65365, 9078 => 65366, 9079 => 65367, 9080 => 65368, 9081 => 65369, 9082 => 65370, 9083 => 65371, 9084 => 65372, 9085 => 65373, 9086 => 65507, 9249 => 12353, 9250 => 12354, 9251 => 12355, 9252 => 12356, 9253 => 12357, 9254 => 12358, 9255 => 12359, 9256 => 12360, 9257 => 12361, 9258 => 12362, 9259 => 12363, 9260 => 12364, 9261 => 12365, 9262 => 12366, 9263 => 12367, 9264 => 12368, 9265 => 12369, 9266 => 12370, 9267 => 12371, 9268 => 12372, 9269 => 12373, 9270 => 12374, 9271 => 12375, 9272 => 12376, 9273 => 12377, 9274 => 12378, 9275 => 12379, 9276 => 12380, 9277 => 12381, 9278 => 12382, 9279 => 12383, 9280 => 12384, 9281 => 12385, 9282 => 12386, 9283 => 12387, 9284 => 12388, 9285 => 12389, 9286 => 12390, 9287 => 12391, 9288 => 12392, 9289 => 12393, 9290 => 12394, 9291 => 12395, 9292 => 12396, 9293 => 12397, 9294 => 12398, 9295 => 12399, 9296 => 12400, 9297 => 12401, 9298 => 12402, 9299 => 12403, 9300 => 12404, 9301 => 12405, 9302 => 12406, 9303 => 12407, 9304 => 12408, 9305 => 12409, 9306 => 12410, 9307 => 12411, 9308 => 12412, 9309 => 12413, 9310 => 12414, 9311 => 12415, 9312 => 12416, 9313 => 12417, 9314 => 12418, 9315 => 12419, 9316 => 12420, 9317 => 12421, 9318 => 12422, 9319 => 12423, 9320 => 12424, 9321 => 12425, 9322 => 12426, 9323 => 12427, 9324 => 12428, 9325 => 12429, 9326 => 12430, 9327 => 12431, 9328 => 12432, 9329 => 12433, 9330 => 12434, 9331 => 12435, 9505 => 12449, 9506 => 12450, 9507 => 12451, 9508 => 12452, 9509 => 12453, 9510 => 12454, 9511 => 12455, 9512 => 12456, 9513 => 12457, 9514 => 12458, 9515 => 12459, 9516 => 12460, 9517 => 12461, 9518 => 12462, 9519 => 12463, 9520 => 12464, 9521 => 12465, 9522 => 12466, 9523 => 12467, 9524 => 12468, 9525 => 12469, 9526 => 12470, 9527 => 12471, 9528 => 12472, 9529 => 12473, 9530 => 12474, 9531 => 12475, 9532 => 12476, 9533 => 12477, 9534 => 12478, 9535 => 12479, 9536 => 12480, 9537 => 12481, 9538 => 12482, 9539 => 12483, 9540 => 12484, 9541 => 12485, 9542 => 12486, 9543 => 12487, 9544 => 12488, 9545 => 12489, 9546 => 12490, 9547 => 12491, 9548 => 12492, 9549 => 12493, 9550 => 12494, 9551 => 12495, 9552 => 12496, 9553 => 12497, 9554 => 12498, 9555 => 12499, 9556 => 12500, 9557 => 12501, 9558 => 12502, 9559 => 12503, 9560 => 12504, 9561 => 12505, 9562 => 12506, 9563 => 12507, 9564 => 12508, 9565 => 12509, 9566 => 12510, 9567 => 12511, 9568 => 12512, 9569 => 12513, 9570 => 12514, 9571 => 12515, 9572 => 12516, 9573 => 12517, 9574 => 12518, 9575 => 12519, 9576 => 12520, 9577 => 12521, 9578 => 12522, 9579 => 12523, 9580 => 12524, 9581 => 12525, 9582 => 12526, 9583 => 12527, 9584 => 12528, 9585 => 12529, 9586 => 12530, 9587 => 12531, 9588 => 12532, 9589 => 12533, 9590 => 12534, 9761 => 913, 9762 => 914, 9763 => 915, 9764 => 916, 9765 => 917, 9766 => 918, 9767 => 919, 9768 => 920, 9769 => 921, 9770 => 922, 9771 => 923, 9772 => 924, 9773 => 925, 9774 => 926, 9775 => 927, 9776 => 928, 9777 => 929, 9778 => 931, 9779 => 932, 9780 => 933, 9781 => 934, 9782 => 935, 9783 => 936, 9784 => 937, 9793 => 945, 9794 => 946, 9795 => 947, 9796 => 948, 9797 => 949, 9798 => 950, 9799 => 951, 9800 => 952, 9801 => 953, 9802 => 954, 9803 => 955, 9804 => 956, 9805 => 957, 9806 => 958, 9807 => 959, 9808 => 960, 9809 => 961, 9810 => 963, 9811 => 964, 9812 => 965, 9813 => 966, 9814 => 967, 9815 => 968, 9816 => 969, 10017 => 1040, 10018 => 1041, 10019 => 1042, 10020 => 1043, 10021 => 1044, 10022 => 1045, 10023 => 1025, 10024 => 1046, 10025 => 1047, 10026 => 1048, 10027 => 1049, 10028 => 1050, 10029 => 1051, 10030 => 1052, 10031 => 1053, 10032 => 1054, 10033 => 1055, 10034 => 1056, 10035 => 1057, 10036 => 1058, 10037 => 1059, 10038 => 1060, 10039 => 1061, 10040 => 1062, 10041 => 1063, 10042 => 1064, 10043 => 1065, 10044 => 1066, 10045 => 1067, 10046 => 1068, 10047 => 1069, 10048 => 1070, 10049 => 1071, 10065 => 1072, 10066 => 1073, 10067 => 1074, 10068 => 1075, 10069 => 1076, 10070 => 1077, 10071 => 1105, 10072 => 1078, 10073 => 1079, 10074 => 1080, 10075 => 1081, 10076 => 1082, 10077 => 1083, 10078 => 1084, 10079 => 1085, 10080 => 1086, 10081 => 1087, 10082 => 1088, 10083 => 1089, 10084 => 1090, 10085 => 1091, 10086 => 1092, 10087 => 1093, 10088 => 1094, 10089 => 1095, 10090 => 1096, 10091 => 1097, 10092 => 1098, 10093 => 1099, 10094 => 1100, 10095 => 1101, 10096 => 1102, 10097 => 1103, 10273 => 257, 10274 => 225, 10275 => 462, 10276 => 224, 10277 => 275, 10278 => 233, 10279 => 283, 10280 => 232, 10281 => 299, 10282 => 237, 10283 => 464, 10284 => 236, 10285 => 333, 10286 => 243, 10287 => 466, 10288 => 242, 10289 => 363, 10290 => 250, 10291 => 468, 10292 => 249, 10293 => 470, 10294 => 472, 10295 => 474, 10296 => 476, 10297 => 252, 10298 => 234, 10309 => 12549, 10310 => 12550, 10311 => 12551, 10312 => 12552, 10313 => 12553, 10314 => 12554, 10315 => 12555, 10316 => 12556, 10317 => 12557, 10318 => 12558, 10319 => 12559, 10320 => 12560, 10321 => 12561, 10322 => 12562, 10323 => 12563, 10324 => 12564, 10325 => 12565, 10326 => 12566, 10327 => 12567, 10328 => 12568, 10329 => 12569, 10330 => 12570, 10331 => 12571, 10332 => 12572, 10333 => 12573, 10334 => 12574, 10335 => 12575, 10336 => 12576, 10337 => 12577, 10338 => 12578, 10339 => 12579, 10340 => 12580, 10341 => 12581, 10342 => 12582, 10343 => 12583, 10344 => 12584, 10345 => 12585, 10532 => 9472, 10533 => 9473, 10534 => 9474, 10535 => 9475, 10536 => 9476, 10537 => 9477, 10538 => 9478, 10539 => 9479, 10540 => 9480, 10541 => 9481, 10542 => 9482, 10543 => 9483, 10544 => 9484, 10545 => 9485, 10546 => 9486, 10547 => 9487, 10548 => 9488, 10549 => 9489, 10550 => 9490, 10551 => 9491, 10552 => 9492, 10553 => 9493, 10554 => 9494, 10555 => 9495, 10556 => 9496, 10557 => 9497, 10558 => 9498, 10559 => 9499, 10560 => 9500, 10561 => 9501, 10562 => 9502, 10563 => 9503, 10564 => 9504, 10565 => 9505, 10566 => 9506, 10567 => 9507, 10568 => 9508, 10569 => 9509, 10570 => 9510, 10571 => 9511, 10572 => 9512, 10573 => 9513, 10574 => 9514, 10575 => 9515, 10576 => 9516, 10577 => 9517, 10578 => 9518, 10579 => 9519, 10580 => 9520, 10581 => 9521, 10582 => 9522, 10583 => 9523, 10584 => 9524, 10585 => 9525, 10586 => 9526, 10587 => 9527, 10588 => 9528, 10589 => 9529, 10590 => 9530, 10591 => 9531, 10592 => 9532, 10593 => 9533, 10594 => 9534, 10595 => 9535, 10596 => 9536, 10597 => 9537, 10598 => 9538, 10599 => 9539, 10600 => 9540, 10601 => 9541, 10602 => 9542, 10603 => 9543, 10604 => 9544, 10605 => 9545, 10606 => 9546, 10607 => 9547, 12321 => 21834, 12322 => 38463, 12323 => 22467, 12324 => 25384, 12325 => 21710, 12326 => 21769, 12327 => 21696, 12328 => 30353, 12329 => 30284, 12330 => 34108, 12331 => 30702, 12332 => 33406, 12333 => 30861, 12334 => 29233, 12335 => 38552, 12336 => 38797, 12337 => 27688, 12338 => 23433, 12339 => 20474, 12340 => 25353, 12341 => 26263, 12342 => 23736, 12343 => 33018, 12344 => 26696, 12345 => 32942, 12346 => 26114, 12347 => 30414, 12348 => 20985, 12349 => 25942, 12350 => 29100, 12351 => 32753, 12352 => 34948, 12353 => 20658, 12354 => 22885, 12355 => 25034, 12356 => 28595, 12357 => 33453, 12358 => 25420, 12359 => 25170, 12360 => 21485, 12361 => 21543, 12362 => 31494, 12363 => 20843, 12364 => 30116, 12365 => 24052, 12366 => 25300, 12367 => 36299, 12368 => 38774, 12369 => 25226, 12370 => 32793, 12371 => 22365, 12372 => 38712, 12373 => 32610, 12374 => 29240, 12375 => 30333, 12376 => 26575, 12377 => 30334, 12378 => 25670, 12379 => 20336, 12380 => 36133, 12381 => 25308, 12382 => 31255, 12383 => 26001, 12384 => 29677, 12385 => 25644, 12386 => 25203, 12387 => 33324, 12388 => 39041, 12389 => 26495, 12390 => 29256, 12391 => 25198, 12392 => 25292, 12393 => 20276, 12394 => 29923, 12395 => 21322, 12396 => 21150, 12397 => 32458, 12398 => 37030, 12399 => 24110, 12400 => 26758, 12401 => 27036, 12402 => 33152, 12403 => 32465, 12404 => 26834, 12405 => 30917, 12406 => 34444, 12407 => 38225, 12408 => 20621, 12409 => 35876, 12410 => 33502, 12411 => 32990, 12412 => 21253, 12413 => 35090, 12414 => 21093, 12577 => 34180, 12578 => 38649, 12579 => 20445, 12580 => 22561, 12581 => 39281, 12582 => 23453, 12583 => 25265, 12584 => 25253, 12585 => 26292, 12586 => 35961, 12587 => 40077, 12588 => 29190, 12589 => 26479, 12590 => 30865, 12591 => 24754, 12592 => 21329, 12593 => 21271, 12594 => 36744, 12595 => 32972, 12596 => 36125, 12597 => 38049, 12598 => 20493, 12599 => 29384, 12600 => 22791, 12601 => 24811, 12602 => 28953, 12603 => 34987, 12604 => 22868, 12605 => 33519, 12606 => 26412, 12607 => 31528, 12608 => 23849, 12609 => 32503, 12610 => 29997, 12611 => 27893, 12612 => 36454, 12613 => 36856, 12614 => 36924, 12615 => 40763, 12616 => 27604, 12617 => 37145, 12618 => 31508, 12619 => 24444, 12620 => 30887, 12621 => 34006, 12622 => 34109, 12623 => 27605, 12624 => 27609, 12625 => 27606, 12626 => 24065, 12627 => 24199, 12628 => 30201, 12629 => 38381, 12630 => 25949, 12631 => 24330, 12632 => 24517, 12633 => 36767, 12634 => 22721, 12635 => 33218, 12636 => 36991, 12637 => 38491, 12638 => 38829, 12639 => 36793, 12640 => 32534, 12641 => 36140, 12642 => 25153, 12643 => 20415, 12644 => 21464, 12645 => 21342, 12646 => 36776, 12647 => 36777, 12648 => 36779, 12649 => 36941, 12650 => 26631, 12651 => 24426, 12652 => 33176, 12653 => 34920, 12654 => 40150, 12655 => 24971, 12656 => 21035, 12657 => 30250, 12658 => 24428, 12659 => 25996, 12660 => 28626, 12661 => 28392, 12662 => 23486, 12663 => 25672, 12664 => 20853, 12665 => 20912, 12666 => 26564, 12667 => 19993, 12668 => 31177, 12669 => 39292, 12670 => 28851, 12833 => 30149, 12834 => 24182, 12835 => 29627, 12836 => 33760, 12837 => 25773, 12838 => 25320, 12839 => 38069, 12840 => 27874, 12841 => 21338, 12842 => 21187, 12843 => 25615, 12844 => 38082, 12845 => 31636, 12846 => 20271, 12847 => 24091, 12848 => 33334, 12849 => 33046, 12850 => 33162, 12851 => 28196, 12852 => 27850, 12853 => 39539, 12854 => 25429, 12855 => 21340, 12856 => 21754, 12857 => 34917, 12858 => 22496, 12859 => 19981, 12860 => 24067, 12861 => 27493, 12862 => 31807, 12863 => 37096, 12864 => 24598, 12865 => 25830, 12866 => 29468, 12867 => 35009, 12868 => 26448, 12869 => 25165, 12870 => 36130, 12871 => 30572, 12872 => 36393, 12873 => 37319, 12874 => 24425, 12875 => 33756, 12876 => 34081, 12877 => 39184, 12878 => 21442, 12879 => 34453, 12880 => 27531, 12881 => 24813, 12882 => 24808, 12883 => 28799, 12884 => 33485, 12885 => 33329, 12886 => 20179, 12887 => 27815, 12888 => 34255, 12889 => 25805, 12890 => 31961, 12891 => 27133, 12892 => 26361, 12893 => 33609, 12894 => 21397, 12895 => 31574, 12896 => 20391, 12897 => 20876, 12898 => 27979, 12899 => 23618, 12900 => 36461, 12901 => 25554, 12902 => 21449, 12903 => 33580, 12904 => 33590, 12905 => 26597, 12906 => 30900, 12907 => 25661, 12908 => 23519, 12909 => 23700, 12910 => 24046, 12911 => 35815, 12912 => 25286, 12913 => 26612, 12914 => 35962, 12915 => 25600, 12916 => 25530, 12917 => 34633, 12918 => 39307, 12919 => 35863, 12920 => 32544, 12921 => 38130, 12922 => 20135, 12923 => 38416, 12924 => 39076, 12925 => 26124, 12926 => 29462, 13089 => 22330, 13090 => 23581, 13091 => 24120, 13092 => 38271, 13093 => 20607, 13094 => 32928, 13095 => 21378, 13096 => 25950, 13097 => 30021, 13098 => 21809, 13099 => 20513, 13100 => 36229, 13101 => 25220, 13102 => 38046, 13103 => 26397, 13104 => 22066, 13105 => 28526, 13106 => 24034, 13107 => 21557, 13108 => 28818, 13109 => 36710, 13110 => 25199, 13111 => 25764, 13112 => 25507, 13113 => 24443, 13114 => 28552, 13115 => 37108, 13116 => 33251, 13117 => 36784, 13118 => 23576, 13119 => 26216, 13120 => 24561, 13121 => 27785, 13122 => 38472, 13123 => 36225, 13124 => 34924, 13125 => 25745, 13126 => 31216, 13127 => 22478, 13128 => 27225, 13129 => 25104, 13130 => 21576, 13131 => 20056, 13132 => 31243, 13133 => 24809, 13134 => 28548, 13135 => 35802, 13136 => 25215, 13137 => 36894, 13138 => 39563, 13139 => 31204, 13140 => 21507, 13141 => 30196, 13142 => 25345, 13143 => 21273, 13144 => 27744, 13145 => 36831, 13146 => 24347, 13147 => 39536, 13148 => 32827, 13149 => 40831, 13150 => 20360, 13151 => 23610, 13152 => 36196, 13153 => 32709, 13154 => 26021, 13155 => 28861, 13156 => 20805, 13157 => 20914, 13158 => 34411, 13159 => 23815, 13160 => 23456, 13161 => 25277, 13162 => 37228, 13163 => 30068, 13164 => 36364, 13165 => 31264, 13166 => 24833, 13167 => 31609, 13168 => 20167, 13169 => 32504, 13170 => 30597, 13171 => 19985, 13172 => 33261, 13173 => 21021, 13174 => 20986, 13175 => 27249, 13176 => 21416, 13177 => 36487, 13178 => 38148, 13179 => 38607, 13180 => 28353, 13181 => 38500, 13182 => 26970, 13345 => 30784, 13346 => 20648, 13347 => 30679, 13348 => 25616, 13349 => 35302, 13350 => 22788, 13351 => 25571, 13352 => 24029, 13353 => 31359, 13354 => 26941, 13355 => 20256, 13356 => 33337, 13357 => 21912, 13358 => 20018, 13359 => 30126, 13360 => 31383, 13361 => 24162, 13362 => 24202, 13363 => 38383, 13364 => 21019, 13365 => 21561, 13366 => 28810, 13367 => 25462, 13368 => 38180, 13369 => 22402, 13370 => 26149, 13371 => 26943, 13372 => 37255, 13373 => 21767, 13374 => 28147, 13375 => 32431, 13376 => 34850, 13377 => 25139, 13378 => 32496, 13379 => 30133, 13380 => 33576, 13381 => 30913, 13382 => 38604, 13383 => 36766, 13384 => 24904, 13385 => 29943, 13386 => 35789, 13387 => 27492, 13388 => 21050, 13389 => 36176, 13390 => 27425, 13391 => 32874, 13392 => 33905, 13393 => 22257, 13394 => 21254, 13395 => 20174, 13396 => 19995, 13397 => 20945, 13398 => 31895, 13399 => 37259, 13400 => 31751, 13401 => 20419, 13402 => 36479, 13403 => 31713, 13404 => 31388, 13405 => 25703, 13406 => 23828, 13407 => 20652, 13408 => 33030, 13409 => 30209, 13410 => 31929, 13411 => 28140, 13412 => 32736, 13413 => 26449, 13414 => 23384, 13415 => 23544, 13416 => 30923, 13417 => 25774, 13418 => 25619, 13419 => 25514, 13420 => 25387, 13421 => 38169, 13422 => 25645, 13423 => 36798, 13424 => 31572, 13425 => 30249, 13426 => 25171, 13427 => 22823, 13428 => 21574, 13429 => 27513, 13430 => 20643, 13431 => 25140, 13432 => 24102, 13433 => 27526, 13434 => 20195, 13435 => 36151, 13436 => 34955, 13437 => 24453, 13438 => 36910, 13601 => 24608, 13602 => 32829, 13603 => 25285, 13604 => 20025, 13605 => 21333, 13606 => 37112, 13607 => 25528, 13608 => 32966, 13609 => 26086, 13610 => 27694, 13611 => 20294, 13612 => 24814, 13613 => 28129, 13614 => 35806, 13615 => 24377, 13616 => 34507, 13617 => 24403, 13618 => 25377, 13619 => 20826, 13620 => 33633, 13621 => 26723, 13622 => 20992, 13623 => 25443, 13624 => 36424, 13625 => 20498, 13626 => 23707, 13627 => 31095, 13628 => 23548, 13629 => 21040, 13630 => 31291, 13631 => 24764, 13632 => 36947, 13633 => 30423, 13634 => 24503, 13635 => 24471, 13636 => 30340, 13637 => 36460, 13638 => 28783, 13639 => 30331, 13640 => 31561, 13641 => 30634, 13642 => 20979, 13643 => 37011, 13644 => 22564, 13645 => 20302, 13646 => 28404, 13647 => 36842, 13648 => 25932, 13649 => 31515, 13650 => 29380, 13651 => 28068, 13652 => 32735, 13653 => 23265, 13654 => 25269, 13655 => 24213, 13656 => 22320, 13657 => 33922, 13658 => 31532, 13659 => 24093, 13660 => 24351, 13661 => 36882, 13662 => 32532, 13663 => 39072, 13664 => 25474, 13665 => 28359, 13666 => 30872, 13667 => 28857, 13668 => 20856, 13669 => 38747, 13670 => 22443, 13671 => 30005, 13672 => 20291, 13673 => 30008, 13674 => 24215, 13675 => 24806, 13676 => 22880, 13677 => 28096, 13678 => 27583, 13679 => 30857, 13680 => 21500, 13681 => 38613, 13682 => 20939, 13683 => 20993, 13684 => 25481, 13685 => 21514, 13686 => 38035, 13687 => 35843, 13688 => 36300, 13689 => 29241, 13690 => 30879, 13691 => 34678, 13692 => 36845, 13693 => 35853, 13694 => 21472, 13857 => 19969, 13858 => 30447, 13859 => 21486, 13860 => 38025, 13861 => 39030, 13862 => 40718, 13863 => 38189, 13864 => 23450, 13865 => 35746, 13866 => 20002, 13867 => 19996, 13868 => 20908, 13869 => 33891, 13870 => 25026, 13871 => 21160, 13872 => 26635, 13873 => 20375, 13874 => 24683, 13875 => 20923, 13876 => 27934, 13877 => 20828, 13878 => 25238, 13879 => 26007, 13880 => 38497, 13881 => 35910, 13882 => 36887, 13883 => 30168, 13884 => 37117, 13885 => 30563, 13886 => 27602, 13887 => 29322, 13888 => 29420, 13889 => 35835, 13890 => 22581, 13891 => 30585, 13892 => 36172, 13893 => 26460, 13894 => 38208, 13895 => 32922, 13896 => 24230, 13897 => 28193, 13898 => 22930, 13899 => 31471, 13900 => 30701, 13901 => 38203, 13902 => 27573, 13903 => 26029, 13904 => 32526, 13905 => 22534, 13906 => 20817, 13907 => 38431, 13908 => 23545, 13909 => 22697, 13910 => 21544, 13911 => 36466, 13912 => 25958, 13913 => 39039, 13914 => 22244, 13915 => 38045, 13916 => 30462, 13917 => 36929, 13918 => 25479, 13919 => 21702, 13920 => 22810, 13921 => 22842, 13922 => 22427, 13923 => 36530, 13924 => 26421, 13925 => 36346, 13926 => 33333, 13927 => 21057, 13928 => 24816, 13929 => 22549, 13930 => 34558, 13931 => 23784, 13932 => 40517, 13933 => 20420, 13934 => 39069, 13935 => 35769, 13936 => 23077, 13937 => 24694, 13938 => 21380, 13939 => 25212, 13940 => 36943, 13941 => 37122, 13942 => 39295, 13943 => 24681, 13944 => 32780, 13945 => 20799, 13946 => 32819, 13947 => 23572, 13948 => 39285, 13949 => 27953, 13950 => 20108, 14113 => 36144, 14114 => 21457, 14115 => 32602, 14116 => 31567, 14117 => 20240, 14118 => 20047, 14119 => 38400, 14120 => 27861, 14121 => 29648, 14122 => 34281, 14123 => 24070, 14124 => 30058, 14125 => 32763, 14126 => 27146, 14127 => 30718, 14128 => 38034, 14129 => 32321, 14130 => 20961, 14131 => 28902, 14132 => 21453, 14133 => 36820, 14134 => 33539, 14135 => 36137, 14136 => 29359, 14137 => 39277, 14138 => 27867, 14139 => 22346, 14140 => 33459, 14141 => 26041, 14142 => 32938, 14143 => 25151, 14144 => 38450, 14145 => 22952, 14146 => 20223, 14147 => 35775, 14148 => 32442, 14149 => 25918, 14150 => 33778, 14151 => 38750, 14152 => 21857, 14153 => 39134, 14154 => 32933, 14155 => 21290, 14156 => 35837, 14157 => 21536, 14158 => 32954, 14159 => 24223, 14160 => 27832, 14161 => 36153, 14162 => 33452, 14163 => 37210, 14164 => 21545, 14165 => 27675, 14166 => 20998, 14167 => 32439, 14168 => 22367, 14169 => 28954, 14170 => 27774, 14171 => 31881, 14172 => 22859, 14173 => 20221, 14174 => 24575, 14175 => 24868, 14176 => 31914, 14177 => 20016, 14178 => 23553, 14179 => 26539, 14180 => 34562, 14181 => 23792, 14182 => 38155, 14183 => 39118, 14184 => 30127, 14185 => 28925, 14186 => 36898, 14187 => 20911, 14188 => 32541, 14189 => 35773, 14190 => 22857, 14191 => 20964, 14192 => 20315, 14193 => 21542, 14194 => 22827, 14195 => 25975, 14196 => 32932, 14197 => 23413, 14198 => 25206, 14199 => 25282, 14200 => 36752, 14201 => 24133, 14202 => 27679, 14203 => 31526, 14204 => 20239, 14205 => 20440, 14206 => 26381, 14369 => 28014, 14370 => 28074, 14371 => 31119, 14372 => 34993, 14373 => 24343, 14374 => 29995, 14375 => 25242, 14376 => 36741, 14377 => 20463, 14378 => 37340, 14379 => 26023, 14380 => 33071, 14381 => 33105, 14382 => 24220, 14383 => 33104, 14384 => 36212, 14385 => 21103, 14386 => 35206, 14387 => 36171, 14388 => 22797, 14389 => 20613, 14390 => 20184, 14391 => 38428, 14392 => 29238, 14393 => 33145, 14394 => 36127, 14395 => 23500, 14396 => 35747, 14397 => 38468, 14398 => 22919, 14399 => 32538, 14400 => 21648, 14401 => 22134, 14402 => 22030, 14403 => 35813, 14404 => 25913, 14405 => 27010, 14406 => 38041, 14407 => 30422, 14408 => 28297, 14409 => 24178, 14410 => 29976, 14411 => 26438, 14412 => 26577, 14413 => 31487, 14414 => 32925, 14415 => 36214, 14416 => 24863, 14417 => 31174, 14418 => 25954, 14419 => 36195, 14420 => 20872, 14421 => 21018, 14422 => 38050, 14423 => 32568, 14424 => 32923, 14425 => 32434, 14426 => 23703, 14427 => 28207, 14428 => 26464, 14429 => 31705, 14430 => 30347, 14431 => 39640, 14432 => 33167, 14433 => 32660, 14434 => 31957, 14435 => 25630, 14436 => 38224, 14437 => 31295, 14438 => 21578, 14439 => 21733, 14440 => 27468, 14441 => 25601, 14442 => 25096, 14443 => 40509, 14444 => 33011, 14445 => 30105, 14446 => 21106, 14447 => 38761, 14448 => 33883, 14449 => 26684, 14450 => 34532, 14451 => 38401, 14452 => 38548, 14453 => 38124, 14454 => 20010, 14455 => 21508, 14456 => 32473, 14457 => 26681, 14458 => 36319, 14459 => 32789, 14460 => 26356, 14461 => 24218, 14462 => 32697, 14625 => 22466, 14626 => 32831, 14627 => 26775, 14628 => 24037, 14629 => 25915, 14630 => 21151, 14631 => 24685, 14632 => 40858, 14633 => 20379, 14634 => 36524, 14635 => 20844, 14636 => 23467, 14637 => 24339, 14638 => 24041, 14639 => 27742, 14640 => 25329, 14641 => 36129, 14642 => 20849, 14643 => 38057, 14644 => 21246, 14645 => 27807, 14646 => 33503, 14647 => 29399, 14648 => 22434, 14649 => 26500, 14650 => 36141, 14651 => 22815, 14652 => 36764, 14653 => 33735, 14654 => 21653, 14655 => 31629, 14656 => 20272, 14657 => 27837, 14658 => 23396, 14659 => 22993, 14660 => 40723, 14661 => 21476, 14662 => 34506, 14663 => 39592, 14664 => 35895, 14665 => 32929, 14666 => 25925, 14667 => 39038, 14668 => 22266, 14669 => 38599, 14670 => 21038, 14671 => 29916, 14672 => 21072, 14673 => 23521, 14674 => 25346, 14675 => 35074, 14676 => 20054, 14677 => 25296, 14678 => 24618, 14679 => 26874, 14680 => 20851, 14681 => 23448, 14682 => 20896, 14683 => 35266, 14684 => 31649, 14685 => 39302, 14686 => 32592, 14687 => 24815, 14688 => 28748, 14689 => 36143, 14690 => 20809, 14691 => 24191, 14692 => 36891, 14693 => 29808, 14694 => 35268, 14695 => 22317, 14696 => 30789, 14697 => 24402, 14698 => 40863, 14699 => 38394, 14700 => 36712, 14701 => 39740, 14702 => 35809, 14703 => 30328, 14704 => 26690, 14705 => 26588, 14706 => 36330, 14707 => 36149, 14708 => 21053, 14709 => 36746, 14710 => 28378, 14711 => 26829, 14712 => 38149, 14713 => 37101, 14714 => 22269, 14715 => 26524, 14716 => 35065, 14717 => 36807, 14718 => 21704, 14881 => 39608, 14882 => 23401, 14883 => 28023, 14884 => 27686, 14885 => 20133, 14886 => 23475, 14887 => 39559, 14888 => 37219, 14889 => 25000, 14890 => 37039, 14891 => 38889, 14892 => 21547, 14893 => 28085, 14894 => 23506, 14895 => 20989, 14896 => 21898, 14897 => 32597, 14898 => 32752, 14899 => 25788, 14900 => 25421, 14901 => 26097, 14902 => 25022, 14903 => 24717, 14904 => 28938, 14905 => 27735, 14906 => 27721, 14907 => 22831, 14908 => 26477, 14909 => 33322, 14910 => 22741, 14911 => 22158, 14912 => 35946, 14913 => 27627, 14914 => 37085, 14915 => 22909, 14916 => 32791, 14917 => 21495, 14918 => 28009, 14919 => 21621, 14920 => 21917, 14921 => 33655, 14922 => 33743, 14923 => 26680, 14924 => 31166, 14925 => 21644, 14926 => 20309, 14927 => 21512, 14928 => 30418, 14929 => 35977, 14930 => 38402, 14931 => 27827, 14932 => 28088, 14933 => 36203, 14934 => 35088, 14935 => 40548, 14936 => 36154, 14937 => 22079, 14938 => 40657, 14939 => 30165, 14940 => 24456, 14941 => 29408, 14942 => 24680, 14943 => 21756, 14944 => 20136, 14945 => 27178, 14946 => 34913, 14947 => 24658, 14948 => 36720, 14949 => 21700, 14950 => 28888, 14951 => 34425, 14952 => 40511, 14953 => 27946, 14954 => 23439, 14955 => 24344, 14956 => 32418, 14957 => 21897, 14958 => 20399, 14959 => 29492, 14960 => 21564, 14961 => 21402, 14962 => 20505, 14963 => 21518, 14964 => 21628, 14965 => 20046, 14966 => 24573, 14967 => 29786, 14968 => 22774, 14969 => 33899, 14970 => 32993, 14971 => 34676, 14972 => 29392, 14973 => 31946, 14974 => 28246, 15137 => 24359, 15138 => 34382, 15139 => 21804, 15140 => 25252, 15141 => 20114, 15142 => 27818, 15143 => 25143, 15144 => 33457, 15145 => 21719, 15146 => 21326, 15147 => 29502, 15148 => 28369, 15149 => 30011, 15150 => 21010, 15151 => 21270, 15152 => 35805, 15153 => 27088, 15154 => 24458, 15155 => 24576, 15156 => 28142, 15157 => 22351, 15158 => 27426, 15159 => 29615, 15160 => 26707, 15161 => 36824, 15162 => 32531, 15163 => 25442, 15164 => 24739, 15165 => 21796, 15166 => 30186, 15167 => 35938, 15168 => 28949, 15169 => 28067, 15170 => 23462, 15171 => 24187, 15172 => 33618, 15173 => 24908, 15174 => 40644, 15175 => 30970, 15176 => 34647, 15177 => 31783, 15178 => 30343, 15179 => 20976, 15180 => 24822, 15181 => 29004, 15182 => 26179, 15183 => 24140, 15184 => 24653, 15185 => 35854, 15186 => 28784, 15187 => 25381, 15188 => 36745, 15189 => 24509, 15190 => 24674, 15191 => 34516, 15192 => 22238, 15193 => 27585, 15194 => 24724, 15195 => 24935, 15196 => 21321, 15197 => 24800, 15198 => 26214, 15199 => 36159, 15200 => 31229, 15201 => 20250, 15202 => 28905, 15203 => 27719, 15204 => 35763, 15205 => 35826, 15206 => 32472, 15207 => 33636, 15208 => 26127, 15209 => 23130, 15210 => 39746, 15211 => 27985, 15212 => 28151, 15213 => 35905, 15214 => 27963, 15215 => 20249, 15216 => 28779, 15217 => 33719, 15218 => 25110, 15219 => 24785, 15220 => 38669, 15221 => 36135, 15222 => 31096, 15223 => 20987, 15224 => 22334, 15225 => 22522, 15226 => 26426, 15227 => 30072, 15228 => 31293, 15229 => 31215, 15230 => 31637, 15393 => 32908, 15394 => 39269, 15395 => 36857, 15396 => 28608, 15397 => 35749, 15398 => 40481, 15399 => 23020, 15400 => 32489, 15401 => 32521, 15402 => 21513, 15403 => 26497, 15404 => 26840, 15405 => 36753, 15406 => 31821, 15407 => 38598, 15408 => 21450, 15409 => 24613, 15410 => 30142, 15411 => 27762, 15412 => 21363, 15413 => 23241, 15414 => 32423, 15415 => 25380, 15416 => 20960, 15417 => 33034, 15418 => 24049, 15419 => 34015, 15420 => 25216, 15421 => 20864, 15422 => 23395, 15423 => 20238, 15424 => 31085, 15425 => 21058, 15426 => 24760, 15427 => 27982, 15428 => 23492, 15429 => 23490, 15430 => 35745, 15431 => 35760, 15432 => 26082, 15433 => 24524, 15434 => 38469, 15435 => 22931, 15436 => 32487, 15437 => 32426, 15438 => 22025, 15439 => 26551, 15440 => 22841, 15441 => 20339, 15442 => 23478, 15443 => 21152, 15444 => 33626, 15445 => 39050, 15446 => 36158, 15447 => 30002, 15448 => 38078, 15449 => 20551, 15450 => 31292, 15451 => 20215, 15452 => 26550, 15453 => 39550, 15454 => 23233, 15455 => 27516, 15456 => 30417, 15457 => 22362, 15458 => 23574, 15459 => 31546, 15460 => 38388, 15461 => 29006, 15462 => 20860, 15463 => 32937, 15464 => 33392, 15465 => 22904, 15466 => 32516, 15467 => 33575, 15468 => 26816, 15469 => 26604, 15470 => 30897, 15471 => 30839, 15472 => 25315, 15473 => 25441, 15474 => 31616, 15475 => 20461, 15476 => 21098, 15477 => 20943, 15478 => 33616, 15479 => 27099, 15480 => 37492, 15481 => 36341, 15482 => 36145, 15483 => 35265, 15484 => 38190, 15485 => 31661, 15486 => 20214, 15649 => 20581, 15650 => 33328, 15651 => 21073, 15652 => 39279, 15653 => 28176, 15654 => 28293, 15655 => 28071, 15656 => 24314, 15657 => 20725, 15658 => 23004, 15659 => 23558, 15660 => 27974, 15661 => 27743, 15662 => 30086, 15663 => 33931, 15664 => 26728, 15665 => 22870, 15666 => 35762, 15667 => 21280, 15668 => 37233, 15669 => 38477, 15670 => 34121, 15671 => 26898, 15672 => 30977, 15673 => 28966, 15674 => 33014, 15675 => 20132, 15676 => 37066, 15677 => 27975, 15678 => 39556, 15679 => 23047, 15680 => 22204, 15681 => 25605, 15682 => 38128, 15683 => 30699, 15684 => 20389, 15685 => 33050, 15686 => 29409, 15687 => 35282, 15688 => 39290, 15689 => 32564, 15690 => 32478, 15691 => 21119, 15692 => 25945, 15693 => 37237, 15694 => 36735, 15695 => 36739, 15696 => 21483, 15697 => 31382, 15698 => 25581, 15699 => 25509, 15700 => 30342, 15701 => 31224, 15702 => 34903, 15703 => 38454, 15704 => 25130, 15705 => 21163, 15706 => 33410, 15707 => 26708, 15708 => 26480, 15709 => 25463, 15710 => 30571, 15711 => 31469, 15712 => 27905, 15713 => 32467, 15714 => 35299, 15715 => 22992, 15716 => 25106, 15717 => 34249, 15718 => 33445, 15719 => 30028, 15720 => 20511, 15721 => 20171, 15722 => 30117, 15723 => 35819, 15724 => 23626, 15725 => 24062, 15726 => 31563, 15727 => 26020, 15728 => 37329, 15729 => 20170, 15730 => 27941, 15731 => 35167, 15732 => 32039, 15733 => 38182, 15734 => 20165, 15735 => 35880, 15736 => 36827, 15737 => 38771, 15738 => 26187, 15739 => 31105, 15740 => 36817, 15741 => 28908, 15742 => 28024, 15905 => 23613, 15906 => 21170, 15907 => 33606, 15908 => 20834, 15909 => 33550, 15910 => 30555, 15911 => 26230, 15912 => 40120, 15913 => 20140, 15914 => 24778, 15915 => 31934, 15916 => 31923, 15917 => 32463, 15918 => 20117, 15919 => 35686, 15920 => 26223, 15921 => 39048, 15922 => 38745, 15923 => 22659, 15924 => 25964, 15925 => 38236, 15926 => 24452, 15927 => 30153, 15928 => 38742, 15929 => 31455, 15930 => 31454, 15931 => 20928, 15932 => 28847, 15933 => 31384, 15934 => 25578, 15935 => 31350, 15936 => 32416, 15937 => 29590, 15938 => 38893, 15939 => 20037, 15940 => 28792, 15941 => 20061, 15942 => 37202, 15943 => 21417, 15944 => 25937, 15945 => 26087, 15946 => 33276, 15947 => 33285, 15948 => 21646, 15949 => 23601, 15950 => 30106, 15951 => 38816, 15952 => 25304, 15953 => 29401, 15954 => 30141, 15955 => 23621, 15956 => 39545, 15957 => 33738, 15958 => 23616, 15959 => 21632, 15960 => 30697, 15961 => 20030, 15962 => 27822, 15963 => 32858, 15964 => 25298, 15965 => 25454, 15966 => 24040, 15967 => 20855, 15968 => 36317, 15969 => 36382, 15970 => 38191, 15971 => 20465, 15972 => 21477, 15973 => 24807, 15974 => 28844, 15975 => 21095, 15976 => 25424, 15977 => 40515, 15978 => 23071, 15979 => 20518, 15980 => 30519, 15981 => 21367, 15982 => 32482, 15983 => 25733, 15984 => 25899, 15985 => 25225, 15986 => 25496, 15987 => 20500, 15988 => 29237, 15989 => 35273, 15990 => 20915, 15991 => 35776, 15992 => 32477, 15993 => 22343, 15994 => 33740, 15995 => 38055, 15996 => 20891, 15997 => 21531, 15998 => 23803, 16161 => 20426, 16162 => 31459, 16163 => 27994, 16164 => 37089, 16165 => 39567, 16166 => 21888, 16167 => 21654, 16168 => 21345, 16169 => 21679, 16170 => 24320, 16171 => 25577, 16172 => 26999, 16173 => 20975, 16174 => 24936, 16175 => 21002, 16176 => 22570, 16177 => 21208, 16178 => 22350, 16179 => 30733, 16180 => 30475, 16181 => 24247, 16182 => 24951, 16183 => 31968, 16184 => 25179, 16185 => 25239, 16186 => 20130, 16187 => 28821, 16188 => 32771, 16189 => 25335, 16190 => 28900, 16191 => 38752, 16192 => 22391, 16193 => 33499, 16194 => 26607, 16195 => 26869, 16196 => 30933, 16197 => 39063, 16198 => 31185, 16199 => 22771, 16200 => 21683, 16201 => 21487, 16202 => 28212, 16203 => 20811, 16204 => 21051, 16205 => 23458, 16206 => 35838, 16207 => 32943, 16208 => 21827, 16209 => 22438, 16210 => 24691, 16211 => 22353, 16212 => 21549, 16213 => 31354, 16214 => 24656, 16215 => 23380, 16216 => 25511, 16217 => 25248, 16218 => 21475, 16219 => 25187, 16220 => 23495, 16221 => 26543, 16222 => 21741, 16223 => 31391, 16224 => 33510, 16225 => 37239, 16226 => 24211, 16227 => 35044, 16228 => 22840, 16229 => 22446, 16230 => 25358, 16231 => 36328, 16232 => 33007, 16233 => 22359, 16234 => 31607, 16235 => 20393, 16236 => 24555, 16237 => 23485, 16238 => 27454, 16239 => 21281, 16240 => 31568, 16241 => 29378, 16242 => 26694, 16243 => 30719, 16244 => 30518, 16245 => 26103, 16246 => 20917, 16247 => 20111, 16248 => 30420, 16249 => 23743, 16250 => 31397, 16251 => 33909, 16252 => 22862, 16253 => 39745, 16254 => 20608, 16417 => 39304, 16418 => 24871, 16419 => 28291, 16420 => 22372, 16421 => 26118, 16422 => 25414, 16423 => 22256, 16424 => 25324, 16425 => 25193, 16426 => 24275, 16427 => 38420, 16428 => 22403, 16429 => 25289, 16430 => 21895, 16431 => 34593, 16432 => 33098, 16433 => 36771, 16434 => 21862, 16435 => 33713, 16436 => 26469, 16437 => 36182, 16438 => 34013, 16439 => 23146, 16440 => 26639, 16441 => 25318, 16442 => 31726, 16443 => 38417, 16444 => 20848, 16445 => 28572, 16446 => 35888, 16447 => 25597, 16448 => 35272, 16449 => 25042, 16450 => 32518, 16451 => 28866, 16452 => 28389, 16453 => 29701, 16454 => 27028, 16455 => 29436, 16456 => 24266, 16457 => 37070, 16458 => 26391, 16459 => 28010, 16460 => 25438, 16461 => 21171, 16462 => 29282, 16463 => 32769, 16464 => 20332, 16465 => 23013, 16466 => 37226, 16467 => 28889, 16468 => 28061, 16469 => 21202, 16470 => 20048, 16471 => 38647, 16472 => 38253, 16473 => 34174, 16474 => 30922, 16475 => 32047, 16476 => 20769, 16477 => 22418, 16478 => 25794, 16479 => 32907, 16480 => 31867, 16481 => 27882, 16482 => 26865, 16483 => 26974, 16484 => 20919, 16485 => 21400, 16486 => 26792, 16487 => 29313, 16488 => 40654, 16489 => 31729, 16490 => 29432, 16491 => 31163, 16492 => 28435, 16493 => 29702, 16494 => 26446, 16495 => 37324, 16496 => 40100, 16497 => 31036, 16498 => 33673, 16499 => 33620, 16500 => 21519, 16501 => 26647, 16502 => 20029, 16503 => 21385, 16504 => 21169, 16505 => 30782, 16506 => 21382, 16507 => 21033, 16508 => 20616, 16509 => 20363, 16510 => 20432, 16673 => 30178, 16674 => 31435, 16675 => 31890, 16676 => 27813, 16677 => 38582, 16678 => 21147, 16679 => 29827, 16680 => 21737, 16681 => 20457, 16682 => 32852, 16683 => 33714, 16684 => 36830, 16685 => 38256, 16686 => 24265, 16687 => 24604, 16688 => 28063, 16689 => 24088, 16690 => 25947, 16691 => 33080, 16692 => 38142, 16693 => 24651, 16694 => 28860, 16695 => 32451, 16696 => 31918, 16697 => 20937, 16698 => 26753, 16699 => 31921, 16700 => 33391, 16701 => 20004, 16702 => 36742, 16703 => 37327, 16704 => 26238, 16705 => 20142, 16706 => 35845, 16707 => 25769, 16708 => 32842, 16709 => 20698, 16710 => 30103, 16711 => 29134, 16712 => 23525, 16713 => 36797, 16714 => 28518, 16715 => 20102, 16716 => 25730, 16717 => 38243, 16718 => 24278, 16719 => 26009, 16720 => 21015, 16721 => 35010, 16722 => 28872, 16723 => 21155, 16724 => 29454, 16725 => 29747, 16726 => 26519, 16727 => 30967, 16728 => 38678, 16729 => 20020, 16730 => 37051, 16731 => 40158, 16732 => 28107, 16733 => 20955, 16734 => 36161, 16735 => 21533, 16736 => 25294, 16737 => 29618, 16738 => 33777, 16739 => 38646, 16740 => 40836, 16741 => 38083, 16742 => 20278, 16743 => 32666, 16744 => 20940, 16745 => 28789, 16746 => 38517, 16747 => 23725, 16748 => 39046, 16749 => 21478, 16750 => 20196, 16751 => 28316, 16752 => 29705, 16753 => 27060, 16754 => 30827, 16755 => 39311, 16756 => 30041, 16757 => 21016, 16758 => 30244, 16759 => 27969, 16760 => 26611, 16761 => 20845, 16762 => 40857, 16763 => 32843, 16764 => 21657, 16765 => 31548, 16766 => 31423, 16929 => 38534, 16930 => 22404, 16931 => 25314, 16932 => 38471, 16933 => 27004, 16934 => 23044, 16935 => 25602, 16936 => 31699, 16937 => 28431, 16938 => 38475, 16939 => 33446, 16940 => 21346, 16941 => 39045, 16942 => 24208, 16943 => 28809, 16944 => 25523, 16945 => 21348, 16946 => 34383, 16947 => 40065, 16948 => 40595, 16949 => 30860, 16950 => 38706, 16951 => 36335, 16952 => 36162, 16953 => 40575, 16954 => 28510, 16955 => 31108, 16956 => 24405, 16957 => 38470, 16958 => 25134, 16959 => 39540, 16960 => 21525, 16961 => 38109, 16962 => 20387, 16963 => 26053, 16964 => 23653, 16965 => 23649, 16966 => 32533, 16967 => 34385, 16968 => 27695, 16969 => 24459, 16970 => 29575, 16971 => 28388, 16972 => 32511, 16973 => 23782, 16974 => 25371, 16975 => 23402, 16976 => 28390, 16977 => 21365, 16978 => 20081, 16979 => 25504, 16980 => 30053, 16981 => 25249, 16982 => 36718, 16983 => 20262, 16984 => 20177, 16985 => 27814, 16986 => 32438, 16987 => 35770, 16988 => 33821, 16989 => 34746, 16990 => 32599, 16991 => 36923, 16992 => 38179, 16993 => 31657, 16994 => 39585, 16995 => 35064, 16996 => 33853, 16997 => 27931, 16998 => 39558, 16999 => 32476, 17000 => 22920, 17001 => 40635, 17002 => 29595, 17003 => 30721, 17004 => 34434, 17005 => 39532, 17006 => 39554, 17007 => 22043, 17008 => 21527, 17009 => 22475, 17010 => 20080, 17011 => 40614, 17012 => 21334, 17013 => 36808, 17014 => 33033, 17015 => 30610, 17016 => 39314, 17017 => 34542, 17018 => 28385, 17019 => 34067, 17020 => 26364, 17021 => 24930, 17022 => 28459, 17185 => 35881, 17186 => 33426, 17187 => 33579, 17188 => 30450, 17189 => 27667, 17190 => 24537, 17191 => 33725, 17192 => 29483, 17193 => 33541, 17194 => 38170, 17195 => 27611, 17196 => 30683, 17197 => 38086, 17198 => 21359, 17199 => 33538, 17200 => 20882, 17201 => 24125, 17202 => 35980, 17203 => 36152, 17204 => 20040, 17205 => 29611, 17206 => 26522, 17207 => 26757, 17208 => 37238, 17209 => 38665, 17210 => 29028, 17211 => 27809, 17212 => 30473, 17213 => 23186, 17214 => 38209, 17215 => 27599, 17216 => 32654, 17217 => 26151, 17218 => 23504, 17219 => 22969, 17220 => 23194, 17221 => 38376, 17222 => 38391, 17223 => 20204, 17224 => 33804, 17225 => 33945, 17226 => 27308, 17227 => 30431, 17228 => 38192, 17229 => 29467, 17230 => 26790, 17231 => 23391, 17232 => 30511, 17233 => 37274, 17234 => 38753, 17235 => 31964, 17236 => 36855, 17237 => 35868, 17238 => 24357, 17239 => 31859, 17240 => 31192, 17241 => 35269, 17242 => 27852, 17243 => 34588, 17244 => 23494, 17245 => 24130, 17246 => 26825, 17247 => 30496, 17248 => 32501, 17249 => 20885, 17250 => 20813, 17251 => 21193, 17252 => 23081, 17253 => 32517, 17254 => 38754, 17255 => 33495, 17256 => 25551, 17257 => 30596, 17258 => 34256, 17259 => 31186, 17260 => 28218, 17261 => 24217, 17262 => 22937, 17263 => 34065, 17264 => 28781, 17265 => 27665, 17266 => 25279, 17267 => 30399, 17268 => 25935, 17269 => 24751, 17270 => 38397, 17271 => 26126, 17272 => 34719, 17273 => 40483, 17274 => 38125, 17275 => 21517, 17276 => 21629, 17277 => 35884, 17278 => 25720, 17441 => 25721, 17442 => 34321, 17443 => 27169, 17444 => 33180, 17445 => 30952, 17446 => 25705, 17447 => 39764, 17448 => 25273, 17449 => 26411, 17450 => 33707, 17451 => 22696, 17452 => 40664, 17453 => 27819, 17454 => 28448, 17455 => 23518, 17456 => 38476, 17457 => 35851, 17458 => 29279, 17459 => 26576, 17460 => 25287, 17461 => 29281, 17462 => 20137, 17463 => 22982, 17464 => 27597, 17465 => 22675, 17466 => 26286, 17467 => 24149, 17468 => 21215, 17469 => 24917, 17470 => 26408, 17471 => 30446, 17472 => 30566, 17473 => 29287, 17474 => 31302, 17475 => 25343, 17476 => 21738, 17477 => 21584, 17478 => 38048, 17479 => 37027, 17480 => 23068, 17481 => 32435, 17482 => 27670, 17483 => 20035, 17484 => 22902, 17485 => 32784, 17486 => 22856, 17487 => 21335, 17488 => 30007, 17489 => 38590, 17490 => 22218, 17491 => 25376, 17492 => 33041, 17493 => 24700, 17494 => 38393, 17495 => 28118, 17496 => 21602, 17497 => 39297, 17498 => 20869, 17499 => 23273, 17500 => 33021, 17501 => 22958, 17502 => 38675, 17503 => 20522, 17504 => 27877, 17505 => 23612, 17506 => 25311, 17507 => 20320, 17508 => 21311, 17509 => 33147, 17510 => 36870, 17511 => 28346, 17512 => 34091, 17513 => 25288, 17514 => 24180, 17515 => 30910, 17516 => 25781, 17517 => 25467, 17518 => 24565, 17519 => 23064, 17520 => 37247, 17521 => 40479, 17522 => 23615, 17523 => 25423, 17524 => 32834, 17525 => 23421, 17526 => 21870, 17527 => 38218, 17528 => 38221, 17529 => 28037, 17530 => 24744, 17531 => 26592, 17532 => 29406, 17533 => 20957, 17534 => 23425, 17697 => 25319, 17698 => 27870, 17699 => 29275, 17700 => 25197, 17701 => 38062, 17702 => 32445, 17703 => 33043, 17704 => 27987, 17705 => 20892, 17706 => 24324, 17707 => 22900, 17708 => 21162, 17709 => 24594, 17710 => 22899, 17711 => 26262, 17712 => 34384, 17713 => 30111, 17714 => 25386, 17715 => 25062, 17716 => 31983, 17717 => 35834, 17718 => 21734, 17719 => 27431, 17720 => 40485, 17721 => 27572, 17722 => 34261, 17723 => 21589, 17724 => 20598, 17725 => 27812, 17726 => 21866, 17727 => 36276, 17728 => 29228, 17729 => 24085, 17730 => 24597, 17731 => 29750, 17732 => 25293, 17733 => 25490, 17734 => 29260, 17735 => 24472, 17736 => 28227, 17737 => 27966, 17738 => 25856, 17739 => 28504, 17740 => 30424, 17741 => 30928, 17742 => 30460, 17743 => 30036, 17744 => 21028, 17745 => 21467, 17746 => 20051, 17747 => 24222, 17748 => 26049, 17749 => 32810, 17750 => 32982, 17751 => 25243, 17752 => 21638, 17753 => 21032, 17754 => 28846, 17755 => 34957, 17756 => 36305, 17757 => 27873, 17758 => 21624, 17759 => 32986, 17760 => 22521, 17761 => 35060, 17762 => 36180, 17763 => 38506, 17764 => 37197, 17765 => 20329, 17766 => 27803, 17767 => 21943, 17768 => 30406, 17769 => 30768, 17770 => 25256, 17771 => 28921, 17772 => 28558, 17773 => 24429, 17774 => 34028, 17775 => 26842, 17776 => 30844, 17777 => 31735, 17778 => 33192, 17779 => 26379, 17780 => 40527, 17781 => 25447, 17782 => 30896, 17783 => 22383, 17784 => 30738, 17785 => 38713, 17786 => 25209, 17787 => 25259, 17788 => 21128, 17789 => 29749, 17790 => 27607, 17953 => 21860, 17954 => 33086, 17955 => 30130, 17956 => 30382, 17957 => 21305, 17958 => 30174, 17959 => 20731, 17960 => 23617, 17961 => 35692, 17962 => 31687, 17963 => 20559, 17964 => 29255, 17965 => 39575, 17966 => 39128, 17967 => 28418, 17968 => 29922, 17969 => 31080, 17970 => 25735, 17971 => 30629, 17972 => 25340, 17973 => 39057, 17974 => 36139, 17975 => 21697, 17976 => 32856, 17977 => 20050, 17978 => 22378, 17979 => 33529, 17980 => 33805, 17981 => 24179, 17982 => 20973, 17983 => 29942, 17984 => 35780, 17985 => 23631, 17986 => 22369, 17987 => 27900, 17988 => 39047, 17989 => 23110, 17990 => 30772, 17991 => 39748, 17992 => 36843, 17993 => 31893, 17994 => 21078, 17995 => 25169, 17996 => 38138, 17997 => 20166, 17998 => 33670, 17999 => 33889, 18000 => 33769, 18001 => 33970, 18002 => 22484, 18003 => 26420, 18004 => 22275, 18005 => 26222, 18006 => 28006, 18007 => 35889, 18008 => 26333, 18009 => 28689, 18010 => 26399, 18011 => 27450, 18012 => 26646, 18013 => 25114, 18014 => 22971, 18015 => 19971, 18016 => 20932, 18017 => 28422, 18018 => 26578, 18019 => 27791, 18020 => 20854, 18021 => 26827, 18022 => 22855, 18023 => 27495, 18024 => 30054, 18025 => 23822, 18026 => 33040, 18027 => 40784, 18028 => 26071, 18029 => 31048, 18030 => 31041, 18031 => 39569, 18032 => 36215, 18033 => 23682, 18034 => 20062, 18035 => 20225, 18036 => 21551, 18037 => 22865, 18038 => 30732, 18039 => 22120, 18040 => 27668, 18041 => 36804, 18042 => 24323, 18043 => 27773, 18044 => 27875, 18045 => 35755, 18046 => 25488, 18209 => 24688, 18210 => 27965, 18211 => 29301, 18212 => 25190, 18213 => 38030, 18214 => 38085, 18215 => 21315, 18216 => 36801, 18217 => 31614, 18218 => 20191, 18219 => 35878, 18220 => 20094, 18221 => 40660, 18222 => 38065, 18223 => 38067, 18224 => 21069, 18225 => 28508, 18226 => 36963, 18227 => 27973, 18228 => 35892, 18229 => 22545, 18230 => 23884, 18231 => 27424, 18232 => 27465, 18233 => 26538, 18234 => 21595, 18235 => 33108, 18236 => 32652, 18237 => 22681, 18238 => 34103, 18239 => 24378, 18240 => 25250, 18241 => 27207, 18242 => 38201, 18243 => 25970, 18244 => 24708, 18245 => 26725, 18246 => 30631, 18247 => 20052, 18248 => 20392, 18249 => 24039, 18250 => 38808, 18251 => 25772, 18252 => 32728, 18253 => 23789, 18254 => 20431, 18255 => 31373, 18256 => 20999, 18257 => 33540, 18258 => 19988, 18259 => 24623, 18260 => 31363, 18261 => 38054, 18262 => 20405, 18263 => 20146, 18264 => 31206, 18265 => 29748, 18266 => 21220, 18267 => 33465, 18268 => 25810, 18269 => 31165, 18270 => 23517, 18271 => 27777, 18272 => 38738, 18273 => 36731, 18274 => 27682, 18275 => 20542, 18276 => 21375, 18277 => 28165, 18278 => 25806, 18279 => 26228, 18280 => 27696, 18281 => 24773, 18282 => 39031, 18283 => 35831, 18284 => 24198, 18285 => 29756, 18286 => 31351, 18287 => 31179, 18288 => 19992, 18289 => 37041, 18290 => 29699, 18291 => 27714, 18292 => 22234, 18293 => 37195, 18294 => 27845, 18295 => 36235, 18296 => 21306, 18297 => 34502, 18298 => 26354, 18299 => 36527, 18300 => 23624, 18301 => 39537, 18302 => 28192, 18465 => 21462, 18466 => 23094, 18467 => 40843, 18468 => 36259, 18469 => 21435, 18470 => 22280, 18471 => 39079, 18472 => 26435, 18473 => 37275, 18474 => 27849, 18475 => 20840, 18476 => 30154, 18477 => 25331, 18478 => 29356, 18479 => 21048, 18480 => 21149, 18481 => 32570, 18482 => 28820, 18483 => 30264, 18484 => 21364, 18485 => 40522, 18486 => 27063, 18487 => 30830, 18488 => 38592, 18489 => 35033, 18490 => 32676, 18491 => 28982, 18492 => 29123, 18493 => 20873, 18494 => 26579, 18495 => 29924, 18496 => 22756, 18497 => 25880, 18498 => 22199, 18499 => 35753, 18500 => 39286, 18501 => 25200, 18502 => 32469, 18503 => 24825, 18504 => 28909, 18505 => 22764, 18506 => 20161, 18507 => 20154, 18508 => 24525, 18509 => 38887, 18510 => 20219, 18511 => 35748, 18512 => 20995, 18513 => 22922, 18514 => 32427, 18515 => 25172, 18516 => 20173, 18517 => 26085, 18518 => 25102, 18519 => 33592, 18520 => 33993, 18521 => 33635, 18522 => 34701, 18523 => 29076, 18524 => 28342, 18525 => 23481, 18526 => 32466, 18527 => 20887, 18528 => 25545, 18529 => 26580, 18530 => 32905, 18531 => 33593, 18532 => 34837, 18533 => 20754, 18534 => 23418, 18535 => 22914, 18536 => 36785, 18537 => 20083, 18538 => 27741, 18539 => 20837, 18540 => 35109, 18541 => 36719, 18542 => 38446, 18543 => 34122, 18544 => 29790, 18545 => 38160, 18546 => 38384, 18547 => 28070, 18548 => 33509, 18549 => 24369, 18550 => 25746, 18551 => 27922, 18552 => 33832, 18553 => 33134, 18554 => 40131, 18555 => 22622, 18556 => 36187, 18557 => 19977, 18558 => 21441, 18721 => 20254, 18722 => 25955, 18723 => 26705, 18724 => 21971, 18725 => 20007, 18726 => 25620, 18727 => 39578, 18728 => 25195, 18729 => 23234, 18730 => 29791, 18731 => 33394, 18732 => 28073, 18733 => 26862, 18734 => 20711, 18735 => 33678, 18736 => 30722, 18737 => 26432, 18738 => 21049, 18739 => 27801, 18740 => 32433, 18741 => 20667, 18742 => 21861, 18743 => 29022, 18744 => 31579, 18745 => 26194, 18746 => 29642, 18747 => 33515, 18748 => 26441, 18749 => 23665, 18750 => 21024, 18751 => 29053, 18752 => 34923, 18753 => 38378, 18754 => 38485, 18755 => 25797, 18756 => 36193, 18757 => 33203, 18758 => 21892, 18759 => 27733, 18760 => 25159, 18761 => 32558, 18762 => 22674, 18763 => 20260, 18764 => 21830, 18765 => 36175, 18766 => 26188, 18767 => 19978, 18768 => 23578, 18769 => 35059, 18770 => 26786, 18771 => 25422, 18772 => 31245, 18773 => 28903, 18774 => 33421, 18775 => 21242, 18776 => 38902, 18777 => 23569, 18778 => 21736, 18779 => 37045, 18780 => 32461, 18781 => 22882, 18782 => 36170, 18783 => 34503, 18784 => 33292, 18785 => 33293, 18786 => 36198, 18787 => 25668, 18788 => 23556, 18789 => 24913, 18790 => 28041, 18791 => 31038, 18792 => 35774, 18793 => 30775, 18794 => 30003, 18795 => 21627, 18796 => 20280, 18797 => 36523, 18798 => 28145, 18799 => 23072, 18800 => 32453, 18801 => 31070, 18802 => 27784, 18803 => 23457, 18804 => 23158, 18805 => 29978, 18806 => 32958, 18807 => 24910, 18808 => 28183, 18809 => 22768, 18810 => 29983, 18811 => 29989, 18812 => 29298, 18813 => 21319, 18814 => 32499, 18977 => 30465, 18978 => 30427, 18979 => 21097, 18980 => 32988, 18981 => 22307, 18982 => 24072, 18983 => 22833, 18984 => 29422, 18985 => 26045, 18986 => 28287, 18987 => 35799, 18988 => 23608, 18989 => 34417, 18990 => 21313, 18991 => 30707, 18992 => 25342, 18993 => 26102, 18994 => 20160, 18995 => 39135, 18996 => 34432, 18997 => 23454, 18998 => 35782, 18999 => 21490, 19000 => 30690, 19001 => 20351, 19002 => 23630, 19003 => 39542, 19004 => 22987, 19005 => 24335, 19006 => 31034, 19007 => 22763, 19008 => 19990, 19009 => 26623, 19010 => 20107, 19011 => 25325, 19012 => 35475, 19013 => 36893, 19014 => 21183, 19015 => 26159, 19016 => 21980, 19017 => 22124, 19018 => 36866, 19019 => 20181, 19020 => 20365, 19021 => 37322, 19022 => 39280, 19023 => 27663, 19024 => 24066, 19025 => 24643, 19026 => 23460, 19027 => 35270, 19028 => 35797, 19029 => 25910, 19030 => 25163, 19031 => 39318, 19032 => 23432, 19033 => 23551, 19034 => 25480, 19035 => 21806, 19036 => 21463, 19037 => 30246, 19038 => 20861, 19039 => 34092, 19040 => 26530, 19041 => 26803, 19042 => 27530, 19043 => 25234, 19044 => 36755, 19045 => 21460, 19046 => 33298, 19047 => 28113, 19048 => 30095, 19049 => 20070, 19050 => 36174, 19051 => 23408, 19052 => 29087, 19053 => 34223, 19054 => 26257, 19055 => 26329, 19056 => 32626, 19057 => 34560, 19058 => 40653, 19059 => 40736, 19060 => 23646, 19061 => 26415, 19062 => 36848, 19063 => 26641, 19064 => 26463, 19065 => 25101, 19066 => 31446, 19067 => 22661, 19068 => 24246, 19069 => 25968, 19070 => 28465, 19233 => 24661, 19234 => 21047, 19235 => 32781, 19236 => 25684, 19237 => 34928, 19238 => 29993, 19239 => 24069, 19240 => 26643, 19241 => 25332, 19242 => 38684, 19243 => 21452, 19244 => 29245, 19245 => 35841, 19246 => 27700, 19247 => 30561, 19248 => 31246, 19249 => 21550, 19250 => 30636, 19251 => 39034, 19252 => 33308, 19253 => 35828, 19254 => 30805, 19255 => 26388, 19256 => 28865, 19257 => 26031, 19258 => 25749, 19259 => 22070, 19260 => 24605, 19261 => 31169, 19262 => 21496, 19263 => 19997, 19264 => 27515, 19265 => 32902, 19266 => 23546, 19267 => 21987, 19268 => 22235, 19269 => 20282, 19270 => 20284, 19271 => 39282, 19272 => 24051, 19273 => 26494, 19274 => 32824, 19275 => 24578, 19276 => 39042, 19277 => 36865, 19278 => 23435, 19279 => 35772, 19280 => 35829, 19281 => 25628, 19282 => 33368, 19283 => 25822, 19284 => 22013, 19285 => 33487, 19286 => 37221, 19287 => 20439, 19288 => 32032, 19289 => 36895, 19290 => 31903, 19291 => 20723, 19292 => 22609, 19293 => 28335, 19294 => 23487, 19295 => 35785, 19296 => 32899, 19297 => 37240, 19298 => 33948, 19299 => 31639, 19300 => 34429, 19301 => 38539, 19302 => 38543, 19303 => 32485, 19304 => 39635, 19305 => 30862, 19306 => 23681, 19307 => 31319, 19308 => 36930, 19309 => 38567, 19310 => 31071, 19311 => 23385, 19312 => 25439, 19313 => 31499, 19314 => 34001, 19315 => 26797, 19316 => 21766, 19317 => 32553, 19318 => 29712, 19319 => 32034, 19320 => 38145, 19321 => 25152, 19322 => 22604, 19323 => 20182, 19324 => 23427, 19325 => 22905, 19326 => 22612, 19489 => 29549, 19490 => 25374, 19491 => 36427, 19492 => 36367, 19493 => 32974, 19494 => 33492, 19495 => 25260, 19496 => 21488, 19497 => 27888, 19498 => 37214, 19499 => 22826, 19500 => 24577, 19501 => 27760, 19502 => 22349, 19503 => 25674, 19504 => 36138, 19505 => 30251, 19506 => 28393, 19507 => 22363, 19508 => 27264, 19509 => 30192, 19510 => 28525, 19511 => 35885, 19512 => 35848, 19513 => 22374, 19514 => 27631, 19515 => 34962, 19516 => 30899, 19517 => 25506, 19518 => 21497, 19519 => 28845, 19520 => 27748, 19521 => 22616, 19522 => 25642, 19523 => 22530, 19524 => 26848, 19525 => 33179, 19526 => 21776, 19527 => 31958, 19528 => 20504, 19529 => 36538, 19530 => 28108, 19531 => 36255, 19532 => 28907, 19533 => 25487, 19534 => 28059, 19535 => 28372, 19536 => 32486, 19537 => 33796, 19538 => 26691, 19539 => 36867, 19540 => 28120, 19541 => 38518, 19542 => 35752, 19543 => 22871, 19544 => 29305, 19545 => 34276, 19546 => 33150, 19547 => 30140, 19548 => 35466, 19549 => 26799, 19550 => 21076, 19551 => 36386, 19552 => 38161, 19553 => 25552, 19554 => 39064, 19555 => 36420, 19556 => 21884, 19557 => 20307, 19558 => 26367, 19559 => 22159, 19560 => 24789, 19561 => 28053, 19562 => 21059, 19563 => 23625, 19564 => 22825, 19565 => 28155, 19566 => 22635, 19567 => 30000, 19568 => 29980, 19569 => 24684, 19570 => 33300, 19571 => 33094, 19572 => 25361, 19573 => 26465, 19574 => 36834, 19575 => 30522, 19576 => 36339, 19577 => 36148, 19578 => 38081, 19579 => 24086, 19580 => 21381, 19581 => 21548, 19582 => 28867, 19745 => 27712, 19746 => 24311, 19747 => 20572, 19748 => 20141, 19749 => 24237, 19750 => 25402, 19751 => 33351, 19752 => 36890, 19753 => 26704, 19754 => 37230, 19755 => 30643, 19756 => 21516, 19757 => 38108, 19758 => 24420, 19759 => 31461, 19760 => 26742, 19761 => 25413, 19762 => 31570, 19763 => 32479, 19764 => 30171, 19765 => 20599, 19766 => 25237, 19767 => 22836, 19768 => 36879, 19769 => 20984, 19770 => 31171, 19771 => 31361, 19772 => 22270, 19773 => 24466, 19774 => 36884, 19775 => 28034, 19776 => 23648, 19777 => 22303, 19778 => 21520, 19779 => 20820, 19780 => 28237, 19781 => 22242, 19782 => 25512, 19783 => 39059, 19784 => 33151, 19785 => 34581, 19786 => 35114, 19787 => 36864, 19788 => 21534, 19789 => 23663, 19790 => 33216, 19791 => 25302, 19792 => 25176, 19793 => 33073, 19794 => 40501, 19795 => 38464, 19796 => 39534, 19797 => 39548, 19798 => 26925, 19799 => 22949, 19800 => 25299, 19801 => 21822, 19802 => 25366, 19803 => 21703, 19804 => 34521, 19805 => 27964, 19806 => 23043, 19807 => 29926, 19808 => 34972, 19809 => 27498, 19810 => 22806, 19811 => 35916, 19812 => 24367, 19813 => 28286, 19814 => 29609, 19815 => 39037, 19816 => 20024, 19817 => 28919, 19818 => 23436, 19819 => 30871, 19820 => 25405, 19821 => 26202, 19822 => 30358, 19823 => 24779, 19824 => 23451, 19825 => 23113, 19826 => 19975, 19827 => 33109, 19828 => 27754, 19829 => 29579, 19830 => 20129, 19831 => 26505, 19832 => 32593, 19833 => 24448, 19834 => 26106, 19835 => 26395, 19836 => 24536, 19837 => 22916, 19838 => 23041, 20001 => 24013, 20002 => 24494, 20003 => 21361, 20004 => 38886, 20005 => 36829, 20006 => 26693, 20007 => 22260, 20008 => 21807, 20009 => 24799, 20010 => 20026, 20011 => 28493, 20012 => 32500, 20013 => 33479, 20014 => 33806, 20015 => 22996, 20016 => 20255, 20017 => 20266, 20018 => 23614, 20019 => 32428, 20020 => 26410, 20021 => 34074, 20022 => 21619, 20023 => 30031, 20024 => 32963, 20025 => 21890, 20026 => 39759, 20027 => 20301, 20028 => 28205, 20029 => 35859, 20030 => 23561, 20031 => 24944, 20032 => 21355, 20033 => 30239, 20034 => 28201, 20035 => 34442, 20036 => 25991, 20037 => 38395, 20038 => 32441, 20039 => 21563, 20040 => 31283, 20041 => 32010, 20042 => 38382, 20043 => 21985, 20044 => 32705, 20045 => 29934, 20046 => 25373, 20047 => 34583, 20048 => 28065, 20049 => 31389, 20050 => 25105, 20051 => 26017, 20052 => 21351, 20053 => 25569, 20054 => 27779, 20055 => 24043, 20056 => 21596, 20057 => 38056, 20058 => 20044, 20059 => 27745, 20060 => 35820, 20061 => 23627, 20062 => 26080, 20063 => 33436, 20064 => 26791, 20065 => 21566, 20066 => 21556, 20067 => 27595, 20068 => 27494, 20069 => 20116, 20070 => 25410, 20071 => 21320, 20072 => 33310, 20073 => 20237, 20074 => 20398, 20075 => 22366, 20076 => 25098, 20077 => 38654, 20078 => 26212, 20079 => 29289, 20080 => 21247, 20081 => 21153, 20082 => 24735, 20083 => 35823, 20084 => 26132, 20085 => 29081, 20086 => 26512, 20087 => 35199, 20088 => 30802, 20089 => 30717, 20090 => 26224, 20091 => 22075, 20092 => 21560, 20093 => 38177, 20094 => 29306, 20257 => 31232, 20258 => 24687, 20259 => 24076, 20260 => 24713, 20261 => 33181, 20262 => 22805, 20263 => 24796, 20264 => 29060, 20265 => 28911, 20266 => 28330, 20267 => 27728, 20268 => 29312, 20269 => 27268, 20270 => 34989, 20271 => 24109, 20272 => 20064, 20273 => 23219, 20274 => 21916, 20275 => 38115, 20276 => 27927, 20277 => 31995, 20278 => 38553, 20279 => 25103, 20280 => 32454, 20281 => 30606, 20282 => 34430, 20283 => 21283, 20284 => 38686, 20285 => 36758, 20286 => 26247, 20287 => 23777, 20288 => 20384, 20289 => 29421, 20290 => 19979, 20291 => 21414, 20292 => 22799, 20293 => 21523, 20294 => 25472, 20295 => 38184, 20296 => 20808, 20297 => 20185, 20298 => 40092, 20299 => 32420, 20300 => 21688, 20301 => 36132, 20302 => 34900, 20303 => 33335, 20304 => 38386, 20305 => 28046, 20306 => 24358, 20307 => 23244, 20308 => 26174, 20309 => 38505, 20310 => 29616, 20311 => 29486, 20312 => 21439, 20313 => 33146, 20314 => 39301, 20315 => 32673, 20316 => 23466, 20317 => 38519, 20318 => 38480, 20319 => 32447, 20320 => 30456, 20321 => 21410, 20322 => 38262, 20323 => 39321, 20324 => 31665, 20325 => 35140, 20326 => 28248, 20327 => 20065, 20328 => 32724, 20329 => 31077, 20330 => 35814, 20331 => 24819, 20332 => 21709, 20333 => 20139, 20334 => 39033, 20335 => 24055, 20336 => 27233, 20337 => 20687, 20338 => 21521, 20339 => 35937, 20340 => 33831, 20341 => 30813, 20342 => 38660, 20343 => 21066, 20344 => 21742, 20345 => 22179, 20346 => 38144, 20347 => 28040, 20348 => 23477, 20349 => 28102, 20350 => 26195, 20513 => 23567, 20514 => 23389, 20515 => 26657, 20516 => 32918, 20517 => 21880, 20518 => 31505, 20519 => 25928, 20520 => 26964, 20521 => 20123, 20522 => 27463, 20523 => 34638, 20524 => 38795, 20525 => 21327, 20526 => 25375, 20527 => 25658, 20528 => 37034, 20529 => 26012, 20530 => 32961, 20531 => 35856, 20532 => 20889, 20533 => 26800, 20534 => 21368, 20535 => 34809, 20536 => 25032, 20537 => 27844, 20538 => 27899, 20539 => 35874, 20540 => 23633, 20541 => 34218, 20542 => 33455, 20543 => 38156, 20544 => 27427, 20545 => 36763, 20546 => 26032, 20547 => 24571, 20548 => 24515, 20549 => 20449, 20550 => 34885, 20551 => 26143, 20552 => 33125, 20553 => 29481, 20554 => 24826, 20555 => 20852, 20556 => 21009, 20557 => 22411, 20558 => 24418, 20559 => 37026, 20560 => 34892, 20561 => 37266, 20562 => 24184, 20563 => 26447, 20564 => 24615, 20565 => 22995, 20566 => 20804, 20567 => 20982, 20568 => 33016, 20569 => 21256, 20570 => 27769, 20571 => 38596, 20572 => 29066, 20573 => 20241, 20574 => 20462, 20575 => 32670, 20576 => 26429, 20577 => 21957, 20578 => 38152, 20579 => 31168, 20580 => 34966, 20581 => 32483, 20582 => 22687, 20583 => 25100, 20584 => 38656, 20585 => 34394, 20586 => 22040, 20587 => 39035, 20588 => 24464, 20589 => 35768, 20590 => 33988, 20591 => 37207, 20592 => 21465, 20593 => 26093, 20594 => 24207, 20595 => 30044, 20596 => 24676, 20597 => 32110, 20598 => 23167, 20599 => 32490, 20600 => 32493, 20601 => 36713, 20602 => 21927, 20603 => 23459, 20604 => 24748, 20605 => 26059, 20606 => 29572, 20769 => 36873, 20770 => 30307, 20771 => 30505, 20772 => 32474, 20773 => 38772, 20774 => 34203, 20775 => 23398, 20776 => 31348, 20777 => 38634, 20778 => 34880, 20779 => 21195, 20780 => 29071, 20781 => 24490, 20782 => 26092, 20783 => 35810, 20784 => 23547, 20785 => 39535, 20786 => 24033, 20787 => 27529, 20788 => 27739, 20789 => 35757, 20790 => 35759, 20791 => 36874, 20792 => 36805, 20793 => 21387, 20794 => 25276, 20795 => 40486, 20796 => 40493, 20797 => 21568, 20798 => 20011, 20799 => 33469, 20800 => 29273, 20801 => 34460, 20802 => 23830, 20803 => 34905, 20804 => 28079, 20805 => 38597, 20806 => 21713, 20807 => 20122, 20808 => 35766, 20809 => 28937, 20810 => 21693, 20811 => 38409, 20812 => 28895, 20813 => 28153, 20814 => 30416, 20815 => 20005, 20816 => 30740, 20817 => 34578, 20818 => 23721, 20819 => 24310, 20820 => 35328, 20821 => 39068, 20822 => 38414, 20823 => 28814, 20824 => 27839, 20825 => 22852, 20826 => 25513, 20827 => 30524, 20828 => 34893, 20829 => 28436, 20830 => 33395, 20831 => 22576, 20832 => 29141, 20833 => 21388, 20834 => 30746, 20835 => 38593, 20836 => 21761, 20837 => 24422, 20838 => 28976, 20839 => 23476, 20840 => 35866, 20841 => 39564, 20842 => 27523, 20843 => 22830, 20844 => 40495, 20845 => 31207, 20846 => 26472, 20847 => 25196, 20848 => 20335, 20849 => 30113, 20850 => 32650, 20851 => 27915, 20852 => 38451, 20853 => 27687, 20854 => 20208, 20855 => 30162, 20856 => 20859, 20857 => 26679, 20858 => 28478, 20859 => 36992, 20860 => 33136, 20861 => 22934, 20862 => 29814, 21025 => 25671, 21026 => 23591, 21027 => 36965, 21028 => 31377, 21029 => 35875, 21030 => 23002, 21031 => 21676, 21032 => 33280, 21033 => 33647, 21034 => 35201, 21035 => 32768, 21036 => 26928, 21037 => 22094, 21038 => 32822, 21039 => 29239, 21040 => 37326, 21041 => 20918, 21042 => 20063, 21043 => 39029, 21044 => 25494, 21045 => 19994, 21046 => 21494, 21047 => 26355, 21048 => 33099, 21049 => 22812, 21050 => 28082, 21051 => 19968, 21052 => 22777, 21053 => 21307, 21054 => 25558, 21055 => 38129, 21056 => 20381, 21057 => 20234, 21058 => 34915, 21059 => 39056, 21060 => 22839, 21061 => 36951, 21062 => 31227, 21063 => 20202, 21064 => 33008, 21065 => 30097, 21066 => 27778, 21067 => 23452, 21068 => 23016, 21069 => 24413, 21070 => 26885, 21071 => 34433, 21072 => 20506, 21073 => 24050, 21074 => 20057, 21075 => 30691, 21076 => 20197, 21077 => 33402, 21078 => 25233, 21079 => 26131, 21080 => 37009, 21081 => 23673, 21082 => 20159, 21083 => 24441, 21084 => 33222, 21085 => 36920, 21086 => 32900, 21087 => 30123, 21088 => 20134, 21089 => 35028, 21090 => 24847, 21091 => 27589, 21092 => 24518, 21093 => 20041, 21094 => 30410, 21095 => 28322, 21096 => 35811, 21097 => 35758, 21098 => 35850, 21099 => 35793, 21100 => 24322, 21101 => 32764, 21102 => 32716, 21103 => 32462, 21104 => 33589, 21105 => 33643, 21106 => 22240, 21107 => 27575, 21108 => 38899, 21109 => 38452, 21110 => 23035, 21111 => 21535, 21112 => 38134, 21113 => 28139, 21114 => 23493, 21115 => 39278, 21116 => 23609, 21117 => 24341, 21118 => 38544, 21281 => 21360, 21282 => 33521, 21283 => 27185, 21284 => 23156, 21285 => 40560, 21286 => 24212, 21287 => 32552, 21288 => 33721, 21289 => 33828, 21290 => 33829, 21291 => 33639, 21292 => 34631, 21293 => 36814, 21294 => 36194, 21295 => 30408, 21296 => 24433, 21297 => 39062, 21298 => 30828, 21299 => 26144, 21300 => 21727, 21301 => 25317, 21302 => 20323, 21303 => 33219, 21304 => 30152, 21305 => 24248, 21306 => 38605, 21307 => 36362, 21308 => 34553, 21309 => 21647, 21310 => 27891, 21311 => 28044, 21312 => 27704, 21313 => 24703, 21314 => 21191, 21315 => 29992, 21316 => 24189, 21317 => 20248, 21318 => 24736, 21319 => 24551, 21320 => 23588, 21321 => 30001, 21322 => 37038, 21323 => 38080, 21324 => 29369, 21325 => 27833, 21326 => 28216, 21327 => 37193, 21328 => 26377, 21329 => 21451, 21330 => 21491, 21331 => 20305, 21332 => 37321, 21333 => 35825, 21334 => 21448, 21335 => 24188, 21336 => 36802, 21337 => 28132, 21338 => 20110, 21339 => 30402, 21340 => 27014, 21341 => 34398, 21342 => 24858, 21343 => 33286, 21344 => 20313, 21345 => 20446, 21346 => 36926, 21347 => 40060, 21348 => 24841, 21349 => 28189, 21350 => 28180, 21351 => 38533, 21352 => 20104, 21353 => 23089, 21354 => 38632, 21355 => 19982, 21356 => 23679, 21357 => 31161, 21358 => 23431, 21359 => 35821, 21360 => 32701, 21361 => 29577, 21362 => 22495, 21363 => 33419, 21364 => 37057, 21365 => 21505, 21366 => 36935, 21367 => 21947, 21368 => 23786, 21369 => 24481, 21370 => 24840, 21371 => 27442, 21372 => 29425, 21373 => 32946, 21374 => 35465, 21537 => 28020, 21538 => 23507, 21539 => 35029, 21540 => 39044, 21541 => 35947, 21542 => 39533, 21543 => 40499, 21544 => 28170, 21545 => 20900, 21546 => 20803, 21547 => 22435, 21548 => 34945, 21549 => 21407, 21550 => 25588, 21551 => 36757, 21552 => 22253, 21553 => 21592, 21554 => 22278, 21555 => 29503, 21556 => 28304, 21557 => 32536, 21558 => 36828, 21559 => 33489, 21560 => 24895, 21561 => 24616, 21562 => 38498, 21563 => 26352, 21564 => 32422, 21565 => 36234, 21566 => 36291, 21567 => 38053, 21568 => 23731, 21569 => 31908, 21570 => 26376, 21571 => 24742, 21572 => 38405, 21573 => 32792, 21574 => 20113, 21575 => 37095, 21576 => 21248, 21577 => 38504, 21578 => 20801, 21579 => 36816, 21580 => 34164, 21581 => 37213, 21582 => 26197, 21583 => 38901, 21584 => 23381, 21585 => 21277, 21586 => 30776, 21587 => 26434, 21588 => 26685, 21589 => 21705, 21590 => 28798, 21591 => 23472, 21592 => 36733, 21593 => 20877, 21594 => 22312, 21595 => 21681, 21596 => 25874, 21597 => 26242, 21598 => 36190, 21599 => 36163, 21600 => 33039, 21601 => 33900, 21602 => 36973, 21603 => 31967, 21604 => 20991, 21605 => 34299, 21606 => 26531, 21607 => 26089, 21608 => 28577, 21609 => 34468, 21610 => 36481, 21611 => 22122, 21612 => 36896, 21613 => 30338, 21614 => 28790, 21615 => 29157, 21616 => 36131, 21617 => 25321, 21618 => 21017, 21619 => 27901, 21620 => 36156, 21621 => 24590, 21622 => 22686, 21623 => 24974, 21624 => 26366, 21625 => 36192, 21626 => 25166, 21627 => 21939, 21628 => 28195, 21629 => 26413, 21630 => 36711, 21793 => 38113, 21794 => 38392, 21795 => 30504, 21796 => 26629, 21797 => 27048, 21798 => 21643, 21799 => 20045, 21800 => 28856, 21801 => 35784, 21802 => 25688, 21803 => 25995, 21804 => 23429, 21805 => 31364, 21806 => 20538, 21807 => 23528, 21808 => 30651, 21809 => 27617, 21810 => 35449, 21811 => 31896, 21812 => 27838, 21813 => 30415, 21814 => 26025, 21815 => 36759, 21816 => 23853, 21817 => 23637, 21818 => 34360, 21819 => 26632, 21820 => 21344, 21821 => 25112, 21822 => 31449, 21823 => 28251, 21824 => 32509, 21825 => 27167, 21826 => 31456, 21827 => 24432, 21828 => 28467, 21829 => 24352, 21830 => 25484, 21831 => 28072, 21832 => 26454, 21833 => 19976, 21834 => 24080, 21835 => 36134, 21836 => 20183, 21837 => 32960, 21838 => 30260, 21839 => 38556, 21840 => 25307, 21841 => 26157, 21842 => 25214, 21843 => 27836, 21844 => 36213, 21845 => 29031, 21846 => 32617, 21847 => 20806, 21848 => 32903, 21849 => 21484, 21850 => 36974, 21851 => 25240, 21852 => 21746, 21853 => 34544, 21854 => 36761, 21855 => 32773, 21856 => 38167, 21857 => 34071, 21858 => 36825, 21859 => 27993, 21860 => 29645, 21861 => 26015, 21862 => 30495, 21863 => 29956, 21864 => 30759, 21865 => 33275, 21866 => 36126, 21867 => 38024, 21868 => 20390, 21869 => 26517, 21870 => 30137, 21871 => 35786, 21872 => 38663, 21873 => 25391, 21874 => 38215, 21875 => 38453, 21876 => 33976, 21877 => 25379, 21878 => 30529, 21879 => 24449, 21880 => 29424, 21881 => 20105, 21882 => 24596, 21883 => 25972, 21884 => 25327, 21885 => 27491, 21886 => 25919, 22049 => 24103, 22050 => 30151, 22051 => 37073, 22052 => 35777, 22053 => 33437, 22054 => 26525, 22055 => 25903, 22056 => 21553, 22057 => 34584, 22058 => 30693, 22059 => 32930, 22060 => 33026, 22061 => 27713, 22062 => 20043, 22063 => 32455, 22064 => 32844, 22065 => 30452, 22066 => 26893, 22067 => 27542, 22068 => 25191, 22069 => 20540, 22070 => 20356, 22071 => 22336, 22072 => 25351, 22073 => 27490, 22074 => 36286, 22075 => 21482, 22076 => 26088, 22077 => 32440, 22078 => 24535, 22079 => 25370, 22080 => 25527, 22081 => 33267, 22082 => 33268, 22083 => 32622, 22084 => 24092, 22085 => 23769, 22086 => 21046, 22087 => 26234, 22088 => 31209, 22089 => 31258, 22090 => 36136, 22091 => 28825, 22092 => 30164, 22093 => 28382, 22094 => 27835, 22095 => 31378, 22096 => 20013, 22097 => 30405, 22098 => 24544, 22099 => 38047, 22100 => 34935, 22101 => 32456, 22102 => 31181, 22103 => 32959, 22104 => 37325, 22105 => 20210, 22106 => 20247, 22107 => 33311, 22108 => 21608, 22109 => 24030, 22110 => 27954, 22111 => 35788, 22112 => 31909, 22113 => 36724, 22114 => 32920, 22115 => 24090, 22116 => 21650, 22117 => 30385, 22118 => 23449, 22119 => 26172, 22120 => 39588, 22121 => 29664, 22122 => 26666, 22123 => 34523, 22124 => 26417, 22125 => 29482, 22126 => 35832, 22127 => 35803, 22128 => 36880, 22129 => 31481, 22130 => 28891, 22131 => 29038, 22132 => 25284, 22133 => 30633, 22134 => 22065, 22135 => 20027, 22136 => 33879, 22137 => 26609, 22138 => 21161, 22139 => 34496, 22140 => 36142, 22141 => 38136, 22142 => 31569, 22305 => 20303, 22306 => 27880, 22307 => 31069, 22308 => 39547, 22309 => 25235, 22310 => 29226, 22311 => 25341, 22312 => 19987, 22313 => 30742, 22314 => 36716, 22315 => 25776, 22316 => 36186, 22317 => 31686, 22318 => 26729, 22319 => 24196, 22320 => 35013, 22321 => 22918, 22322 => 25758, 22323 => 22766, 22324 => 29366, 22325 => 26894, 22326 => 38181, 22327 => 36861, 22328 => 36184, 22329 => 22368, 22330 => 32512, 22331 => 35846, 22332 => 20934, 22333 => 25417, 22334 => 25305, 22335 => 21331, 22336 => 26700, 22337 => 29730, 22338 => 33537, 22339 => 37196, 22340 => 21828, 22341 => 30528, 22342 => 28796, 22343 => 27978, 22344 => 20857, 22345 => 21672, 22346 => 36164, 22347 => 23039, 22348 => 28363, 22349 => 28100, 22350 => 23388, 22351 => 32043, 22352 => 20180, 22353 => 31869, 22354 => 28371, 22355 => 23376, 22356 => 33258, 22357 => 28173, 22358 => 23383, 22359 => 39683, 22360 => 26837, 22361 => 36394, 22362 => 23447, 22363 => 32508, 22364 => 24635, 22365 => 32437, 22366 => 37049, 22367 => 36208, 22368 => 22863, 22369 => 25549, 22370 => 31199, 22371 => 36275, 22372 => 21330, 22373 => 26063, 22374 => 31062, 22375 => 35781, 22376 => 38459, 22377 => 32452, 22378 => 38075, 22379 => 32386, 22380 => 22068, 22381 => 37257, 22382 => 26368, 22383 => 32618, 22384 => 23562, 22385 => 36981, 22386 => 26152, 22387 => 24038, 22388 => 20304, 22389 => 26590, 22390 => 20570, 22391 => 20316, 22392 => 22352, 22393 => 24231, 22561 => 20109, 22562 => 19980, 22563 => 20800, 22564 => 19984, 22565 => 24319, 22566 => 21317, 22567 => 19989, 22568 => 20120, 22569 => 19998, 22570 => 39730, 22571 => 23404, 22572 => 22121, 22573 => 20008, 22574 => 31162, 22575 => 20031, 22576 => 21269, 22577 => 20039, 22578 => 22829, 22579 => 29243, 22580 => 21358, 22581 => 27664, 22582 => 22239, 22583 => 32996, 22584 => 39319, 22585 => 27603, 22586 => 30590, 22587 => 40727, 22588 => 20022, 22589 => 20127, 22590 => 40720, 22591 => 20060, 22592 => 20073, 22593 => 20115, 22594 => 33416, 22595 => 23387, 22596 => 21868, 22597 => 22031, 22598 => 20164, 22599 => 21389, 22600 => 21405, 22601 => 21411, 22602 => 21413, 22603 => 21422, 22604 => 38757, 22605 => 36189, 22606 => 21274, 22607 => 21493, 22608 => 21286, 22609 => 21294, 22610 => 21310, 22611 => 36188, 22612 => 21350, 22613 => 21347, 22614 => 20994, 22615 => 21000, 22616 => 21006, 22617 => 21037, 22618 => 21043, 22619 => 21055, 22620 => 21056, 22621 => 21068, 22622 => 21086, 22623 => 21089, 22624 => 21084, 22625 => 33967, 22626 => 21117, 22627 => 21122, 22628 => 21121, 22629 => 21136, 22630 => 21139, 22631 => 20866, 22632 => 32596, 22633 => 20155, 22634 => 20163, 22635 => 20169, 22636 => 20162, 22637 => 20200, 22638 => 20193, 22639 => 20203, 22640 => 20190, 22641 => 20251, 22642 => 20211, 22643 => 20258, 22644 => 20324, 22645 => 20213, 22646 => 20261, 22647 => 20263, 22648 => 20233, 22649 => 20267, 22650 => 20318, 22651 => 20327, 22652 => 25912, 22653 => 20314, 22654 => 20317, 22817 => 20319, 22818 => 20311, 22819 => 20274, 22820 => 20285, 22821 => 20342, 22822 => 20340, 22823 => 20369, 22824 => 20361, 22825 => 20355, 22826 => 20367, 22827 => 20350, 22828 => 20347, 22829 => 20394, 22830 => 20348, 22831 => 20396, 22832 => 20372, 22833 => 20454, 22834 => 20456, 22835 => 20458, 22836 => 20421, 22837 => 20442, 22838 => 20451, 22839 => 20444, 22840 => 20433, 22841 => 20447, 22842 => 20472, 22843 => 20521, 22844 => 20556, 22845 => 20467, 22846 => 20524, 22847 => 20495, 22848 => 20526, 22849 => 20525, 22850 => 20478, 22851 => 20508, 22852 => 20492, 22853 => 20517, 22854 => 20520, 22855 => 20606, 22856 => 20547, 22857 => 20565, 22858 => 20552, 22859 => 20558, 22860 => 20588, 22861 => 20603, 22862 => 20645, 22863 => 20647, 22864 => 20649, 22865 => 20666, 22866 => 20694, 22867 => 20742, 22868 => 20717, 22869 => 20716, 22870 => 20710, 22871 => 20718, 22872 => 20743, 22873 => 20747, 22874 => 20189, 22875 => 27709, 22876 => 20312, 22877 => 20325, 22878 => 20430, 22879 => 40864, 22880 => 27718, 22881 => 31860, 22882 => 20846, 22883 => 24061, 22884 => 40649, 22885 => 39320, 22886 => 20865, 22887 => 22804, 22888 => 21241, 22889 => 21261, 22890 => 35335, 22891 => 21264, 22892 => 20971, 22893 => 22809, 22894 => 20821, 22895 => 20128, 22896 => 20822, 22897 => 20147, 22898 => 34926, 22899 => 34980, 22900 => 20149, 22901 => 33044, 22902 => 35026, 22903 => 31104, 22904 => 23348, 22905 => 34819, 22906 => 32696, 22907 => 20907, 22908 => 20913, 22909 => 20925, 22910 => 20924, 23073 => 20935, 23074 => 20886, 23075 => 20898, 23076 => 20901, 23077 => 35744, 23078 => 35750, 23079 => 35751, 23080 => 35754, 23081 => 35764, 23082 => 35765, 23083 => 35767, 23084 => 35778, 23085 => 35779, 23086 => 35787, 23087 => 35791, 23088 => 35790, 23089 => 35794, 23090 => 35795, 23091 => 35796, 23092 => 35798, 23093 => 35800, 23094 => 35801, 23095 => 35804, 23096 => 35807, 23097 => 35808, 23098 => 35812, 23099 => 35816, 23100 => 35817, 23101 => 35822, 23102 => 35824, 23103 => 35827, 23104 => 35830, 23105 => 35833, 23106 => 35836, 23107 => 35839, 23108 => 35840, 23109 => 35842, 23110 => 35844, 23111 => 35847, 23112 => 35852, 23113 => 35855, 23114 => 35857, 23115 => 35858, 23116 => 35860, 23117 => 35861, 23118 => 35862, 23119 => 35865, 23120 => 35867, 23121 => 35864, 23122 => 35869, 23123 => 35871, 23124 => 35872, 23125 => 35873, 23126 => 35877, 23127 => 35879, 23128 => 35882, 23129 => 35883, 23130 => 35886, 23131 => 35887, 23132 => 35890, 23133 => 35891, 23134 => 35893, 23135 => 35894, 23136 => 21353, 23137 => 21370, 23138 => 38429, 23139 => 38434, 23140 => 38433, 23141 => 38449, 23142 => 38442, 23143 => 38461, 23144 => 38460, 23145 => 38466, 23146 => 38473, 23147 => 38484, 23148 => 38495, 23149 => 38503, 23150 => 38508, 23151 => 38514, 23152 => 38516, 23153 => 38536, 23154 => 38541, 23155 => 38551, 23156 => 38576, 23157 => 37015, 23158 => 37019, 23159 => 37021, 23160 => 37017, 23161 => 37036, 23162 => 37025, 23163 => 37044, 23164 => 37043, 23165 => 37046, 23166 => 37050, 23329 => 37048, 23330 => 37040, 23331 => 37071, 23332 => 37061, 23333 => 37054, 23334 => 37072, 23335 => 37060, 23336 => 37063, 23337 => 37075, 23338 => 37094, 23339 => 37090, 23340 => 37084, 23341 => 37079, 23342 => 37083, 23343 => 37099, 23344 => 37103, 23345 => 37118, 23346 => 37124, 23347 => 37154, 23348 => 37150, 23349 => 37155, 23350 => 37169, 23351 => 37167, 23352 => 37177, 23353 => 37187, 23354 => 37190, 23355 => 21005, 23356 => 22850, 23357 => 21154, 23358 => 21164, 23359 => 21165, 23360 => 21182, 23361 => 21759, 23362 => 21200, 23363 => 21206, 23364 => 21232, 23365 => 21471, 23366 => 29166, 23367 => 30669, 23368 => 24308, 23369 => 20981, 23370 => 20988, 23371 => 39727, 23372 => 21430, 23373 => 24321, 23374 => 30042, 23375 => 24047, 23376 => 22348, 23377 => 22441, 23378 => 22433, 23379 => 22654, 23380 => 22716, 23381 => 22725, 23382 => 22737, 23383 => 22313, 23384 => 22316, 23385 => 22314, 23386 => 22323, 23387 => 22329, 23388 => 22318, 23389 => 22319, 23390 => 22364, 23391 => 22331, 23392 => 22338, 23393 => 22377, 23394 => 22405, 23395 => 22379, 23396 => 22406, 23397 => 22396, 23398 => 22395, 23399 => 22376, 23400 => 22381, 23401 => 22390, 23402 => 22387, 23403 => 22445, 23404 => 22436, 23405 => 22412, 23406 => 22450, 23407 => 22479, 23408 => 22439, 23409 => 22452, 23410 => 22419, 23411 => 22432, 23412 => 22485, 23413 => 22488, 23414 => 22490, 23415 => 22489, 23416 => 22482, 23417 => 22456, 23418 => 22516, 23419 => 22511, 23420 => 22520, 23421 => 22500, 23422 => 22493, 23585 => 22539, 23586 => 22541, 23587 => 22525, 23588 => 22509, 23589 => 22528, 23590 => 22558, 23591 => 22553, 23592 => 22596, 23593 => 22560, 23594 => 22629, 23595 => 22636, 23596 => 22657, 23597 => 22665, 23598 => 22682, 23599 => 22656, 23600 => 39336, 23601 => 40729, 23602 => 25087, 23603 => 33401, 23604 => 33405, 23605 => 33407, 23606 => 33423, 23607 => 33418, 23608 => 33448, 23609 => 33412, 23610 => 33422, 23611 => 33425, 23612 => 33431, 23613 => 33433, 23614 => 33451, 23615 => 33464, 23616 => 33470, 23617 => 33456, 23618 => 33480, 23619 => 33482, 23620 => 33507, 23621 => 33432, 23622 => 33463, 23623 => 33454, 23624 => 33483, 23625 => 33484, 23626 => 33473, 23627 => 33449, 23628 => 33460, 23629 => 33441, 23630 => 33450, 23631 => 33439, 23632 => 33476, 23633 => 33486, 23634 => 33444, 23635 => 33505, 23636 => 33545, 23637 => 33527, 23638 => 33508, 23639 => 33551, 23640 => 33543, 23641 => 33500, 23642 => 33524, 23643 => 33490, 23644 => 33496, 23645 => 33548, 23646 => 33531, 23647 => 33491, 23648 => 33553, 23649 => 33562, 23650 => 33542, 23651 => 33556, 23652 => 33557, 23653 => 33504, 23654 => 33493, 23655 => 33564, 23656 => 33617, 23657 => 33627, 23658 => 33628, 23659 => 33544, 23660 => 33682, 23661 => 33596, 23662 => 33588, 23663 => 33585, 23664 => 33691, 23665 => 33630, 23666 => 33583, 23667 => 33615, 23668 => 33607, 23669 => 33603, 23670 => 33631, 23671 => 33600, 23672 => 33559, 23673 => 33632, 23674 => 33581, 23675 => 33594, 23676 => 33587, 23677 => 33638, 23678 => 33637, 23841 => 33640, 23842 => 33563, 23843 => 33641, 23844 => 33644, 23845 => 33642, 23846 => 33645, 23847 => 33646, 23848 => 33712, 23849 => 33656, 23850 => 33715, 23851 => 33716, 23852 => 33696, 23853 => 33706, 23854 => 33683, 23855 => 33692, 23856 => 33669, 23857 => 33660, 23858 => 33718, 23859 => 33705, 23860 => 33661, 23861 => 33720, 23862 => 33659, 23863 => 33688, 23864 => 33694, 23865 => 33704, 23866 => 33722, 23867 => 33724, 23868 => 33729, 23869 => 33793, 23870 => 33765, 23871 => 33752, 23872 => 22535, 23873 => 33816, 23874 => 33803, 23875 => 33757, 23876 => 33789, 23877 => 33750, 23878 => 33820, 23879 => 33848, 23880 => 33809, 23881 => 33798, 23882 => 33748, 23883 => 33759, 23884 => 33807, 23885 => 33795, 23886 => 33784, 23887 => 33785, 23888 => 33770, 23889 => 33733, 23890 => 33728, 23891 => 33830, 23892 => 33776, 23893 => 33761, 23894 => 33884, 23895 => 33873, 23896 => 33882, 23897 => 33881, 23898 => 33907, 23899 => 33927, 23900 => 33928, 23901 => 33914, 23902 => 33929, 23903 => 33912, 23904 => 33852, 23905 => 33862, 23906 => 33897, 23907 => 33910, 23908 => 33932, 23909 => 33934, 23910 => 33841, 23911 => 33901, 23912 => 33985, 23913 => 33997, 23914 => 34000, 23915 => 34022, 23916 => 33981, 23917 => 34003, 23918 => 33994, 23919 => 33983, 23920 => 33978, 23921 => 34016, 23922 => 33953, 23923 => 33977, 23924 => 33972, 23925 => 33943, 23926 => 34021, 23927 => 34019, 23928 => 34060, 23929 => 29965, 23930 => 34104, 23931 => 34032, 23932 => 34105, 23933 => 34079, 23934 => 34106, 24097 => 34134, 24098 => 34107, 24099 => 34047, 24100 => 34044, 24101 => 34137, 24102 => 34120, 24103 => 34152, 24104 => 34148, 24105 => 34142, 24106 => 34170, 24107 => 30626, 24108 => 34115, 24109 => 34162, 24110 => 34171, 24111 => 34212, 24112 => 34216, 24113 => 34183, 24114 => 34191, 24115 => 34169, 24116 => 34222, 24117 => 34204, 24118 => 34181, 24119 => 34233, 24120 => 34231, 24121 => 34224, 24122 => 34259, 24123 => 34241, 24124 => 34268, 24125 => 34303, 24126 => 34343, 24127 => 34309, 24128 => 34345, 24129 => 34326, 24130 => 34364, 24131 => 24318, 24132 => 24328, 24133 => 22844, 24134 => 22849, 24135 => 32823, 24136 => 22869, 24137 => 22874, 24138 => 22872, 24139 => 21263, 24140 => 23586, 24141 => 23589, 24142 => 23596, 24143 => 23604, 24144 => 25164, 24145 => 25194, 24146 => 25247, 24147 => 25275, 24148 => 25290, 24149 => 25306, 24150 => 25303, 24151 => 25326, 24152 => 25378, 24153 => 25334, 24154 => 25401, 24155 => 25419, 24156 => 25411, 24157 => 25517, 24158 => 25590, 24159 => 25457, 24160 => 25466, 24161 => 25486, 24162 => 25524, 24163 => 25453, 24164 => 25516, 24165 => 25482, 24166 => 25449, 24167 => 25518, 24168 => 25532, 24169 => 25586, 24170 => 25592, 24171 => 25568, 24172 => 25599, 24173 => 25540, 24174 => 25566, 24175 => 25550, 24176 => 25682, 24177 => 25542, 24178 => 25534, 24179 => 25669, 24180 => 25665, 24181 => 25611, 24182 => 25627, 24183 => 25632, 24184 => 25612, 24185 => 25638, 24186 => 25633, 24187 => 25694, 24188 => 25732, 24189 => 25709, 24190 => 25750, 24353 => 25722, 24354 => 25783, 24355 => 25784, 24356 => 25753, 24357 => 25786, 24358 => 25792, 24359 => 25808, 24360 => 25815, 24361 => 25828, 24362 => 25826, 24363 => 25865, 24364 => 25893, 24365 => 25902, 24366 => 24331, 24367 => 24530, 24368 => 29977, 24369 => 24337, 24370 => 21343, 24371 => 21489, 24372 => 21501, 24373 => 21481, 24374 => 21480, 24375 => 21499, 24376 => 21522, 24377 => 21526, 24378 => 21510, 24379 => 21579, 24380 => 21586, 24381 => 21587, 24382 => 21588, 24383 => 21590, 24384 => 21571, 24385 => 21537, 24386 => 21591, 24387 => 21593, 24388 => 21539, 24389 => 21554, 24390 => 21634, 24391 => 21652, 24392 => 21623, 24393 => 21617, 24394 => 21604, 24395 => 21658, 24396 => 21659, 24397 => 21636, 24398 => 21622, 24399 => 21606, 24400 => 21661, 24401 => 21712, 24402 => 21677, 24403 => 21698, 24404 => 21684, 24405 => 21714, 24406 => 21671, 24407 => 21670, 24408 => 21715, 24409 => 21716, 24410 => 21618, 24411 => 21667, 24412 => 21717, 24413 => 21691, 24414 => 21695, 24415 => 21708, 24416 => 21721, 24417 => 21722, 24418 => 21724, 24419 => 21673, 24420 => 21674, 24421 => 21668, 24422 => 21725, 24423 => 21711, 24424 => 21726, 24425 => 21787, 24426 => 21735, 24427 => 21792, 24428 => 21757, 24429 => 21780, 24430 => 21747, 24431 => 21794, 24432 => 21795, 24433 => 21775, 24434 => 21777, 24435 => 21799, 24436 => 21802, 24437 => 21863, 24438 => 21903, 24439 => 21941, 24440 => 21833, 24441 => 21869, 24442 => 21825, 24443 => 21845, 24444 => 21823, 24445 => 21840, 24446 => 21820, 24609 => 21815, 24610 => 21846, 24611 => 21877, 24612 => 21878, 24613 => 21879, 24614 => 21811, 24615 => 21808, 24616 => 21852, 24617 => 21899, 24618 => 21970, 24619 => 21891, 24620 => 21937, 24621 => 21945, 24622 => 21896, 24623 => 21889, 24624 => 21919, 24625 => 21886, 24626 => 21974, 24627 => 21905, 24628 => 21883, 24629 => 21983, 24630 => 21949, 24631 => 21950, 24632 => 21908, 24633 => 21913, 24634 => 21994, 24635 => 22007, 24636 => 21961, 24637 => 22047, 24638 => 21969, 24639 => 21995, 24640 => 21996, 24641 => 21972, 24642 => 21990, 24643 => 21981, 24644 => 21956, 24645 => 21999, 24646 => 21989, 24647 => 22002, 24648 => 22003, 24649 => 21964, 24650 => 21965, 24651 => 21992, 24652 => 22005, 24653 => 21988, 24654 => 36756, 24655 => 22046, 24656 => 22024, 24657 => 22028, 24658 => 22017, 24659 => 22052, 24660 => 22051, 24661 => 22014, 24662 => 22016, 24663 => 22055, 24664 => 22061, 24665 => 22104, 24666 => 22073, 24667 => 22103, 24668 => 22060, 24669 => 22093, 24670 => 22114, 24671 => 22105, 24672 => 22108, 24673 => 22092, 24674 => 22100, 24675 => 22150, 24676 => 22116, 24677 => 22129, 24678 => 22123, 24679 => 22139, 24680 => 22140, 24681 => 22149, 24682 => 22163, 24683 => 22191, 24684 => 22228, 24685 => 22231, 24686 => 22237, 24687 => 22241, 24688 => 22261, 24689 => 22251, 24690 => 22265, 24691 => 22271, 24692 => 22276, 24693 => 22282, 24694 => 22281, 24695 => 22300, 24696 => 24079, 24697 => 24089, 24698 => 24084, 24699 => 24081, 24700 => 24113, 24701 => 24123, 24702 => 24124, 24865 => 24119, 24866 => 24132, 24867 => 24148, 24868 => 24155, 24869 => 24158, 24870 => 24161, 24871 => 23692, 24872 => 23674, 24873 => 23693, 24874 => 23696, 24875 => 23702, 24876 => 23688, 24877 => 23704, 24878 => 23705, 24879 => 23697, 24880 => 23706, 24881 => 23708, 24882 => 23733, 24883 => 23714, 24884 => 23741, 24885 => 23724, 24886 => 23723, 24887 => 23729, 24888 => 23715, 24889 => 23745, 24890 => 23735, 24891 => 23748, 24892 => 23762, 24893 => 23780, 24894 => 23755, 24895 => 23781, 24896 => 23810, 24897 => 23811, 24898 => 23847, 24899 => 23846, 24900 => 23854, 24901 => 23844, 24902 => 23838, 24903 => 23814, 24904 => 23835, 24905 => 23896, 24906 => 23870, 24907 => 23860, 24908 => 23869, 24909 => 23916, 24910 => 23899, 24911 => 23919, 24912 => 23901, 24913 => 23915, 24914 => 23883, 24915 => 23882, 24916 => 23913, 24917 => 23924, 24918 => 23938, 24919 => 23961, 24920 => 23965, 24921 => 35955, 24922 => 23991, 24923 => 24005, 24924 => 24435, 24925 => 24439, 24926 => 24450, 24927 => 24455, 24928 => 24457, 24929 => 24460, 24930 => 24469, 24931 => 24473, 24932 => 24476, 24933 => 24488, 24934 => 24493, 24935 => 24501, 24936 => 24508, 24937 => 34914, 24938 => 24417, 24939 => 29357, 24940 => 29360, 24941 => 29364, 24942 => 29367, 24943 => 29368, 24944 => 29379, 24945 => 29377, 24946 => 29390, 24947 => 29389, 24948 => 29394, 24949 => 29416, 24950 => 29423, 24951 => 29417, 24952 => 29426, 24953 => 29428, 24954 => 29431, 24955 => 29441, 24956 => 29427, 24957 => 29443, 24958 => 29434, 25121 => 29435, 25122 => 29463, 25123 => 29459, 25124 => 29473, 25125 => 29450, 25126 => 29470, 25127 => 29469, 25128 => 29461, 25129 => 29474, 25130 => 29497, 25131 => 29477, 25132 => 29484, 25133 => 29496, 25134 => 29489, 25135 => 29520, 25136 => 29517, 25137 => 29527, 25138 => 29536, 25139 => 29548, 25140 => 29551, 25141 => 29566, 25142 => 33307, 25143 => 22821, 25144 => 39143, 25145 => 22820, 25146 => 22786, 25147 => 39267, 25148 => 39271, 25149 => 39272, 25150 => 39273, 25151 => 39274, 25152 => 39275, 25153 => 39276, 25154 => 39284, 25155 => 39287, 25156 => 39293, 25157 => 39296, 25158 => 39300, 25159 => 39303, 25160 => 39306, 25161 => 39309, 25162 => 39312, 25163 => 39313, 25164 => 39315, 25165 => 39316, 25166 => 39317, 25167 => 24192, 25168 => 24209, 25169 => 24203, 25170 => 24214, 25171 => 24229, 25172 => 24224, 25173 => 24249, 25174 => 24245, 25175 => 24254, 25176 => 24243, 25177 => 36179, 25178 => 24274, 25179 => 24273, 25180 => 24283, 25181 => 24296, 25182 => 24298, 25183 => 33210, 25184 => 24516, 25185 => 24521, 25186 => 24534, 25187 => 24527, 25188 => 24579, 25189 => 24558, 25190 => 24580, 25191 => 24545, 25192 => 24548, 25193 => 24574, 25194 => 24581, 25195 => 24582, 25196 => 24554, 25197 => 24557, 25198 => 24568, 25199 => 24601, 25200 => 24629, 25201 => 24614, 25202 => 24603, 25203 => 24591, 25204 => 24589, 25205 => 24617, 25206 => 24619, 25207 => 24586, 25208 => 24639, 25209 => 24609, 25210 => 24696, 25211 => 24697, 25212 => 24699, 25213 => 24698, 25214 => 24642, 25377 => 24682, 25378 => 24701, 25379 => 24726, 25380 => 24730, 25381 => 24749, 25382 => 24733, 25383 => 24707, 25384 => 24722, 25385 => 24716, 25386 => 24731, 25387 => 24812, 25388 => 24763, 25389 => 24753, 25390 => 24797, 25391 => 24792, 25392 => 24774, 25393 => 24794, 25394 => 24756, 25395 => 24864, 25396 => 24870, 25397 => 24853, 25398 => 24867, 25399 => 24820, 25400 => 24832, 25401 => 24846, 25402 => 24875, 25403 => 24906, 25404 => 24949, 25405 => 25004, 25406 => 24980, 25407 => 24999, 25408 => 25015, 25409 => 25044, 25410 => 25077, 25411 => 24541, 25412 => 38579, 25413 => 38377, 25414 => 38379, 25415 => 38385, 25416 => 38387, 25417 => 38389, 25418 => 38390, 25419 => 38396, 25420 => 38398, 25421 => 38403, 25422 => 38404, 25423 => 38406, 25424 => 38408, 25425 => 38410, 25426 => 38411, 25427 => 38412, 25428 => 38413, 25429 => 38415, 25430 => 38418, 25431 => 38421, 25432 => 38422, 25433 => 38423, 25434 => 38425, 25435 => 38426, 25436 => 20012, 25437 => 29247, 25438 => 25109, 25439 => 27701, 25440 => 27732, 25441 => 27740, 25442 => 27722, 25443 => 27811, 25444 => 27781, 25445 => 27792, 25446 => 27796, 25447 => 27788, 25448 => 27752, 25449 => 27753, 25450 => 27764, 25451 => 27766, 25452 => 27782, 25453 => 27817, 25454 => 27856, 25455 => 27860, 25456 => 27821, 25457 => 27895, 25458 => 27896, 25459 => 27889, 25460 => 27863, 25461 => 27826, 25462 => 27872, 25463 => 27862, 25464 => 27898, 25465 => 27883, 25466 => 27886, 25467 => 27825, 25468 => 27859, 25469 => 27887, 25470 => 27902, 25633 => 27961, 25634 => 27943, 25635 => 27916, 25636 => 27971, 25637 => 27976, 25638 => 27911, 25639 => 27908, 25640 => 27929, 25641 => 27918, 25642 => 27947, 25643 => 27981, 25644 => 27950, 25645 => 27957, 25646 => 27930, 25647 => 27983, 25648 => 27986, 25649 => 27988, 25650 => 27955, 25651 => 28049, 25652 => 28015, 25653 => 28062, 25654 => 28064, 25655 => 27998, 25656 => 28051, 25657 => 28052, 25658 => 27996, 25659 => 28000, 25660 => 28028, 25661 => 28003, 25662 => 28186, 25663 => 28103, 25664 => 28101, 25665 => 28126, 25666 => 28174, 25667 => 28095, 25668 => 28128, 25669 => 28177, 25670 => 28134, 25671 => 28125, 25672 => 28121, 25673 => 28182, 25674 => 28075, 25675 => 28172, 25676 => 28078, 25677 => 28203, 25678 => 28270, 25679 => 28238, 25680 => 28267, 25681 => 28338, 25682 => 28255, 25683 => 28294, 25684 => 28243, 25685 => 28244, 25686 => 28210, 25687 => 28197, 25688 => 28228, 25689 => 28383, 25690 => 28337, 25691 => 28312, 25692 => 28384, 25693 => 28461, 25694 => 28386, 25695 => 28325, 25696 => 28327, 25697 => 28349, 25698 => 28347, 25699 => 28343, 25700 => 28375, 25701 => 28340, 25702 => 28367, 25703 => 28303, 25704 => 28354, 25705 => 28319, 25706 => 28514, 25707 => 28486, 25708 => 28487, 25709 => 28452, 25710 => 28437, 25711 => 28409, 25712 => 28463, 25713 => 28470, 25714 => 28491, 25715 => 28532, 25716 => 28458, 25717 => 28425, 25718 => 28457, 25719 => 28553, 25720 => 28557, 25721 => 28556, 25722 => 28536, 25723 => 28530, 25724 => 28540, 25725 => 28538, 25726 => 28625, 25889 => 28617, 25890 => 28583, 25891 => 28601, 25892 => 28598, 25893 => 28610, 25894 => 28641, 25895 => 28654, 25896 => 28638, 25897 => 28640, 25898 => 28655, 25899 => 28698, 25900 => 28707, 25901 => 28699, 25902 => 28729, 25903 => 28725, 25904 => 28751, 25905 => 28766, 25906 => 23424, 25907 => 23428, 25908 => 23445, 25909 => 23443, 25910 => 23461, 25911 => 23480, 25912 => 29999, 25913 => 39582, 25914 => 25652, 25915 => 23524, 25916 => 23534, 25917 => 35120, 25918 => 23536, 25919 => 36423, 25920 => 35591, 25921 => 36790, 25922 => 36819, 25923 => 36821, 25924 => 36837, 25925 => 36846, 25926 => 36836, 25927 => 36841, 25928 => 36838, 25929 => 36851, 25930 => 36840, 25931 => 36869, 25932 => 36868, 25933 => 36875, 25934 => 36902, 25935 => 36881, 25936 => 36877, 25937 => 36886, 25938 => 36897, 25939 => 36917, 25940 => 36918, 25941 => 36909, 25942 => 36911, 25943 => 36932, 25944 => 36945, 25945 => 36946, 25946 => 36944, 25947 => 36968, 25948 => 36952, 25949 => 36962, 25950 => 36955, 25951 => 26297, 25952 => 36980, 25953 => 36989, 25954 => 36994, 25955 => 37000, 25956 => 36995, 25957 => 37003, 25958 => 24400, 25959 => 24407, 25960 => 24406, 25961 => 24408, 25962 => 23611, 25963 => 21675, 25964 => 23632, 25965 => 23641, 25966 => 23409, 25967 => 23651, 25968 => 23654, 25969 => 32700, 25970 => 24362, 25971 => 24361, 25972 => 24365, 25973 => 33396, 25974 => 24380, 25975 => 39739, 25976 => 23662, 25977 => 22913, 25978 => 22915, 25979 => 22925, 25980 => 22953, 25981 => 22954, 25982 => 22947, 26145 => 22935, 26146 => 22986, 26147 => 22955, 26148 => 22942, 26149 => 22948, 26150 => 22994, 26151 => 22962, 26152 => 22959, 26153 => 22999, 26154 => 22974, 26155 => 23045, 26156 => 23046, 26157 => 23005, 26158 => 23048, 26159 => 23011, 26160 => 23000, 26161 => 23033, 26162 => 23052, 26163 => 23049, 26164 => 23090, 26165 => 23092, 26166 => 23057, 26167 => 23075, 26168 => 23059, 26169 => 23104, 26170 => 23143, 26171 => 23114, 26172 => 23125, 26173 => 23100, 26174 => 23138, 26175 => 23157, 26176 => 33004, 26177 => 23210, 26178 => 23195, 26179 => 23159, 26180 => 23162, 26181 => 23230, 26182 => 23275, 26183 => 23218, 26184 => 23250, 26185 => 23252, 26186 => 23224, 26187 => 23264, 26188 => 23267, 26189 => 23281, 26190 => 23254, 26191 => 23270, 26192 => 23256, 26193 => 23260, 26194 => 23305, 26195 => 23319, 26196 => 23318, 26197 => 23346, 26198 => 23351, 26199 => 23360, 26200 => 23573, 26201 => 23580, 26202 => 23386, 26203 => 23397, 26204 => 23411, 26205 => 23377, 26206 => 23379, 26207 => 23394, 26208 => 39541, 26209 => 39543, 26210 => 39544, 26211 => 39546, 26212 => 39551, 26213 => 39549, 26214 => 39552, 26215 => 39553, 26216 => 39557, 26217 => 39560, 26218 => 39562, 26219 => 39568, 26220 => 39570, 26221 => 39571, 26222 => 39574, 26223 => 39576, 26224 => 39579, 26225 => 39580, 26226 => 39581, 26227 => 39583, 26228 => 39584, 26229 => 39586, 26230 => 39587, 26231 => 39589, 26232 => 39591, 26233 => 32415, 26234 => 32417, 26235 => 32419, 26236 => 32421, 26237 => 32424, 26238 => 32425, 26401 => 32429, 26402 => 32432, 26403 => 32446, 26404 => 32448, 26405 => 32449, 26406 => 32450, 26407 => 32457, 26408 => 32459, 26409 => 32460, 26410 => 32464, 26411 => 32468, 26412 => 32471, 26413 => 32475, 26414 => 32480, 26415 => 32481, 26416 => 32488, 26417 => 32491, 26418 => 32494, 26419 => 32495, 26420 => 32497, 26421 => 32498, 26422 => 32525, 26423 => 32502, 26424 => 32506, 26425 => 32507, 26426 => 32510, 26427 => 32513, 26428 => 32514, 26429 => 32515, 26430 => 32519, 26431 => 32520, 26432 => 32523, 26433 => 32524, 26434 => 32527, 26435 => 32529, 26436 => 32530, 26437 => 32535, 26438 => 32537, 26439 => 32540, 26440 => 32539, 26441 => 32543, 26442 => 32545, 26443 => 32546, 26444 => 32547, 26445 => 32548, 26446 => 32549, 26447 => 32550, 26448 => 32551, 26449 => 32554, 26450 => 32555, 26451 => 32556, 26452 => 32557, 26453 => 32559, 26454 => 32560, 26455 => 32561, 26456 => 32562, 26457 => 32563, 26458 => 32565, 26459 => 24186, 26460 => 30079, 26461 => 24027, 26462 => 30014, 26463 => 37013, 26464 => 29582, 26465 => 29585, 26466 => 29614, 26467 => 29602, 26468 => 29599, 26469 => 29647, 26470 => 29634, 26471 => 29649, 26472 => 29623, 26473 => 29619, 26474 => 29632, 26475 => 29641, 26476 => 29640, 26477 => 29669, 26478 => 29657, 26479 => 39036, 26480 => 29706, 26481 => 29673, 26482 => 29671, 26483 => 29662, 26484 => 29626, 26485 => 29682, 26486 => 29711, 26487 => 29738, 26488 => 29787, 26489 => 29734, 26490 => 29733, 26491 => 29736, 26492 => 29744, 26493 => 29742, 26494 => 29740, 26657 => 29723, 26658 => 29722, 26659 => 29761, 26660 => 29788, 26661 => 29783, 26662 => 29781, 26663 => 29785, 26664 => 29815, 26665 => 29805, 26666 => 29822, 26667 => 29852, 26668 => 29838, 26669 => 29824, 26670 => 29825, 26671 => 29831, 26672 => 29835, 26673 => 29854, 26674 => 29864, 26675 => 29865, 26676 => 29840, 26677 => 29863, 26678 => 29906, 26679 => 29882, 26680 => 38890, 26681 => 38891, 26682 => 38892, 26683 => 26444, 26684 => 26451, 26685 => 26462, 26686 => 26440, 26687 => 26473, 26688 => 26533, 26689 => 26503, 26690 => 26474, 26691 => 26483, 26692 => 26520, 26693 => 26535, 26694 => 26485, 26695 => 26536, 26696 => 26526, 26697 => 26541, 26698 => 26507, 26699 => 26487, 26700 => 26492, 26701 => 26608, 26702 => 26633, 26703 => 26584, 26704 => 26634, 26705 => 26601, 26706 => 26544, 26707 => 26636, 26708 => 26585, 26709 => 26549, 26710 => 26586, 26711 => 26547, 26712 => 26589, 26713 => 26624, 26714 => 26563, 26715 => 26552, 26716 => 26594, 26717 => 26638, 26718 => 26561, 26719 => 26621, 26720 => 26674, 26721 => 26675, 26722 => 26720, 26723 => 26721, 26724 => 26702, 26725 => 26722, 26726 => 26692, 26727 => 26724, 26728 => 26755, 26729 => 26653, 26730 => 26709, 26731 => 26726, 26732 => 26689, 26733 => 26727, 26734 => 26688, 26735 => 26686, 26736 => 26698, 26737 => 26697, 26738 => 26665, 26739 => 26805, 26740 => 26767, 26741 => 26740, 26742 => 26743, 26743 => 26771, 26744 => 26731, 26745 => 26818, 26746 => 26990, 26747 => 26876, 26748 => 26911, 26749 => 26912, 26750 => 26873, 26913 => 26916, 26914 => 26864, 26915 => 26891, 26916 => 26881, 26917 => 26967, 26918 => 26851, 26919 => 26896, 26920 => 26993, 26921 => 26937, 26922 => 26976, 26923 => 26946, 26924 => 26973, 26925 => 27012, 26926 => 26987, 26927 => 27008, 26928 => 27032, 26929 => 27000, 26930 => 26932, 26931 => 27084, 26932 => 27015, 26933 => 27016, 26934 => 27086, 26935 => 27017, 26936 => 26982, 26937 => 26979, 26938 => 27001, 26939 => 27035, 26940 => 27047, 26941 => 27067, 26942 => 27051, 26943 => 27053, 26944 => 27092, 26945 => 27057, 26946 => 27073, 26947 => 27082, 26948 => 27103, 26949 => 27029, 26950 => 27104, 26951 => 27021, 26952 => 27135, 26953 => 27183, 26954 => 27117, 26955 => 27159, 26956 => 27160, 26957 => 27237, 26958 => 27122, 26959 => 27204, 26960 => 27198, 26961 => 27296, 26962 => 27216, 26963 => 27227, 26964 => 27189, 26965 => 27278, 26966 => 27257, 26967 => 27197, 26968 => 27176, 26969 => 27224, 26970 => 27260, 26971 => 27281, 26972 => 27280, 26973 => 27305, 26974 => 27287, 26975 => 27307, 26976 => 29495, 26977 => 29522, 26978 => 27521, 26979 => 27522, 26980 => 27527, 26981 => 27524, 26982 => 27538, 26983 => 27539, 26984 => 27533, 26985 => 27546, 26986 => 27547, 26987 => 27553, 26988 => 27562, 26989 => 36715, 26990 => 36717, 26991 => 36721, 26992 => 36722, 26993 => 36723, 26994 => 36725, 26995 => 36726, 26996 => 36728, 26997 => 36727, 26998 => 36729, 26999 => 36730, 27000 => 36732, 27001 => 36734, 27002 => 36737, 27003 => 36738, 27004 => 36740, 27005 => 36743, 27006 => 36747, 27169 => 36749, 27170 => 36750, 27171 => 36751, 27172 => 36760, 27173 => 36762, 27174 => 36558, 27175 => 25099, 27176 => 25111, 27177 => 25115, 27178 => 25119, 27179 => 25122, 27180 => 25121, 27181 => 25125, 27182 => 25124, 27183 => 25132, 27184 => 33255, 27185 => 29935, 27186 => 29940, 27187 => 29951, 27188 => 29967, 27189 => 29969, 27190 => 29971, 27191 => 25908, 27192 => 26094, 27193 => 26095, 27194 => 26096, 27195 => 26122, 27196 => 26137, 27197 => 26482, 27198 => 26115, 27199 => 26133, 27200 => 26112, 27201 => 28805, 27202 => 26359, 27203 => 26141, 27204 => 26164, 27205 => 26161, 27206 => 26166, 27207 => 26165, 27208 => 32774, 27209 => 26207, 27210 => 26196, 27211 => 26177, 27212 => 26191, 27213 => 26198, 27214 => 26209, 27215 => 26199, 27216 => 26231, 27217 => 26244, 27218 => 26252, 27219 => 26279, 27220 => 26269, 27221 => 26302, 27222 => 26331, 27223 => 26332, 27224 => 26342, 27225 => 26345, 27226 => 36146, 27227 => 36147, 27228 => 36150, 27229 => 36155, 27230 => 36157, 27231 => 36160, 27232 => 36165, 27233 => 36166, 27234 => 36168, 27235 => 36169, 27236 => 36167, 27237 => 36173, 27238 => 36181, 27239 => 36185, 27240 => 35271, 27241 => 35274, 27242 => 35275, 27243 => 35276, 27244 => 35278, 27245 => 35279, 27246 => 35280, 27247 => 35281, 27248 => 29294, 27249 => 29343, 27250 => 29277, 27251 => 29286, 27252 => 29295, 27253 => 29310, 27254 => 29311, 27255 => 29316, 27256 => 29323, 27257 => 29325, 27258 => 29327, 27259 => 29330, 27260 => 25352, 27261 => 25394, 27262 => 25520, 27425 => 25663, 27426 => 25816, 27427 => 32772, 27428 => 27626, 27429 => 27635, 27430 => 27645, 27431 => 27637, 27432 => 27641, 27433 => 27653, 27434 => 27655, 27435 => 27654, 27436 => 27661, 27437 => 27669, 27438 => 27672, 27439 => 27673, 27440 => 27674, 27441 => 27681, 27442 => 27689, 27443 => 27684, 27444 => 27690, 27445 => 27698, 27446 => 25909, 27447 => 25941, 27448 => 25963, 27449 => 29261, 27450 => 29266, 27451 => 29270, 27452 => 29232, 27453 => 34402, 27454 => 21014, 27455 => 32927, 27456 => 32924, 27457 => 32915, 27458 => 32956, 27459 => 26378, 27460 => 32957, 27461 => 32945, 27462 => 32939, 27463 => 32941, 27464 => 32948, 27465 => 32951, 27466 => 32999, 27467 => 33000, 27468 => 33001, 27469 => 33002, 27470 => 32987, 27471 => 32962, 27472 => 32964, 27473 => 32985, 27474 => 32973, 27475 => 32983, 27476 => 26384, 27477 => 32989, 27478 => 33003, 27479 => 33009, 27480 => 33012, 27481 => 33005, 27482 => 33037, 27483 => 33038, 27484 => 33010, 27485 => 33020, 27486 => 26389, 27487 => 33042, 27488 => 35930, 27489 => 33078, 27490 => 33054, 27491 => 33068, 27492 => 33048, 27493 => 33074, 27494 => 33096, 27495 => 33100, 27496 => 33107, 27497 => 33140, 27498 => 33113, 27499 => 33114, 27500 => 33137, 27501 => 33120, 27502 => 33129, 27503 => 33148, 27504 => 33149, 27505 => 33133, 27506 => 33127, 27507 => 22605, 27508 => 23221, 27509 => 33160, 27510 => 33154, 27511 => 33169, 27512 => 28373, 27513 => 33187, 27514 => 33194, 27515 => 33228, 27516 => 26406, 27517 => 33226, 27518 => 33211, 27681 => 33217, 27682 => 33190, 27683 => 27428, 27684 => 27447, 27685 => 27449, 27686 => 27459, 27687 => 27462, 27688 => 27481, 27689 => 39121, 27690 => 39122, 27691 => 39123, 27692 => 39125, 27693 => 39129, 27694 => 39130, 27695 => 27571, 27696 => 24384, 27697 => 27586, 27698 => 35315, 27699 => 26000, 27700 => 40785, 27701 => 26003, 27702 => 26044, 27703 => 26054, 27704 => 26052, 27705 => 26051, 27706 => 26060, 27707 => 26062, 27708 => 26066, 27709 => 26070, 27710 => 28800, 27711 => 28828, 27712 => 28822, 27713 => 28829, 27714 => 28859, 27715 => 28864, 27716 => 28855, 27717 => 28843, 27718 => 28849, 27719 => 28904, 27720 => 28874, 27721 => 28944, 27722 => 28947, 27723 => 28950, 27724 => 28975, 27725 => 28977, 27726 => 29043, 27727 => 29020, 27728 => 29032, 27729 => 28997, 27730 => 29042, 27731 => 29002, 27732 => 29048, 27733 => 29050, 27734 => 29080, 27735 => 29107, 27736 => 29109, 27737 => 29096, 27738 => 29088, 27739 => 29152, 27740 => 29140, 27741 => 29159, 27742 => 29177, 27743 => 29213, 27744 => 29224, 27745 => 28780, 27746 => 28952, 27747 => 29030, 27748 => 29113, 27749 => 25150, 27750 => 25149, 27751 => 25155, 27752 => 25160, 27753 => 25161, 27754 => 31035, 27755 => 31040, 27756 => 31046, 27757 => 31049, 27758 => 31067, 27759 => 31068, 27760 => 31059, 27761 => 31066, 27762 => 31074, 27763 => 31063, 27764 => 31072, 27765 => 31087, 27766 => 31079, 27767 => 31098, 27768 => 31109, 27769 => 31114, 27770 => 31130, 27771 => 31143, 27772 => 31155, 27773 => 24529, 27774 => 24528, 27937 => 24636, 27938 => 24669, 27939 => 24666, 27940 => 24679, 27941 => 24641, 27942 => 24665, 27943 => 24675, 27944 => 24747, 27945 => 24838, 27946 => 24845, 27947 => 24925, 27948 => 25001, 27949 => 24989, 27950 => 25035, 27951 => 25041, 27952 => 25094, 27953 => 32896, 27954 => 32895, 27955 => 27795, 27956 => 27894, 27957 => 28156, 27958 => 30710, 27959 => 30712, 27960 => 30720, 27961 => 30729, 27962 => 30743, 27963 => 30744, 27964 => 30737, 27965 => 26027, 27966 => 30765, 27967 => 30748, 27968 => 30749, 27969 => 30777, 27970 => 30778, 27971 => 30779, 27972 => 30751, 27973 => 30780, 27974 => 30757, 27975 => 30764, 27976 => 30755, 27977 => 30761, 27978 => 30798, 27979 => 30829, 27980 => 30806, 27981 => 30807, 27982 => 30758, 27983 => 30800, 27984 => 30791, 27985 => 30796, 27986 => 30826, 27987 => 30875, 27988 => 30867, 27989 => 30874, 27990 => 30855, 27991 => 30876, 27992 => 30881, 27993 => 30883, 27994 => 30898, 27995 => 30905, 27996 => 30885, 27997 => 30932, 27998 => 30937, 27999 => 30921, 28000 => 30956, 28001 => 30962, 28002 => 30981, 28003 => 30964, 28004 => 30995, 28005 => 31012, 28006 => 31006, 28007 => 31028, 28008 => 40859, 28009 => 40697, 28010 => 40699, 28011 => 40700, 28012 => 30449, 28013 => 30468, 28014 => 30477, 28015 => 30457, 28016 => 30471, 28017 => 30472, 28018 => 30490, 28019 => 30498, 28020 => 30489, 28021 => 30509, 28022 => 30502, 28023 => 30517, 28024 => 30520, 28025 => 30544, 28026 => 30545, 28027 => 30535, 28028 => 30531, 28029 => 30554, 28030 => 30568, 28193 => 30562, 28194 => 30565, 28195 => 30591, 28196 => 30605, 28197 => 30589, 28198 => 30592, 28199 => 30604, 28200 => 30609, 28201 => 30623, 28202 => 30624, 28203 => 30640, 28204 => 30645, 28205 => 30653, 28206 => 30010, 28207 => 30016, 28208 => 30030, 28209 => 30027, 28210 => 30024, 28211 => 30043, 28212 => 30066, 28213 => 30073, 28214 => 30083, 28215 => 32600, 28216 => 32609, 28217 => 32607, 28218 => 35400, 28219 => 32616, 28220 => 32628, 28221 => 32625, 28222 => 32633, 28223 => 32641, 28224 => 32638, 28225 => 30413, 28226 => 30437, 28227 => 34866, 28228 => 38021, 28229 => 38022, 28230 => 38023, 28231 => 38027, 28232 => 38026, 28233 => 38028, 28234 => 38029, 28235 => 38031, 28236 => 38032, 28237 => 38036, 28238 => 38039, 28239 => 38037, 28240 => 38042, 28241 => 38043, 28242 => 38044, 28243 => 38051, 28244 => 38052, 28245 => 38059, 28246 => 38058, 28247 => 38061, 28248 => 38060, 28249 => 38063, 28250 => 38064, 28251 => 38066, 28252 => 38068, 28253 => 38070, 28254 => 38071, 28255 => 38072, 28256 => 38073, 28257 => 38074, 28258 => 38076, 28259 => 38077, 28260 => 38079, 28261 => 38084, 28262 => 38088, 28263 => 38089, 28264 => 38090, 28265 => 38091, 28266 => 38092, 28267 => 38093, 28268 => 38094, 28269 => 38096, 28270 => 38097, 28271 => 38098, 28272 => 38101, 28273 => 38102, 28274 => 38103, 28275 => 38105, 28276 => 38104, 28277 => 38107, 28278 => 38110, 28279 => 38111, 28280 => 38112, 28281 => 38114, 28282 => 38116, 28283 => 38117, 28284 => 38119, 28285 => 38120, 28286 => 38122, 28449 => 38121, 28450 => 38123, 28451 => 38126, 28452 => 38127, 28453 => 38131, 28454 => 38132, 28455 => 38133, 28456 => 38135, 28457 => 38137, 28458 => 38140, 28459 => 38141, 28460 => 38143, 28461 => 38147, 28462 => 38146, 28463 => 38150, 28464 => 38151, 28465 => 38153, 28466 => 38154, 28467 => 38157, 28468 => 38158, 28469 => 38159, 28470 => 38162, 28471 => 38163, 28472 => 38164, 28473 => 38165, 28474 => 38166, 28475 => 38168, 28476 => 38171, 28477 => 38173, 28478 => 38174, 28479 => 38175, 28480 => 38178, 28481 => 38186, 28482 => 38187, 28483 => 38185, 28484 => 38188, 28485 => 38193, 28486 => 38194, 28487 => 38196, 28488 => 38198, 28489 => 38199, 28490 => 38200, 28491 => 38204, 28492 => 38206, 28493 => 38207, 28494 => 38210, 28495 => 38197, 28496 => 38212, 28497 => 38213, 28498 => 38214, 28499 => 38217, 28500 => 38220, 28501 => 38222, 28502 => 38223, 28503 => 38226, 28504 => 38227, 28505 => 38228, 28506 => 38230, 28507 => 38231, 28508 => 38232, 28509 => 38233, 28510 => 38235, 28511 => 38238, 28512 => 38239, 28513 => 38237, 28514 => 38241, 28515 => 38242, 28516 => 38244, 28517 => 38245, 28518 => 38246, 28519 => 38247, 28520 => 38248, 28521 => 38249, 28522 => 38250, 28523 => 38251, 28524 => 38252, 28525 => 38255, 28526 => 38257, 28527 => 38258, 28528 => 38259, 28529 => 38202, 28530 => 30695, 28531 => 30700, 28532 => 38601, 28533 => 31189, 28534 => 31213, 28535 => 31203, 28536 => 31211, 28537 => 31238, 28538 => 23879, 28539 => 31235, 28540 => 31234, 28541 => 31262, 28542 => 31252, 28705 => 31289, 28706 => 31287, 28707 => 31313, 28708 => 40655, 28709 => 39333, 28710 => 31344, 28711 => 30344, 28712 => 30350, 28713 => 30355, 28714 => 30361, 28715 => 30372, 28716 => 29918, 28717 => 29920, 28718 => 29996, 28719 => 40480, 28720 => 40482, 28721 => 40488, 28722 => 40489, 28723 => 40490, 28724 => 40491, 28725 => 40492, 28726 => 40498, 28727 => 40497, 28728 => 40502, 28729 => 40504, 28730 => 40503, 28731 => 40505, 28732 => 40506, 28733 => 40510, 28734 => 40513, 28735 => 40514, 28736 => 40516, 28737 => 40518, 28738 => 40519, 28739 => 40520, 28740 => 40521, 28741 => 40523, 28742 => 40524, 28743 => 40526, 28744 => 40529, 28745 => 40533, 28746 => 40535, 28747 => 40538, 28748 => 40539, 28749 => 40540, 28750 => 40542, 28751 => 40547, 28752 => 40550, 28753 => 40551, 28754 => 40552, 28755 => 40553, 28756 => 40554, 28757 => 40555, 28758 => 40556, 28759 => 40561, 28760 => 40557, 28761 => 40563, 28762 => 30098, 28763 => 30100, 28764 => 30102, 28765 => 30112, 28766 => 30109, 28767 => 30124, 28768 => 30115, 28769 => 30131, 28770 => 30132, 28771 => 30136, 28772 => 30148, 28773 => 30129, 28774 => 30128, 28775 => 30147, 28776 => 30146, 28777 => 30166, 28778 => 30157, 28779 => 30179, 28780 => 30184, 28781 => 30182, 28782 => 30180, 28783 => 30187, 28784 => 30183, 28785 => 30211, 28786 => 30193, 28787 => 30204, 28788 => 30207, 28789 => 30224, 28790 => 30208, 28791 => 30213, 28792 => 30220, 28793 => 30231, 28794 => 30218, 28795 => 30245, 28796 => 30232, 28797 => 30229, 28798 => 30233, 28961 => 30235, 28962 => 30268, 28963 => 30242, 28964 => 30240, 28965 => 30272, 28966 => 30253, 28967 => 30256, 28968 => 30271, 28969 => 30261, 28970 => 30275, 28971 => 30270, 28972 => 30259, 28973 => 30285, 28974 => 30302, 28975 => 30292, 28976 => 30300, 28977 => 30294, 28978 => 30315, 28979 => 30319, 28980 => 32714, 28981 => 31462, 28982 => 31352, 28983 => 31353, 28984 => 31360, 28985 => 31366, 28986 => 31368, 28987 => 31381, 28988 => 31398, 28989 => 31392, 28990 => 31404, 28991 => 31400, 28992 => 31405, 28993 => 31411, 28994 => 34916, 28995 => 34921, 28996 => 34930, 28997 => 34941, 28998 => 34943, 28999 => 34946, 29000 => 34978, 29001 => 35014, 29002 => 34999, 29003 => 35004, 29004 => 35017, 29005 => 35042, 29006 => 35022, 29007 => 35043, 29008 => 35045, 29009 => 35057, 29010 => 35098, 29011 => 35068, 29012 => 35048, 29013 => 35070, 29014 => 35056, 29015 => 35105, 29016 => 35097, 29017 => 35091, 29018 => 35099, 29019 => 35082, 29020 => 35124, 29021 => 35115, 29022 => 35126, 29023 => 35137, 29024 => 35174, 29025 => 35195, 29026 => 30091, 29027 => 32997, 29028 => 30386, 29029 => 30388, 29030 => 30684, 29031 => 32786, 29032 => 32788, 29033 => 32790, 29034 => 32796, 29035 => 32800, 29036 => 32802, 29037 => 32805, 29038 => 32806, 29039 => 32807, 29040 => 32809, 29041 => 32808, 29042 => 32817, 29043 => 32779, 29044 => 32821, 29045 => 32835, 29046 => 32838, 29047 => 32845, 29048 => 32850, 29049 => 32873, 29050 => 32881, 29051 => 35203, 29052 => 39032, 29053 => 39040, 29054 => 39043, 29217 => 39049, 29218 => 39052, 29219 => 39053, 29220 => 39055, 29221 => 39060, 29222 => 39066, 29223 => 39067, 29224 => 39070, 29225 => 39071, 29226 => 39073, 29227 => 39074, 29228 => 39077, 29229 => 39078, 29230 => 34381, 29231 => 34388, 29232 => 34412, 29233 => 34414, 29234 => 34431, 29235 => 34426, 29236 => 34428, 29237 => 34427, 29238 => 34472, 29239 => 34445, 29240 => 34443, 29241 => 34476, 29242 => 34461, 29243 => 34471, 29244 => 34467, 29245 => 34474, 29246 => 34451, 29247 => 34473, 29248 => 34486, 29249 => 34500, 29250 => 34485, 29251 => 34510, 29252 => 34480, 29253 => 34490, 29254 => 34481, 29255 => 34479, 29256 => 34505, 29257 => 34511, 29258 => 34484, 29259 => 34537, 29260 => 34545, 29261 => 34546, 29262 => 34541, 29263 => 34547, 29264 => 34512, 29265 => 34579, 29266 => 34526, 29267 => 34548, 29268 => 34527, 29269 => 34520, 29270 => 34513, 29271 => 34563, 29272 => 34567, 29273 => 34552, 29274 => 34568, 29275 => 34570, 29276 => 34573, 29277 => 34569, 29278 => 34595, 29279 => 34619, 29280 => 34590, 29281 => 34597, 29282 => 34606, 29283 => 34586, 29284 => 34622, 29285 => 34632, 29286 => 34612, 29287 => 34609, 29288 => 34601, 29289 => 34615, 29290 => 34623, 29291 => 34690, 29292 => 34594, 29293 => 34685, 29294 => 34686, 29295 => 34683, 29296 => 34656, 29297 => 34672, 29298 => 34636, 29299 => 34670, 29300 => 34699, 29301 => 34643, 29302 => 34659, 29303 => 34684, 29304 => 34660, 29305 => 34649, 29306 => 34661, 29307 => 34707, 29308 => 34735, 29309 => 34728, 29310 => 34770, 29473 => 34758, 29474 => 34696, 29475 => 34693, 29476 => 34733, 29477 => 34711, 29478 => 34691, 29479 => 34731, 29480 => 34789, 29481 => 34732, 29482 => 34741, 29483 => 34739, 29484 => 34763, 29485 => 34771, 29486 => 34749, 29487 => 34769, 29488 => 34752, 29489 => 34762, 29490 => 34779, 29491 => 34794, 29492 => 34784, 29493 => 34798, 29494 => 34838, 29495 => 34835, 29496 => 34814, 29497 => 34826, 29498 => 34843, 29499 => 34849, 29500 => 34873, 29501 => 34876, 29502 => 32566, 29503 => 32578, 29504 => 32580, 29505 => 32581, 29506 => 33296, 29507 => 31482, 29508 => 31485, 29509 => 31496, 29510 => 31491, 29511 => 31492, 29512 => 31509, 29513 => 31498, 29514 => 31531, 29515 => 31503, 29516 => 31559, 29517 => 31544, 29518 => 31530, 29519 => 31513, 29520 => 31534, 29521 => 31537, 29522 => 31520, 29523 => 31525, 29524 => 31524, 29525 => 31539, 29526 => 31550, 29527 => 31518, 29528 => 31576, 29529 => 31578, 29530 => 31557, 29531 => 31605, 29532 => 31564, 29533 => 31581, 29534 => 31584, 29535 => 31598, 29536 => 31611, 29537 => 31586, 29538 => 31602, 29539 => 31601, 29540 => 31632, 29541 => 31654, 29542 => 31655, 29543 => 31672, 29544 => 31660, 29545 => 31645, 29546 => 31656, 29547 => 31621, 29548 => 31658, 29549 => 31644, 29550 => 31650, 29551 => 31659, 29552 => 31668, 29553 => 31697, 29554 => 31681, 29555 => 31692, 29556 => 31709, 29557 => 31706, 29558 => 31717, 29559 => 31718, 29560 => 31722, 29561 => 31756, 29562 => 31742, 29563 => 31740, 29564 => 31759, 29565 => 31766, 29566 => 31755, 29729 => 31775, 29730 => 31786, 29731 => 31782, 29732 => 31800, 29733 => 31809, 29734 => 31808, 29735 => 33278, 29736 => 33281, 29737 => 33282, 29738 => 33284, 29739 => 33260, 29740 => 34884, 29741 => 33313, 29742 => 33314, 29743 => 33315, 29744 => 33325, 29745 => 33327, 29746 => 33320, 29747 => 33323, 29748 => 33336, 29749 => 33339, 29750 => 33331, 29751 => 33332, 29752 => 33342, 29753 => 33348, 29754 => 33353, 29755 => 33355, 29756 => 33359, 29757 => 33370, 29758 => 33375, 29759 => 33384, 29760 => 34942, 29761 => 34949, 29762 => 34952, 29763 => 35032, 29764 => 35039, 29765 => 35166, 29766 => 32669, 29767 => 32671, 29768 => 32679, 29769 => 32687, 29770 => 32688, 29771 => 32690, 29772 => 31868, 29773 => 25929, 29774 => 31889, 29775 => 31901, 29776 => 31900, 29777 => 31902, 29778 => 31906, 29779 => 31922, 29780 => 31932, 29781 => 31933, 29782 => 31937, 29783 => 31943, 29784 => 31948, 29785 => 31949, 29786 => 31944, 29787 => 31941, 29788 => 31959, 29789 => 31976, 29790 => 33390, 29791 => 26280, 29792 => 32703, 29793 => 32718, 29794 => 32725, 29795 => 32741, 29796 => 32737, 29797 => 32742, 29798 => 32745, 29799 => 32750, 29800 => 32755, 29801 => 31992, 29802 => 32119, 29803 => 32166, 29804 => 32174, 29805 => 32327, 29806 => 32411, 29807 => 40632, 29808 => 40628, 29809 => 36211, 29810 => 36228, 29811 => 36244, 29812 => 36241, 29813 => 36273, 29814 => 36199, 29815 => 36205, 29816 => 35911, 29817 => 35913, 29818 => 37194, 29819 => 37200, 29820 => 37198, 29821 => 37199, 29822 => 37220, 29985 => 37218, 29986 => 37217, 29987 => 37232, 29988 => 37225, 29989 => 37231, 29990 => 37245, 29991 => 37246, 29992 => 37234, 29993 => 37236, 29994 => 37241, 29995 => 37260, 29996 => 37253, 29997 => 37264, 29998 => 37261, 29999 => 37265, 30000 => 37282, 30001 => 37283, 30002 => 37290, 30003 => 37293, 30004 => 37294, 30005 => 37295, 30006 => 37301, 30007 => 37300, 30008 => 37306, 30009 => 35925, 30010 => 40574, 30011 => 36280, 30012 => 36331, 30013 => 36357, 30014 => 36441, 30015 => 36457, 30016 => 36277, 30017 => 36287, 30018 => 36284, 30019 => 36282, 30020 => 36292, 30021 => 36310, 30022 => 36311, 30023 => 36314, 30024 => 36318, 30025 => 36302, 30026 => 36303, 30027 => 36315, 30028 => 36294, 30029 => 36332, 30030 => 36343, 30031 => 36344, 30032 => 36323, 30033 => 36345, 30034 => 36347, 30035 => 36324, 30036 => 36361, 30037 => 36349, 30038 => 36372, 30039 => 36381, 30040 => 36383, 30041 => 36396, 30042 => 36398, 30043 => 36387, 30044 => 36399, 30045 => 36410, 30046 => 36416, 30047 => 36409, 30048 => 36405, 30049 => 36413, 30050 => 36401, 30051 => 36425, 30052 => 36417, 30053 => 36418, 30054 => 36433, 30055 => 36434, 30056 => 36426, 30057 => 36464, 30058 => 36470, 30059 => 36476, 30060 => 36463, 30061 => 36468, 30062 => 36485, 30063 => 36495, 30064 => 36500, 30065 => 36496, 30066 => 36508, 30067 => 36510, 30068 => 35960, 30069 => 35970, 30070 => 35978, 30071 => 35973, 30072 => 35992, 30073 => 35988, 30074 => 26011, 30075 => 35286, 30076 => 35294, 30077 => 35290, 30078 => 35292, 30241 => 35301, 30242 => 35307, 30243 => 35311, 30244 => 35390, 30245 => 35622, 30246 => 38739, 30247 => 38633, 30248 => 38643, 30249 => 38639, 30250 => 38662, 30251 => 38657, 30252 => 38664, 30253 => 38671, 30254 => 38670, 30255 => 38698, 30256 => 38701, 30257 => 38704, 30258 => 38718, 30259 => 40832, 30260 => 40835, 30261 => 40837, 30262 => 40838, 30263 => 40839, 30264 => 40840, 30265 => 40841, 30266 => 40842, 30267 => 40844, 30268 => 40702, 30269 => 40715, 30270 => 40717, 30271 => 38585, 30272 => 38588, 30273 => 38589, 30274 => 38606, 30275 => 38610, 30276 => 30655, 30277 => 38624, 30278 => 37518, 30279 => 37550, 30280 => 37576, 30281 => 37694, 30282 => 37738, 30283 => 37834, 30284 => 37775, 30285 => 37950, 30286 => 37995, 30287 => 40063, 30288 => 40066, 30289 => 40069, 30290 => 40070, 30291 => 40071, 30292 => 40072, 30293 => 31267, 30294 => 40075, 30295 => 40078, 30296 => 40080, 30297 => 40081, 30298 => 40082, 30299 => 40084, 30300 => 40085, 30301 => 40090, 30302 => 40091, 30303 => 40094, 30304 => 40095, 30305 => 40096, 30306 => 40097, 30307 => 40098, 30308 => 40099, 30309 => 40101, 30310 => 40102, 30311 => 40103, 30312 => 40104, 30313 => 40105, 30314 => 40107, 30315 => 40109, 30316 => 40110, 30317 => 40112, 30318 => 40113, 30319 => 40114, 30320 => 40115, 30321 => 40116, 30322 => 40117, 30323 => 40118, 30324 => 40119, 30325 => 40122, 30326 => 40123, 30327 => 40124, 30328 => 40125, 30329 => 40132, 30330 => 40133, 30331 => 40134, 30332 => 40135, 30333 => 40138, 30334 => 40139, 30497 => 40140, 30498 => 40141, 30499 => 40142, 30500 => 40143, 30501 => 40144, 30502 => 40147, 30503 => 40148, 30504 => 40149, 30505 => 40151, 30506 => 40152, 30507 => 40153, 30508 => 40156, 30509 => 40157, 30510 => 40159, 30511 => 40162, 30512 => 38780, 30513 => 38789, 30514 => 38801, 30515 => 38802, 30516 => 38804, 30517 => 38831, 30518 => 38827, 30519 => 38819, 30520 => 38834, 30521 => 38836, 30522 => 39601, 30523 => 39600, 30524 => 39607, 30525 => 40536, 30526 => 39606, 30527 => 39610, 30528 => 39612, 30529 => 39617, 30530 => 39616, 30531 => 39621, 30532 => 39618, 30533 => 39627, 30534 => 39628, 30535 => 39633, 30536 => 39749, 30537 => 39747, 30538 => 39751, 30539 => 39753, 30540 => 39752, 30541 => 39757, 30542 => 39761, 30543 => 39144, 30544 => 39181, 30545 => 39214, 30546 => 39253, 30547 => 39252, 30548 => 39647, 30549 => 39649, 30550 => 39654, 30551 => 39663, 30552 => 39659, 30553 => 39675, 30554 => 39661, 30555 => 39673, 30556 => 39688, 30557 => 39695, 30558 => 39699, 30559 => 39711, 30560 => 39715, 30561 => 40637, 30562 => 40638, 30563 => 32315, 30564 => 40578, 30565 => 40583, 30566 => 40584, 30567 => 40587, 30568 => 40594, 30569 => 37846, 30570 => 40605, 30571 => 40607, 30572 => 40667, 30573 => 40668, 30574 => 40669, 30575 => 40672, 30576 => 40671, 30577 => 40674, 30578 => 40681, 30579 => 40679, 30580 => 40677, 30581 => 40682, 30582 => 40687, 30583 => 40738, 30584 => 40748, 30585 => 40751, 30586 => 40761, 30587 => 40759, 30588 => 40765, 30589 => 40766, 30590 => 40772, 0 => 0 ); function gb2utf8($gb) { if( !trim($gb) ) return $gb; $utf8=''; while($gb) { if( ord(substr($gb,0,1)) > 127 ) { $t=substr($gb,0,2); $gb=substr($gb,2); $utf8 .= $this->u2utf8($this->codetable[hexdec(bin2hex($t))-0x8080]); } else { $t=substr($gb,0,1); $gb=substr($gb,1); $utf8 .= $this->u2utf8($t); } } return $utf8; } function u2utf8($c) { $str=''; if ($c < 0x80) { $str.=$c; } else if ($c < 0x800) { $str.=chr(0xC0 | $c>>6); $str.=chr(0x80 | $c & 0x3F); } else if ($c < 0x10000) { $str.=chr(0xE0 | $c>>12); $str.=chr(0x80 | $c>>6 & 0x3F); $str.=chr(0x80 | $c & 0x3F); } else if ($c < 0x200000) { $str.=chr(0xF0 | $c>>18); $str.=chr(0x80 | $c>>12 & 0x3F); $str.=chr(0x80 | $c>>6 & 0x3F); $str.=chr(0x80 | $c & 0x3F); } return $str; } } // END Class ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_gradient.php ================================================ img = &$img; } function SetNumColors($aNum) { $this->numcolors=$aNum; } //--------------- // PUBLIC METHODS // Produce a gradient filled rectangle with a smooth transition between // two colors. // ($xl,$yt) Top left corner // ($xr,$yb) Bottom right // $from_color Starting color in gradient // $to_color End color in the gradient // $style Which way is the gradient oriented? function FilledRectangle($xl,$yt,$xr,$yb,$from_color,$to_color,$style=1) { switch( $style ) { case GRAD_VER: $steps = round(abs($xr-$xl)); $delta = $xr>=$xl ? 1 : -1; $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); for( $i=0, $x=$xl; $i < $steps; ++$i ) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yt,$x,$yb); $x += $delta; } break; case GRAD_HOR: $steps = round(abs($yb-$yt)); $delta = $yb>=$yt ? 1 : -1; $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); for($i=0,$y=$yt; $i < $steps; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($xl,$y,$xr,$y); $y += $delta; } break; case GRAD_MIDHOR: $steps = round(abs($yb-$yt)/2); $delta = $yb >= $yt ? 1 : -1; $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); for($y=$yt, $i=0; $i < $steps; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($xl,$y,$xr,$y); $y += $delta; } --$i; if( abs($yb-$yt) % 2 == 1 ) --$steps; for($j=0; $j < $steps; ++$j, --$i) { $this->img->current_color = $colors[$i]; $this->img->Line($xl,$y,$xr,$y); $y += $delta; } $this->img->Line($xl,$y,$xr,$y); break; case GRAD_MIDVER: $steps = round(abs($xr-$xl)/2); $delta = $xr>=$xl ? 1 : -1; $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); for($x=$xl, $i=0; $i < $steps; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } --$i; if( abs($xr-$xl) % 2 == 1 ) --$steps; for($j=0; $j < $steps; ++$j, --$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } $this->img->Line($x,$yb,$x,$yt); break; case GRAD_WIDE_MIDVER: $diff = round(abs($xr-$xl)); $steps = floor(abs($diff)/3); $firststep = $diff - 2*$steps ; $delta = $xr >= $xl ? 1 : -1; $this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors); for($x=$xl, $i=0; $i < $firststep; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } --$i; $this->img->current_color = $colors[$i]; for($j=0; $j< $steps; ++$j) { $this->img->Line($x,$yb,$x,$yt); $x += $delta; } for($j=0; $j < $steps; ++$j, --$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } break; case GRAD_WIDE_MIDHOR: $diff = round(abs($yb-$yt)); $steps = floor(abs($diff)/3); $firststep = $diff - 2*$steps ; $delta = $yb >= $yt? 1 : -1; $this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors); for($y=$yt, $i=0; $i < $firststep; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($xl,$y,$xr,$y); $y += $delta; } --$i; $this->img->current_color = $colors[$i]; for($j=0; $j < $steps; ++$j) { $this->img->Line($xl,$y,$xr,$y); $y += $delta; } for($j=0; $j < $steps; ++$j, --$i) { $this->img->current_color = $colors[$i]; $this->img->Line($xl,$y,$xr,$y); $y += $delta; } break; case GRAD_LEFT_REFLECTION: $steps1 = round(0.3*abs($xr-$xl)); $delta = $xr>=$xl ? 1 : -1; $from_color = $this->img->rgb->Color($from_color); $adj = 1.4; $m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2])))); $from_color2 = array(min(255,$from_color[0]+$m), min(255,$from_color[1]+$m), min(255,$from_color[2]+$m)); $this->GetColArray($from_color2,$to_color,$steps1,$colors,$this->numcolors); $n = count($colors); for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } $steps2 = max(1,round(0.08*abs($xr-$xl))); $this->img->SetColor($to_color); for($j=0; $j< $steps2; ++$j) { $this->img->Line($x,$yb,$x,$yt); $x += $delta; } $steps = abs($xr-$xl)-$steps1-$steps2; $this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors); $n = count($colors); for($i=0; $i < $steps && $i < $n; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } break; case GRAD_RIGHT_REFLECTION: $steps1 = round(0.7*abs($xr-$xl)); $delta = $xr>=$xl ? 1 : -1; $this->GetColArray($from_color,$to_color,$steps1,$colors,$this->numcolors); $n = count($colors); for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } $steps2 = max(1,round(0.08*abs($xr-$xl))); $this->img->SetColor($to_color); for($j=0; $j< $steps2; ++$j) { $this->img->Line($x,$yb,$x,$yt); $x += $delta; } $from_color = $this->img->rgb->Color($from_color); $adj = 1.4; $m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2])))); $from_color = array(min(255,$from_color[0]+$m), min(255,$from_color[1]+$m), min(255,$from_color[2]+$m)); $steps = abs($xr-$xl)-$steps1-$steps2; $this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors); $n = count($colors); for($i=0; $i < $steps && $i < $n; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } break; case GRAD_CENTER: $steps = ceil(min(($yb-$yt)+1,($xr-$xl)+1)/2); $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); $dx = ($xr-$xl)/2; $dy = ($yb-$yt)/2; $x=$xl;$y=$yt;$x2=$xr;$y2=$yb; $n = count($colors); for($x=$xl, $i=0; $x < $xl+$dx && $y < $yt+$dy && $i < $n; ++$x, ++$y, --$x2, --$y2, ++$i) { $this->img->current_color = $colors[$i]; $this->img->Rectangle($x,$y,$x2,$y2); } $this->img->Line($x,$y,$x2,$y2); break; case GRAD_RAISED_PANEL: // right to left $steps1 = $xr-$xl; $delta = $xr>=$xl ? 1 : -1; $this->GetColArray($to_color,$from_color,$steps1,$colors,$this->numcolors); $n = count($colors); for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { $this->img->current_color = $colors[$i]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } // left to right $xr -= 3; $xl += 3; $yb -= 3; $yt += 3; $steps2 = $xr-$xl; $delta = $xr>=$xl ? 1 : -1; for($x=$xl, $j=$steps2; $j >= 0; --$j) { $this->img->current_color = $colors[$j]; $this->img->Line($x,$yb,$x,$yt); $x += $delta; } break; default: JpGraphError::RaiseL(7001,$style); //("Unknown gradient style (=$style)."); break; } } // Fill a special case of a polygon with a flat bottom // with a gradient. Can be used for filled line plots. // Please note that this is NOT a generic gradient polygon fill // routine. It assumes that the bottom is flat (like a drawing // of a mountain) function FilledFlatPolygon($pts,$from_color,$to_color) { if( count($pts) == 0 ) return; $maxy=$pts[1]; $miny=$pts[1]; $n = count($pts) ; for( $i=0, $idx=0; $i < $n; $i += 2) { $x = round($pts[$i]); $y = round($pts[$i+1]); $miny = min($miny,$y); $maxy = max($maxy,$y); } $colors = array(); $this->GetColArray($from_color,$to_color,abs($maxy-$miny)+1,$colors,$this->numcolors); for($i=$miny, $idx=0; $i <= $maxy; ++$i ) { $colmap[$i] = $colors[$idx++]; } $n = count($pts)/2 ; $idx = 0 ; while( $idx < $n-1 ) { $p1 = array(round($pts[$idx*2]),round($pts[$idx*2+1])); $p2 = array(round($pts[++$idx*2]),round($pts[$idx*2+1])); // Find the largest rectangle we can fill $y = max($p1[1],$p2[1]) ; for($yy=$maxy; $yy > $y; --$yy) { $this->img->current_color = $colmap[$yy]; $this->img->Line($p1[0],$yy,$p2[0]-1,$yy); } if( $p1[1] == $p2[1] ) continue; // Fill the rest using lines (slow...) $slope = ($p2[0]-$p1[0])/($p1[1]-$p2[1]); $x1 = $p1[0]; $x2 = $p2[0]; //-1; $start = $y; if( $p1[1] > $p2[1] ) { while( $y >= $p2[1] ) { $x1=$slope*($start-$y)+$p1[0]; $this->img->current_color = $colmap[$y]; $this->img->Line($x1,$y,$x2,$y); --$y; } } else { while( $y >= $p1[1] ) { $x2=$p2[0]+$slope*($start-$y); $this->img->current_color = $colmap[$y]; $this->img->Line($x1,$y,$x2,$y); --$y; } } } } //--------------- // PRIVATE METHODS // Add to the image color map the necessary colors to do the transition // between the two colors using $numcolors intermediate colors function GetColArray($from_color,$to_color,$arr_size,&$colors,$numcols=100) { if( $arr_size==0 ) return; // If color is given as text get it's corresponding r,g,b values $from_color = $this->img->rgb->Color($from_color); $to_color = $this->img->rgb->Color($to_color); $rdelta=($to_color[0]-$from_color[0])/$numcols; $gdelta=($to_color[1]-$from_color[1])/$numcols; $bdelta=($to_color[2]-$from_color[2])/$numcols; $colorsperstep = $numcols/$arr_size; $prevcolnum = -1; $from_alpha = $from_color[3]; $to_alpha = $to_color[3]; $adelta = ( $to_alpha - $from_alpha ) / $numcols ; for ($i=0; $i < $arr_size; ++$i) { $colnum = floor($colorsperstep*$i); if ( $colnum == $prevcolnum ) $colors[$i] = $colidx; else { $r = floor($from_color[0] + $colnum*$rdelta); $g = floor($from_color[1] + $colnum*$gdelta); $b = floor($from_color[2] + $colnum*$bdelta); $alpha = $from_alpha + $colnum*$adelta; $colidx = $this->img->rgb->Allocate(sprintf("#%02x%02x%02x",$r,$g,$b),$alpha); $colors[$i] = $colidx; } $prevcolnum = $colnum; } } } // Class ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_iconplot.php ================================================ iFile = $aFile; $this->iX=$aX; $this->iY=$aY; $this->iScale= $aScale; if( $aMix < 0 || $aMix > 100 ) { JpGraphError::RaiseL(8001); //('Mix value for icon must be between 0 and 100.'); } $this->iMix = $aMix ; } function CreateFromString($aStr) { $this->iImgString = $aStr; } function SetCountryFlag($aFlag,$aX=0,$aY=0,$aScale=1.0,$aMix=100,$aStdSize=3) { $this->iCountryFlag = $aFlag; $this->iX=$aX; $this->iY=$aY; $this->iScale= $aScale; if( $aMix < 0 || $aMix > 100 ) { JpGraphError::RaiseL(8001);//'Mix value for icon must be between 0 and 100.'); } $this->iMix = $aMix; $this->iCountryStdSize = $aStdSize; } function SetPos($aX,$aY) { $this->iX=$aX; $this->iY=$aY; } function SetScalePos($aX,$aY) { $this->iScalePosX = $aX; $this->iScalePosY = $aY; } function SetScale($aScale) { $this->iScale = $aScale; } function SetMix($aMix) { if( $aMix < 0 || $aMix > 100 ) { JpGraphError::RaiseL(8001);//('Mix value for icon must be between 0 and 100.'); } $this->iMix = $aMix ; } function SetAnchor($aXAnchor='left',$aYAnchor='center') { if( !in_array($aXAnchor,$this->iAnchors) || !in_array($aYAnchor,$this->iAnchors) ) { JpGraphError::RaiseL(8002);//("Anchor position for icons must be one of 'top', 'bottom', 'left', 'right' or 'center'"); } $this->iHorAnchor=$aXAnchor; $this->iVertAnchor=$aYAnchor; } function PreStrokeAdjust($aGraph) { // Nothing to do ... } function DoLegend($aGraph) { // Nothing to do ... } function Max() { return array(false,false); } // The next four function are framework function tht gets called // from Gantt and is not menaiungfull in the context of Icons but // they must be implemented to avoid errors. function GetMaxDate() { return false; } function GetMinDate() { return false; } function GetLineNbr() { return 0; } function GetAbsHeight() {return 0; } function Min() { return array(false,false); } function StrokeMargin(&$aImg) { return true; } function Stroke(&$aImg,$axscale,$ayscale) { $this->StrokeWithScale($aImg,$axscale,$ayscale); } function StrokeWithScale(&$aImg,$axscale,$ayscale) { if( $this->iScalePosX === null || $this->iScalePosY === null ) { $this->_Stroke($aImg); } else { $this->_Stroke($aImg, round($axscale->Translate($this->iScalePosX)), round($ayscale->Translate($this->iScalePosY))); } } function GetWidthHeight() { $dummy=0; return $this->_Stroke($dummy,null,null,true); } function _Stroke(&$aImg,$x=null,$y=null,$aReturnWidthHeight=false) { if( $this->iFile != '' && $this->iCountryFlag != '' ) { JpGraphError::RaiseL(8003);//('It is not possible to specify both an image file and a country flag for the same icon.'); } if( $this->iFile != '' ) { $gdimg = Graph::LoadBkgImage('',$this->iFile); } elseif( $this->iImgString != '') { $gdimg = Image::CreateFromString($this->iImgString); } else { if( ! class_exists('FlagImages') ) { JpGraphError::RaiseL(8004);//('In order to use Country flags as icons you must include the "jpgraph_flags.php" file.'); } $fobj = new FlagImages($this->iCountryStdSize); $dummy=''; $gdimg = $fobj->GetImgByName($this->iCountryFlag,$dummy); } $iconw = imagesx($gdimg); $iconh = imagesy($gdimg); if( $aReturnWidthHeight ) { return array(round($iconw*$this->iScale),round($iconh*$this->iScale)); } if( $x !== null && $y !== null ) { $this->iX = $x; $this->iY = $y; } if( $this->iX >= 0 && $this->iX <= 1.0 ) { $w = imagesx($aImg->img); $this->iX = round($w*$this->iX); } if( $this->iY >= 0 && $this->iY <= 1.0 ) { $h = imagesy($aImg->img); $this->iY = round($h*$this->iY); } if( $this->iHorAnchor == 'center' ) $this->iX -= round($iconw*$this->iScale/2); if( $this->iHorAnchor == 'right' ) $this->iX -= round($iconw*$this->iScale); if( $this->iVertAnchor == 'center' ) $this->iY -= round($iconh*$this->iScale/2); if( $this->iVertAnchor == 'bottom' ) $this->iY -= round($iconh*$this->iScale); $aImg->CopyMerge($gdimg,$this->iX,$this->iY,0,0, round($iconw*$this->iScale),round($iconh*$this->iScale), $iconw,$iconh, $this->iMix); } } ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_imgtrans.php ================================================ gdImg = $aGdImg; } // -------------------------------------------------------------------- // _TransVert3D() and _TransHor3D() are helper methods to // Skew3D(). // -------------------------------------------------------------------- function _TransVert3D($aGdImg,$aHorizon=100,$aSkewDist=120,$aDir=SKEW3D_DOWN,$aMinSize=true,$aFillColor='#FFFFFF',$aQuality=false,$aBorder=false,$aHorizonPos=0.5) { // Parameter check if( $aHorizonPos < 0 || $aHorizonPos > 1.0 ) { JpGraphError::RaiseL(9001); //("Value for image transformation out of bounds.\nVanishing point on horizon must be specified as a value between 0 and 1."); } $w = imagesx($aGdImg); $h = imagesy($aGdImg); // Create new image $ww = $w; if( $aMinSize ) $hh = ceil($h * $aHorizon / ($aSkewDist+$h)); else $hh = $h; $newgdh = imagecreatetruecolor($ww,$hh); $crgb = new RGB( $newgdh ); $fillColor = $crgb->Allocate($aFillColor); imagefilledrectangle($newgdh,0,0,$ww-1,$hh-1,$fillColor); if( $aBorder ) { $colidx = $crgb->Allocate($aBorder); imagerectangle($newgdh,0,0,$ww-1,$hh-1,$colidx); } $mid = round($w * $aHorizonPos); $last=$h; for($y=0; $y < $h; ++$y) { $yp = $h-$y-1; $yt = floor($yp * $aHorizon / ($aSkewDist + $yp)); if( !$aQuality ) { if( $last <= $yt ) continue ; $last = $yt; } for($x=0; $x < $w; ++$x) { $xt = ($x-$mid) * $aSkewDist / ($aSkewDist + $yp); if( $aDir == SKEW3D_UP ) $rgb = imagecolorat($aGdImg,$x,$h-$y-1); else $rgb = imagecolorat($aGdImg,$x,$y); $r = ($rgb >> 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; $colidx = imagecolorallocate($newgdh,$r,$g,$b); $xt = round($xt+$mid); if( $aDir == SKEW3D_UP ) { $syt = $yt; } else { $syt = $hh-$yt-1; } if( !empty($set[$yt]) ) { $nrgb = imagecolorat($newgdh,$xt,$syt); $nr = ($nrgb >> 16) & 0xFF; $ng = ($nrgb >> 8) & 0xFF; $nb = $nrgb & 0xFF; $colidx = imagecolorallocate($newgdh,floor(($r+$nr)/2), floor(($g+$ng)/2),floor(($b+$nb)/2)); } imagesetpixel($newgdh,$xt,$syt,$colidx); } $set[$yt] = true; } return $newgdh; } // -------------------------------------------------------------------- // _TransVert3D() and _TransHor3D() are helper methods to // Skew3D(). // -------------------------------------------------------------------- function _TransHor3D($aGdImg,$aHorizon=100,$aSkewDist=120,$aDir=SKEW3D_LEFT,$aMinSize=true,$aFillColor='#FFFFFF',$aQuality=false,$aBorder=false,$aHorizonPos=0.5) { $w = imagesx($aGdImg); $h = imagesy($aGdImg); // Create new image $hh = $h; if( $aMinSize ) $ww = ceil($w * $aHorizon / ($aSkewDist+$w)); else $ww = $w; $newgdh = imagecreatetruecolor($ww,$hh); $crgb = new RGB( $newgdh ); $fillColor = $crgb->Allocate($aFillColor); imagefilledrectangle($newgdh,0,0,$ww-1,$hh-1,$fillColor); if( $aBorder ) { $colidx = $crgb->Allocate($aBorder); imagerectangle($newgdh,0,0,$ww-1,$hh-1,$colidx); } $mid = round($h * $aHorizonPos); $last = -1; for($x=0; $x < $w-1; ++$x) { $xt = floor($x * $aHorizon / ($aSkewDist + $x)); if( !$aQuality ) { if( $last >= $xt ) continue ; $last = $xt; } for($y=0; $y < $h; ++$y) { $yp = $h-$y-1; $yt = ($yp-$mid) * $aSkewDist / ($aSkewDist + $x); if( $aDir == SKEW3D_RIGHT ) $rgb = imagecolorat($aGdImg,$w-$x-1,$y); else $rgb = imagecolorat($aGdImg,$x,$y); $r = ($rgb >> 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; $colidx = imagecolorallocate($newgdh,$r,$g,$b); $yt = floor($hh-$yt-$mid-1); if( $aDir == SKEW3D_RIGHT ) { $sxt = $ww-$xt-1; } else $sxt = $xt ; if( !empty($set[$xt]) ) { $nrgb = imagecolorat($newgdh,$sxt,$yt); $nr = ($nrgb >> 16) & 0xFF; $ng = ($nrgb >> 8) & 0xFF; $nb = $nrgb & 0xFF; $colidx = imagecolorallocate($newgdh,floor(($r+$nr)/2), floor(($g+$ng)/2),floor(($b+$nb)/2)); } imagesetpixel($newgdh,$sxt,$yt,$colidx); } $set[$xt] = true; } return $newgdh; } // -------------------------------------------------------------------- // Skew image for the apperance of a 3D effect // This transforms an image into a 3D-skewed version // of the image. The transformation is specified by giving the height // of the artificial horizon and specifying a "skew" factor which // is the distance on the horizon line between the point of // convergence and perspective line. // // The function returns the GD handle of the transformed image // leaving the original image untouched. // // Parameters: // * $aGdImg, GD handle to the image to be transformed // * $aHorizon, Distance to the horizon // * $aSkewDist, Distance from the horizon point of convergence // on the horizon line to the perspective points. A larger // value will fore-shorten the image more // * $aDir, parameter specifies type of convergence. This of this // as the walls in a room you are looking at. This specifies if the // image should be applied on the left,right,top or bottom walls. // * $aMinSize, true=make the new image just as big as needed, // false = keep the image the same size as the original image // * $aFillColor, Background fill color in the image // * $aHiQuality, true=performa some interpolation that improves // the image quality but at the expense of performace. Enabling // high quality will have a dramatic effect on the time it takes // to transform an image. // * $aBorder, if set to anything besides false this will draw a // a border of the speciied color around the image // -------------------------------------------------------------------- function Skew3D($aHorizon=120,$aSkewDist=150,$aDir=SKEW3D_DOWN,$aHiQuality=false,$aMinSize=true,$aFillColor='#FFFFFF',$aBorder=false) { return $this->_Skew3D($this->gdImg,$aHorizon,$aSkewDist,$aDir,$aHiQuality, $aMinSize,$aFillColor,$aBorder); } function _Skew3D($aGdImg,$aHorizon=120,$aSkewDist=150,$aDir=SKEW3D_DOWN,$aHiQuality=false,$aMinSize=true,$aFillColor='#FFFFFF',$aBorder=false) { if( $aDir == SKEW3D_DOWN || $aDir == SKEW3D_UP ) return $this->_TransVert3D($aGdImg,$aHorizon,$aSkewDist,$aDir,$aMinSize,$aFillColor,$aHiQuality,$aBorder); else return $this->_TransHor3D($aGdImg,$aHorizon,$aSkewDist,$aDir,$aMinSize,$aFillColor,$aHiQuality,$aBorder); } } ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_line.php ================================================ Plot($datay,$datax); $this->mark = new PlotMark(); } //--------------- // PUBLIC METHODS // Set style, filled or open function SetFilled($aFlag=true) { JpGraphError::RaiseL(10001);//('LinePlot::SetFilled() is deprecated. Use SetFillColor()'); } function SetBarCenter($aFlag=true) { $this->barcenter=$aFlag; } function SetStyle($aStyle) { $this->line_style=$aStyle; } function SetStepStyle($aFlag=true) { $this->step_style = $aFlag; } function SetColor($aColor) { parent::SetColor($aColor); } function SetFillFromYMin($f=true) { $this->fillFromMin = $f ; } function SetFillColor($aColor,$aFilled=true) { $this->fill_color=$aColor; $this->filled=$aFilled; } function SetFillGradient($aFromColor,$aToColor,$aNumColors=100,$aFilled=true) { $this->fillgrad_fromcolor = $aFromColor; $this->fillgrad_tocolor = $aToColor; $this->fillgrad_numcolors = $aNumColors; $this->filled = $aFilled; $this->fillgrad = true; } function Legend(&$graph) { if( $this->legend!="" ) { if( $this->filled && !$this->fillgrad ) { $graph->legend->Add($this->legend, $this->fill_color,$this->mark,0, $this->legendcsimtarget,$this->legendcsimalt); } elseif( $this->fillgrad ) { $color=array($this->fillgrad_fromcolor,$this->fillgrad_tocolor); // In order to differentiate between gradients and cooors specified as an RGB triple $graph->legend->Add($this->legend,$color,"",-2 /* -GRAD_HOR */, $this->legendcsimtarget,$this->legendcsimalt); } else { $graph->legend->Add($this->legend, $this->color,$this->mark,$this->line_style, $this->legendcsimtarget,$this->legendcsimalt); } } } function AddArea($aMin=0,$aMax=0,$aFilled=LP_AREA_NOT_FILLED,$aColor="gray9",$aBorder=LP_AREA_BORDER) { if($aMin > $aMax) { // swap $tmp = $aMin; $aMin = $aMax; $aMax = $tmp; } $this->filledAreas[] = array($aMin,$aMax,$aColor,$aFilled,$aBorder); } // Gets called before any axis are stroked function PreStrokeAdjust(&$graph) { // If another plot type have already adjusted the // offset we don't touch it. // (We check for empty in case the scale is a log scale // and hence doesn't contain any xlabel_offset) if( empty($graph->xaxis->scale->ticks->xlabel_offset) || $graph->xaxis->scale->ticks->xlabel_offset == 0 ) { if( $this->center ) { ++$this->numpoints; $a=0.5; $b=0.5; } else { $a=0; $b=0; } $graph->xaxis->scale->ticks->SetXLabelOffset($a); $graph->SetTextScaleOff($b); //$graph->xaxis->scale->ticks->SupressMinorTickMarks(); } } function SetFastStroke($aFlg=true) { $this->iFastStroke = $aFlg; } function FastStroke(&$img,&$xscale,&$yscale,$aStartPoint=0,$exist_x=true) { // An optimized stroke for many data points with no extra // features but 60% faster. You can't have values or line styles, or null // values in plots. $numpoints=count($this->coords[0]); if( $this->barcenter ) $textadj = 0.5-$xscale->text_scale_off; else $textadj = 0; $img->SetColor($this->color); $img->SetLineWeight($this->weight); $pnts=$aStartPoint; while( $pnts < $numpoints ) { if( $exist_x ) $x=$this->coords[1][$pnts]; else $x=$pnts+$textadj; $xt = $xscale->Translate($x); $y=$this->coords[0][$pnts]; $yt = $yscale->Translate($y); if( is_numeric($y) ) { $cord[] = $xt; $cord[] = $yt; } elseif( $y == '-' && $pnts > 0 ) { // Just ignore } else { JpGraphError::RaiseL(10002);//('Plot too complicated for fast line Stroke. Use standard Stroke()'); return; } ++$pnts; } // WHILE $img->Polygon($cord,false,true); } function Stroke(&$img,&$xscale,&$yscale) { $idx=0; $numpoints=count($this->coords[0]); if( isset($this->coords[1]) ) { if( count($this->coords[1])!=$numpoints ) JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); //("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); else $exist_x = true; } else $exist_x = false; if( $this->barcenter ) $textadj = 0.5-$xscale->text_scale_off; else $textadj = 0; // Find the first numeric data point $startpoint=0; while( $startpoint < $numpoints && !is_numeric($this->coords[0][$startpoint]) ) ++$startpoint; // Bail out if no data points if( $startpoint == $numpoints ) return; if( $this->iFastStroke ) { $this->FastStroke($img,$xscale,$yscale,$startpoint,$exist_x); return; } if( $exist_x ) $xs=$this->coords[1][$startpoint]; else $xs= $textadj+$startpoint; $img->SetStartPoint($xscale->Translate($xs), $yscale->Translate($this->coords[0][$startpoint])); if( $this->filled ) { $min = $yscale->GetMinVal(); if( $min > 0 || $this->fillFromMin ) $fillmin = $yscale->scale_abs[0];//Translate($min); else $fillmin = $yscale->Translate(0); $cord[$idx++] = $xscale->Translate($xs); $cord[$idx++] = $fillmin; } $xt = $xscale->Translate($xs); $yt = $yscale->Translate($this->coords[0][$startpoint]); $cord[$idx++] = $xt; $cord[$idx++] = $yt; $yt_old = $yt; $xt_old = $xt; $y_old = $this->coords[0][$startpoint]; $this->value->Stroke($img,$this->coords[0][$startpoint],$xt,$yt); $img->SetColor($this->color); $img->SetLineWeight($this->weight); $img->SetLineStyle($this->line_style); $pnts=$startpoint+1; $firstnonumeric = false; while( $pnts < $numpoints ) { if( $exist_x ) $x=$this->coords[1][$pnts]; else $x=$pnts+$textadj; $xt = $xscale->Translate($x); $yt = $yscale->Translate($this->coords[0][$pnts]); $y=$this->coords[0][$pnts]; if( $this->step_style ) { // To handle null values within step style we need to record the // first non numeric value so we know from where to start if the // non value is '-'. if( is_numeric($y) ) { $firstnonumeric = false; if( is_numeric($y_old) ) { $img->StyleLine($xt_old,$yt_old,$xt,$yt_old); $img->StyleLine($xt,$yt_old,$xt,$yt); } elseif( $y_old == '-' ) { $img->StyleLine($xt_first,$yt_first,$xt,$yt_first); $img->StyleLine($xt,$yt_first,$xt,$yt); } else { $yt_old = $yt; $xt_old = $xt; } $cord[$idx++] = $xt; $cord[$idx++] = $yt_old; $cord[$idx++] = $xt; $cord[$idx++] = $yt; } elseif( $firstnonumeric==false ) { $firstnonumeric = true; $yt_first = $yt_old; $xt_first = $xt_old; } } else { $tmp1=$y; $prev=$this->coords[0][$pnts-1]; if( $tmp1==='' || $tmp1===NULL || $tmp1==='X' ) $tmp1 = 'x'; if( $prev==='' || $prev===null || $prev==='X' ) $prev = 'x'; if( is_numeric($y) || (is_string($y) && $y != '-') ) { if( is_numeric($y) && (is_numeric($prev) || $prev === '-' ) ) { $img->StyleLineTo($xt,$yt); } else { $img->SetStartPoint($xt,$yt); } } if( $this->filled && $tmp1 !== '-' ) { if( $tmp1 === 'x' ) { $cord[$idx++] = $cord[$idx-3]; $cord[$idx++] = $fillmin; } elseif( $prev === 'x' ) { $cord[$idx++] = $xt; $cord[$idx++] = $fillmin; $cord[$idx++] = $xt; $cord[$idx++] = $yt; } else { $cord[$idx++] = $xt; $cord[$idx++] = $yt; } } else { if( is_numeric($tmp1) && (is_numeric($prev) || $prev === '-' ) ) { $cord[$idx++] = $xt; $cord[$idx++] = $yt; } } } $yt_old = $yt; $xt_old = $xt; $y_old = $y; $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt); ++$pnts; } if( $this->filled ) { $cord[$idx++] = $xt; if( $min > 0 || $this->fillFromMin ) $cord[$idx++] = $yscale->Translate($min); else $cord[$idx++] = $yscale->Translate(0); if( $this->fillgrad ) { $img->SetLineWeight(1); $grad = new Gradient($img); $grad->SetNumColors($this->fillgrad_numcolors); $grad->FilledFlatPolygon($cord,$this->fillgrad_fromcolor,$this->fillgrad_tocolor); $img->SetLineWeight($this->weight); } else { $img->SetColor($this->fill_color); $img->FilledPolygon($cord); } if( $this->line_weight > 0 ) { $img->SetColor($this->color); $img->Polygon($cord); } } if(!empty($this->filledAreas)) { $minY = $yscale->Translate($yscale->GetMinVal()); $factor = ($this->step_style ? 4 : 2); for($i = 0; $i < sizeof($this->filledAreas); ++$i) { // go through all filled area elements ordered by insertion // fill polygon array $areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor]; $areaCoords[] = $minY; $areaCoords = array_merge($areaCoords, array_slice($cord, $this->filledAreas[$i][0] * $factor, ($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style ? 0 : 1)) * $factor)); $areaCoords[] = $areaCoords[sizeof($areaCoords)-2]; // last x $areaCoords[] = $minY; // last y if($this->filledAreas[$i][3]) { $img->SetColor($this->filledAreas[$i][2]); $img->FilledPolygon($areaCoords); $img->SetColor($this->color); } // Check if we should draw the frame. // If not we still re-draw the line since it might have been // partially overwritten by the filled area and it doesn't look // very good. // TODO: The behaviour is undefined if the line does not have // any line at the position of the area. if( $this->filledAreas[$i][4] ) $img->Polygon($areaCoords); else $img->Polygon($cord); $areaCoords = array(); } } if( $this->mark->type == -1 || $this->mark->show == false ) return; for( $pnts=0; $pnts<$numpoints; ++$pnts) { if( $exist_x ) $x=$this->coords[1][$pnts]; else $x=$pnts+$textadj; $xt = $xscale->Translate($x); $yt = $yscale->Translate($this->coords[0][$pnts]); if( is_numeric($this->coords[0][$pnts]) ) { if( !empty($this->csimtargets[$pnts]) ) { $this->mark->SetCSIMTarget($this->csimtargets[$pnts]); $this->mark->SetCSIMAlt($this->csimalts[$pnts]); } if( $exist_x ) $x=$this->coords[1][$pnts]; else $x=$pnts; $this->mark->SetCSIMAltVal($this->coords[0][$pnts],$x); $this->mark->Stroke($img,$xt,$yt); $this->csimareas .= $this->mark->GetCSIMAreas(); $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt); } } } } // Class //=================================================== // CLASS AccLinePlot // Description: //=================================================== class AccLinePlot extends Plot { var $plots=null,$nbrplots=0,$numpoints=0; var $iStartEndZero=true; //--------------- // CONSTRUCTOR function AccLinePlot($plots) { $this->plots = $plots; $this->nbrplots = count($plots); $this->numpoints = $plots[0]->numpoints; for($i=0; $i < $this->nbrplots; ++$i ) { $this->LineInterpolate($this->plots[$i]->coords[0]); } } //--------------- // PUBLIC METHODS function Legend(&$graph) { $n=count($this->plots); for($i=0; $i < $n; ++$i ) $this->plots[$i]->DoLegend($graph); } function Max() { list($xmax) = $this->plots[0]->Max(); $nmax=0; $n = count($this->plots); for($i=0; $i < $n; ++$i) { $nc = count($this->plots[$i]->coords[0]); $nmax = max($nmax,$nc); list($x) = $this->plots[$i]->Max(); $xmax = Max($xmax,$x); } for( $i = 0; $i < $nmax; $i++ ) { // Get y-value for line $i by adding the // individual bars from all the plots added. // It would be wrong to just add the // individual plots max y-value since that // would in most cases give to large y-value. $y=$this->plots[0]->coords[0][$i]; for( $j = 1; $j < $this->nbrplots; $j++ ) { $y += $this->plots[ $j ]->coords[0][$i]; } $ymax[$i] = $y; } $ymax = max($ymax); return array($xmax,$ymax); } function Min() { $nmax=0; list($xmin,$ysetmin) = $this->plots[0]->Min(); $n = count($this->plots); for($i=0; $i < $n; ++$i) { $nc = count($this->plots[$i]->coords[0]); $nmax = max($nmax,$nc); list($x,$y) = $this->plots[$i]->Min(); $xmin = Min($xmin,$x); $ysetmin = Min($y,$ysetmin); } for( $i = 0; $i < $nmax; $i++ ) { // Get y-value for line $i by adding the // individual bars from all the plots added. // It would be wrong to just add the // individual plots min y-value since that // would in most cases give to small y-value. $y=$this->plots[0]->coords[0][$i]; for( $j = 1; $j < $this->nbrplots; $j++ ) { $y += $this->plots[ $j ]->coords[0][$i]; } $ymin[$i] = $y; } $ymin = Min($ysetmin,Min($ymin)); return array($xmin,$ymin); } // Gets called before any axis are stroked function PreStrokeAdjust(&$graph) { // If another plot type have already adjusted the // offset we don't touch it. // (We check for empty in case the scale is a log scale // and hence doesn't contain any xlabel_offset) if( empty($graph->xaxis->scale->ticks->xlabel_offset) || $graph->xaxis->scale->ticks->xlabel_offset == 0 ) { if( $this->center ) { ++$this->numpoints; $a=0.5; $b=0.5; } else { $a=0; $b=0; } $graph->xaxis->scale->ticks->SetXLabelOffset($a); $graph->SetTextScaleOff($b); $graph->xaxis->scale->ticks->SupressMinorTickMarks(); } } function SetInterpolateMode($aIntMode) { $this->iStartEndZero=$aIntMode; } // Replace all '-' with an interpolated value. We use straightforward // linear interpolation. If the data starts with one or several '-' they // will be replaced by the the first valid data point function LineInterpolate(&$aData) { $n=count($aData); $i=0; // If first point is undefined we will set it to the same as the first // valid data if( $aData[$i]==='-' ) { // Find the first valid data while( $i < $n && $aData[$i]==='-' ) { ++$i; } if( $i < $n ) { for($j=0; $j < $i; ++$j ) { if( $this->iStartEndZero ) $aData[$i] = 0; else $aData[$j] = $aData[$i]; } } else { // All '-' => Error return false; } } while($i < $n) { while( $i < $n && $aData[$i] !== '-' ) { ++$i; } if( $i < $n ) { $pstart=$i-1; // Now see how long this segment of '-' are while( $i < $n && $aData[$i] === '-' ) ++$i; if( $i < $n ) { $pend=$i; $size=$pend-$pstart; $k=($aData[$pend]-$aData[$pstart])/$size; // Replace the segment of '-' with a linear interpolated value. for($j=1; $j < $size; ++$j ) { $aData[$pstart+$j] = $aData[$pstart] + $j*$k ; } } else { // There are no valid end point. The '-' goes all the way to the end // In that case we just set all the remaining values the the same as the // last valid data point. for( $j=$pstart+1; $j < $n; ++$j ) if( $this->iStartEndZero ) $aData[$j] = 0; else $aData[$j] = $aData[$pstart] ; } } } return true; } // To avoid duplicate of line drawing code here we just // change the y-values for each plot and then restore it // after we have made the stroke. We must do this copy since // it wouldn't be possible to create an acc line plot // with the same graphs, i.e AccLinePlot(array($pl,$pl,$pl)); // since this method would have a side effect. function Stroke(&$img,&$xscale,&$yscale) { $img->SetLineWeight($this->weight); $this->numpoints = count($this->plots[0]->coords[0]); // Allocate array $coords[$this->nbrplots][$this->numpoints]=0; for($i=0; $i<$this->numpoints; $i++) { $coords[0][$i]=$this->plots[0]->coords[0][$i]; $accy=$coords[0][$i]; for($j=1; $j<$this->nbrplots; ++$j ) { $coords[$j][$i] = $this->plots[$j]->coords[0][$i]+$accy; $accy = $coords[$j][$i]; } } for($j=$this->nbrplots-1; $j>=0; --$j) { $p=$this->plots[$j]; for( $i=0; $i<$this->numpoints; ++$i) { $tmp[$i]=$p->coords[0][$i]; $p->coords[0][$i]=$coords[$j][$i]; } $p->Stroke($img,$xscale,$yscale); for( $i=0; $i<$this->numpoints; ++$i) $p->coords[0][$i]=$tmp[$i]; $p->coords[0][]=$tmp; } } } // Class /* EOF */ ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_log.php ================================================ LinearScale($min,$max,$type); $this->ticks = new LogTicks(); $this->name = 'log'; } //---------------- // PUBLIC METHODS // Translate between world and screen function Translate($a) { if( !is_numeric($a) ) { if( $a != '' && $a != '-' && $a != 'x' ) JpGraphError::RaiseL(11001); //('Your data contains non-numeric values.'); return 1; } if( $a < 0 ) { JpGraphError::RaiseL(11002); //("Negative data values can not be used in a log scale."); exit(1); } if( $a==0 ) $a=1; $a=log10($a); return ceil($this->off + ($a*1.0 - $this->scale[0]) * $this->scale_factor); } // Relative translate (don't include offset) usefull when we just want // to know the relative position (in pixels) on the axis function RelTranslate($a) { if( !is_numeric($a) ) { if( $a != '' && $a != '-' && $a != 'x' ) JpGraphError::RaiseL(11001); //('Your data contains non-numeric values.'); return 1; } if( $a==0 ) $a=1; $a=log10($a); return round(($a*1.0 - $this->scale[0]) * $this->scale_factor); } // Use bcpow() for increased precision function GetMinVal() { if( function_exists("bcpow") ) return round(bcpow(10,$this->scale[0],15),14); else return round(pow(10,$this->scale[0]),14); } function GetMaxVal() { if( function_exists("bcpow") ) return round(bcpow(10,$this->scale[1],15),14); else return round(pow(10,$this->scale[1]),14); } // Logarithmic autoscaling is much simplier since we just // set the min and max to logs of the min and max values. // Note that for log autoscale the "maxstep" the fourth argument // isn't used. This is just included to give the method the same // signature as the linear counterpart. function AutoScale(&$img,$min,$max,$dummy) { if( $min==0 ) $min=1; if( $max <= 0 ) { JpGraphError::RaiseL(11004); //('Scale error for logarithmic scale. You have a problem with your data values. The max value must be greater than 0. It is mathematically impossible to have 0 in a logarithmic scale.'); } $smin = floor(log10($min)); $smax = ceil(log10($max)); $this->Update($img,$smin,$smax); } //--------------- // PRIVATE METHODS } // Class //=================================================== // CLASS LogTicks // Description: //=================================================== class LogTicks extends Ticks{ var $label_logtype=LOGLABELS_MAGNITUDE; //--------------- // CONSTRUCTOR function LogTicks() { } //--------------- // PUBLIC METHODS function IsSpecified() { return true; } function SetLabelLogType($aType) { $this->label_logtype = $aType; } // For log scale it's meaningless to speak about a major step // We just return -1 to make the framework happy (specifically // StrokeLabels() ) function GetMajor() { return -1; } function SetTextLabelStart($aStart) { JpGraphError::RaiseL(11005); //('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.'); } function SetXLabelOffset($dummy) { // For log scales we dont care about XLabel offset } // Draw ticks on image "img" using scale "scale". The axis absolute // position in the image is specified in pos, i.e. for an x-axis // it specifies the absolute y-coord and for Y-ticks it specified the // absolute x-position. function Stroke(&$img,&$scale,$pos) { $start = $scale->GetMinVal(); $limit = $scale->GetMaxVal(); $nextMajor = 10*$start; $step = $nextMajor / 10.0; $img->SetLineWeight($this->weight); if( $scale->type == "y" ) { // member direction specified if the ticks should be on // left or right side. $a=$pos + $this->direction*$this->GetMinTickAbsSize(); $a2=$pos + $this->direction*$this->GetMajTickAbsSize(); $count=1; $this->maj_ticks_pos[0]=$scale->Translate($start); $this->maj_ticklabels_pos[0]=$scale->Translate($start); if( $this->supress_first ) $this->maj_ticks_label[0]=""; else { if( $this->label_formfunc != '' ) { $f = $this->label_formfunc; $this->maj_ticks_label[0]=call_user_func($f,$start); } elseif( $this->label_logtype == LOGLABELS_PLAIN ) $this->maj_ticks_label[0]=$start; else $this->maj_ticks_label[0]='10^'.round(log10($start)); } $i=1; for($y=$start; $y<=$limit; $y+=$step,++$count ) { $ys=$scale->Translate($y); $this->ticks_pos[]=$ys; $this->ticklabels_pos[]=$ys; if( $count % 10 == 0 ) { if( !$this->supress_tickmarks ) { if( $this->majcolor!="" ) { $img->PushColor($this->majcolor); $img->Line($pos,$ys,$a2,$ys); $img->PopColor(); } else $img->Line($pos,$ys,$a2,$ys); } $this->maj_ticks_pos[$i]=$ys; $this->maj_ticklabels_pos[$i]=$ys; if( $this->label_formfunc != '' ) { $f = $this->label_formfunc; $this->maj_ticks_label[$i]=call_user_func($f,$nextMajor); } elseif( $this->label_logtype == 0 ) $this->maj_ticks_label[$i]=$nextMajor; else $this->maj_ticks_label[$i]='10^'.round(log10($nextMajor)); ++$i; $nextMajor *= 10; $step *= 10; $count=1; } else { if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { if( $this->mincolor!="" ) $img->PushColor($this->mincolor); $img->Line($pos,$ys,$a,$ys); if( $this->mincolor!="" ) $img->PopColor(); } } } } else { $a=$pos - $this->direction*$this->GetMinTickAbsSize(); $a2=$pos - $this->direction*$this->GetMajTickAbsSize(); $count=1; $this->maj_ticks_pos[0]=$scale->Translate($start); $this->maj_ticklabels_pos[0]=$scale->Translate($start); if( $this->supress_first ) $this->maj_ticks_label[0]=""; else { if( $this->label_formfunc != '' ) { $f = $this->label_formfunc; $this->maj_ticks_label[0]=call_user_func($f,$start); } elseif( $this->label_logtype == 0 ) $this->maj_ticks_label[0]=$start; else $this->maj_ticks_label[0]='10^'.round(log10($start)); } $i=1; for($x=$start; $x<=$limit; $x+=$step,++$count ) { $xs=$scale->Translate($x); $this->ticks_pos[]=$xs; $this->ticklabels_pos[]=$xs; if( $count % 10 == 0 ) { if( !$this->supress_tickmarks ) { $img->Line($xs,$pos,$xs,$a2); } $this->maj_ticks_pos[$i]=$xs; $this->maj_ticklabels_pos[$i]=$xs; if( $this->label_formfunc != '' ) { $f = $this->label_formfunc; $this->maj_ticks_label[$i]=call_user_func($f,$nextMajor); } elseif( $this->label_logtype == 0 ) $this->maj_ticks_label[$i]=$nextMajor; else $this->maj_ticks_label[$i]='10^'.round(log10($nextMajor)); ++$i; $nextMajor *= 10; $step *= 10; $count=1; } else { if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { $img->Line($xs,$pos,$xs,$a); } } } } return true; } } // Class /* EOF */ ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_pie.php ================================================ array(136,34,40,45,46,62,63,134,74,10,120,136,141,168,180,77,209,218,346,395,89,430), "pastel" => array(27,415,128,59,66,79,105,110,42,147,152,230,236,240,331,337,405,38), "water" => array(8,370,24,40,335,56,213,237,268,14,326,387,10,388), "sand" => array(27,168,34,170,19,50,65,72,131,209,46,393)); var $theme="earth"; var $setslicecolors=array(); var $labeltype=0; // Default to percentage var $pie_border=true,$pie_interior_border=true; var $value; var $ishadowcolor='',$ishadowdrop=4; var $ilabelposadj=1; var $legendcsimtargets = array(); var $legendcsimalts = array(); var $adjusted_data = array(); var $guideline = null,$guidelinemargin=10; var $iShowGuideLineForSingle = false; var $iGuideLineCurve = false,$iGuideVFactor=1.4,$iGuideLineRFactor=0.8; //--------------- // CONSTRUCTOR function PiePlot($data) { $this->data = array_reverse($data); $this->title = new Text(""); $this->title->SetFont(FF_FONT1,FS_BOLD); $this->value = new DisplayValue(); $this->value->Show(); $this->value->SetFormat('%.1f%%'); $this->guideline = new LineProperty(); } //--------------- // PUBLIC METHODS function SetCenter($x,$y=0.5) { $this->posx = $x; $this->posy = $y; } // Enable guideline and set drwaing policy function SetGuideLines($aFlg=true,$aCurved=true,$aAlways=false) { $this->guideline->Show($aFlg); $this->iShowGuideLineForSingle = $aAlways; $this->iGuideLineCurve = $aCurved; } // Adjuste the distance between labels and labels and pie function SetGuideLinesAdjust($aVFactor,$aRFactor=0.8) { $this->iGuideVFactor=$aVFactor; $this->iGuideLineRFactor=$aRFactor; } function SetColor($aColor) { $this->color = $aColor; } function SetSliceColors($aColors) { $this->setslicecolors = $aColors; } function SetShadow($aColor='darkgray',$aDropWidth=4) { $this->ishadowcolor = $aColor; $this->ishadowdrop = $aDropWidth; } function SetCSIMTargets($targets,$alts=null) { $this->csimtargets=array_reverse($targets); if( is_array($alts) ) $this->csimalts=array_reverse($alts); } function GetCSIMareas() { return $this->csimareas; } function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) { //Slice number, ellipse centre (x,y), height, width, start angle, end angle while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI; while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI; $sa = 2*M_PI - $sa; $ea = 2*M_PI - $ea; // Special case when we have only one slice since then both start and end // angle will be == 0 if( abs($sa - $ea) < 0.0001 ) { $sa=2*M_PI; $ea=0; } //add coordinates of the centre to the map $xc = floor($xc);$yc=floor($yc); $coords = "$xc, $yc"; //add coordinates of the first point on the arc to the map $xp = floor(($radius*cos($ea))+$xc); $yp = floor($yc-$radius*sin($ea)); $coords.= ", $xp, $yp"; //add coordinates every 0.2 radians $a=$ea+0.2; // If we cross the 260-limit with a slice we need to handle // the fact that end angle is smaller than start if( $sa < $ea ) { while ($a <= 2*M_PI) { $xp = floor($radius*cos($a)+$xc); $yp = floor($yc-$radius*sin($a)); $coords.= ", $xp, $yp"; $a += 0.2; } $a -= 2*M_PI; } while ($a < $sa) { $xp = floor($radius*cos($a)+$xc); $yp = floor($yc-$radius*sin($a)); $coords.= ", $xp, $yp"; $a += 0.2; } //Add the last point on the arc $xp = floor($radius*cos($sa)+$xc); $yp = floor($yc-$radius*sin($sa)); $coords.= ", $xp, $yp"; if( !empty($this->csimtargets[$i]) ) { $this->csimareas .= "csimtargets[$i]."\""; $tmp=""; if( !empty($this->csimalts[$i]) ) { $tmp=sprintf($this->csimalts[$i],$this->data[$i]); $this->csimareas .= " title=\"$tmp\""; } $this->csimareas .= " alt=\"$tmp\" />\n"; } } function SetTheme($aTheme) { if( in_array($aTheme,array_keys($this->themearr)) ) $this->theme = $aTheme; else JpGraphError::RaiseL(15001,$aTheme);//("PiePLot::SetTheme() Unknown theme: $aTheme"); } function ExplodeSlice($e,$radius=20) { if( ! is_integer($e) ) JpGraphError::RaiseL(15002);//('Argument to PiePlot::ExplodeSlice() must be an integer'); $this->explode_radius[$e]=$radius; } function ExplodeAll($radius=20) { $this->explode_all=true; $this->explode_r = $radius; } function Explode($aExplodeArr) { if( !is_array($aExplodeArr) ) { JpGraphError::RaiseL(15003); //("Argument to PiePlot::Explode() must be an array with integer distances."); } $this->explode_radius = $aExplodeArr; } function SetStartAngle($aStart) { if( $aStart < 0 || $aStart > 360 ) { JpGraphError::RaiseL(15004);//('Slice start angle must be between 0 and 360 degrees.'); } $this->startangle = 360-$aStart; $this->startangle *= M_PI/180; } function SetFont($family,$style=FS_NORMAL,$size=10) { JpGraphError::RaiseL(15005);//('PiePlot::SetFont() is deprecated. Use PiePlot->value->SetFont() instead.'); } // Size in percentage function SetSize($aSize) { if( ($aSize>0 && $aSize<=0.5) || ($aSize>10 && $aSize<1000) ) $this->radius = $aSize; else JpGraphError::RaiseL(15006); //("PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels in the range [10, 1000]"); } function SetFontColor($aColor) { JpGraphError::RaiseL(15007); //('PiePlot::SetFontColor() is deprecated. Use PiePlot->value->SetColor() instead.'); } // Set label arrays function SetLegends($aLegend) { $this->legends = $aLegend; } // Set text labels for slices function SetLabels($aLabels,$aLblPosAdj="auto") { $this->labels = array_reverse($aLabels); $this->ilabelposadj=$aLblPosAdj; } function SetLabelPos($aLblPosAdj) { $this->ilabelposadj=$aLblPosAdj; } // Should we display actual value or percentage? function SetLabelType($t) { if( $t < 0 || $t > 2 ) JpGraphError::RaiseL(15008,$t); //("PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not $t)."); $this->labeltype=$t; } // Deprecated. function SetValueType($aType) { $this->SetLabelType($aType); } // Should the circle around a pie plot be displayed function ShowBorder($exterior=true,$interior=true) { $this->pie_border = $exterior; $this->pie_interior_border = $interior; } // Setup the legends (Framework method) function Legend(&$graph) { $colors = array_keys($graph->img->rgb->rgb_table); sort($colors); $ta=$this->themearr[$this->theme]; $n = count($this->data); if( $this->setslicecolors==null ) { $numcolors=count($ta); if( is_a($this,'PiePlot3D') ) { $ta = array_reverse(array_slice($ta,0,$n)); } } else { $this->setslicecolors = array_slice($this->setslicecolors,0,$n); $numcolors=count($this->setslicecolors); if( $graph->pieaa && is_a($this,'PiePlot') ) { $this->setslicecolors = array_reverse($this->setslicecolors); } } $sum=0; for($i=0; $i < $n; ++$i) $sum += $this->data[$i]; // Bail out with error if the sum is 0 if( $sum==0 ) JpGraphError::RaiseL(15009);//("Illegal pie plot. Sum of all data is zero for Pie!"); // Make sure we don't plot more values than data points // (in case the user added more legends than data points) $n = min(count($this->legends),count($this->data)); if( $this->legends != "" ) { $this->legends = array_reverse(array_slice($this->legends,0,$n)); } for( $i=$n-1; $i >= 0; --$i ) { $l = $this->legends[$i]; // Replace possible format with actual values if( count($this->csimalts) > $i ) { $fmt = $this->csimalts[$i]; } else { $fmt = "%d"; // Deafult Alt if no other has been specified } if( $this->labeltype==0 ) { $l = sprintf($l,100*$this->data[$i]/$sum); $alt = sprintf($fmt,$this->data[$i]); } elseif( $this->labeltype == 1) { $l = sprintf($l,$this->data[$i]); $alt = sprintf($fmt,$this->data[$i]); } else { $l = sprintf($l,$this->adjusted_data[$i]); $alt = sprintf($fmt,$this->adjusted_data[$i]); } if( $this->setslicecolors==null ) { $graph->legend->Add($l,$colors[$ta[$i%$numcolors]],"",0,$this->csimtargets[$i],$alt); } else { $graph->legend->Add($l,$this->setslicecolors[$i%$numcolors],"",0,$this->csimtargets[$i],$alt); } } } // Adjust the rounded percetage value so that the sum of // of the pie slices are always 100% // Using the Hare/Niemeyer method function AdjPercentage($aData,$aPrec=0) { $mul=100; if( $aPrec > 0 && $aPrec < 3 ) { if( $aPrec == 1 ) $mul=1000; else $mul=10000; } $tmp = array(); $result = array(); $quote_sum=0; $n = count($aData) ; for( $i=0, $sum=0; $i < $n; ++$i ) $sum+=$aData[$i]; foreach($aData as $index => $value) { $tmp_percentage=$value/$sum*$mul; $result[$index]=floor($tmp_percentage); $tmp[$index]=$tmp_percentage-$result[$index]; $quote_sum+=$result[$index]; } if( $quote_sum == $mul) { if( $mul > 100 ) { $tmp = $mul / 100; for( $i=0; $i < $n; ++$i ) { $result[$i] /= $tmp ; } } return $result; } arsort($tmp,SORT_NUMERIC); reset($tmp); for($i=0; $i < $mul-$quote_sum; $i++) { $result[key($tmp)]++; next($tmp); } if( $mul > 100 ) { $tmp = $mul / 100; for( $i=0; $i < $n; ++$i ) { $result[$i] /= $tmp ; } } return $result; } function Stroke(&$img,$aaoption=0) { // aaoption is used to handle antialias // aaoption == 0 a normal pie // aaoption == 1 just the body // aaoption == 2 just the values // Explode scaling. If anti anti alias we scale the image // twice and we also need to scale the exploding distance $expscale = $aaoption === 1 ? 2 : 1; if( $this->labeltype == 2 ) { // Adjust the data so that it will add up to 100% $this->adjusted_data = $this->AdjPercentage($this->data); } $colors = array_keys($img->rgb->rgb_table); sort($colors); $ta=$this->themearr[$this->theme]; $n = count($this->data); if( $this->setslicecolors==null ) { $numcolors=count($ta); } else { $this->setslicecolors = array_reverse(array_slice($this->setslicecolors,0,$n)); $numcolors=count($this->setslicecolors); $tt = array_slice($this->setslicecolors,$n % $numcolors); $tt2 = array_slice($this->setslicecolors,0,$n % $numcolors); $tt2 = array_merge($tt, $tt2); $this->setslicecolors = $tt + $tt2; } // Draw the slices $sum=0; for($i=0; $i < $n; ++$i) $sum += $this->data[$i]; // Bail out with error if the sum is 0 if( $sum==0 ) JpGraphError::RaiseL(15009);//("Sum of all data is 0 for Pie."); // Set up the pie-circle if( $this->radius <= 1 ) $radius = floor($this->radius*min($img->width,$img->height)); else { $radius = $aaoption === 1 ? $this->radius*2 : $this->radius; } if( $this->posx <= 1 && $this->posx > 0 ) $xc = round($this->posx*$img->width); else $xc = $this->posx ; if( $this->posy <= 1 && $this->posy > 0 ) $yc = round($this->posy*$img->height); else $yc = $this->posy ; $n = count($this->data); if( $this->explode_all ) for($i=0; $i < $n; ++$i) $this->explode_radius[$i]=$this->explode_r; if( $this->ishadowcolor != "" && $aaoption !== 2) { $accsum=0; $angle2 = $this->startangle; $img->SetColor($this->ishadowcolor); for($i=0; $sum > 0 && $i < $n; ++$i) { $j = $n-$i-1; $d = $this->data[$i]; $angle1 = $angle2; $accsum += $d; $angle2 = $this->startangle+2*M_PI*$accsum/$sum; if( empty($this->explode_radius[$j]) ) $this->explode_radius[$j]=0; $la = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1); $xcm = $xc + $this->explode_radius[$j]*cos($la)*$expscale; $ycm = $yc - $this->explode_radius[$j]*sin($la)*$expscale; $xcm += $this->ishadowdrop*$expscale; $ycm += $this->ishadowdrop*$expscale; $img->CakeSlice($xcm,$ycm,$radius,$radius, $angle1*180/M_PI,$angle2*180/M_PI,$this->ishadowcolor); } } $accsum=0; $angle2 = $this->startangle; $img->SetColor($this->color); for($i=0; $sum>0 && $i < $n; ++$i) { $j = $n-$i-1; if( empty($this->explode_radius[$j]) ) $this->explode_radius[$j]=0; $d = $this->data[$i]; $angle1 = $angle2; $accsum += $d; $angle2 = $this->startangle+2*M_PI*$accsum/$sum; $this->la[$i] = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1); if( $d == 0 ) continue; if( $this->setslicecolors==null ) $slicecolor=$colors[$ta[$i%$numcolors]]; else $slicecolor=$this->setslicecolors[$i%$numcolors]; if( $this->pie_interior_border && $aaoption===0 ) $img->SetColor($this->color); else $img->SetColor($slicecolor); $arccolor = $this->pie_border && $aaoption===0 ? $this->color : ""; $xcm = $xc + $this->explode_radius[$j]*cos($this->la[$i])*$expscale; $ycm = $yc - $this->explode_radius[$j]*sin($this->la[$i])*$expscale; if( $aaoption !== 2 ) { $img->CakeSlice($xcm,$ycm,$radius-1,$radius-1, $angle1*180/M_PI,$angle2*180/M_PI,$slicecolor,$arccolor); } if( $this->csimtargets && $aaoption !== 1 ) { $this->AddSliceToCSIM($i,$xcm,$ycm,$radius,$angle1,$angle2); } } // Format the titles for each slice if( $aaoption!==2) { for( $i=0; $i < $n; ++$i) { if( $this->labeltype==0 ) { if( $sum != 0 ) $l = 100.0*$this->data[$i]/$sum; else $l = 0.0; } elseif( $this->labeltype==1 ) { $l = $this->data[$i]*1.0; } else { $l = $this->adjusted_data[$i]; } if( isset($this->labels[$i]) && is_string($this->labels[$i]) ) $this->labels[$i]=sprintf($this->labels[$i],$l); else $this->labels[$i]=$l; } } If( $this->value->show && $aaoption !== 1 ) { $this->StrokeAllLabels($img,$xc,$yc,$radius); } // Adjust title position if( $aaoption !== 1 ) { $this->title->Pos($xc, $yc-$this->title->GetFontHeight($img)-$radius-$this->title->margin, "center","bottom"); $this->title->Stroke($img); } } //--------------- // PRIVATE METHODS function NormAngle($a) { while( $a < 0 ) $a += 2*M_PI; while( $a > 2*M_PI ) $a -= 2*M_PI; return $a; } function Quadrant($a) { $a=$this->NormAngle($a); if( $a > 0 && $a <= M_PI/2 ) return 0; if( $a > M_PI/2 && $a <= M_PI ) return 1; if( $a > M_PI && $a <= 1.5*M_PI ) return 2; if( $a > 1.5*M_PI ) return 3; } function StrokeGuideLabels($img,$xc,$yc,$radius) { $n = count($this->labels); //----------------------------------------------------------------------- // Step 1 of the algorithm is to construct a number of clusters // a cluster is defined as all slices within the same quadrant (almost) // that has an angular distance less than the threshold //----------------------------------------------------------------------- $tresh_hold=25 * M_PI/180; // 25 degrees difference to be in a cluster $incluster=false; // flag if we are currently in a cluster or not $clusters = array(); // array of clusters $cidx=-1; // running cluster index // Go through all the labels and construct a number of clusters for($i=0; $i < $n-1; ++$i) { // Calc the angle distance between two consecutive slices $a1=$this->la[$i]; $a2=$this->la[$i+1]; $q1 = $this->Quadrant($a1); $q2 = $this->Quadrant($a2); $diff = abs($a1-$a2); if( $diff < $tresh_hold ) { if( $incluster ) { $clusters[$cidx][1]++; // Each cluster can only cover one quadrant // Do we cross a quadrant ( and must break the cluster) if( $q1 != $q2 ) { // If we cross a quadrant boundary we normally start a // new cluster. However we need to take the 12'a clock // and 6'a clock positions into a special consideration. // Case 1: WE go from q=1 to q=2 if the last slice on // the cluster for q=1 is close to 12'a clock and the // first slice in q=0 is small we extend the previous // cluster if( $q1 == 1 && $q2 == 0 && $a2 > (90-15)*M_PI/180 ) { if( $i < $n-2 ) { $a3 = $this->la[$i+2]; // If there isn't a cluster coming up with the next-next slice // we extend the previous cluster to cover this slice as well if( abs($a3-$a2) >= $tresh_hold ) { $clusters[$cidx][1]++; $i++; } } } elseif( $q1 == 3 && $q2 == 2 && $a2 > (270-15)*M_PI/180 ) { if( $i < $n-2 ) { $a3 = $this->la[$i+2]; // If there isn't a cluster coming up with the next-next slice // we extend the previous cluster to cover this slice as well if( abs($a3-$a2) >= $tresh_hold ) { $clusters[$cidx][1]++; $i++; } } } if( $q1==2 && $q2==1 && $a2 > (180-15)*M_PI/180 ) { $clusters[$cidx][1]++; $i++; } $incluster = false; } } elseif( $q1 == $q2) { $incluster = true; // Now we have a special case for quadrant 0. If we previously // have a cluster of one in quadrant 0 we just extend that // cluster. If we don't do this then we risk that the label // for the cluster of one will cross the guide-line if( $q1 == 0 && $cidx > -1 && $clusters[$cidx][1] == 1 && $this->Quadrant($this->la[$clusters[$cidx][0]]) == 0 ) { $clusters[$cidx][1]++; } else { $cidx++; $clusters[$cidx][0] = $i; $clusters[$cidx][1] = 1; } } else { // Create a "cluster" of one since we are just crossing // a quadrant $cidx++; $clusters[$cidx][0] = $i; $clusters[$cidx][1] = 1; } } else { if( $incluster ) { // Add the last slice $clusters[$cidx][1]++; $incluster = false; } else { // Create a "cluster" of one $cidx++; $clusters[$cidx][0] = $i; $clusters[$cidx][1] = 1; } } } // Handle the very last slice if( $incluster ) { $clusters[$cidx][1]++; } else { // Create a "cluster" of one $cidx++; $clusters[$cidx][0] = $i; $clusters[$cidx][1] = 1; } /* if( true ) { // Debug printout in labels for( $i=0; $i <= $cidx; ++$i ) { for( $j=0; $j < $clusters[$i][1]; ++$j ) { $a = $this->la[$clusters[$i][0]+$j]; $aa = round($a*180/M_PI); $q = $this->Quadrant($a); $this->labels[$clusters[$i][0]+$j]="[$q:$aa] $i:$j"; } } } */ //----------------------------------------------------------------------- // Step 2 of the algorithm is use the clusters and draw the labels // and guidelines //----------------------------------------------------------------------- // We use the font height as the base factor for how far we need to // spread the labels in the Y-direction. $img->SetFont($this->value->ff,$this->value->fs,$this->value->fsize); $fh = $img->GetFontHeight(); $origvstep=$fh*$this->iGuideVFactor; $this->value->SetMargin(0); // Number of clusters found $nc = count($clusters); // Walk through all the clusters for($i=0; $i < $nc; ++$i) { // Start angle and number of slices in this cluster $csize = $clusters[$i][1]; $a = $this->la[$clusters[$i][0]]; $q = $this->Quadrant($a); // Now set up the start and end conditions to make sure that // in each cluster we walk through the all the slices starting with the slice // closest to the equator. Since all slices are numbered clockwise from "3'a clock" // we have different conditions depending on in which quadrant the slice lies within. if( $q == 0 ) { $start = $csize-1; $idx = $start; $step = -1; $vstep = -$origvstep; } elseif( $q == 1 ) { $start = 0; $idx = $start; $step = 1; $vstep = -$origvstep; } elseif( $q == 2 ) { $start = $csize-1; $idx = $start; $step = -1; $vstep = $origvstep; } elseif( $q == 3 ) { $start = 0; $idx = $start; $step = 1; $vstep = $origvstep; } // Walk through all slices within this cluster for($j=0; $j < $csize; ++$j) { // Now adjust the position of the labels in each cluster starting // with the slice that is closest to the equator of the pie $a = $this->la[$clusters[$i][0]+$idx]; // Guide line start in the center of the arc of the slice $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)]; $x = round($r*cos($a)+$xc); $y = round($yc-$r*sin($a)); // The distance from the arc depends on chosen font and the "R-Factor" $r += $fh*$this->iGuideLineRFactor; // Should the labels be placed curved along the pie or in straight columns // outside the pie? if( $this->iGuideLineCurve ) $xt=round($r*cos($a)+$xc); // If this is the first slice in the cluster we need some first time // proessing if( $idx == $start ) { if( ! $this->iGuideLineCurve ) $xt=round($r*cos($a)+$xc); $yt=round($yc-$r*sin($a)); // Some special consideration in case this cluster starts // in quadrant 1 or 3 very close to the "equator" (< 20 degrees) // and the previous clusters last slice is within the tolerance. // In that case we add a font height to this labels Y-position // so it doesn't collide with // the slice in the previous cluster $prevcluster = ($i + ($nc-1) ) % $nc; $previdx=$clusters[$prevcluster][0]+$clusters[$prevcluster][1]-1; if( $q == 1 && $a > 160*M_PI/180 ) { // Get the angle for the previous clusters last slice $diff = abs($a-$this->la[$previdx]); if( $diff < $tresh_hold ) { $yt -= $fh; } } elseif( $q == 3 && $a > 340*M_PI/180 ) { // We need to subtract 360 to compare angle distance between // q=0 and q=3 $diff = abs($a-$this->la[$previdx]-360*M_PI/180); if( $diff < $tresh_hold ) { $yt += $fh; } } } else { // The step is at minimum $vstep but if the slices are relatively large // we make sure that we add at least a step that corresponds to the vertical // distance between the centers at the arc on the slice $prev_a = $this->la[$clusters[$i][0]+($idx-$step)]; $dy = abs($radius*(sin($a)-sin($prev_a))*1.2); if( $vstep > 0 ) $yt += max($vstep,$dy); else $yt += min($vstep,-$dy); } $label = $this->labels[$clusters[$i][0]+$idx]; if( $csize == 1 ) { // A "meta" cluster with only one slice $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)]; $rr = $r+$img->GetFontHeight()/2; $xt=round($rr*cos($a)+$xc); $yt=round($yc-$rr*sin($a)); $this->StrokeLabel($label,$img,$xc,$yc,$a,$r); if( $this->iShowGuideLineForSingle ) $this->guideline->Stroke($img,$x,$y,$xt,$yt); } else { $this->guideline->Stroke($img,$x,$y,$xt,$yt); if( $q==1 || $q==2 ) { // Left side of Pie $this->guideline->Stroke($img,$xt,$yt,$xt-$this->guidelinemargin,$yt); $lbladj = -$this->guidelinemargin-5; $this->value->halign = "right"; $this->value->valign = "center"; } else { // Right side of pie $this->guideline->Stroke($img,$xt,$yt,$xt+$this->guidelinemargin,$yt); $lbladj = $this->guidelinemargin+5; $this->value->halign = "left"; $this->value->valign = "center"; } $this->value->Stroke($img,$label,$xt+$lbladj,$yt); } // Udate idx to point to next slice in the cluster to process $idx += $step; } } } function StrokeAllLabels($img,$xc,$yc,$radius) { // First normalize all angles for labels $n = count($this->la); for($i=0; $i < $n; ++$i) { $this->la[$i] = $this->NormAngle($this->la[$i]); } if( $this->guideline->iShow ) { $this->StrokeGuideLabels($img,$xc,$yc,$radius); } else { $n = count($this->labels); for($i=0; $i < $n; ++$i) { $this->StrokeLabel($this->labels[$i],$img,$xc,$yc, $this->la[$i], $radius + $this->explode_radius[$n-1-$i]); } } } // Position the labels of each slice function StrokeLabel($label,$img,$xc,$yc,$a,$radius) { // Default value if( $this->ilabelposadj === 'auto' ) $this->ilabelposadj = 0.65; $r = $radius; // We position the values diferently depending on if they are inside // or outside the pie if( $this->ilabelposadj < 1.0 ) { $this->value->SetAlign('center','center'); $this->value->margin = 0; $xt=round($this->ilabelposadj*$r*cos($a)+$xc); $yt=round($yc-$this->ilabelposadj*$r*sin($a)); $this->value->Stroke($img,$label,$xt,$yt); } else { $this->value->halign = "left"; $this->value->valign = "top"; $this->value->margin = 0; // Position the axis title. // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text // that intersects with the extension of the corresponding axis. The code looks a little // bit messy but this is really the only way of having a reasonable position of the // axis titles. $img->SetFont($this->value->ff,$this->value->fs,$this->value->fsize); $h=$img->GetTextHeight($label); // For numeric values the format of the display value // must be taken into account if( is_numeric($label) ) { if( $label > 0 ) $w=$img->GetTextWidth(sprintf($this->value->format,$label)); else $w=$img->GetTextWidth(sprintf($this->value->negformat,$label)); } else $w=$img->GetTextWidth($label); if( $this->ilabelposadj > 1.0 && $this->ilabelposadj < 5.0) { $r *= $this->ilabelposadj; } $r += $img->GetFontHeight()/1.5; $xt=round($r*cos($a)+$xc); $yt=round($yc-$r*sin($a)); // Normalize angle while( $a < 0 ) $a += 2*M_PI; while( $a > 2*M_PI ) $a -= 2*M_PI; if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI); if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; $this->value->Stroke($img,$label,$xt-$dx*$w,$yt-$dy*$h); } } } // Class //=================================================== // CLASS PiePlotC // Description: Same as a normal pie plot but with a // filled circle in the center //=================================================== class PiePlotC extends PiePlot { var $imidsize=0.5; // Fraction of total width var $imidcolor='white'; var $midtitle=''; var $middlecsimtarget="",$middlecsimalt=""; function PiePlotC($data,$aCenterTitle='') { parent::PiePlot($data); $this->midtitle = new Text(); $this->midtitle->ParagraphAlign('center'); } function SetMid($aTitle,$aColor='white',$aSize=0.5) { $this->midtitle->Set($aTitle); $this->imidsize = $aSize ; $this->imidcolor = $aColor ; } function SetMidTitle($aTitle) { $this->midtitle->Set($aTitle); } function SetMidSize($aSize) { $this->imidsize = $aSize ; } function SetMidColor($aColor) { $this->imidcolor = $aColor ; } function SetMidCSIM($aTarget,$aAlt) { $this->middlecsimtarget = $aTarget; $this->middlecsimalt = $aAlt; } function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) { //Slice number, ellipse centre (x,y), radius, start angle, end angle while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI; while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI; $sa = 2*M_PI - $sa; $ea = 2*M_PI - $ea; // Special case when we have only one slice since then both start and end // angle will be == 0 if( abs($sa - $ea) < 0.0001 ) { $sa=2*M_PI; $ea=0; } // Add inner circle first point $xp = floor(($this->imidsize*$radius*cos($ea))+$xc); $yp = floor($yc-($this->imidsize*$radius*sin($ea))); $coords = "$xp, $yp"; //add coordinates every 0.25 radians $a=$ea+0.25; // If we cross the 260-limit with a slice we need to handle // the fact that end angle is smaller than start if( $sa < $ea ) { while ($a <= 2*M_PI) { $xp = floor($radius*cos($a)+$xc); $yp = floor($yc-$radius*sin($a)); $coords.= ", $xp, $yp"; $a += 0.25; } $a -= 2*M_PI; } while ($a < $sa) { $xp = floor(($this->imidsize*$radius*cos($a)+$xc)); $yp = floor($yc-($this->imidsize*$radius*sin($a))); $coords.= ", $xp, $yp"; $a += 0.25; } // Make sure we end at the last point $xp = floor(($this->imidsize*$radius*cos($sa)+$xc)); $yp = floor($yc-($this->imidsize*$radius*sin($sa))); $coords.= ", $xp, $yp"; // Straight line to outer circle $xp = floor($radius*cos($sa)+$xc); $yp = floor($yc-$radius*sin($sa)); $coords.= ", $xp, $yp"; //add coordinates every 0.25 radians $a=$sa - 0.25; while ($a > $ea) { $xp = floor($radius*cos($a)+$xc); $yp = floor($yc-$radius*sin($a)); $coords.= ", $xp, $yp"; $a -= 0.25; } //Add the last point on the arc $xp = floor($radius*cos($ea)+$xc); $yp = floor($yc-$radius*sin($ea)); $coords.= ", $xp, $yp"; // Close the arc $xp = floor(($this->imidsize*$radius*cos($ea))+$xc); $yp = floor($yc-($this->imidsize*$radius*sin($ea))); $coords .= ", $xp, $yp"; if( !empty($this->csimtargets[$i]) ) { $this->csimareas .= "csimtargets[$i]."\""; if( !empty($this->csimalts[$i]) ) { $tmp=sprintf($this->csimalts[$i],$this->data[$i]); $this->csimareas .= " title=\"$tmp\""; } $this->csimareas .= " alt=\"$tmp\" />\n"; } } function Stroke($img,$aaoption=0) { // Stroke the pie but don't stroke values $tmp = $this->value->show; $this->value->show = false; parent::Stroke($img,$aaoption); $this->value->show = $tmp; $xc = round($this->posx*$img->width); $yc = round($this->posy*$img->height); $radius = floor($this->radius * min($img->width,$img->height)) ; if( $this->imidsize > 0 && $aaoption !== 2 ) { if( $this->ishadowcolor != "" ) { $img->SetColor($this->ishadowcolor); $img->FilledCircle($xc+$this->ishadowdrop,$yc+$this->ishadowdrop, round($radius*$this->imidsize)); } $img->SetColor($this->imidcolor); $img->FilledCircle($xc,$yc,round($radius*$this->imidsize)); if( $this->pie_border && $aaoption === 0 ) { $img->SetColor($this->color); $img->Circle($xc,$yc,round($radius*$this->imidsize)); } if( !empty($this->middlecsimtarget) ) $this->AddMiddleCSIM($xc,$yc,round($radius*$this->imidsize)); } if( $this->value->show && $aaoption !== 1) { $this->StrokeAllLabels($img,$xc,$yc,$radius); $this->midtitle->Pos($xc,$yc,'center','center'); $this->midtitle->Stroke($img); } } function AddMiddleCSIM($xc,$yc,$r) { $xc=round($xc);$yc=round($yc);$r=round($r); $this->csimareas .= "middlecsimtarget."\""; if( !empty($this->middlecsimalt) ) { $tmp = $this->middlecsimalt; $this->csimareas .= " title=\"$tmp\""; } $this->csimareas .= " alt=\"$tmp\" />\n"; } function StrokeLabel($label,$img,$xc,$yc,$a,$r) { if( $this->ilabelposadj === 'auto' ) $this->ilabelposadj = (1-$this->imidsize)/2+$this->imidsize; parent::StrokeLabel($label,$img,$xc,$yc,$a,$r); } } //=================================================== // CLASS PieGraph // Description: //=================================================== class PieGraph extends Graph { var $posx, $posy, $radius; var $legends=array(); var $plots=array(); var $pieaa = false ; //--------------- // CONSTRUCTOR function PieGraph($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) { $this->Graph($width,$height,$cachedName,$timeout,$inline); $this->posx=$width/2; $this->posy=$height/2; $this->SetColor(array(255,255,255)); } //--------------- // PUBLIC METHODS function Add($aObj) { if( is_array($aObj) && count($aObj) > 0 ) $cl = $aObj[0]; else $cl = $aObj; if( is_a($cl,'Text') ) $this->AddText($aObj); elseif( is_a($cl,'IconPlot') ) $this->AddIcon($aObj); else { if( is_array($aObj) ) { $n = count($aObj); for($i=0; $i < $n; ++$i ) { $this->plots[] = $aObj[$i]; } } else { $this->plots[] = $aObj; } } } function SetAntiAliasing($aFlg=true) { $this->pieaa = $aFlg; } function SetColor($c) { $this->SetMarginColor($c); } function DisplayCSIMAreas() { $csim=""; foreach($this->plots as $p ) { $csim .= $p->GetCSIMareas(); } //$csim.= $this->legend->GetCSIMareas(); if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) { $this->img->SetColor($this->csimcolor); $n = count($coords[0]); for ($i=0; $i < $n; $i++) { if ($coords[1][$i]=="poly") { preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts); $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]); $m = count($pts[0]); for ($j=0; $j < $m; $j++) { $this->img->LineTo($pts[1][$j],$pts[2][$j]); } } else if ($coords[1][$i]=="rect") { $pts = preg_split('/,/', $coords[2][$i]); $this->img->SetStartPoint($pts[0],$pts[1]); $this->img->LineTo($pts[2],$pts[1]); $this->img->LineTo($pts[2],$pts[3]); $this->img->LineTo($pts[0],$pts[3]); $this->img->LineTo($pts[0],$pts[1]); } } } } // Method description function Stroke($aStrokeFileName="") { // If the filename is the predefined value = '_csim_special_' // we assume that the call to stroke only needs to do enough // to correctly generate the CSIM maps. // We use this variable to skip things we don't strictly need // to do to generate the image map to improve performance // a best we can. Therefor you will see a lot of tests !$_csim in the // code below. $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); // We need to know if we have stroked the plot in the // GetCSIMareas. Otherwise the CSIM hasn't been generated // and in the case of GetCSIM called before stroke to generate // CSIM without storing an image to disk GetCSIM must call Stroke. $this->iHasStroked = true; $n = count($this->plots); if( $this->pieaa ) { if( !$_csim ) { if( $this->background_image != "" ) { $this->StrokeFrameBackground(); } else { $this->StrokeFrame(); } } $w = $this->img->width; $h = $this->img->height; $oldimg = $this->img->img; $this->img->CreateImgCanvas(2*$w,2*$h); $this->img->SetColor( $this->margin_color ); $this->img->FilledRectangle(0,0,2*$w-1,2*$h-1); // Make all icons *2 i size since we will be scaling down the // image to do the anti aliasing $ni = count($this->iIcons); for($i=0; $i < $ni; ++$i) { $this->iIcons[$i]->iScale *= 2 ; } $this->StrokeIcons(); for($i=0; $i < $n; ++$i) { if( $this->plots[$i]->posx > 1 ) $this->plots[$i]->posx *= 2 ; if( $this->plots[$i]->posy > 1 ) $this->plots[$i]->posy *= 2 ; $this->plots[$i]->Stroke($this->img,1); if( $this->plots[$i]->posx > 1 ) $this->plots[$i]->posx /= 2 ; if( $this->plots[$i]->posy > 1 ) $this->plots[$i]->posy /= 2 ; } $indent = $this->doframe ? ($this->frame_weight + ($this->doshadow ? $this->shadow_width : 0 )) : 0 ; $indent += $this->framebevel ? $this->framebeveldepth + 1 : 0 ; $this->img->CopyCanvasH($oldimg,$this->img->img,$indent,$indent,$indent,$indent, $w-2*$indent,$h-2*$indent,2*($w-$indent),2*($h-$indent)); $this->img->img = $oldimg ; $this->img->width = $w ; $this->img->height = $h ; for($i=0; $i < $n; ++$i) { $this->plots[$i]->Stroke($this->img,2); // Stroke labels $this->plots[$i]->Legend($this); } } else { // No antialias if( !$_csim ) { if( $this->background_image != "" ) { $this->StrokeFrameBackground(); } else { $this->StrokeFrame(); $this->StrokeBackgroundGrad(); } } $this->StrokeIcons(); for($i=0; $i < $n; ++$i) { $this->plots[$i]->Stroke($this->img); $this->plots[$i]->Legend($this); } } $this->legend->Stroke($this->img); $this->footer->Stroke($this->img); $this->StrokeTitles(); if( !$_csim ) { // Stroke texts if( $this->texts != null ) { $n = count($this->texts); for($i=0; $i < $n; ++$i ) { $this->texts[$i]->Stroke($this->img); } } if( _JPG_DEBUG ) { $this->DisplayCSIMAreas(); } // Should we do any final image transformation if( $this->iImgTrans ) { if( !class_exists('ImgTrans') ) { require_once('jpgraph_imgtrans.php'); //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.'); } $tform = new ImgTrans($this->img->img); $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, $this->iImgTransDirection,$this->iImgTransHighQ, $this->iImgTransMinSize,$this->iImgTransFillColor, $this->iImgTransBorder); } // If the filename is given as the special "__handle" // then the image handler is returned and the image is NOT // streamed back if( $aStrokeFileName == _IMG_HANDLER ) { return $this->img->img; } else { // Finally stream the generated picture $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, $aStrokeFileName); } } } } // Class /* EOF */ ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_pie3d.php ================================================ radius = 0.5; $this->data = $data; $this->title = new Text(""); $this->title->SetFont(FF_FONT1,FS_BOLD); $this->value = new DisplayValue(); $this->value->Show(); $this->value->SetFormat('%.0f%%'); } //--------------- // PUBLIC METHODS // Set label arrays function SetLegends($aLegend) { $this->legends = array_reverse(array_slice($aLegend,0,count($this->data))); } function SetSliceColors($aColors) { $this->setslicecolors = $aColors; } function Legend(&$aGraph) { parent::Legend($aGraph); $aGraph->legend->txtcol = array_reverse($aGraph->legend->txtcol); } function SetCSIMTargets($targets,$alts=null) { $this->csimtargets = $targets; $this->csimalts = $alts; } // Should the slices be separated by a line? If color is specified as "" no line // will be used to separate pie slices. function SetEdge($aColor='black',$aWeight=1) { $this->edgecolor = $aColor; $this->edgeweight = $aWeight; } // Dummy function to make Pie3D behave in a similair way to 2D function ShowBorder($exterior=true,$interior=true) { JpGraphError::RaiseL(14001); //('Pie3D::ShowBorder() . Deprecated function. Use Pie3D::SetEdge() to control the edges around slices.'); } // Specify projection angle for 3D in degrees // Must be between 20 and 70 degrees function SetAngle($a) { if( $a<5 || $a>90 ) JpGraphError::RaiseL(14002); //("PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees."); else $this->angle = $a; } function AddSliceToCSIM($i,$xc,$yc,$height,$width,$thick,$sa,$ea) { //Slice number, ellipse centre (x,y), height, width, start angle, end angle $sa *= M_PI/180; $ea *= M_PI/180; //add coordinates of the centre to the map $coords = "$xc, $yc"; //add coordinates of the first point on the arc to the map $xp = floor($width*cos($sa)/2+$xc); $yp = floor($yc-$height*sin($sa)/2); $coords.= ", $xp, $yp"; //If on the front half, add the thickness offset if ($sa >= M_PI && $sa <= 2*M_PI*1.01) { $yp = floor($yp+$thick); $coords.= ", $xp, $yp"; } //add coordinates every 0.2 radians $a=$sa+0.2; while ($a<$ea) { $xp = floor($width*cos($a)/2+$xc); if ($a >= M_PI && $a <= 2*M_PI*1.01) { $yp = floor($yc-($height*sin($a)/2)+$thick); } else { $yp = floor($yc-$height*sin($a)/2); } $coords.= ", $xp, $yp"; $a += 0.2; } //Add the last point on the arc $xp = floor($width*cos($ea)/2+$xc); $yp = floor($yc-$height*sin($ea)/2); if ($ea >= M_PI && $ea <= 2*M_PI*1.01) { $coords.= ", $xp, ".floor($yp+$thick); } $coords.= ", $xp, $yp"; $alt=''; if( !empty($this->csimalts[$i]) ) { $tmp=sprintf($this->csimalts[$i],$this->data[$i]); $alt="alt=\"$tmp\" title=\"$tmp\""; } if( !empty($this->csimtargets[$i]) ) $this->csimareas .= "csimtargets[$i]."\" $alt />\n"; } function SetLabels($aLabels,$aLblPosAdj="auto") { $this->labels = $aLabels; $this->ilabelposadj=$aLblPosAdj; } // Distance from the pie to the labels function SetLabelMargin($m) { $this->value->SetMargin($m); } // Show a thin line from the pie to the label for a specific slice function ShowLabelHint($f=true) { $this->showlabelhint=$f; } // Set color of hint line to label for each slice function SetLabelHintColor($c) { $this->labelhintcolor=$c; } function SetHeight($aHeight) { $this->iThickness = $aHeight; } // Normalize Angle between 0-360 function NormAngle($a) { // Normalize anle to 0 to 2M_PI // if( $a > 0 ) { while($a > 360) $a -= 360; } else { while($a < 0) $a += 360; } if( $a < 0 ) $a = 360 + $a; if( $a == 360 ) $a=0; return $a; } // Draw one 3D pie slice at position ($xc,$yc) with height $z function Pie3DSlice($img,$xc,$yc,$w,$h,$sa,$ea,$z,$fillcolor,$shadow=0.65) { // Due to the way the 3D Pie algorithm works we are // guaranteed that any slice we get into this method // belongs to either the left or right side of the // pie ellipse. Hence, no slice will cross 90 or 270 // point. if( ($sa < 90 && $ea > 90) || ( ($sa > 90 && $sa < 270) && $ea > 270) ) { JpGraphError::RaiseL(14003);//('Internal assertion failed. Pie3D::Pie3DSlice'); exit(1); } $p[] = array(); // Setup pre-calculated values $rsa = $sa/180*M_PI; // to Rad $rea = $ea/180*M_PI; // to Rad $sinsa = sin($rsa); $cossa = cos($rsa); $sinea = sin($rea); $cosea = cos($rea); // p[] is the points for the overall slice and // pt[] is the points for the top pie // Angular step when approximating the arc with a polygon train. $step = 0.05; if( $sa >= 270 ) { if( $ea > 360 || ($ea > 0 && $ea <= 90) ) { if( $ea > 0 && $ea <= 90 ) { // Adjust angle to simplify conditions in loops $rea += 2*M_PI; } $p = array($xc,$yc,$xc,$yc+$z, $xc+$w*$cossa,$z+$yc-$h*$sinsa); $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa); for( $a=$rsa; $a < 2*M_PI; $a += $step ) { $tca = cos($a); $tsa = sin($a); $p[] = $xc+$w*$tca; $p[] = $z+$yc-$h*$tsa; $pt[] = $xc+$w*$tca; $pt[] = $yc-$h*$tsa; } $pt[] = $xc+$w; $pt[] = $yc; $p[] = $xc+$w; $p[] = $z+$yc; $p[] = $xc+$w; $p[] = $yc; $p[] = $xc; $p[] = $yc; for( $a=2*M_PI+$step; $a < $rea; $a += $step ) { $pt[] = $xc + $w*cos($a); $pt[] = $yc - $h*sin($a); } $pt[] = $xc+$w*$cosea; $pt[] = $yc-$h*$sinea; $pt[] = $xc; $pt[] = $yc; } else { $p = array($xc,$yc,$xc,$yc+$z, $xc+$w*$cossa,$z+$yc-$h*$sinsa); $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa); $rea = $rea == 0.0 ? 2*M_PI : $rea; for( $a=$rsa; $a < $rea; $a += $step ) { $tca = cos($a); $tsa = sin($a); $p[] = $xc+$w*$tca; $p[] = $z+$yc-$h*$tsa; $pt[] = $xc+$w*$tca; $pt[] = $yc-$h*$tsa; } $pt[] = $xc+$w*$cosea; $pt[] = $yc-$h*$sinea; $pt[] = $xc; $pt[] = $yc; $p[] = $xc+$w*$cosea; $p[] = $z+$yc-$h*$sinea; $p[] = $xc+$w*$cosea; $p[] = $yc-$h*$sinea; $p[] = $xc; $p[] = $yc; } } elseif( $sa >= 180 ) { $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea); $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea); for( $a=$rea; $a>$rsa; $a -= $step ) { $tca = cos($a); $tsa = sin($a); $p[] = $xc+$w*$tca; $p[] = $z+$yc-$h*$tsa; $pt[] = $xc+$w*$tca; $pt[] = $yc-$h*$tsa; } $pt[] = $xc+$w*$cossa; $pt[] = $yc-$h*$sinsa; $pt[] = $xc; $pt[] = $yc; $p[] = $xc+$w*$cossa; $p[] = $z+$yc-$h*$sinsa; $p[] = $xc+$w*$cossa; $p[] = $yc-$h*$sinsa; $p[] = $xc; $p[] = $yc; } elseif( $sa >= 90 ) { if( $ea > 180 ) { $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea); $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea); for( $a=$rea; $a > M_PI; $a -= $step ) { $tca = cos($a); $tsa = sin($a); $p[] = $xc+$w*$tca; $p[] = $z + $yc - $h*$tsa; $pt[] = $xc+$w*$tca; $pt[] = $yc-$h*$tsa; } $p[] = $xc-$w; $p[] = $z+$yc; $p[] = $xc-$w; $p[] = $yc; $p[] = $xc; $p[] = $yc; $pt[] = $xc-$w; $pt[] = $z+$yc; $pt[] = $xc-$w; $pt[] = $yc; for( $a=M_PI-$step; $a > $rsa; $a -= $step ) { $pt[] = $xc + $w*cos($a); $pt[] = $yc - $h*sin($a); } $pt[] = $xc+$w*$cossa; $pt[] = $yc-$h*$sinsa; $pt[] = $xc; $pt[] = $yc; } else { // $sa >= 90 && $ea <= 180 $p = array($xc,$yc,$xc,$yc+$z, $xc+$w*$cosea,$z+$yc-$h*$sinea, $xc+$w*$cosea,$yc-$h*$sinea, $xc,$yc); $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea); for( $a=$rea; $a>$rsa; $a -= $step ) { $pt[] = $xc + $w*cos($a); $pt[] = $yc - $h*sin($a); } $pt[] = $xc+$w*$cossa; $pt[] = $yc-$h*$sinsa; $pt[] = $xc; $pt[] = $yc; } } else { // sa > 0 && ea < 90 $p = array($xc,$yc,$xc,$yc+$z, $xc+$w*$cossa,$z+$yc-$h*$sinsa, $xc+$w*$cossa,$yc-$h*$sinsa, $xc,$yc); $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa); for( $a=$rsa; $a < $rea; $a += $step ) { $pt[] = $xc + $w*cos($a); $pt[] = $yc - $h*sin($a); } $pt[] = $xc+$w*$cosea; $pt[] = $yc-$h*$sinea; $pt[] = $xc; $pt[] = $yc; } $img->PushColor($fillcolor.":".$shadow); $img->FilledPolygon($p); $img->PopColor(); $img->PushColor($fillcolor); $img->FilledPolygon($pt); $img->PopColor(); } function SetStartAngle($aStart) { if( $aStart < 0 || $aStart > 360 ) { JpGraphError::RaiseL(14004);//('Slice start angle must be between 0 and 360 degrees.'); } $this->startangle = $aStart; } // Draw a 3D Pie function Pie3D($aaoption,$img,$data,$colors,$xc,$yc,$d,$angle,$z, $shadow=0.65,$startangle=0,$edgecolor="",$edgeweight=1) { //--------------------------------------------------------------------------- // As usual the algorithm get more complicated than I originally // envisioned. I believe that this is as simple as it is possible // to do it with the features I want. It's a good exercise to start // thinking on how to do this to convince your self that all this // is really needed for the general case. // // The algorithm two draw 3D pies without "real 3D" is done in // two steps. // First imagine the pie cut in half through a thought line between // 12'a clock and 6'a clock. It now easy to imagine that we can plot // the individual slices for each half by starting with the topmost // pie slice and continue down to 6'a clock. // // In the algortithm this is done in three principal steps // Step 1. Do the knife cut to ensure by splitting slices that extends // over the cut line. This is done by splitting the original slices into // upto 3 subslices. // Step 2. Find the top slice for each half // Step 3. Draw the slices from top to bottom // // The thing that slightly complicates this scheme with all the // angle comparisons below is that we can have an arbitrary start // angle so we must take into account the different equivalence classes. // For the same reason we must walk through the angle array in a // modulo fashion. // // Limitations of algorithm: // * A small exploded slice which crosses the 270 degree point // will get slightly nagged close to the center due to the fact that // we print the slices in Z-order and that the slice left part // get printed first and might get slightly nagged by a larger // slice on the right side just before the right part of the small // slice. Not a major problem though. //--------------------------------------------------------------------------- // Determine the height of the ellippse which gives an // indication of the inclination angle $h = ($angle/90.0)*$d; $sum = 0; for($i=0; $ilabeltype == 2 ) { $this->adjusted_data = $this->AdjPercentage($data); } // Setup the start $accsum = 0; $a = $startangle; $a = $this->NormAngle($a); // // Step 1 . Split all slices that crosses 90 or 270 // $idx=0; $adjexplode=array(); $numcolors = count($colors); for($i=0; $iexplode_radius[$i]) ) $this->explode_radius[$i]=0; $expscale=1; if( $aaoption == 1 ) $expscale=2; $la = $a + $da/2; $explode = array( $xc + $this->explode_radius[$i]*cos($la*M_PI/180)*$expscale, $yc - $this->explode_radius[$i]*sin($la*M_PI/180) * ($h/$d) *$expscale ); $adjexplode[$idx] = $explode; $labeldata[$i] = array($la,$explode[0],$explode[1]); $originalangles[$i] = array($a,$a+$da); $ne = $this->NormAngle($a+$da); if( $da <= 180 ) { // If the slice size is <= 90 it can at maximum cut across // one boundary (either 90 or 270) where it needs to be split $split=-1; // no split if( ($da<=90 && ($a <= 90 && $ne > 90)) || (($da <= 180 && $da >90) && (($a < 90 || $a >= 270) && $ne > 90)) ) { $split = 90; } elseif( ($da<=90 && ($a <= 270 && $ne > 270)) || (($da<=180 && $da>90) && ($a >= 90 && $a < 270 && ($a+$da) > 270 )) ) { $split = 270; } if( $split > 0 ) { // split in two $angles[$idx] = array($a,$split); $adjcolors[$idx] = $colors[$i % $numcolors]; $adjexplode[$idx] = $explode; $angles[++$idx] = array($split,$ne); $adjcolors[$idx] = $colors[$i % $numcolors]; $adjexplode[$idx] = $explode; } else { // no split $angles[$idx] = array($a,$ne); $adjcolors[$idx] = $colors[$i % $numcolors]; $adjexplode[$idx] = $explode; } } else { // da>180 // Slice may, depending on position, cross one or two // bonudaries if( $a < 90 ) $split = 90; elseif( $a <= 270 ) $split = 270; else $split = 90; $angles[$idx] = array($a,$split); $adjcolors[$idx] = $colors[$i % $numcolors]; $adjexplode[$idx] = $explode; //if( $a+$da > 360-$split ) { // For slices larger than 270 degrees we might cross // another boundary as well. This means that we must // split the slice further. The comparison gets a little // bit complicated since we must take into accound that // a pie might have a startangle >0 and hence a slice might // wrap around the 0 angle. // Three cases: // a) Slice starts before 90 and hence gets a split=90, but // we must also check if we need to split at 270 // b) Slice starts after 90 but before 270 and slices // crosses 90 (after a wrap around of 0) // c) If start is > 270 (hence the firstr split is at 90) // and the slice is so large that it goes all the way // around 270. if( ($a < 90 && ($a+$da > 270)) || ($a > 90 && $a<=270 && ($a+$da>360+90) ) || ($a > 270 && $this->NormAngle($a+$da)>270) ) { $angles[++$idx] = array($split,360-$split); $adjcolors[$idx] = $colors[$i % $numcolors]; $adjexplode[$idx] = $explode; $angles[++$idx] = array(360-$split,$ne); $adjcolors[$idx] = $colors[$i % $numcolors]; $adjexplode[$idx] = $explode; } else { // Just a simple split to the previous decided // angle. $angles[++$idx] = array($split,$ne); $adjcolors[$idx] = $colors[$i % $numcolors]; $adjexplode[$idx] = $explode; } } $a += $da; $a = $this->NormAngle($a); } // Total number of slices $n = count($angles); for($i=0; $i<$n; ++$i) { list($dbgs,$dbge) = $angles[$i]; } // // Step 2. Find start index (first pie that starts in upper left quadrant) // $minval = $angles[0][0]; $min = 0; for( $i=0; $i<$n; ++$i ) { if( $angles[$i][0] < $minval ) { $minval = $angles[$i][0]; $min = $i; } } $j = $min; $cnt = 0; while( $angles[$j][1] <= 90 ) { $j++; if( $j>=$n) { $j=0; } if( $cnt > $n ) { JpGraphError::RaiseL(14005); //("Pie3D Internal error (#1). Trying to wrap twice when looking for start index"); } ++$cnt; } $start = $j; // // Step 3. Print slices in z-order // $cnt = 0; // First stroke all the slices between 90 and 270 (left half circle) // counterclockwise while( $angles[$j][0] < 270 && $aaoption !== 2 ) { list($x,$y) = $adjexplode[$j]; $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1], $z,$adjcolors[$j],$shadow); $last = array($x,$y,$j); $j++; if( $j >= $n ) $j=0; if( $cnt > $n ) { JpGraphError::RaiseL(14006); //("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking."); } ++$cnt; } $slice_left = $n-$cnt; $j=$start-1; if($j<0) $j=$n-1; $cnt = 0; // The stroke all slices from 90 to -90 (right half circle) // clockwise while( $cnt < $slice_left && $aaoption !== 2 ) { list($x,$y) = $adjexplode[$j]; $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1], $z,$adjcolors[$j],$shadow); $j--; if( $cnt > $n ) { JpGraphError::RaiseL(14006); //("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking."); } if($j<0) $j=$n-1; $cnt++; } // Now do a special thing. Stroke the last slice on the left // halfcircle one more time. This is needed in the case where // the slice close to 270 have been exploded. In that case the // part of the slice close to the center of the pie might be // slightly nagged. if( $aaoption !== 2 ) $this->Pie3DSlice($img,$last[0],$last[1],$d,$h,$angles[$last[2]][0], $angles[$last[2]][1],$z,$adjcolors[$last[2]],$shadow); if( $aaoption !== 1 ) { // Now print possible labels and add csim $img->SetFont($this->value->ff,$this->value->fs); $margin = $img->GetFontHeight()/2 + $this->value->margin ; for($i=0; $i < count($data); ++$i ) { $la = $labeldata[$i][0]; $x = $labeldata[$i][1] + cos($la*M_PI/180)*($d+$margin); $y = $labeldata[$i][2] - sin($la*M_PI/180)*($h+$margin); if( $la > 180 && $la < 360 ) $y += $z; if( $this->labeltype == 0 ) { if( $sum > 0 ) $l = 100*$data[$i]/$sum; else $l = 0; } elseif( $this->labeltype == 1 ) { $l = $data[$i]; } else { $l = $this->adjusted_data[$i]; } if( isset($this->labels[$i]) && is_string($this->labels[$i]) ) $l=sprintf($this->labels[$i],$l); $this->StrokeLabels($l,$img,$labeldata[$i][0]*M_PI/180,$x,$y,$z); $this->AddSliceToCSIM($i,$labeldata[$i][1],$labeldata[$i][2],$h*2,$d*2,$z, $originalangles[$i][0],$originalangles[$i][1]); } } // // Finally add potential lines in pie // if( $edgecolor=="" || $aaoption !== 0 ) return; $accsum = 0; $a = $startangle; $a = $this->NormAngle($a); $a *= M_PI/180.0; $idx=0; $img->PushColor($edgecolor); $img->SetLineWeight($edgeweight); $fulledge = true; for($i=0; $i < count($data) && $fulledge; ++$i ) { if( empty($this->explode_radius[$i]) ) $this->explode_radius[$i]=0; if( $this->explode_radius[$i] > 0 ) { $fulledge = false; } } for($i=0; $i < count($data); ++$i, ++$idx ) { $da = $data[$i]/$sum * 2*M_PI; $this->StrokeFullSliceFrame($img,$xc,$yc,$a,$a+$da,$d,$h,$z,$edgecolor, $this->explode_radius[$i],$fulledge); $a += $da; } $img->PopColor(); } function StrokeFullSliceFrame($img,$xc,$yc,$sa,$ea,$w,$h,$z,$edgecolor,$exploderadius,$fulledge) { $step = 0.02; if( $exploderadius > 0 ) { $la = ($sa+$ea)/2; $xc += $exploderadius*cos($la); $yc -= $exploderadius*sin($la) * ($h/$w) ; } $p = array($xc,$yc,$xc+$w*cos($sa),$yc-$h*sin($sa)); for($a=$sa; $a < $ea; $a += $step ) { $p[] = $xc + $w*cos($a); $p[] = $yc - $h*sin($a); } $p[] = $xc+$w*cos($ea); $p[] = $yc-$h*sin($ea); $p[] = $xc; $p[] = $yc; $img->SetColor($edgecolor); $img->Polygon($p); // Unfortunately we can't really draw the full edge around the whole of // of the slice if any of the slices are exploded. The reason is that // this algorithm is to simply. There are cases where the edges will // "overwrite" other slices when they have been exploded. // Doing the full, proper 3D hidden lines stiff is actually quite // tricky. So for exploded pies we only draw the top edge. Not perfect // but the "real" solution is much more complicated. if( $fulledge && !( $sa > 0 && $sa < M_PI && $ea < M_PI) ) { if($sa < M_PI && $ea > M_PI) $sa = M_PI; if($sa < 2*M_PI && (($ea >= 2*M_PI) || ($ea > 0 && $ea < $sa ) ) ) $ea = 2*M_PI; if( $sa >= M_PI && $ea <= 2*M_PI ) { $p = array($xc + $w*cos($sa),$yc - $h*sin($sa), $xc + $w*cos($sa),$z + $yc - $h*sin($sa)); for($a=$sa+$step; $a < $ea; $a += $step ) { $p[] = $xc + $w*cos($a); $p[] = $z + $yc - $h*sin($a); } $p[] = $xc + $w*cos($ea); $p[] = $z + $yc - $h*sin($ea); $p[] = $xc + $w*cos($ea); $p[] = $yc - $h*sin($ea); $img->SetColor($edgecolor); $img->Polygon($p); } } } function Stroke($img,$aaoption=0) { $n = count($this->data); // If user hasn't set the colors use the theme array if( $this->setslicecolors==null ) { $colors = array_keys($img->rgb->rgb_table); sort($colors); $idx_a=$this->themearr[$this->theme]; $ca = array(); $m = count($idx_a); for($i=0; $i < $m; ++$i) $ca[$i] = $colors[$idx_a[$i]]; $ca = array_reverse(array_slice($ca,0,$n)); } else { $ca = $this->setslicecolors; } if( $this->posx <= 1 && $this->posx > 0 ) $xc = round($this->posx*$img->width); else $xc = $this->posx ; if( $this->posy <= 1 && $this->posy > 0 ) $yc = round($this->posy*$img->height); else $yc = $this->posy ; if( $this->radius <= 1 ) { $width = floor($this->radius*min($img->width,$img->height)); // Make sure that the pie doesn't overflow the image border // The 0.9 factor is simply an extra margin to leave some space // between the pie an the border of the image. $width = min($width,min($xc*0.9,($yc*90/$this->angle-$width/4)*0.9)); } else { $width = $this->radius * ($aaoption === 1 ? 2 : 1 ) ; } // Add a sanity check for width if( $width < 1 ) { JpGraphError::RaiseL(14007);//("Width for 3D Pie is 0. Specify a size > 0"); } // Establish a thickness. By default the thickness is a fifth of the // pie slice width (=pie radius) but since the perspective depends // on the inclination angle we use some heuristics to make the edge // slightly thicker the less the angle. // Has user specified an absolute thickness? In that case use // that instead if( $this->iThickness ) { $thick = $this->iThickness; $thick *= ($aaoption === 1 ? 2 : 1 ); } else $thick = $width/12; $a = $this->angle; if( $a <= 30 ) $thick *= 1.6; elseif( $a <= 40 ) $thick *= 1.4; elseif( $a <= 50 ) $thick *= 1.2; elseif( $a <= 60 ) $thick *= 1.0; elseif( $a <= 70 ) $thick *= 0.8; elseif( $a <= 80 ) $thick *= 0.7; else $thick *= 0.6; $thick = floor($thick); if( $this->explode_all ) for($i=0; $i < $n; ++$i) $this->explode_radius[$i]=$this->explode_r; $this->Pie3D($aaoption,$img,$this->data, $ca, $xc, $yc, $width, $this->angle, $thick, 0.65, $this->startangle, $this->edgecolor, $this->edgeweight); // Adjust title position if( $aaoption != 1 ) { $this->title->Pos($xc,$yc-$this->title->GetFontHeight($img)-$width/2-$this->title->margin, "center","bottom"); $this->title->Stroke($img); } } //--------------- // PRIVATE METHODS // Position the labels of each slice function StrokeLabels($label,$img,$a,$xp,$yp,$z) { $this->value->halign="left"; $this->value->valign="top"; // Position the axis title. // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text // that intersects with the extension of the corresponding axis. The code looks a little // bit messy but this is really the only way of having a reasonable position of the // axis titles. $img->SetFont($this->value->ff,$this->value->fs,$this->value->fsize); $h=$img->GetTextHeight($label); // For numeric values the format of the display value // must be taken into account if( is_numeric($label) ) { if( $label >= 0 ) $w=$img->GetTextWidth(sprintf($this->value->format,$label)); else $w=$img->GetTextWidth(sprintf($this->value->negformat,$label)); } else $w=$img->GetTextWidth($label); while( $a > 2*M_PI ) $a -= 2*M_PI; if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI); if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; $x = round($xp-$dx*$w); $y = round($yp-$dy*$h); // Mark anchor point for debugging /* $img->SetColor('red'); $img->Line($xp-10,$yp,$xp+10,$yp); $img->Line($xp,$yp-10,$xp,$yp+10); */ $oldmargin = $this->value->margin; $this->value->margin=0; $this->value->Stroke($img,$label,$x,$y); $this->value->margin=$oldmargin; } } // Class /* EOF */ ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_plotband.php ================================================ x=$aX; $this->y=$aY; $this->w=$aWidth; $this->h=$aHeight; $this->xe=$aX+$aWidth-1; $this->ye=$aY+$aHeight-1; } } //===================================================================== // Class RectPattern // Base class for pattern hierarchi that is used to display patterned // bands on the graph. Any subclass that doesn't override Stroke() // must at least implement method DoPattern(&$aImg) which is responsible // for drawing the pattern onto the graph. //===================================================================== class RectPattern { var $color; var $weight; var $rect=null; var $doframe=true; var $linespacing; // Line spacing in pixels var $iBackgroundColor=-1; // Default is no background fill function RectPattern($aColor,$aWeight=1) { $this->color = $aColor; $this->weight = $aWeight; } function SetBackground($aBackgroundColor) { $this->iBackgroundColor=$aBackgroundColor; } function SetPos(&$aRect) { $this->rect = $aRect; } function ShowFrame($aShow=true) { $this->doframe=$aShow; } function SetDensity($aDens) { if( $aDens < 1 || $aDens > 100 ) JpGraphError::RaiseL(16001,$aDens); //(" Desity for pattern must be between 1 and 100. (You tried $aDens)"); // 1% corresponds to linespacing=50 // 100 % corresponds to linespacing 1 $this->linespacing = floor(((100-$aDens)/100.0)*50)+1; } function Stroke(&$aImg) { if( $this->rect == null ) JpGraphError::RaiseL(16002); //(" No positions specified for pattern."); if( !(is_numeric($this->iBackgroundColor) && $this->iBackgroundColor==-1) ) { $aImg->SetColor($this->iBackgroundColor); $aImg->FilledRectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye); } $aImg->SetColor($this->color); $aImg->SetLineWeight($this->weight); // Virtual function implemented by subclass $this->DoPattern($aImg); // Frame around the pattern area if( $this->doframe ) $aImg->Rectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye); } } //===================================================================== // Class RectPatternSolid // Implements a solid band //===================================================================== class RectPatternSolid extends RectPattern { function RectPatternSolid($aColor="black",$aWeight=1) { parent::RectPattern($aColor,$aWeight); } function DoPattern(&$aImg) { $aImg->SetColor($this->color); $aImg->FilledRectangle($this->rect->x,$this->rect->y, $this->rect->xe,$this->rect->ye); } } //===================================================================== // Class RectPatternHor // Implements horizontal line pattern //===================================================================== class RectPatternHor extends RectPattern { function RectPatternHor($aColor="black",$aWeight=1,$aLineSpacing=7) { parent::RectPattern($aColor,$aWeight); $this->linespacing = $aLineSpacing; } function DoPattern(&$aImg) { $x0 = $this->rect->x; $x1 = $this->rect->xe; $y = $this->rect->y; while( $y < $this->rect->ye ) { $aImg->Line($x0,$y,$x1,$y); $y += $this->linespacing; } } } //===================================================================== // Class RectPatternVert // Implements vertical line pattern //===================================================================== class RectPatternVert extends RectPattern { var $linespacing=10; // Line spacing in pixels function RectPatternVert($aColor="black",$aWeight=1,$aLineSpacing=7) { parent::RectPattern($aColor,$aWeight); $this->linespacing = $aLineSpacing; } //-------------------- // Private methods // function DoPattern(&$aImg) { $x = $this->rect->x; $y0 = $this->rect->y; $y1 = $this->rect->ye; while( $x < $this->rect->xe ) { $aImg->Line($x,$y0,$x,$y1); $x += $this->linespacing; } } } //===================================================================== // Class RectPatternRDiag // Implements right diagonal pattern //===================================================================== class RectPatternRDiag extends RectPattern { var $linespacing; // Line spacing in pixels function RectPatternRDiag($aColor="black",$aWeight=1,$aLineSpacing=12) { parent::RectPattern($aColor,$aWeight); $this->linespacing = $aLineSpacing; } function DoPattern(&$aImg) { // -------------------- // | / / / / /| // |/ / / / / | // | / / / / | // -------------------- $xe = $this->rect->xe; $ye = $this->rect->ye; $x0 = $this->rect->x + round($this->linespacing/2); $y0 = $this->rect->y; $x1 = $this->rect->x; $y1 = $this->rect->y + round($this->linespacing/2); while($x0<=$xe && $y1<=$ye) { $aImg->Line($x0,$y0,$x1,$y1); $x0 += $this->linespacing; $y1 += $this->linespacing; } if( $xe-$x1 > $ye-$y0 ) { // Width larger than height $x1 = $this->rect->x + ($y1-$ye); $y1 = $ye; $y0 = $this->rect->y; while( $x0 <= $xe ) { $aImg->Line($x0,$y0,$x1,$y1); $x0 += $this->linespacing; $x1 += $this->linespacing; } $y0=$this->rect->y + ($x0-$xe); $x0=$xe; } else { // Height larger than width $diff = $x0-$xe; $y0 = $diff+$this->rect->y; $x0 = $xe; $x1 = $this->rect->x; while( $y1 <= $ye ) { $aImg->Line($x0,$y0,$x1,$y1); $y1 += $this->linespacing; $y0 += $this->linespacing; } $diff = $y1-$ye; $y1 = $ye; $x1 = $diff + $this->rect->x; } while( $y0 <= $ye ) { $aImg->Line($x0,$y0,$x1,$y1); $y0 += $this->linespacing; $x1 += $this->linespacing; } } } //===================================================================== // Class RectPatternLDiag // Implements left diagonal pattern //===================================================================== class RectPatternLDiag extends RectPattern { var $linespacing; // Line spacing in pixels function RectPatternLDiag($aColor="black",$aWeight=1,$aLineSpacing=12) { $this->linespacing = $aLineSpacing; parent::RectPattern($aColor,$aWeight); } function DoPattern(&$aImg) { // -------------------- // |\ \ \ \ \ | // | \ \ \ \ \| // | \ \ \ \ | // |------------------| $xe = $this->rect->xe; $ye = $this->rect->ye; $x0 = $this->rect->x + round($this->linespacing/2); $y0 = $this->rect->ye; $x1 = $this->rect->x; $y1 = $this->rect->ye - round($this->linespacing/2); while($x0<=$xe && $y1>=$this->rect->y) { $aImg->Line($x0,$y0,$x1,$y1); $x0 += $this->linespacing; $y1 -= $this->linespacing; } if( $xe-$x1 > $ye-$this->rect->y ) { // Width larger than height $x1 = $this->rect->x + ($this->rect->y-$y1); $y0=$ye; $y1=$this->rect->y; while( $x0 <= $xe ) { $aImg->Line($x0,$y0,$x1,$y1); $x0 += $this->linespacing; $x1 += $this->linespacing; } $y0=$this->rect->ye - ($x0-$xe); $x0=$xe; } else { // Height larger than width $diff = $x0-$xe; $y0 = $ye-$diff; $x0 = $xe; while( $y1 >= $this->rect->y ) { $aImg->Line($x0,$y0,$x1,$y1); $y0 -= $this->linespacing; $y1 -= $this->linespacing; } $diff = $this->rect->y - $y1; $x1 = $this->rect->x + $diff; $y1 = $this->rect->y; } while( $y0 >= $this->rect->y ) { $aImg->Line($x0,$y0,$x1,$y1); $y0 -= $this->linespacing; $x1 += $this->linespacing; } } } //===================================================================== // Class RectPattern3DPlane // Implements "3D" plane pattern //===================================================================== class RectPattern3DPlane extends RectPattern { var $alpha=50; // Parameter that specifies the distance // to "simulated" horizon in pixel from the // top of the band. Specifies how fast the lines // converge. function RectPattern3DPlane($aColor="black",$aWeight=1) { parent::RectPattern($aColor,$aWeight); $this->SetDensity(10); // Slightly larger default } function SetHorizon($aHorizon) { $this->alpha=$aHorizon; } function DoPattern(&$aImg) { // "Fake" a nice 3D grid-effect. $x0 = $this->rect->x + $this->rect->w/2; $y0 = $this->rect->y; $x1 = $x0; $y1 = $this->rect->ye; $x0_right = $x0; $x1_right = $x1; // BTW "apa" means monkey in Swedish but is really a shortform for // "alpha+a" which was the labels I used on paper when I derived the // geometric to get the 3D perspective right. // $apa is the height of the bounding rectangle plus the distance to the // artifical horizon (alpha) $apa = $this->rect->h + $this->alpha; // Three cases and three loops // 1) The endpoint of the line ends on the bottom line // 2) The endpoint ends on the side // 3) Horizontal lines // Endpoint falls on bottom line $middle=$this->rect->x + $this->rect->w/2; $dist=$this->linespacing; $factor=$this->alpha /($apa); while($x1>$this->rect->x) { $aImg->Line($x0,$y0,$x1,$y1); $aImg->Line($x0_right,$y0,$x1_right,$y1); $x1 = $middle - $dist; $x0 = $middle - $dist * $factor; $x1_right = $middle + $dist; $x0_right = $middle + $dist * $factor; $dist += $this->linespacing; } // Endpoint falls on sides $dist -= $this->linespacing; $d=$this->rect->w/2; $c = $apa - $d*$apa/$dist; while( $x0>$this->rect->x ) { $aImg->Line($x0,$y0,$this->rect->x,$this->rect->ye-$c); $aImg->Line($x0_right,$y0,$this->rect->xe,$this->rect->ye-$c); $dist += $this->linespacing; $x0 = $middle - $dist * $factor; $x1 = $middle - $dist; $x0_right = $middle + $dist * $factor; $c = $apa - $d*$apa/$dist; } // Horizontal lines // They need some serious consideration since they are a function // of perspective depth (alpha) and density (linespacing) $x0=$this->rect->x; $x1=$this->rect->xe; $y=$this->rect->ye; // The first line is drawn directly. Makes the loop below slightly // more readable. $aImg->Line($x0,$y,$x1,$y); $hls = $this->linespacing; // A correction factor for vertical "brick" line spacing to account for // a) the difference in number of pixels hor vs vert // b) visual apperance to make the first layer of "bricks" look more // square. $vls = $this->linespacing*0.6; $ds = $hls*($apa-$vls)/$apa; // Get the slope for the "perspective line" going from bottom right // corner to top left corner of the "first" brick. // Uncomment the following lines if you want to get a visual understanding // of what this helpline does. BTW this mimics the way you would get the // perspective right when drawing on paper. /* $x0 = $middle; $y0 = $this->rect->ye; $len=floor(($this->rect->ye-$this->rect->y)/$vls); $x1 = $middle+round($len*$ds); $y1 = $this->rect->ye-$len*$vls; $aImg->PushColor("red"); $aImg->Line($x0,$y0,$x1,$y1); $aImg->PopColor(); */ $y -= $vls; $k=($this->rect->ye-($this->rect->ye-$vls))/($middle-($middle-$ds)); $dist = $hls; while( $y>$this->rect->y ) { $aImg->Line($this->rect->x,$y,$this->rect->xe,$y); $adj = $k*$dist/(1+$dist*$k/$apa); if( $adj < 2 ) $adj=1; $y = $this->rect->ye - round($adj); $dist += $hls; } } } //===================================================================== // Class RectPatternCross // Vert/Hor crosses //===================================================================== class RectPatternCross extends RectPattern { var $vert=null; var $hor=null; function RectPatternCross($aColor="black",$aWeight=1) { parent::RectPattern($aColor,$aWeight); $this->vert = new RectPatternVert($aColor,$aWeight); $this->hor = new RectPatternHor($aColor,$aWeight); } function SetOrder($aDepth) { $this->vert->SetOrder($aDepth); $this->hor->SetOrder($aDepth); } function SetPos(&$aRect) { parent::SetPos($aRect); $this->vert->SetPos($aRect); $this->hor->SetPos($aRect); } function SetDensity($aDens) { $this->vert->SetDensity($aDens); $this->hor->SetDensity($aDens); } function DoPattern(&$aImg) { $this->vert->DoPattern($aImg); $this->hor->DoPattern($aImg); } } //===================================================================== // Class RectPatternDiagCross // Vert/Hor crosses //===================================================================== class RectPatternDiagCross extends RectPattern { var $left=null; var $right=null; function RectPatternDiagCross($aColor="black",$aWeight=1) { parent::RectPattern($aColor,$aWeight); $this->right = new RectPatternRDiag($aColor,$aWeight); $this->left = new RectPatternLDiag($aColor,$aWeight); } function SetOrder($aDepth) { $this->left->SetOrder($aDepth); $this->right->SetOrder($aDepth); } function SetPos(&$aRect) { parent::SetPos($aRect); $this->left->SetPos($aRect); $this->right->SetPos($aRect); } function SetDensity($aDens) { $this->left->SetDensity($aDens); $this->right->SetDensity($aDens); } function DoPattern(&$aImg) { $this->left->DoPattern($aImg); $this->right->DoPattern($aImg); } } //===================================================================== // Class RectPatternFactory // Factory class for rectangular pattern //===================================================================== class RectPatternFactory { function RectPatternFactory() { // Empty } function Create($aPattern,$aColor,$aWeight=1) { switch($aPattern) { case BAND_RDIAG: $obj = new RectPatternRDiag($aColor,$aWeight); break; case BAND_LDIAG: $obj = new RectPatternLDiag($aColor,$aWeight); break; case BAND_SOLID: $obj = new RectPatternSolid($aColor,$aWeight); break; case BAND_VLINE: $obj = new RectPatternVert($aColor,$aWeight); break; case BAND_HLINE: $obj = new RectPatternHor($aColor,$aWeight); break; case BAND_3DPLANE: $obj = new RectPattern3DPlane($aColor,$aWeight); break; case BAND_HVCROSS: $obj = new RectPatternCross($aColor,$aWeight); break; case BAND_DIAGCROSS: $obj = new RectPatternDiagCross($aColor,$aWeight); break; default: JpGraphError::RaiseL(16003,$aPattern); //(" Unknown pattern specification ($aPattern)"); } return $obj; } } //===================================================================== // Class PlotBand // Factory class which is used by the client. // It is responsible for factoring the corresponding pattern // concrete class. //===================================================================== class PlotBand { var $prect=null; var $depth; var $dir, $min, $max; function PlotBand($aDir,$aPattern,$aMin,$aMax,$aColor="black",$aWeight=1,$aDepth=DEPTH_BACK) { $f = new RectPatternFactory(); $this->prect = $f->Create($aPattern,$aColor,$aWeight); if( is_numeric($aMin) && is_numeric($aMax) && ($aMin > $aMax) ) JpGraphError::RaiseL(16004); //('Min value for plotband is larger than specified max value. Please correct.'); $this->dir = $aDir; $this->min = $aMin; $this->max = $aMax; $this->depth=$aDepth; } // Set position. aRect contains absolute image coordinates function SetPos(&$aRect) { assert( $this->prect != null ) ; $this->prect->SetPos($aRect); } function ShowFrame($aFlag=true) { $this->prect->ShowFrame($aFlag); } // Set z-order. In front of pplot or in the back function SetOrder($aDepth) { $this->depth=$aDepth; } function SetDensity($aDens) { $this->prect->SetDensity($aDens); } function GetDir() { return $this->dir; } function GetMin() { return $this->min; } function GetMax() { return $this->max; } // Display band function Stroke(&$aImg,&$aXScale,&$aYScale) { assert( $this->prect != null ) ; if( $this->dir == HORIZONTAL ) { if( $this->min === 'min' ) $this->min = $aYScale->GetMinVal(); if( $this->max === 'max' ) $this->max = $aYScale->GetMaxVal(); // Only draw the bar if it actually appears in the range if ($this->min < $aYScale->GetMaxVal() && $this->max > $aYScale->GetMinVal()) { // Trucate to limit of axis $this->min = max($this->min, $aYScale->GetMinVal()); $this->max = min($this->max, $aYScale->GetMaxVal()); $x=$aXScale->scale_abs[0]; $y=$aYScale->Translate($this->max); $width=$aXScale->scale_abs[1]-$aXScale->scale_abs[0]+1; $height=abs($y-$aYScale->Translate($this->min))+1; $this->prect->SetPos(new Rectangle($x,$y,$width,$height)); $this->prect->Stroke($aImg); } } else { // VERTICAL if( $this->min === 'min' ) $this->min = $aXScale->GetMinVal(); if( $this->max === 'max' ) $this->max = $aXScale->GetMaxVal(); // Only draw the bar if it actually appears in the range if ($this->min < $aXScale->GetMaxVal() && $this->max > $aXScale->GetMinVal()) { // Trucate to limit of axis $this->min = max($this->min, $aXScale->GetMinVal()); $this->max = min($this->max, $aXScale->GetMaxVal()); $y=$aYScale->scale_abs[1]; $x=$aXScale->Translate($this->min); $height=abs($aYScale->scale_abs[1]-$aYScale->scale_abs[0]); $width=abs($x-$aXScale->Translate($this->max)); $this->prect->SetPos(new Rectangle($x,$y,$width,$height)); $this->prect->Stroke($aImg); } } } } ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_plotmark.inc ================================================ an[$aMark]; if( is_string($aIdx) ) { if( !in_array($aIdx,$this->colors) ) { JpGraphError::RaiseL(23001,$this->name,$aIdx); //('This marker "'.($this->name).'" does not exist in color: '.$aIdx); } $idx = $this->index[$aIdx]; } elseif( !is_integer($aIdx) || (is_integer($aIdx) && $aIdx > $this->maxidx ) ) { JpGraphError::RaiseL(23002,$this->name); //('Mark color index too large for marker "'.($this->name).'"'); } else $idx = $aIdx ; return Image::CreateFromString(base64_decode($this->{$n}[$idx][1])); } function GetAnchor() { return array($this->anchor_x,$this->anchor_y); } } // Keep a global flag cache to reduce memory usage $_gFlagCache=array( 1 => null, 2 => null, 3 => null, 4 => null, ); // Only supposed to b called as statics class FlagCache { function GetFlagImgByName($aSize,$aName) { global $_gFlagCache; require_once('jpgraph_flags.php'); if( $_gFlagCache[$aSize] === null ) { $_gFlagCache[$aSize] =& new FlagImages($aSize); } $f =& $_gFlagCache[$aSize]; $idx = $f->GetIdxByName($aName,$aFullName); return $f->GetImgByIdx($idx); } } //=================================================== // CLASS PlotMark // Description: Handles the plot marks in graphs //=================================================== class PlotMark { var $title, $show=true; var $type,$weight=1; var $color="black", $width=4, $fill_color="blue"; var $yvalue,$xvalue='',$csimtarget,$csimalt,$csimareas; var $iFormatCallback=""; var $iFormatCallback2=""; var $markimg='',$iScale=1.0; var $oldfilename='',$iFileName=''; var $imgdata_balls = null; var $imgdata_diamonds = null; var $imgdata_squares = null; var $imgdata_bevels = null; var $imgdata_stars = null; var $imgdata_pushpins = null; //-------------- // CONSTRUCTOR function PlotMark() { $this->title = new Text(); $this->title->Hide(); $this->csimareas = ''; $this->csimalt = ''; $this->type=-1; } //--------------- // PUBLIC METHODS function SetType($aType,$aFileName='',$aScale=1.0) { $this->type = $aType; if( $aType == MARK_IMG && $aFileName=='' ) { JpGraphError::RaiseL(23003);//('A filename must be specified if you set the mark type to MARK_IMG.'); } $this->iFileName = $aFileName; $this->iScale = $aScale; } function SetCallback($aFunc) { $this->iFormatCallback = $aFunc; } function SetCallbackYX($aFunc) { $this->iFormatCallback2 = $aFunc; } function GetType() { return $this->type; } function SetColor($aColor) { $this->color=$aColor; } function SetFillColor($aFillColor) { $this->fill_color = $aFillColor; } function SetWeight($aWeight) { $this->weight = $aWeight; } // Synonym for SetWidth() function SetSize($aWidth) { $this->width=$aWidth; } function SetWidth($aWidth) { $this->width=$aWidth; } function SetDefaultWidth() { switch( $this->type ) { case MARK_CIRCLE: case MARK_FILLEDCIRCLE: $this->width=4; break; default: $this->width=7; } } function GetWidth() { return $this->width; } function Hide($aHide=true) { $this->show = !$aHide; } function Show($aShow=true) { $this->show = $aShow; } function SetCSIMAltVal($aY,$aX='') { $this->yvalue=$aY; $this->xvalue=$aX; } function SetCSIMTarget($aTarget) { $this->csimtarget=$aTarget; } function SetCSIMAlt($aAlt) { $this->csimalt=$aAlt; } function GetCSIMAreas(){ return $this->csimareas; } function AddCSIMPoly($aPts) { $coords = round($aPts[0]).", ".round($aPts[1]); $n = count($aPts)/2; for( $i=1; $i < $n; ++$i){ $coords .= ", ".round($aPts[2*$i]).", ".round($aPts[2*$i+1]); } $this->csimareas=""; if( !empty($this->csimtarget) ) { $this->csimareas .= "csimtarget."\""; if( !empty($this->csimalt) ) { $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue); $this->csimareas .= " title=\"$tmp\""; } $this->csimareas .= " alt=\"$tmp\" />\n"; } } function AddCSIMCircle($x,$y,$r) { $x = round($x); $y=round($y); $r=round($r); $this->csimareas=""; if( !empty($this->csimtarget) ) { $this->csimareas .= "csimtarget."\""; if( !empty($this->csimalt) ) { $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue); $this->csimareas .= " title=\"$tmp\""; } $this->csimareas .= " alt=\"$tmp\" />\n"; } } function Stroke(&$img,$x,$y) { if( !$this->show ) return; if( $this->iFormatCallback != '' || $this->iFormatCallback2 != '' ) { if( $this->iFormatCallback != '' ) { $f = $this->iFormatCallback; list($width,$color,$fcolor) = call_user_func($f,$this->yvalue); $filename = $this->iFileName; $imgscale = $this->iScale; } else { $f = $this->iFormatCallback2; list($width,$color,$fcolor,$filename,$imgscale) = call_user_func($f,$this->yvalue,$this->xvalue); if( $filename=="" ) $filename = $this->iFileName; if( $imgscale=="" ) $imgscale = $this->iScale; } if( $width=="" ) $width = $this->width; if( $color=="" ) $color = $this->color; if( $fcolor=="" ) $fcolor = $this->fill_color; } else { $fcolor = $this->fill_color; $color = $this->color; $width = $this->width; $filename = $this->iFileName; $imgscale = $this->iScale; } if( $this->type == MARK_IMG || ($this->type >= MARK_FLAG1 && $this->type <= MARK_FLAG4 ) || $this->type >= MARK_IMG_PUSHPIN ) { // Note: For the builtin images we use the "filename" parameter // to denote the color $anchor_x = 0.5; $anchor_y = 0.5; switch( $this->type ) { case MARK_FLAG1: case MARK_FLAG2: case MARK_FLAG3: case MARK_FLAG4: $this->markimg = FlagCache::GetFlagImgByName($this->type-MARK_FLAG1+1,$filename); break; case MARK_IMG : // Load an image and use that as a marker // Small optimization, if we have already read an image don't // waste time reading it again. if( $this->markimg == '' || !($this->oldfilename === $filename) ) { $this->markimg = Graph::LoadBkgImage('',$filename); $this->oldfilename = $filename ; } break; case MARK_IMG_PUSHPIN: case MARK_IMG_SPUSHPIN: case MARK_IMG_LPUSHPIN: if( $this->imgdata_pushpins == null ) { require_once 'imgdata_pushpins.inc'; $this->imgdata_pushpins = new ImgData_PushPins(); } $this->markimg = $this->imgdata_pushpins->GetImg($this->type,$filename); list($anchor_x,$anchor_y) = $this->imgdata_pushpins->GetAnchor(); break; case MARK_IMG_SQUARE: if( $this->imgdata_squares == null ) { require_once 'imgdata_squares.inc'; $this->imgdata_squares = new ImgData_Squares(); } $this->markimg = $this->imgdata_squares->GetImg($this->type,$filename); list($anchor_x,$anchor_y) = $this->imgdata_squares->GetAnchor(); break; case MARK_IMG_STAR: if( $this->imgdata_stars == null ) { require_once 'imgdata_stars.inc'; $this->imgdata_stars = new ImgData_Stars(); } $this->markimg = $this->imgdata_stars->GetImg($this->type,$filename); list($anchor_x,$anchor_y) = $this->imgdata_stars->GetAnchor(); break; case MARK_IMG_BEVEL: if( $this->imgdata_bevels == null ) { require_once 'imgdata_bevels.inc'; $this->imgdata_bevels = new ImgData_Bevels(); } $this->markimg = $this->imgdata_bevels->GetImg($this->type,$filename); list($anchor_x,$anchor_y) = $this->imgdata_bevels->GetAnchor(); break; case MARK_IMG_DIAMOND: if( $this->imgdata_diamonds == null ) { require_once 'imgdata_diamonds.inc'; $this->imgdata_diamonds = new ImgData_Diamonds(); } $this->markimg = $this->imgdata_diamonds->GetImg($this->type,$filename); list($anchor_x,$anchor_y) = $this->imgdata_diamonds->GetAnchor(); break; case MARK_IMG_BALL: case MARK_IMG_SBALL: case MARK_IMG_MBALL: case MARK_IMG_LBALL: if( $this->imgdata_balls == null ) { require_once 'imgdata_balls.inc'; $this->imgdata_balls = new ImgData_Balls(); } $this->markimg = $this->imgdata_balls->GetImg($this->type,$filename); list($anchor_x,$anchor_y) = $this->imgdata_balls->GetAnchor(); break; } $w = $img->GetWidth($this->markimg); $h = $img->GetHeight($this->markimg); $dw = round($imgscale * $w ); $dh = round($imgscale * $h ); // Do potential rotation list($x,$y) = $img->Rotate($x,$y); $dx = round($x-$dw*$anchor_x); $dy = round($y-$dh*$anchor_y); $this->width = max($dx,$dy); $img->Copy($this->markimg,$dx,$dy,0,0,$dw,$dh,$w,$h); if( !empty($this->csimtarget) ) { $this->csimareas = "csimtarget."\""; if( !empty($this->csimalt) ) { $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue); $this->csimareas .= " title=\"$tmp\""; } $this->csimareas .= " alt=\"$tmp\" />\n"; } // Stroke title $this->title->Align("center","top"); $this->title->Stroke($img,$x,$y+round($dh/2)); return; } $weight = $this->weight; $dx=round($width/2,0); $dy=round($width/2,0); $pts=0; switch( $this->type ) { case MARK_SQUARE: $c[]=$x-$dx;$c[]=$y-$dy; $c[]=$x+$dx;$c[]=$y-$dy; $c[]=$x+$dx;$c[]=$y+$dy; $c[]=$x-$dx;$c[]=$y+$dy; $c[]=$x-$dx;$c[]=$y-$dy; $pts=5; break; case MARK_UTRIANGLE: ++$dx;++$dy; $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx $c[]=$x;$c[]=$y-0.87*$dy; $c[]=$x+$dx;$c[]=$y+0.87*$dy; $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx $pts=4; break; case MARK_DTRIANGLE: ++$dx;++$dy; $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx $c[]=$x-$dx;$c[]=$y-0.87*$dy; $c[]=$x+$dx;$c[]=$y-0.87*$dy; $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx $pts=4; break; case MARK_DIAMOND: $c[]=$x;$c[]=$y+$dy; $c[]=$x-$dx;$c[]=$y; $c[]=$x;$c[]=$y-$dy; $c[]=$x+$dx;$c[]=$y; $c[]=$x;$c[]=$y+$dy; $pts=5; break; case MARK_LEFTTRIANGLE: $c[]=$x;$c[]=$y; $c[]=$x;$c[]=$y+2*$dy; $c[]=$x+$dx*2;$c[]=$y; $c[]=$x;$c[]=$y; $pts=4; break; case MARK_RIGHTTRIANGLE: $c[]=$x-$dx*2;$c[]=$y; $c[]=$x;$c[]=$y+2*$dy; $c[]=$x;$c[]=$y; $c[]=$x-$dx*2;$c[]=$y; $pts=4; break; case MARK_FLASH: $dy *= 2; $c[]=$x+$dx/2; $c[]=$y-$dy; $c[]=$x-$dx+$dx/2; $c[]=$y+$dy*0.7-$dy; $c[]=$x+$dx/2; $c[]=$y+$dy*1.3-$dy; $c[]=$x-$dx+$dx/2; $c[]=$y+2*$dy-$dy; $img->SetLineWeight($weight); $img->SetColor($color); $img->Polygon($c); $img->SetLineWeight(1); $this->AddCSIMPoly($c); break; } if( $pts>0 ) { $this->AddCSIMPoly($c); $img->SetLineWeight($weight); $img->SetColor($fcolor); $img->FilledPolygon($c); $img->SetColor($color); $img->Polygon($c); $img->SetLineWeight(1); } elseif( $this->type==MARK_CIRCLE ) { $img->SetColor($color); $img->Circle($x,$y,$width); $this->AddCSIMCircle($x,$y,$width); } elseif( $this->type==MARK_FILLEDCIRCLE ) { $img->SetColor($fcolor); $img->FilledCircle($x,$y,$width); $img->SetColor($color); $img->Circle($x,$y,$width); $this->AddCSIMCircle($x,$y,$width); } elseif( $this->type==MARK_CROSS ) { // Oversize by a pixel to match the X $img->SetColor($color); $img->SetLineWeight($weight); $img->Line($x,$y+$dy+1,$x,$y-$dy-1); $img->Line($x-$dx-1,$y,$x+$dx+1,$y); $this->AddCSIMCircle($x,$y,$dx); } elseif( $this->type==MARK_X ) { $img->SetColor($color); $img->SetLineWeight($weight); $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy); $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy); $this->AddCSIMCircle($x,$y,$dx+$dy); } elseif( $this->type==MARK_STAR ) { $img->SetColor($color); $img->SetLineWeight($weight); $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy); $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy); // Oversize by a pixel to match the X $img->Line($x,$y+$dy+1,$x,$y-$dy-1); $img->Line($x-$dx-1,$y,$x+$dx+1,$y); $this->AddCSIMCircle($x,$y,$dx+$dy); } // Stroke title $this->title->Align("center","center"); $this->title->Stroke($img,$x,$y); } } // Class ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_polar.php ================================================ numpoints = $n/2; $this->coord = $aData; $this->mark = new PlotMark(); } function SetWeight($aWeight) { $this->iLineWeight = $aWeight; } function SetColor($aColor){ $this->iColor = $aColor; } function SetFillColor($aColor){ $this->iFillColor = $aColor; } function Max() { $m = $this->coord[1]; $i=1; while( $i < $this->numpoints ) { $m = max($m,$this->coord[2*$i+1]); ++$i; } return $m; } // Set href targets for CSIM function SetCSIMTargets($aTargets,$aAlts=null) { $this->csimtargets=$aTargets; $this->csimalts=$aAlts; } // Get all created areas function GetCSIMareas() { return $this->csimareas; } function SetLegend($aLegend,$aCSIM="",$aCSIMAlt="") { $this->legend = $aLegend; $this->legendcsimtarget = $aCSIM; $this->legendcsimalt = $aCSIMAlt; } // Private methods function Legend(&$aGraph) { $color = $this->iColor ; if( $this->legend != "" ) { if( $this->iFillColor!='' ) { $color = $this->iFillColor; $aGraph->legend->Add($this->legend,$color,$this->mark,0, $this->legendcsimtarget,$this->legendcsimalt); } else { $aGraph->legend->Add($this->legend,$color,$this->mark,$this->line_style, $this->legendcsimtarget,$this->legendcsimalt); } } } function Stroke(&$img,$scale) { $i=0; $p=array(); $this->csimareas=''; while($i < $this->numpoints) { list($x1,$y1) = $scale->PTranslate($this->coord[2*$i],$this->coord[2*$i+1]); $p[2*$i] = $x1; $p[2*$i+1] = $y1; if( isset($this->csimtargets[$i]) ) { $this->mark->SetCSIMTarget($this->csimtargets[$i]); $this->mark->SetCSIMAlt($this->csimalts[$i]); $this->mark->SetCSIMAltVal($this->coord[2*$i], $this->coord[2*$i+1]); $this->mark->Stroke($img,$x1,$y1); $this->csimareas .= $this->mark->GetCSIMAreas(); } else $this->mark->Stroke($img,$x1,$y1); ++$i; } if( $this->iFillColor != '' ) { $img->SetColor($this->iFillColor); $img->FilledPolygon($p); } $img->SetLineWeight($this->iLineWeight); $img->SetColor($this->iColor); $img->Polygon($p,$this->iFillColor!=''); } } //-------------------------------------------------------------------------- // class PolarAxis //-------------------------------------------------------------------------- class PolarAxis extends Axis { var $angle_step=15,$angle_color='lightgray',$angle_label_color='black'; var $angle_fontfam=FF_FONT1,$angle_fontstyle=FS_NORMAL,$angle_fontsize=10; var $angle_fontcolor = 'navy'; var $gridminor_color='lightgray',$gridmajor_color='lightgray'; var $show_minor_grid = false, $show_major_grid = true ; var $show_angle_mark=true, $show_angle_grid=true, $show_angle_label=true; var $angle_tick_len=3, $angle_tick_len2=3, $angle_tick_color='black'; var $show_angle_tick=true; var $radius_tick_color='black'; function PolarAxis(&$img,&$aScale) { parent::Axis($img,$aScale); } function ShowAngleDegreeMark($aFlg=true) { $this->show_angle_mark = $aFlg; } function SetAngleStep($aStep) { $this->angle_step=$aStep; } function HideTicks($aFlg=true,$aAngleFlg=true) { parent::HideTicks($aFlg,$aFlg); $this->show_angle_tick = !$aAngleFlg; } function ShowAngleLabel($aFlg=true) { $this->show_angle_label = $aFlg; } function ShowGrid($aMajor=true,$aMinor=false,$aAngle=true) { $this->show_minor_grid = $aMinor; $this->show_major_grid = $aMajor; $this->show_angle_grid = $aAngle ; } function SetAngleFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=10) { $this->angle_fontfam = $aFontFam; $this->angle_fontstyle = $aFontStyle; $this->angle_fontsize = $aFontSize; } function SetColor($aColor,$aRadColor='',$aAngleColor='') { if( $aAngleColor == '' ) $aAngleColor=$aColor; parent::SetColor($aColor,$aRadColor); $this->angle_fontcolor = $aAngleColor; } function SetGridColor($aMajorColor,$aMinorColor='',$aAngleColor='') { if( $aMinorColor == '' ) $aMinorColor = $aMajorColor; if( $aAngleColor == '' ) $aAngleColor = $aMajorColor; $this->gridminor_color = $aMinorColor; $this->gridmajor_color = $aMajorColor; $this->angle_color = $aAngleColor; } function SetTickColors($aRadColor,$aAngleColor='') { $this->radius_tick_color = $aRadColor; $this->angle_tick_color = $aAngleColor; } // Private methods function StrokeGrid($pos) { $x = round($this->img->left_margin + $this->img->plotwidth/2); $this->scale->ticks->Stroke($this->img,$this->scale,$pos); // Stroke the minor arcs $pmin = array(); $p = $this->scale->ticks->ticks_pos; $n = count($p); $i = 0; $this->img->SetColor($this->gridminor_color); while( $i < $n ) { $r = $p[$i]-$x+1; $pmin[]=$r; if( $this->show_minor_grid ) { $this->img->Circle($x,$pos,$r); } $i++; } $limit = max($this->img->plotwidth,$this->img->plotheight)*1.4 ; while( $r < $limit ) { $off = $r; $i=1; $r = $off + round($p[$i]-$x+1); while( $r < $limit && $i < $n ) { $r = $off+$p[$i]-$x; $pmin[]=$r; if( $this->show_minor_grid ) { $this->img->Circle($x,$pos,$r); } $i++; } } // Stroke the major arcs if( $this->show_major_grid ) { // First determine how many minor step on // every major step. We have recorded the minor radius // in pmin and use these values. This is done in order // to avoid rounding errors if we were to recalculate the // different major radius. $pmaj = $this->scale->ticks->maj_ticks_pos; $p = $this->scale->ticks->ticks_pos; if( $this->scale->name == 'lin' ) { $step=round(($pmaj[1] - $pmaj[0])/($p[1] - $p[0])); } else { $step=9; } $n = round(count($pmin)/$step); $i = 0; $this->img->SetColor($this->gridmajor_color); $limit = max($this->img->plotwidth,$this->img->plotheight)*1.4 ; $off = $r; $i=0; $r = $pmin[$i*$step]; while( $r < $limit && $i < $n ) { $r = $pmin[$i*$step]; $this->img->Circle($x,$pos,$r); $i++; } } // Draw angles if( $this->show_angle_grid ) { $this->img->SetColor($this->angle_color); $d = max($this->img->plotheight,$this->img->plotwidth)*1.4 ; $a = 0; $p = $this->scale->ticks->ticks_pos; $start_radius = $p[1]-$x; while( $a < 360 ) { if( $a == 90 || $a == 270 ) { // Make sure there are no rounding problem with // exactly vertical lines $this->img->Line($x+$start_radius*cos($a/180*M_PI)+1, $pos-$start_radius*sin($a/180*M_PI), $x+$start_radius*cos($a/180*M_PI)+1, $pos-$d*sin($a/180*M_PI)); } else { $this->img->Line($x+$start_radius*cos($a/180*M_PI)+1, $pos-$start_radius*sin($a/180*M_PI), $x+$d*cos($a/180*M_PI), $pos-$d*sin($a/180*M_PI)); } $a += $this->angle_step; } } } function StrokeAngleLabels($pos,$type) { if( !$this->show_angle_label ) return; $x0 = round($this->img->left_margin+$this->img->plotwidth/2)+1; $d = max($this->img->plotwidth,$this->img->plotheight)*1.42; $a = $this->angle_step; $t = new Text(); $t->SetColor($this->angle_fontcolor); $t->SetFont($this->angle_fontfam,$this->angle_fontstyle,$this->angle_fontsize); $xright = $this->img->width - $this->img->right_margin; $ytop = $this->img->top_margin; $xleft = $this->img->left_margin; $ybottom = $this->img->height - $this->img->bottom_margin; $ha = 'left'; $va = 'center'; $w = $this->img->plotwidth/2; $h = $this->img->plotheight/2; $xt = $x0; $yt = $pos; $margin=5; $tl = $this->angle_tick_len ; // Outer len $tl2 = $this->angle_tick_len2 ; // Interior len $this->img->SetColor($this->angle_tick_color); $rot90 = $this->img->a == 90 ; if( $type == POLAR_360 ) { $ca1 = atan($h/$w)/M_PI*180; $ca2 = 180-$ca1; $ca3 = $ca1+180; $ca4 = 360-$ca1; $end = 360; while( $a < $end ) { $ca = cos($a/180*M_PI); $sa = sin($a/180*M_PI); $x = $d*$ca; $y = $d*$sa; $xt=1000;$yt=1000; if( $a <= $ca1 || $a >= $ca4 ) { $yt = $pos - $w * $y/$x; $xt = $xright + $margin; if( $rot90 ) { $ha = 'center'; $va = 'top'; } else { $ha = 'left'; $va = 'center'; } $x1=$xright-$tl2; $x2=$xright+$tl; $y1=$y2=$yt; } elseif( $a > $ca1 && $a < $ca2 ) { $xt = $x0 + $h * $x/$y; $yt = $ytop - $margin; if( $rot90 ) { $ha = 'left'; $va = 'center'; } else { $ha = 'center'; $va = 'bottom'; } $y1=$ytop+$tl2;$y2=$ytop-$tl; $x1=$x2=$xt; } elseif( $a >= $ca2 && $a <= $ca3 ) { $yt = $pos + $w * $y/$x; $xt = $xleft - $margin; if( $rot90 ) { $ha = 'center'; $va = 'bottom'; } else { $ha = 'right'; $va = 'center'; } $x1=$xleft+$tl2;$x2=$xleft-$tl; $y1=$y2=$yt; } else { $xt = $x0 - $h * $x/$y; $yt = $ybottom + $margin; if( $rot90 ) { $ha = 'right'; $va = 'center'; } else { $ha = 'center'; $va = 'top'; } $y1=$ybottom-$tl2;$y2=$ybottom+$tl; $x1=$x2=$xt; } if( $a != 0 && $a != 180 ) { $t->Align($ha,$va); if( $this->show_angle_mark ) $a .= ''; $t->Set($a); $t->Stroke($this->img,$xt,$yt); if( $this->show_angle_tick ) $this->img->Line($x1,$y1,$x2,$y2); } $a += $this->angle_step; } } else { // POLAR_HALF $ca1 = atan($h/$w*2)/M_PI*180; $ca2 = 180-$ca1; $end = 180; while( $a < $end ) { $ca = cos($a/180*M_PI); $sa = sin($a/180*M_PI); $x = $d*$ca; $y = $d*$sa; if( $a <= $ca1 ) { $yt = $pos - $w * $y/$x; $xt = $xright + $margin; if( $rot90 ) { $ha = 'center'; $va = 'top'; } else { $ha = 'left'; $va = 'center'; } $x1=$xright-$tl2; $x2=$xright+$tl; $y1=$y2=$yt; } elseif( $a > $ca1 && $a < $ca2 ) { $xt = $x0 + 2*$h * $x/$y; $yt = $ytop - $margin; if( $rot90 ) { $ha = 'left'; $va = 'center'; } else { $ha = 'center'; $va = 'bottom'; } $y1=$ytop+$tl2;$y2=$ytop-$tl; $x1=$x2=$xt; } elseif( $a >= $ca2 ) { $yt = $pos + $w * $y/$x; $xt = $xleft - $margin; if( $rot90 ) { $ha = 'center'; $va = 'bottom'; } else { $ha = 'right'; $va = 'center'; } $x1=$xleft+$tl2;$x2=$xleft-$tl; $y1=$y2=$yt; } $t->Align($ha,$va); if( $this->show_angle_mark ) $a .= ''; $t->Set($a); $t->Stroke($this->img,$xt,$yt); if( $this->show_angle_tick ) $this->img->Line($x1,$y1,$x2,$y2); $a += $this->angle_step; } } } function Stroke($pos) { $this->img->SetLineWeight($this->weight); $this->img->SetColor($this->color); $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); if( !$this->hide_line ) $this->img->FilledRectangle($this->img->left_margin,$pos, $this->img->width-$this->img->right_margin,$pos+$this->weight-1); $y=$pos+$this->img->GetFontHeight()+$this->title_margin+$this->title->margin; if( $this->title_adjust=="high" ) $this->title->Pos($this->img->width-$this->img->right_margin,$y,"right","top"); elseif( $this->title_adjust=="middle" || $this->title_adjust=="center" ) $this->title->Pos(($this->img->width-$this->img->left_margin- $this->img->right_margin)/2+$this->img->left_margin, $y,"center","top"); elseif($this->title_adjust=="low") $this->title->Pos($this->img->left_margin,$y,"left","top"); else { JpGraphError::RaiseL(17002,$this->title_adjust); //('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')'); } if (!$this->hide_labels) { $this->StrokeLabels($pos,false); } $this->img->SetColor($this->radius_tick_color); $this->scale->ticks->Stroke($this->img,$this->scale,$pos); // // Mirror the positions for the left side of the scale // $mid = 2*($this->img->left_margin+$this->img->plotwidth/2); $n = count($this->scale->ticks->ticks_pos); $i=0; while( $i < $n ) { $this->scale->ticks->ticks_pos[$i] = $mid-$this->scale->ticks->ticks_pos[$i] ; ++$i; } $n = count($this->scale->ticks->maj_ticks_pos); $i=0; while( $i < $n ) { $this->scale->ticks->maj_ticks_pos[$i] = $mid-$this->scale->ticks->maj_ticks_pos[$i] ; ++$i; } $n = count($this->scale->ticks->maj_ticklabels_pos); $i=1; while( $i < $n ) { $this->scale->ticks->maj_ticklabels_pos[$i] = $mid-$this->scale->ticks->maj_ticklabels_pos[$i] ; ++$i; } // Draw the left side of the scale $n = count($this->scale->ticks->ticks_pos); $yu = $pos - $this->scale->ticks->direction*$this->scale->ticks->GetMinTickAbsSize(); // Minor ticks if( ! $this->scale->ticks->supress_minor_tickmarks ) { $i=1; while( $i < $n/2 ) { $x = round($this->scale->ticks->ticks_pos[$i]) ; $this->img->Line($x,$pos,$x,$yu); ++$i; } } $n = count($this->scale->ticks->maj_ticks_pos); $yu = $pos - $this->scale->ticks->direction*$this->scale->ticks->GetMajTickAbsSize(); // Major ticks if( ! $this->scale->ticks->supress_tickmarks ) { $i=1; while( $i < $n/2 ) { $x = round($this->scale->ticks->maj_ticks_pos[$i]) ; $this->img->Line($x,$pos,$x,$yu); ++$i; } } if (!$this->hide_labels) { $this->StrokeLabels($pos,false); } $this->title->Stroke($this->img); } } class PolarScale extends LinearScale { var $graph; function PolarScale($aMax=0,&$graph) { parent::LinearScale(0,$aMax,'x'); $this->graph = &$graph; } function _Translate($v) { return parent::Translate($v); } function PTranslate($aAngle,$aRad) { $m = $this->scale[1]; $w = $this->graph->img->plotwidth/2; $aRad = $aRad/$m*$w; $x = cos( $aAngle/180 * M_PI ) * $aRad; $y = sin( $aAngle/180 * M_PI ) * $aRad; $x += $this->_Translate(0); if( $this->graph->iType == POLAR_360 ) { $y = ($this->graph->img->top_margin + $this->graph->img->plotheight/2) - $y; } else { $y = ($this->graph->img->top_margin + $this->graph->img->plotheight) - $y; } return array($x,$y); } } class PolarLogScale extends LogScale { var $graph; function PolarLogScale($aMax=1,&$graph) { parent::LogScale(0,$aMax,'x'); $this->graph = &$graph; $this->ticks->SetLabelLogType(LOGLABELS_MAGNITUDE); } function PTranslate($aAngle,$aRad) { if( $aRad == 0 ) $aRad = 1; $aRad = log10($aRad); $m = $this->scale[1]; $w = $this->graph->img->plotwidth/2; $aRad = $aRad/$m*$w; $x = cos( $aAngle/180 * M_PI ) * $aRad; $y = sin( $aAngle/180 * M_PI ) * $aRad; $x += $w+$this->graph->img->left_margin;//$this->_Translate(0); if( $this->graph->iType == POLAR_360 ) { $y = ($this->graph->img->top_margin + $this->graph->img->plotheight/2) - $y; } else { $y = ($this->graph->img->top_margin + $this->graph->img->plotheight) - $y; } return array($x,$y); } } class PolarGraph extends Graph { var $scale; var $iType=POLAR_360; var $axis; function PolarGraph($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) { parent::Graph($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline) ; $this->SetDensity(TICKD_DENSE); $this->SetBox(); $this->SetMarginColor('white'); } function SetDensity($aDense) { $this->SetTickDensity(TICKD_NORMAL,$aDense); } function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) { $adj = ($this->img->height - $this->img->width)/2; $this->SetAngle(90); $this->img->SetMargin($lm-$adj,$rm-$adj,$tm+$adj,$bm+$adj); $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2)); $this->axis->SetLabelAlign('right','center'); //JpGraphError::Raise('Set90AndMargin() is not supported for polar graphs.'); } function SetScale($aScale,$rmax=0) { if( $aScale == 'lin' ) $this->scale = new PolarScale($rmax,$this); elseif( $aScale == 'log' ) { $this->scale = new PolarLogScale($rmax,$this); } else { JpGraphError::RaiseL(17004);//('Unknown scale type for polar graph. Must be "lin" or "log"'); } $this->axis = new PolarAxis($this->img,$this->scale); $this->SetMargin(40,40,50,40); } function SetType($aType) { $this->iType = $aType; } function SetPlotSize($w,$h) { $this->SetMargin(($this->img->width-$w)/2,($this->img->width-$w)/2, ($this->img->height-$h)/2,($this->img->height-$h)/2); } // Private methods function GetPlotsMax() { $n = count($this->plots); $m = $this->plots[0]->Max(); $i=1; while($i < $n) { $m = max($this->plots[$i]->Max(),$m); ++$i; } return $m; } function Stroke($aStrokeFileName="") { // Start by adjusting the margin so that potential titles will fit. $this->AdjustMarginsForTitles(); // If the filename is the predefined value = '_csim_special_' // we assume that the call to stroke only needs to do enough // to correctly generate the CSIM maps. // We use this variable to skip things we don't strictly need // to do to generate the image map to improve performance // a best we can. Therefor you will see a lot of tests !$_csim in the // code below. $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); // We need to know if we have stroked the plot in the // GetCSIMareas. Otherwise the CSIM hasn't been generated // and in the case of GetCSIM called before stroke to generate // CSIM without storing an image to disk GetCSIM must call Stroke. $this->iHasStroked = true; //Check if we should autoscale axis if( !$this->scale->IsSpecified() && count($this->plots)>0 ) { $max = $this->GetPlotsMax(); $t1 = $this->img->plotwidth; $this->img->plotwidth /= 2; $t2 = $this->img->left_margin; $this->img->left_margin += $this->img->plotwidth+1; $this->scale->AutoScale($this->img,0,$max, $this->img->plotwidth/$this->xtick_factor/2); $this->img->plotwidth = $t1; $this->img->left_margin = $t2; } else { // The tick calculation will use the user suplied min/max values to determine // the ticks. If auto_ticks is false the exact user specifed min and max // values will be used for the scale. // If auto_ticks is true then the scale might be slightly adjusted // so that the min and max values falls on an even major step. //$min = 0; $max = $this->scale->scale[1]; $t1 = $this->img->plotwidth; $this->img->plotwidth /= 2; $t2 = $this->img->left_margin; $this->img->left_margin += $this->img->plotwidth+1; $this->scale->AutoScale($this->img,0,$max, $this->img->plotwidth/$this->xtick_factor/2); $this->img->plotwidth = $t1; $this->img->left_margin = $t2; } if( $this->iType == POLAR_180 ) $pos = $this->img->height - $this->img->bottom_margin; else $pos = $this->img->plotheight/2 + $this->img->top_margin; if( !$_csim ) { $this->StrokePlotArea(); } $this->iDoClipping = true; if( $this->iDoClipping ) { $oldimage = $this->img->CloneCanvasH(); } if( !$_csim ) { $this->axis->StrokeGrid($pos); } // Stroke all plots for Y1 axis for($i=0; $i < count($this->plots); ++$i) { $this->plots[$i]->Stroke($this->img,$this->scale); } if( $this->iDoClipping ) { // Clipping only supports graphs at 0 and 90 degrees if( $this->img->a == 0 ) { $this->img->CopyCanvasH($oldimage,$this->img->img, $this->img->left_margin,$this->img->top_margin, $this->img->left_margin,$this->img->top_margin, $this->img->plotwidth+1,$this->img->plotheight+1); } elseif( $this->img->a == 90 ) { $adj = round(($this->img->height - $this->img->width)/2); $this->img->CopyCanvasH($oldimage,$this->img->img, $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, $this->img->plotheight,$this->img->plotwidth); } $this->img->Destroy(); $this->img->SetCanvasH($oldimage); } if( !$_csim ) { $this->axis->Stroke($pos); $this->axis->StrokeAngleLabels($pos,$this->iType); } if( !$_csim ) { $this->StrokePlotBox(); $this->footer->Stroke($this->img); // The titles and legends never gets rotated so make sure // that the angle is 0 before stroking them $aa = $this->img->SetAngle(0); $this->StrokeTitles(); } for($i=0; $i < count($this->plots) ; ++$i ) { $this->plots[$i]->Legend($this); } $this->legend->Stroke($this->img); if( !$_csim ) { $this->StrokeTexts(); $this->img->SetAngle($aa); // Draw an outline around the image map if(_JPG_DEBUG) $this->DisplayClientSideaImageMapAreas(); // Adjust the appearance of the image $this->AdjustSaturationBrightnessContrast(); // If the filename is given as the special "__handle" // then the image handler is returned and the image is NOT // streamed back if( $aStrokeFileName == _IMG_HANDLER ) { return $this->img->img; } else { // Finally stream the generated picture $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, $aStrokeFileName); } } } } ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_radar.php ================================================ GetMinVal(); $limit = $aScale->GetMaxVal(); $nextMajor = 10*$start; $step = $nextMajor / 10.0; $count=1; $ticklen_maj=5; $dx_maj=round(sin($aAxisAngle)*$ticklen_maj); $dy_maj=round(cos($aAxisAngle)*$ticklen_maj); $ticklen_min=3; $dx_min=round(sin($aAxisAngle)*$ticklen_min); $dy_min=round(cos($aAxisAngle)*$ticklen_min); $aMajPos=array(); $aMajLabel=array(); if( $this->supress_first ) $aMajLabel[]=""; else $aMajLabel[]=$start; $yr=$aScale->RelTranslate($start); $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0]; $yt=$aPos-round($yr*sin($aAxisAngle)); $aMajPos[]=$xt+2*$dx_maj; $aMajPos[]=$yt-$aImg->GetFontheight()/2; $grid[]=$xt; $grid[]=$yt; $aImg->SetLineWeight($this->weight); for($y=$start; $y<=$limit; $y+=$step,++$count ) { $yr=$aScale->RelTranslate($y); $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0]; $yt=$aPos-round($yr*sin($aAxisAngle)); if( $count % 10 == 0 ) { $grid[]=$xt; $grid[]=$yt; $aMajPos[]=$xt+2*$dx_maj; $aMajPos[]=$yt-$aImg->GetFontheight()/2; if( !$this->supress_tickmarks ) { if( $this->majcolor!="" ) $aImg->PushColor($this->majcolor); $aImg->Line($xt+$dx_maj,$yt+$dy_maj,$xt-$dx_maj,$yt-$dy_maj); if( $this->majcolor!="" ) $aImg->PopColor(); } if( $this->label_formfunc != "" ) { $f=$this->label_formfunc; $l = call_user_func($f,$nextMajor); } else $l = $nextMajor; $aMajLabel[]=$l; $nextMajor *= 10; $step *= 10; $count=1; } else if( !$this->supress_minor_tickmarks ) { if( $this->mincolor!="" ) $aImg->PushColor($this->mincolor); $aImg->Line($xt+$dx_min,$yt+$dy_min,$xt-$dx_min,$yt-$dy_min); if( $this->mincolor!="" ) $aImg->PopColor(); } } } } class RadarLinearTicks extends LinearTicks { //--------------- // CONSTRUCTOR function RadarLinearTicks() { // Empty } //--------------- // PUBLIC METHODS // TODO: Add argument grid function Stroke(&$aImg,&$grid,$aPos,$aAxisAngle,&$aScale,&$aMajPos,&$aMajLabel) { // Prepare to draw linear ticks $maj_step_abs = abs($aScale->scale_factor*$this->major_step); $min_step_abs = abs($aScale->scale_factor*$this->minor_step); $nbrmaj = floor(($aScale->world_abs_size)/$maj_step_abs); $nbrmin = floor(($aScale->world_abs_size)/$min_step_abs); $skip = round($nbrmin/$nbrmaj); // Don't draw minor ontop of major // Draw major ticks $ticklen2=$this->major_abs_size; $dx=round(sin($aAxisAngle)*$ticklen2); $dy=round(cos($aAxisAngle)*$ticklen2); $label=$aScale->scale[0]+$this->major_step; $aImg->SetLineWeight($this->weight); for($i=1; $i<=$nbrmaj; ++$i) { $xt=round($i*$maj_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0]; $yt=$aPos-round($i*$maj_step_abs*sin($aAxisAngle)); if( $this->label_formfunc != "" ) { $f=$this->label_formfunc; $l = call_user_func($f,$label); } else $l = $label; $aMajLabel[]=$l; $label += $this->major_step; $grid[]=$xt; $grid[]=$yt; $aMajPos[($i-1)*2]=$xt+2*$dx; $aMajPos[($i-1)*2+1]=$yt-$aImg->GetFontheight()/2; if( !$this->supress_tickmarks ) { if( $this->majcolor!="" ) $aImg->PushColor($this->majcolor); $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy); if( $this->majcolor!="" ) $aImg->PopColor(); } } // Draw minor ticks $ticklen2=$this->minor_abs_size; $dx=round(sin($aAxisAngle)*$ticklen2); $dy=round(cos($aAxisAngle)*$ticklen2); if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { if( $this->mincolor!="" ) $aImg->PushColor($this->mincolor); for($i=1; $i<=$nbrmin; ++$i) { if( ($i % $skip) == 0 ) continue; $xt=round($i*$min_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0]; $yt=$aPos-round($i*$min_step_abs*sin($aAxisAngle)); $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy); } if( $this->mincolor!="" ) $aImg->PopColor(); } } } //=================================================== // CLASS RadarAxis // Description: Implements axis for the radar graph //=================================================== class RadarAxis extends Axis { var $title_color="navy"; var $title=null; //--------------- // CONSTRUCTOR function RadarAxis(&$img,&$aScale,$color=array(0,0,0)) { parent::Axis($img,$aScale,$color); $this->len=$img->plotheight; $this->title = new Text(); $this->title->SetFont(FF_FONT1,FS_BOLD); $this->color = array(0,0,0); } //--------------- // PUBLIC METHODS function SetTickLabels($l) { $this->ticks_label = $l; } // Stroke the axis // $pos = Vertical position of axis // $aAxisAngle = Axis angle // $grid = Returns an array with positions used to draw the grid // $lf = Label flag, TRUE if the axis should have labels function Stroke($pos,$aAxisAngle,&$grid,$title,$lf) { $this->img->SetColor($this->color); // Determine end points for the axis $x=round($this->scale->world_abs_size*cos($aAxisAngle)+$this->scale->scale_abs[0]); $y=round($pos-$this->scale->world_abs_size*sin($aAxisAngle)); // Draw axis $this->img->SetColor($this->color); $this->img->SetLineWeight($this->weight); if( !$this->hide ) $this->img->Line($this->scale->scale_abs[0],$pos,$x,$y); $this->scale->ticks->Stroke($this->img,$grid,$pos,$aAxisAngle,$this->scale,$majpos,$majlabel); // Draw labels if( $lf && !$this->hide ) { $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); $this->img->SetTextAlign("left","top"); $this->img->SetColor($this->label_color); // majpos contains (x,y) coordinates for labels if( ! $this->hide_labels ) { $n = floor(count($majpos)/2); for($i=0; $i < $n; ++$i) { if( $this->ticks_label != null && isset($this->ticks_label[$i]) ) $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$this->ticks_label[$i]); else $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$majlabel[$i]); } } } $this->_StrokeAxisTitle($pos,$aAxisAngle,$title); } //--------------- // PRIVATE METHODS function _StrokeAxisTitle($pos,$aAxisAngle,$title) { $this->title->Set($title); $marg=6+$this->title->margin; $xt=round(($this->scale->world_abs_size+$marg)*cos($aAxisAngle)+$this->scale->scale_abs[0]); $yt=round($pos-($this->scale->world_abs_size+$marg)*sin($aAxisAngle)); // Position the axis title. // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text // that intersects with the extension of the corresponding axis. The code looks a little // bit messy but this is really the only way of having a reasonable position of the // axis titles. if( $this->title->iWordwrap > 0 ) { $title = wordwrap($title,$this->title->iWordwrap,"\n"); } $h=$this->img->GetTextHeight($title)*1.2; $w=$this->img->GetTextWidth($title)*1.2; while( $aAxisAngle > 2*M_PI ) $aAxisAngle -= 2*M_PI; if( $aAxisAngle>=7*M_PI/4 || $aAxisAngle <= M_PI/4 ) $dx=0; if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dx=($aAxisAngle-M_PI/4)*2/M_PI; if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dx=1; if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dx=(1-($aAxisAngle-M_PI*5/4)*2/M_PI); if( $aAxisAngle>=7*M_PI/4 ) $dy=(($aAxisAngle-M_PI)-3*M_PI/4)*2/M_PI; if( $aAxisAngle<=M_PI/4 ) $dy=(1-$aAxisAngle*2/M_PI); if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dy=1; if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dy=(1-($aAxisAngle-3*M_PI/4)*2/M_PI); if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dy=0; if( !$this->hide ) { $this->title->Stroke($this->img,$xt-$dx*$w,$yt-$dy*$h,$title); } } } // Class //=================================================== // CLASS RadarGrid // Description: Draws grid for the radar graph //=================================================== class RadarGrid extends Grid { //------------ // CONSTRUCTOR function RadarGrid() { } //---------------- // PRIVATE METHODS function Stroke(&$img,&$grid) { if( !$this->show ) return; $nbrticks = count($grid[0])/2; $nbrpnts = count($grid); $img->SetColor($this->grid_color); $img->SetLineWeight($this->weight); for($i=0; $i<$nbrticks; ++$i) { for($j=0; $j<$nbrpnts; ++$j) { $pnts[$j*2]=$grid[$j][$i*2]; $pnts[$j*2+1]=$grid[$j][$i*2+1]; } for($k=0; $k<$nbrpnts; ++$k ){ $l=($k+1)%$nbrpnts; if( $this->type == "solid" ) $img->Line($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1]); elseif( $this->type == "dotted" ) $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],1,6); elseif( $this->type == "dashed" ) $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],2,4); elseif( $this->type == "longdashed" ) $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],8,6); } $pnts=array(); } } } // Class //=================================================== // CLASS RadarPlot // Description: Plot a radarplot //=================================================== class RadarPlot { var $data=array(); var $fill=false, $fill_color=array(200,170,180); var $color=array(0,0,0); var $legend=""; var $weight=1; var $linestyle='solid'; var $mark=null; //--------------- // CONSTRUCTOR function RadarPlot($data) { $this->data = $data; $this->mark = new PlotMark(); } //--------------- // PUBLIC METHODS function Min() { return Min($this->data); } function Max() { return Max($this->data); } function SetLegend($legend) { $this->legend=$legend; } function SetLineStyle($aStyle) { $this->linestyle=$aStyle; } function SetLineWeight($w) { $this->weight=$w; } function SetFillColor($aColor) { $this->fill_color = $aColor; $this->fill = true; } function SetFill($f=true) { $this->fill = $f; } function SetColor($aColor,$aFillColor=false) { $this->color = $aColor; if( $aFillColor ) { $this->SetFillColor($aFillColor); $this->fill = true; } } function GetCSIMareas() { JpGraphError::RaiseL(18001); //("Client side image maps not supported for RadarPlots."); } function Stroke(&$img, $pos, &$scale, $startangle) { $nbrpnts = count($this->data); $astep=2*M_PI/$nbrpnts; $a=$startangle; // Rotate each point to the correct axis-angle // TODO: Update for LogScale for($i=0; $i<$nbrpnts; ++$i) { //$c=$this->data[$i]; $cs=$scale->RelTranslate($this->data[$i]); $x=round($cs*cos($a)+$scale->scale_abs[0]); $y=round($pos-$cs*sin($a)); /* $c=log10($c); $x=round(($c-$scale->scale[0])*$scale->scale_factor*cos($a)+$scale->scale_abs[0]); $y=round($pos-($c-$scale->scale[0])*$scale->scale_factor*sin($a)); */ $pnts[$i*2]=$x; $pnts[$i*2+1]=$y; $a += $astep; } if( $this->fill ) { $img->SetColor($this->fill_color); $img->FilledPolygon($pnts); } $img->SetLineWeight($this->weight); $img->SetColor($this->color); $img->SetLineStyle($this->linestyle); $pnts[]=$pnts[0]; $pnts[]=$pnts[1]; $img->Polygon($pnts); $img->SetLineStyle('solid'); // Reset line style to default // Add plotmarks on top if( $this->mark->show ) { for($i=0; $i < $nbrpnts; ++$i) { $this->mark->Stroke($img,$pnts[$i*2],$pnts[$i*2+1]); } } } //--------------- // PRIVATE METHODS function GetCount() { return count($this->data); } function Legend(&$graph) { if( $this->legend=="" ) return; if( $this->fill ) $graph->legend->Add($this->legend,$this->fill_color,$this->mark); else $graph->legend->Add($this->legend,$this->color,$this->mark); } } // Class //=================================================== // CLASS RadarGraph // Description: Main container for a radar graph //=================================================== class RadarGraph extends Graph { var $posx; var $posy; var $len; var $plots=null, $axis_title=null; var $grid,$axis=null; //--------------- // CONSTRUCTOR function RadarGraph($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) { $this->Graph($width,$height,$cachedName,$timeout,$inline); $this->posx=$width/2; $this->posy=$height/2; $this->len=min($width,$height)*0.35; $this->SetColor(array(255,255,255)); $this->SetTickDensity(TICKD_NORMAL); $this->SetScale("lin"); $this->SetGridDepth(DEPTH_FRONT); } //--------------- // PUBLIC METHODS function SupressTickMarks($f=true) { if( ERR_DEPRECATED ) JpGraphError::RaiseL(18002); //('RadarGraph::SupressTickMarks() is deprecated. Use HideTickMarks() instead.'); $this->axis->scale->ticks->SupressTickMarks($f); } function HideTickMarks($aFlag=true) { $this->axis->scale->ticks->SupressTickMarks($aFlag); } function ShowMinorTickmarks($aFlag=true) { $this->yscale->ticks->SupressMinorTickMarks(!$aFlag); } function SetScale($axtype,$ymin=1,$ymax=1) { if( $axtype != "lin" && $axtype != "log" ) { JpGraphError::RaiseL(18003,$axtype); //("Illegal scale for radarplot ($axtype). Must be \"lin\" or \"log\""); } if( $axtype=="lin" ) { $this->yscale = & new LinearScale($ymin,$ymax); $this->yscale->ticks = & new RadarLinearTicks(); $this->yscale->ticks->SupressMinorTickMarks(); } elseif( $axtype=="log" ) { $this->yscale = & new LogScale($ymin,$ymax); $this->yscale->ticks = & new RadarLogTicks(); } $this->axis = & new RadarAxis($this->img,$this->yscale); $this->grid = & new RadarGrid(); } function SetSize($aSize) { if( $aSize < 0.1 || $aSize>1 ) JpGraphError::RaiseL(18004,$aSize); //("Radar Plot size must be between 0.1 and 1. (Your value=$s)"); $this->len=min($this->img->width,$this->img->height)*$aSize/2; } function SetPlotSize($aSize) { $this->SetSize($aSize); } function SetTickDensity($densy=TICKD_NORMAL) { $this->ytick_factor=25; switch( $densy ) { case TICKD_DENSE: $this->ytick_factor=12; break; case TICKD_NORMAL: $this->ytick_factor=25; break; case TICKD_SPARSE: $this->ytick_factor=40; break; case TICKD_VERYSPARSE: $this->ytick_factor=70; break; default: JpGraphError::RaiseL(18005,$densy); //("RadarPlot Unsupported Tick density: $densy"); } } function SetPos($px,$py=0.5) { $this->SetCenter($px,$py); } function SetCenter($px,$py=0.5) { assert($px > 0 && $py > 0 ); $this->posx=$this->img->width*$px; $this->posy=$this->img->height*$py; } function SetColor($c) { $this->SetMarginColor($c); } function SetTitles($title) { $this->axis_title = $title; } function Add(&$splot) { $this->plots[]=$splot; } function GetPlotsYMinMax() { $min=$this->plots[0]->Min(); $max=$this->plots[0]->Max(); foreach( $this->plots as $p ) { $max=max($max,$p->Max()); $min=min($min,$p->Min()); } if( $min < 0 ) JpGraphError::RaiseL(18006,$min); //("Minimum data $min (Radar plots should only be used when all data points > 0)"); return array($min,$max); } // Stroke the Radar graph function Stroke($aStrokeFileName="") { $n = count($this->plots); // Set Y-scale if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) { list($min,$max) = $this->GetPlotsYMinMax(); $this->yscale->AutoScale($this->img,0,$max,$this->len/$this->ytick_factor); } // Set start position end length of scale (in absolute pixels) $this->yscale->SetConstants($this->posx,$this->len); // We need as many axis as there are data points $nbrpnts=$this->plots[0]->GetCount(); // If we have no titles just number the axis 1,2,3,... if( $this->axis_title==null ) { for($i=0; $i < $nbrpnts; ++$i ) $this->axis_title[$i] = $i+1; } elseif(count($this->axis_title)<$nbrpnts) JpGraphError::RaiseL(18007); //("Number of titles does not match number of points in plot."); for($i=0; $i < $n; ++$i ) if( $nbrpnts != $this->plots[$i]->GetCount() ) JpGraphError::RaiseL(18008); //("Each radar plot must have the same number of data points."); if( $this->background_image != "" ) { $this->StrokeFrameBackground(); } else { $this->StrokeFrame(); } $astep=2*M_PI/$nbrpnts; // Prepare legends for($i=0; $i < $n; ++$i) $this->plots[$i]->Legend($this); $this->legend->Stroke($this->img); $this->footer->Stroke($this->img); if( $this->grid_depth == DEPTH_BACK ) { // Draw axis and grid for( $i=0,$a=M_PI/2; $i < $nbrpnts; ++$i, $a += $astep ) { $this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0); } } // Plot points $a=M_PI/2; for($i=0; $i < $n; ++$i ) $this->plots[$i]->Stroke($this->img, $this->posy, $this->yscale, $a); if( $this->grid_depth != DEPTH_BACK ) { // Draw axis and grid for( $i=0,$a=M_PI/2; $i < $nbrpnts; ++$i, $a += $astep ) { $this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0); } } $this->grid->Stroke($this->img,$grid); $this->StrokeTitles(); // Stroke texts if( $this->texts != null ) { foreach( $this->texts as $t) $t->Stroke($this->img); } // Should we do any final image transformation if( $this->iImgTrans ) { if( !class_exists('ImgTrans') ) { require_once('jpgraph_imgtrans.php'); } $tform = new ImgTrans($this->img->img); $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, $this->iImgTransDirection,$this->iImgTransHighQ, $this->iImgTransMinSize,$this->iImgTransFillColor, $this->iImgTransBorder); } // If the filename is given as the special "__handle" // then the image handler is returned and the image is NOT // streamed back if( $aStrokeFileName == _IMG_HANDLER ) { return $this->img->img; } else { // Finally stream the generated picture $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, $aStrokeFileName); } } } // Class /* EOF */ ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_regstat.php ================================================ y2 = array(); $this->xdata = $xdata; $this->ydata = $ydata; $n = count($ydata); $this->n = $n; if( $this->n !== count($xdata) ) { JpGraphError::RaiseL(19001); //('Spline: Number of X and Y coordinates must be the same'); } // Natural spline 2:derivate == 0 at endpoints $this->y2[0] = 0.0; $this->y2[$n-1] = 0.0; $delta[0] = 0.0; // Calculate 2:nd derivate for($i=1; $i < $n-1; ++$i) { $d = ($xdata[$i+1]-$xdata[$i-1]); if( $d == 0 ) { JpGraphError::RaiseL(19002); //('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.'); } $s = ($xdata[$i]-$xdata[$i-1])/$d; $p = $s*$this->y2[$i-1]+2.0; $this->y2[$i] = ($s-1.0)/$p; $delta[$i] = ($ydata[$i+1]-$ydata[$i])/($xdata[$i+1]-$xdata[$i]) - ($ydata[$i]-$ydata[$i-1])/($xdata[$i]-$xdata[$i-1]); $delta[$i] = (6.0*$delta[$i]/($xdata[$i+1]-$xdata[$i-1])-$s*$delta[$i-1])/$p; } // Backward substitution for( $j=$n-2; $j >= 0; --$j ) { $this->y2[$j] = $this->y2[$j]*$this->y2[$j+1] + $delta[$j]; } } // Return the two new data vectors function Get($num=50) { $n = $this->n ; $step = ($this->xdata[$n-1]-$this->xdata[0]) / ($num-1); $xnew=array(); $ynew=array(); $xnew[0] = $this->xdata[0]; $ynew[0] = $this->ydata[0]; for( $j=1; $j < $num; ++$j ) { $xnew[$j] = $xnew[0]+$j*$step; $ynew[$j] = $this->Interpolate($xnew[$j]); } return array($xnew,$ynew); } // Return a single interpolated Y-value from an x value function Interpolate($xpoint) { $max = $this->n-1; $min = 0; // Binary search to find interval while( $max-$min > 1 ) { $k = ($max+$min) / 2; if( $this->xdata[$k] > $xpoint ) $max=$k; else $min=$k; } // Each interval is interpolated by a 3:degree polynom function $h = $this->xdata[$max]-$this->xdata[$min]; if( $h == 0 ) { JpGraphError::RaiseL(19002); //('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.'); } $a = ($this->xdata[$max]-$xpoint)/$h; $b = ($xpoint-$this->xdata[$min])/$h; return $a*$this->ydata[$min]+$b*$this->ydata[$max]+ (($a*$a*$a-$a)*$this->y2[$min]+($b*$b*$b-$b)*$this->y2[$max])*($h*$h)/6.0; } } //------------------------------------------------------------------------ // CLASS Bezier // Create a new data array from a number of control points //------------------------------------------------------------------------ class Bezier { /** * @author Thomas Despoix, openXtrem company * @license released under QPL * @abstract Bezier interoplated point generation, * computed from control points data sets, based on Paul Bourke algorithm : * http://astronomy.swin.edu.au/~pbourke/curves/bezier/ */ var $datax = array(); var $datay = array(); var $n=0; function Bezier($datax, $datay, $attraction_factor = 1) { // Adding control point multiple time will raise their attraction power over the curve $this->n = count($datax); if( $this->n !== count($datay) ) { JpGraphError::RaiseL(19003); //('Bezier: Number of X and Y coordinates must be the same'); } $idx=0; foreach($datax as $datumx) { for ($i = 0; $i < $attraction_factor; $i++) { $this->datax[$idx++] = $datumx; } } $idx=0; foreach($datay as $datumy) { for ($i = 0; $i < $attraction_factor; $i++) { $this->datay[$idx++] = $datumy; } } } function Get($steps) { $datax = array(); $datay = array(); for ($i = 0; $i < $steps; $i++) { list($datumx, $datumy) = $this->GetPoint((double) $i / (double) $steps); $datax[] = $datumx; $datay[] = $datumy; } $datax[] = end($this->datax); $datay[] = end($this->datay); return array($datax, $datay); } function GetPoint($mu) { $n = $this->n - 1; $k = 0; $kn = 0; $nn = 0; $nkn = 0; $blend = 0.0; $newx = 0.0; $newy = 0.0; $muk = 1.0; $munk = (double) pow(1-$mu,(double) $n); for ($k = 0; $k <= $n; $k++) { $nn = $n; $kn = $k; $nkn = $n - $k; $blend = $muk * $munk; $muk *= $mu; $munk /= (1-$mu); while ($nn >= 1) { $blend *= $nn; $nn--; if ($kn > 1) { $blend /= (double) $kn; $kn--; } if ($nkn > 1) { $blend /= (double) $nkn; $nkn--; } } $newx += $this->datax[$k] * $blend; $newy += $this->datay[$k] * $blend; } return array($newx, $newy); } } // EOF ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_scatter.php ================================================ iSize = $aSize; $this->iArrowSize = $aArrowSize; } function SetColor($aColor) { $this->iColor = $aColor; } function Stroke(&$aImg,$x,$y,$a) { // First rotate the center coordinates list($x,$y) = $aImg->Rotate($x,$y); $old_origin = $aImg->SetCenter($x,$y); $old_a = $aImg->a; $aImg->SetAngle(-$a+$old_a); $dx = round($this->iSize/2); $c = array($x-$dx,$y,$x+$dx,$y); $x += $dx; list($dx,$dy) = $this->isizespec[$this->iArrowSize]; $ca = array($x,$y,$x-$dx,$y-$dy,$x-$dx,$y+$dy,$x,$y); $aImg->SetColor($this->iColor); $aImg->Polygon($c); $aImg->FilledPolygon($ca); $aImg->SetCenter($old_origin[0],$old_origin[1]); $aImg->SetAngle($old_a); } } //=================================================== // CLASS FieldPlot // Description: Render a field plot //=================================================== class FieldPlot extends Plot { var $iAngles; var $iCallback=''; function FieldPlot($datay,$datax,$angles) { if( (count($datax) != count($datay)) ) JpGraphError::RaiseL(20001);//("Fieldplots must have equal number of X and Y points."); if( (count($datax) != count($angles)) ) JpGraphError::RaiseL(20002);//("Fieldplots must have an angle specified for each X and Y points."); $this->iAngles = $angles; $this->Plot($datay,$datax); $this->value->SetAlign('center','center'); $this->value->SetMargin(15); $this->arrow = new FieldArrow(); } function SetCallback($aFunc) { $this->iCallback = $aFunc; } function Stroke(&$img,&$xscale,&$yscale) { // Remeber base color and size $bc = $this->arrow->iColor; $bs = $this->arrow->iSize; $bas = $this->arrow->iArrowSize; for( $i=0; $i<$this->numpoints; ++$i ) { // Skip null values if( $this->coords[0][$i]==="" ) continue; $f = $this->iCallback; if( $f != "" ) { list($cc,$cs,$cas) = call_user_func($f,$this->coords[1][$i],$this->coords[0][$i],$this->iAngles[$i]); // Fall back on global data if the callback isn't set if( $cc == "" ) $cc = $bc; if( $cs == "" ) $cs = $bs; if( $cas == "" ) $cas = $bas; //echo "f=$f, cc=$cc, cs=$cs, cas=$cas
"; $this->arrow->SetColor($cc); $this->arrow->SetSize($cs,$cas); } $xt = $xscale->Translate($this->coords[1][$i]); $yt = $yscale->Translate($this->coords[0][$i]); $this->arrow->Stroke($img,$xt,$yt,$this->iAngles[$i]); $this->value->Stroke($img,$this->coords[0][$i],$xt,$yt); } } // Framework function function Legend(&$aGraph) { if( $this->legend != "" ) { $aGraph->legend->Add($this->legend,$this->mark->fill_color,$this->mark,0, $this->legendcsimtarget,$this->legendcsimalt); } } } //=================================================== // CLASS ScatterPlot // Description: Render X and Y plots //=================================================== class ScatterPlot extends Plot { var $impuls = false; var $linkpoints = false, $linkpointweight=1, $linkpointcolor="black"; //--------------- // CONSTRUCTOR function ScatterPlot($datay,$datax=false) { if( (count($datax) != count($datay)) && is_array($datax)) JpGraphError::RaiseL(20003);//("Scatterplot must have equal number of X and Y points."); $this->Plot($datay,$datax); $this->mark = new PlotMark(); $this->mark->SetType(MARK_SQUARE); $this->mark->SetColor($this->color); $this->value->SetAlign('center','center'); $this->value->SetMargin(0); } //--------------- // PUBLIC METHODS function SetImpuls($f=true) { $this->impuls = $f; } // Combine the scatter plot points with a line function SetLinkPoints($aFlag=true,$aColor="black",$aWeight=1) { $this->linkpoints=$aFlag; $this->linkpointcolor=$aColor; $this->linkpointweight=$aWeight; } function Stroke(&$img,&$xscale,&$yscale) { $ymin=$yscale->scale_abs[0]; if( $yscale->scale[0] < 0 ) $yzero=$yscale->Translate(0); else $yzero=$yscale->scale_abs[0]; $this->csimareas = ''; for( $i=0; $i<$this->numpoints; ++$i ) { // Skip null values if( $this->coords[0][$i]==="" || $this->coords[0][$i]==='-' || $this->coords[0][$i]==='x') continue; if( isset($this->coords[1]) ) $xt = $xscale->Translate($this->coords[1][$i]); else $xt = $xscale->Translate($i); $yt = $yscale->Translate($this->coords[0][$i]); if( $this->linkpoints && isset($yt_old) ) { $img->SetColor($this->linkpointcolor); $img->SetLineWeight($this->linkpointweight); $img->Line($xt_old,$yt_old,$xt,$yt); } if( $this->impuls ) { $img->SetColor($this->color); $img->SetLineWeight($this->weight); $img->Line($xt,$yzero,$xt,$yt); } if( !empty($this->csimtargets[$i]) ) { $this->mark->SetCSIMTarget($this->csimtargets[$i]); $this->mark->SetCSIMAlt($this->csimalts[$i]); } if( isset($this->coords[1]) ) { $this->mark->SetCSIMAltVal($this->coords[0][$i],$this->coords[1][$i]); } else { $this->mark->SetCSIMAltVal($this->coords[0][$i],$i); } $this->mark->Stroke($img,$xt,$yt); $this->csimareas .= $this->mark->GetCSIMAreas(); $this->value->Stroke($img,$this->coords[0][$i],$xt,$yt); $xt_old = $xt; $yt_old = $yt; } } // Framework function function Legend(&$aGraph) { if( $this->legend != "" ) { $aGraph->legend->Add($this->legend,$this->mark->fill_color,$this->mark,0, $this->legendcsimtarget,$this->legendcsimalt); } } } // Class /* EOF */ ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_stock.php ================================================ iTupleSize ) { JpGraphError::RaiseL(21001,$this->iTupleSize);//('Data values for Stock charts must contain an even multiple of '.$this->iTupleSize.' data points.'); } $this->Plot($datay,$datax); $this->numpoints /= $this->iTupleSize; } //--------------- // PUBLIC METHODS function SetColor($aColor,$aColor1='white',$aColor2='darkred',$aColor3='darkred') { $this->color = $aColor; $this->iStockColor1 = $aColor1; $this->iStockColor2 = $aColor2; $this->iStockColor3 = $aColor3; } function SetWidth($aWidth) { // Make sure it's odd $this->iWidth = 2*floor($aWidth/2)+1; } function HideEndLines($aHide=true) { $this->iEndLines = !$aHide; } // Gets called before any axis are stroked function PreStrokeAdjust(&$graph) { if( $this->center ) { $a=0.5; $b=0.5; $this->numpoints++; } else { $a=0; $b=0; } $graph->xaxis->scale->ticks->SetXLabelOffset($a); $graph->SetTextScaleOff($b); } // Stroke stock plot function Stroke(&$img,$xscale,$yscale) { $n=$this->numpoints; if( $this->center ) $n--; if( isset($this->coords[1]) ) { if( count($this->coords[1])!=$n ) JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); //("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); else $exist_x = true; } else $exist_x = false; if( $exist_x ) $xs=$this->coords[1][0]; else $xs=0; $ts = $this->iTupleSize; $this->csimareas = ''; for( $i=0; $i<$n; ++$i) { //If value is NULL, then don't draw a bar at all if ($this->coords[0][$i] === null) continue; if( $exist_x ) $x=$this->coords[1][$i]; else $x=$i; $xt = $xscale->Translate($x); $neg = $this->coords[0][$i*$ts] > $this->coords[0][$i*$ts+1] ; $yopen = $yscale->Translate($this->coords[0][$i*$ts]); $yclose = $yscale->Translate($this->coords[0][$i*$ts+1]); $ymin = $yscale->Translate($this->coords[0][$i*$ts+2]); $ymax = $yscale->Translate($this->coords[0][$i*$ts+3]); $dx = floor($this->iWidth/2); $xl = $xt - $dx; $xr = $xt + $dx; if( $neg ) $img->SetColor($this->iStockColor3); else $img->SetColor($this->iStockColor1); $img->FilledRectangle($xl,$yopen,$xr,$yclose); $img->SetLineWeight($this->weight); if( $neg ) $img->SetColor($this->iStockColor2); else $img->SetColor($this->color); $img->Rectangle($xl,$yopen,$xr,$yclose); if( $yopen < $yclose ) { $ytop = $yopen ; $ybottom = $yclose ; } else { $ytop = $yclose ; $ybottom = $yopen ; } $img->SetColor($this->color); $img->Line($xt,$ytop,$xt,$ymax); $img->Line($xt,$ybottom,$xt,$ymin); if( $this->iEndLines ) { $img->Line($xl,$ymax,$xr,$ymax); $img->Line($xl,$ymin,$xr,$ymin); } // A chance for subclasses to add things to the bar // for data point i $this->ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg); // Setup image maps if( !empty($this->csimtargets[$i]) ) { $this->csimareas.= 'csimareas .= ' href="'.$this->csimtargets[$i].'"'; if( !empty($this->csimalts[$i]) ) { $sval=$this->csimalts[$i]; $this->csimareas .= " title=\"$sval\" "; } $this->csimareas.= " alt=\"$sval\" />\n"; } } return true; } // A hook for subclasses to modify the plot function ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg) {} } // Class //=================================================== // CLASS BoxPlot //=================================================== class BoxPlot extends StockPlot { var $iPColor='black',$iNColor='white'; function BoxPlot($datay,$datax=false) { $this->iTupleSize=5; parent::StockPlot($datay,$datax); } function SetMedianColor($aPos,$aNeg) { $this->iPColor = $aPos; $this->iNColor = $aNeg; } function ModBox(&$img,$xscale,$yscale,$i,$xl,$xr,$neg) { if( $neg ) $img->SetColor($this->iNColor); else $img->SetColor($this->iPColor); $y = $yscale->Translate($this->coords[0][$i*5+4]); $img->Line($xl,$y,$xr,$y); } } /* EOF */ ?> ================================================ FILE: tools/server/admin/jpgraph/jpgraph_utils.inc ================================================ iFunc = $aFunc; $this->iXFunc = $aXFunc; } function E($aXMin,$aXMax,$aSteps=50) { $this->iMin = $aXMin; $this->iMax = $aXMax; $this->iStepSize = ($aXMax-$aXMin)/$aSteps; if( $this->iXFunc != '' ) $t = 'for($i='.$aXMin.'; $i<='.$aXMax.'; $i += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]='.$this->iXFunc.';}'; elseif( $this->iFunc != '' ) $t = 'for($x='.$aXMin.'; $x<='.$aXMax.'; $x += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]=$x;} $x='.$aXMax.';$ya[]='.$this->iFunc.';$xa[]=$x;'; else JpGraphError::RaiseL(24001);//('FuncGenerator : No function specified. '); @eval($t); // If there is an error in the function specifcation this is the only // way we can discover that. if( empty($xa) || empty($ya) ) JpGraphError::RaiseL(24002);//('FuncGenerator : Syntax error in function specification '); return array($xa,$ya); } } //============================================================================= // CLASS SymChar // Description: Code values for some commonly used characters that // normally isn't available directly on the keyboard, for example // mathematical and greek symbols. //============================================================================= class SymChar { function Get($aSymb,$aCapital=FALSE) { static $iSymbols = array( /* Greek */ array('alpha','03B1','0391'), array('beta','03B2','0392'), array('gamma','03B3','0393'), array('delta','03B4','0394'), array('epsilon','03B5','0395'), array('zeta','03B6','0396'), array('ny','03B7','0397'), array('eta','03B8','0398'), array('theta','03B8','0398'), array('iota','03B9','0399'), array('kappa','03BA','039A'), array('lambda','03BB','039B'), array('mu','03BC','039C'), array('nu','03BD','039D'), array('xi','03BE','039E'), array('omicron','03BF','039F'), array('pi','03C0','03A0'), array('rho','03C1','03A1'), array('sigma','03C3','03A3'), array('tau','03C4','03A4'), array('upsilon','03C5','03A5'), array('phi','03C6','03A6'), array('chi','03C7','03A7'), array('psi','03C8','03A8'), array('omega','03C9','03A9'), /* Money */ array('euro','20AC'), array('yen','00A5'), array('pound','20A4'), /* Math */ array('approx','2248'), array('neq','2260'), array('not','2310'), array('def','2261'), array('inf','221E'), array('sqrt','221A'), array('int','222B'), /* Misc */ array('copy','00A9'), array('para','00A7')); $n = count($iSymbols); $i=0; $found = false; $aSymb = strtolower($aSymb); while( $i < $n && !$found ) { $found = $aSymb === $iSymbols[$i++][0]; } if( $found ) { $ca = $iSymbols[--$i]; if( $aCapital && count($ca)==3 ) $s = $ca[2]; else $s = $ca[1]; return sprintf('&#%04d;',hexdec($s)); } else return ''; } } //============================================================================= // CLASS DateScaleUtils // Description: Help to create a manual date scale //============================================================================= DEFINE('DSUTILS_MONTH1',1); // Major and minor ticks on a monthly basis class DateScaleUtils { function GetTicks($aData,$aType=1) { // // Find out the range of the data in order to get the limits for the loops // that creates the position for the labels. This code is generic and can be // used for any ranges of the data. // $n = count($aData); $startmonth = date('n',$aData[0]); $startday = date('j',$aData[0]); $startyear = date('Y',$aData[0]); $endmonth = date('n',$aData[$n-1]); $endyear = date('Y',$aData[$n-1]); $endday = date('j',$aData[$n-1]); // // Now create the positions for all the ticks. In this example we // put a tick at the start of every month and also on the very // first and last X-position. // $tickPositions = array(); $minTickPositions = array(); $i=0;$j=0; // Uncomment this line to put a label at the very left data pos // $tickPositions[$i++] = $datax[0]; $m = $startmonth; $y = $startyear; // Skip the first month label if it is before the startdate if( $startday == 1 ) { $tickPositions[$i++] = mktime(0,0,0,$m,1,$y); } if( $startday < 15 ) { $minTickPositions[$j++] = mktime(0,0,0,$m,15,$y); } ++$m; // Loop through all the years included in the scale for($y=$startyear; $y <= $endyear; ++$y ) { // Loop through all the months. There are three cases to consider: // 1. We are in the first year and must start with the startmonth // 2. We are in the end year and we must stop at last month of the scale // 3. A year in between where we run through all the 12 months $stopmonth = $y == $endyear ? $endmonth : 12; while( $m <= $stopmonth ) { switch( $aType ) { case 1: // Set minor tick at the middle of the month if( $m <= $stopmonth ) { if( !($y==$endyear && $m==$stopmonth && $endday < 15) ) $minTickPositions[$j++] = mktime(0,0,0,$m,15,$y); } // Major at month // Get timestamp of first hour of first day in each month $tickPositions[$i++] = mktime(0,0,0,$m,1,$y); break; } ++$m; } $m=1; } // For the case where all dates are within the same month // we want to make sure we have at least two ticks on the scale // since the scale want work properly otherwise if($startmonth == $endmonth && $startyear == $endyear && $aType==1 ) { $tickPositions[$i++] = mktime(0 ,0 ,0, $startmonth + 1, 1, $startyear); } // Uncomment this line to put a label at the very right data pos // $tickPositions[$i] = $datax[$n-1]; return array($tickPositions,$minTickPositions); } } //============================================================================= // Class ReadFileData //============================================================================= Class ReadFileData { //---------------------------------------------------------------------------- // Desciption: // Read numeric data from a file. // Each value should be separated by either a new line or by a specified // separator character (default is ','). // Before returning the data each value is converted to a proper float // value. The routine is robust in the sense that non numeric data in the // file will be discarded. // // Returns: // The number of data values read on success, FALSE on failure //---------------------------------------------------------------------------- function FromCSV($aFile,&$aData,$aSepChar=',',$aMaxLineLength=1024) { $rh = fopen($aFile,'r'); if( $rh === false ) return false; $tmp = array(); $lineofdata = fgetcsv($rh, 1000, ','); while ( $lineofdata !== FALSE) { $tmp = array_merge($tmp,$lineofdata); $lineofdata = fgetcsv($rh, $aMaxLineLength, $aSepChar); } fclose($rh); // Now make sure that all data is numeric. By default // all data is read as strings $n = count($tmp); $aData = array(); $cnt=0; for($i=0; $i < $n; ++$i) { if( $tmp[$i] !== "" ) { $aData[$cnt++] = floatval($tmp[$i]); } } return $cnt; } } ?> ================================================ FILE: tools/server/admin/jpgraph/lang/en.inc.php ================================================ ,) $_jpg_messages = array( /* ** Headers already sent error. This is formatted as HTML different since this will be sent back directly as text */ 10 => array('
JpGraph Error: HTTP headers have already been sent.
Caused by output from file %s at line %d.
Explanation:
HTTP headers have already been sent back to the browser indicating the data as text before the library got a chance to send it\'s image HTTP header to this browser. This makes it impossible for the library to send back image data to the browser (since that would be interpretated as text by the browser and show up as junk text).

Most likely you have some text in your script before the call to Graph::Stroke(). If this texts gets sent back to the browser the browser will assume that all data is plain text. Look for any text, even spaces and newlines, that might have been sent back to the browser.

For example it is a common mistake to leave a blank line before the opening "<?php".

',2), /* ** Setup errors */ 11 => array('No path specified for CACHE_DIR. Please specify CACHE_DIR manually in jpg-config.inc',0), 12 => array('No path specified for TTF_DIR and path can not be determined automatically. Please specify TTF_DIR manually (in jpg-config.inc).',0), /* ** jpgraph_bar */ 2001 => array('Number of colors is not the same as the number of patterns in BarPlot::SetPattern()',0), 2002 => array('Unknown pattern specified in call to BarPlot::SetPattern()',0), 2003 => array('Number of X and Y points are not equal. Number of X-points: %d Number of Y-points: %d',2), 2004 => array('All values for a barplot must be numeric. You have specified value nr [%d] == %s',2), 2005 => array('You have specified an empty array for shadow colors in the bar plot.',0), 2006 => array('Unknown position for values on bars : %s',1), 2007 => array('Cannot create GroupBarPlot from empty plot array.',0), 2008 => array('Group bar plot element nbr %d is undefined or empty.',0), 2009 => array('One of the objects submitted to GroupBar is not a BarPlot. Make sure that you create the GroupBar plot from an array of BarPlot or AccBarPlot objects. (Class = %s)',1), 2010 => array('Cannot create AccBarPlot from empty plot array.',0), 2011 => array('Acc bar plot element nbr %d is undefined or empty.',1), 2012 => array('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects. (Class=%s)',1), 2013 => array('You have specified an empty array for shadow colors in the bar plot.',0), 2014 => array('Number of datapoints for each data set in accbarplot must be the same',0), /* ** jpgraph_date */ 3001 => array('It is only possible to use either SetDateAlign() or SetTimeAlign() but not both',0), /* ** jpgraph_error */ 4002 => array('Error in input data to LineErrorPlot. Number of data points must be a multiple of 3',0), /* ** jpgraph_flags */ 5001 => array('Unknown flag size (%d).',1), 5002 => array('Flag index %s does not exist.',1), 5003 => array('Invalid ordinal number (%d) specified for flag index.',1), 5004 => array('The (partial) country name %s does not have a corresponding flag image. The flag may still exist but under another name, e.g. instead of "usa" try "united states".',1), /* ** jpgraph_gantt */ 6001 => array('Internal error. Height for ActivityTitles is < 0',0), 6002 => array('You can\'t specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension.',0), 6003 => array('Invalid format for Constrain parameter at index=%d in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)',1), 6004 => array('Invalid format for Progress parameter at index=%d in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)',1), 6005 => array('SetScale() is not meaningful with Gantt charts.',0), 6006 => array('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]',0), 6007 => array('Sanity check for automatic Gantt chart size failed. Either the width (=%d) or height (=%d) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities.',2), 6008 => array('You have specified a constrain from row=%d to row=%d which does not have any activity',2), 6009 => array('Unknown constrain type specified from row=%d to row=%d',2), 6010 => array('Illegal icon index for Gantt builtin icon [%d]',1), 6011 => array('Argument to IconImage must be string or integer',0), 6012 => array('Unknown type in Gantt object title specification',0), 6015 => array('Illegal vertical position %d',1), 6016 => array('Date string (%s) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30',1), 6017 => array('Unknown date format in GanttScale (%s).',1), 6018 => array('Interval for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an interval of %d minutes.',1), 6019 => array('The available width (%d) for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.',1), 6020 => array('Interval for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an interval of %d',1), 6021 => array('Unknown formatting style for week.',0), 6022 => array('Gantt scale has not been specified.',0), 6023 => array('If you display both hour and minutes the hour interval must be 1 (Otherwise it doesn\'t make sense to display minutes).',0), 6024 => array('CSIM Target must be specified as a string. Start of target is: %d',1), 6025 => array('CSIM Alt text must be specified as a string. Start of alt text is: %d',1), 6027 => array('Progress value must in range [0, 1]',0), 6028 => array('Specified height (%d) for gantt bar is out of range.',1), 6029 => array('Offset for vertical line must be in range [0,1]',0), 6030 => array('Unknown arrow direction for link.',0), 6031 => array('Unknown arrow type for link.',0), 6032 => array('Internal error: Unknown path type (=%d) specified for link.',1), /* ** jpgraph_gradient */ 7001 => array('Unknown gradient style (=%d).',1), /* ** jpgraph_iconplot */ 8001 => array('Mix value for icon must be between 0 and 100.',0), 8002 => array('Anchor position for icons must be one of "top", "bottom", "left", "right" or "center"',0), 8003 => array('It is not possible to specify both an image file and a country flag for the same icon.',0), 8004 => array('In order to use Country flags as icons you must include the "jpgraph_flags.php" file.',0), /* ** jpgraph_imgtrans */ 9001 => array('Value for image transformation out of bounds. Vanishing point on horizon must be specified as a value between 0 and 1.',0), /* ** jpgraph_lineplot */ 10001 => array('LinePlot::SetFilled() is deprecated. Use SetFillColor()',0), 10002 => array('Plot too complicated for fast line Stroke. Use standard Stroke()',0), /* ** jpgraph_log */ 11001 => array('Your data contains non-numeric values.',0), 11002 => array('Negative data values can not be used in a log scale.',0), 11003 => array('Your data contains non-numeric values.',0), 11004 => array('Scale error for logarithmic scale. You have a problem with your data values. The max value must be greater than 0. It is mathematically impossible to have 0 in a logarithmic scale.',0), 11005 => array('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.',0), /* ** jpgraph_mgraph */ 12001 => array("You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x it is necessary to enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts.",0), 12002 => array('Incorrect file name for MGraph::SetBackgroundImage() : %s Must have a valid image extension (jpg,gif,png) when using auto detection of image type',1), 12003 => array('Unknown file extension (%s) in MGraph::SetBackgroundImage() for filename: %s',2), 12004 => array('The image format of your background image (%s) is not supported in your system configuration. ',1), 12005 => array('Can\'t read background image: %s',1), 12006 => array('Illegal sizes specified for width or height when creating an image, (width=%d, height=%d)',2), 12007 => array('Argument to MGraph::Add() is not a valid GD image handle.',0), 12008 => array('Your PHP (and GD-lib) installation does not appear to support any known graphic formats.',0), 12009 => array('Your PHP installation does not support the chosen graphic format: %s',1), 12010 => array('Can\'t create or stream image to file %s Check that PHP has enough permission to write a file to the current directory.',1), 12011 => array('Can\'t create truecolor image. Check that you really have GD2 library installed.',0), 12012 => array('Can\'t create image. Check that you really have GD2 library installed.',0), /* ** jpgraph_pie3d */ 14001 => array('Pie3D::ShowBorder() . Deprecated function. Use Pie3D::SetEdge() to control the edges around slices.',0), 14002 => array('PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees.',0), 14003 => array('Internal assertion failed. Pie3D::Pie3DSlice',0), 14004 => array('Slice start angle must be between 0 and 360 degrees.',0), 14005 => array('Pie3D Internal error: Trying to wrap twice when looking for start index',0,), 14006 => array('Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.',0), 14007 => array('Width for 3D Pie is 0. Specify a size > 0',0), /* ** jpgraph_pie */ 15001 => array('PiePLot::SetTheme() Unknown theme: %s',1), 15002 => array('Argument to PiePlot::ExplodeSlice() must be an integer',0), 15003 => array('Argument to PiePlot::Explode() must be an array with integer distances.',0), 15004 => array('Slice start angle must be between 0 and 360 degrees.',0), 15005 => array('PiePlot::SetFont() is deprecated. Use PiePlot->value->SetFont() instead.',0), 15006 => array('PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels in the range [10, 1000]',0), 15007 => array('PiePlot::SetFontColor() is deprecated. Use PiePlot->value->SetColor() instead.',0), 15008 => array('PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not %d).',1), 15009 => array('Illegal pie plot. Sum of all data is zero for Pie Plot',0), 15010 => array('Sum of all data is 0 for Pie.',0), 15011 => array('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.',0), /* ** jpgraph_plotband */ 16001 => array('Density for pattern must be between 1 and 100. (You tried %f)',1), 16002 => array('No positions specified for pattern.',0), 16003 => array('Unknown pattern specification (%d)',0), 16004 => array('Min value for plotband is larger than specified max value. Please correct.',0), /* ** jpgraph_polar */ 17001 => array('Polar plots must have an even number of data point. Each data point is a tuple (angle,radius).',0), 17002 => array('Unknown alignment specified for X-axis title. (%s)',1), //17003 => array('Set90AndMargin() is not supported for polar graphs.',0), 17004 => array('Unknown scale type for polar graph. Must be "lin" or "log"',0), /* ** jpgraph_radar */ 18001 => array('Client side image maps not supported for RadarPlots.',0), 18002 => array('RadarGraph::SupressTickMarks() is deprecated. Use HideTickMarks() instead.',0), 18003 => array('Illegal scale for radarplot (%s). Must be \'lin\' or \'log\'',1), 18004 => array('Radar Plot size must be between 0.1 and 1. (Your value=%f)',1), 18005 => array('RadarPlot Unsupported Tick density: %d',1), 18006 => array('Minimum data %f (Radar plots should only be used when all data points > 0)',1), 18007 => array('Number of titles does not match number of points in plot.',0), 18008 => array('Each radar plot must have the same number of data points.',0), /* ** jpgraph_regstat */ 19001 => array('Spline: Number of X and Y coordinates must be the same',0), 19002 => array('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.',0), 19003 => array('Bezier: Number of X and Y coordinates must be the same',0), /* ** jpgraph_scatter */ 20001 => array('Fieldplots must have equal number of X and Y points.',0), 20002 => array('Fieldplots must have an angle specified for each X and Y points.',0), 20003 => array('Scatterplot must have equal number of X and Y points.',0), /* ** jpgraph_stock */ 21001 => array('Data values for Stock charts must contain an even multiple of %d data points.',1), /* ** jpgraph_plotmark */ 23001 => array('This marker "%s" does not exist in color with index: %d',2), 23002 => array('Mark color index too large for marker "%s"',1), 23003 => array('A filename must be specified if you set the mark type to MARK_IMG.',0), /* ** jpgraph_utils */ 24001 => array('FuncGenerator : No function specified. ',0), 24002 => array('FuncGenerator : Syntax error in function specification ',0), /* ** jpgraph */ 25001 => array('This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)',0), 25002 => array('Your PHP installation does not seem to have the required GD library. Please see the PHP documentation on how to install and enable the GD library.',0), 25003 => array('General PHP error : At %s:%d : %s',3), 25004 => array('General PHP error : %s ',1), 25005 => array('Can\'t access PHP_SELF, PHP global variable. You can\'t run PHP from command line if you want to use the \'auto\' naming of cache or image files.',0), 25006 => array('Usage of FF_CHINESE (FF_BIG5) font family requires that your PHP setup has the iconv() function. By default this is not compiled into PHP (needs the "--width-iconv" when configured).',0), 25007 => array('You are trying to use the locale (%s) which your PHP installation does not support. Hint: Use \'\' to indicate the default locale for this geographic region.',1), 25008 => array('Image width/height argument in Graph::Graph() must be numeric',0), 25009 => array('You must specify what scale to use with a call to Graph::SetScale()',0), 25010 => array('Graph::Add() You tried to add a null plot to the graph.',0), 25011 => array('Graph::AddY2() You tried to add a null plot to the graph.',0), 25012 => array('Graph::AddYN() You tried to add a null plot to the graph.',0), 25013 => array('You can only add standard plots to multiple Y-axis',0), 25014 => array('Graph::AddText() You tried to add a null text to the graph.',0), 25015 => array('Graph::AddLine() You tried to add a null line to the graph.',0), 25016 => array('Graph::AddBand() You tried to add a null band to the graph.',0), 25017 => array('You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x it is necessary to enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts.',0), 25018 => array('Incorrect file name for Graph::SetBackgroundImage() : "%s" Must have a valid image extension (jpg,gif,png) when using auto detection of image type',1), 25019 => array('Unknown file extension (%s) in Graph::SetBackgroundImage() for filename: "%s"',2), 25020 => array('Graph::SetScale(): Specified Max value must be larger than the specified Min value.',0), 25021 => array('Unknown scale specification for Y-scale. (%s)',1), 25022 => array('Unknown scale specification for X-scale. (%s)',1), 25023 => array('Unsupported Y2 axis type: "%s" Must be one of (lin,log,int)',1), 25024 => array('Unsupported Y axis type: "%s" Must be one of (lin,log,int)',1), 25025 => array('Unsupported Tick density: %d',1), 25026 => array('Can\'t draw unspecified Y-scale. You have either: 1. Specified an Y axis for auto scaling but have not supplied any plots. 2. Specified a scale manually but have forgot to specify the tick steps',0), 25027 => array('Can\'t open cached CSIM "%s" for reading.',1), 25028 => array('Apache/PHP does not have permission to write to the CSIM cache directory (%s). Check permissions.',1), 25029 => array('Can\'t write CSIM "%s" for writing. Check free space and permissions.',1), 25030 => array('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().',0), 25031 => array('You must specify what scale to use with a call to Graph::SetScale().',0), 25032 => array('No plots for Y-axis nbr:%d',1), 25033 => array('',0), 25034 => array('Can\'t draw unspecified X-scale. No plots specified.',0), 25035 => array('You have enabled clipping. Clipping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (=%d degrees) or disable clipping.',1), 25036 => array('Unknown AxisStyle() : %s',1), 25037 => array('The image format of your background image (%s) is not supported in your system configuration. ',1), 25038 => array('Background image seems to be of different type (has different file extension) than specified imagetype. Specified: %s File: %s',2), 25039 => array('Can\'t read background image: "%s"',1), 25040 => array('It is not possible to specify both a background image and a background country flag.',0), 25041 => array('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.',0), 25042 => array('Unknown background image layout',0), 25043 => array('Unknown title background style.',0), 25044 => array('Cannot use auto scaling since it is impossible to determine a valid min/max value of the Y-axis (only null values).',0), 25045 => array('Font families FF_HANDWRT and FF_BOOK are no longer available due to copyright problem with these fonts. Fonts can no longer be distributed with JpGraph. Please download fonts from http://corefonts.sourceforge.net/',0), 25046 => array('Specified TTF font family (id=%d) is unknown or does not exist. Please note that TTF fonts are not distributed with JpGraph for copyright reasons. You can find the MS TTF WEB-fonts (arial, courier etc) for download at http://corefonts.sourceforge.net/',1), 25047 => array('Style %s is not available for font family %s',2), 25048 => array('Unknown font style specification [%s].',1), 25049 => array('Font file "%s" is not readable or does not exist.',1), 25050 => array('First argument to Text::Text() must be a string.',0), 25051 => array('Invalid direction specified for text.',0), 25052 => array('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text',0), 25053 => array('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text',0), 25054 => array('Internal error: Unknown grid axis %s',1), 25055 => array('Axis::SetTickDirection() is deprecated. Use Axis::SetTickSide() instead',0), 25056 => array('SetTickLabelMargin() is deprecated. Use Axis::SetLabelMargin() instead.',0), 25057 => array('SetTextTicks() is deprecated. Use SetTextTickInterval() instead.',0), 25058 => array('Text label interval must be specified >= 1.',0), 25059 => array('SetLabelPos() is deprecated. Use Axis::SetLabelSide() instead.',0), 25060 => array('Unknown alignment specified for X-axis title. (%s)',1), 25061 => array('Unknown alignment specified for Y-axis title. (%s)',1), 25062 => array('Labels at an angle are not supported on Y-axis',0), 25063 => array('Ticks::SetPrecision() is deprecated. Use Ticks::SetLabelFormat() (or Ticks::SetFormatCallback()) instead',0), 25064 => array('Minor or major step size is 0. Check that you haven\'t got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem',0), 25065 => array('Tick positions must be specified as an array()',0), 25066 => array('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.',0), 25067 => array('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tick marks.',0), 25068 => array('A plot has an illegal scale. This could for example be that you are trying to use text auto scaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only \'-\' or \'x\')',0), 25069 => array('Grace must be larger then 0',0), 25070 => array('Your data contains non-numeric values.',0), 25071 => array('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.',0), 25072 => array('You have specified a max value with SetAutoMax() which is smaller than the minimum value used for the scale. This is not possible.',0), 25073 => array('Internal error. Integer scale algorithm comparison out of bound (r=%f)',1), 25074 => array('Internal error. The scale range is negative (%f) [for %s scale] This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the auto scaling to fail.',2), 25075 => array('Can\'t automatically determine ticks since min==max.',0), 25077 => array('Adjustment factor for color must be > 0',0), 25078 => array('Unknown color: %s',1), 25079 => array('Unknown color specification: %s, size=%d',2), 25080 => array('Alpha parameter for color must be between 0.0 and 1.0',0), 25081 => array('Selected graphic format is either not supported or unknown [%s]',1), 25082 => array('Illegal sizes specified for width or height when creating an image, (width=%d, height=%d)',2), 25083 => array('Illegal image size when copying image. Size for copied to image is 1 pixel or less.',0), 25084 => array('Failed to create temporary GD canvas. Possible Out of memory problem.',0), 25085 => array('An image can not be created from the supplied string. It is either in a format not supported or the string is representing an corrupt image.',0), 25086 => array('You only seem to have GD 1.x installed. To enable Alphablending requires GD 2.x or higher. Please install GD or make sure the constant USE_GD2 is specified correctly to reflect your installation. By default it tries to auto detect what version of GD you have installed. On some very rare occasions it may falsely detect GD2 where only GD1 is installed. You must then set USE_GD2 to false.',0), 25087 => array('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.',0), 25088 => array('You have a misconfigured GD font support. The call to imagefontwidth() fails.',0), 25089 => array('You have a misconfigured GD font support. The call to imagefontheight() fails.',0), 25090 => array('Unknown direction specified in call to StrokeBoxedText() [%s]',1), 25091 => array('Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead.',0), 25092 => array('There is either a configuration problem with TrueType or a problem reading font file "%s" Make sure file exists and is in a readable place for the HTTP process. (If \'basedir\' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try upgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library.',1), 25093 => array('Can not read font file "%s" in call to Image::GetBBoxTTF. Please make sure that you have set a font before calling this method and that the font is installed in the TTF directory.',1), 25094 => array('Direction for text most be given as an angle between 0 and 90.',0), 25095 => array('Unknown font font family specification. ',0), 25096 => array('Can\'t allocate any more colors in palette image. Image has already allocated maximum of %d colors and the palette is now full. Change to a truecolor image instead',0), 25097 => array('Color specified as empty string in PushColor().',0), 25098 => array('Negative Color stack index. Unmatched call to PopColor()',0), 25099 => array('Parameters for brightness and Contrast out of range [-1,1]',0), 25100 => array('Problem with color palette and your GD setup. Please disable anti-aliasing or use GD2 with true-color. If you have GD2 library installed please make sure that you have set the USE_GD2 constant to true and truecolor is enabled.',0), 25101 => array('Illegal numeric argument to SetLineStyle(): (%d)',1), 25102 => array('Illegal string argument to SetLineStyle(): %s',1), 25103 => array('Illegal argument to SetLineStyle %s',1), 25104 => array('Unknown line style: %s',1), 25105 => array('NULL data specified for a filled polygon. Check that your data is not NULL.',0), 25106 => array('Image::FillToBorder : Can not allocate more colors',0), 25107 => array('Can\'t write to file "%s". Check that the process running PHP has enough permission.',1), 25108 => array('Can\'t stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP.',0), 25109 => array('Your PHP (and GD-lib) installation does not appear to support any known graphic formats. You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images you must get the JPEG library. Please see the PHP docs for details.',0), 25110 => array('Your PHP installation does not support the chosen graphic format: %s',1), 25111 => array('Can\'t delete cached image %s. Permission problem?',1), 25112 => array('Cached imagefile (%s) has file date in the future.',1), 25113 => array('Can\'t delete cached image "%s". Permission problem?',1), 25114 => array('PHP has not enough permissions to write to the cache file "%s". Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.',1), 25115 => array('Can\'t set permission for cached image "%s". Permission problem?',1), 25116 => array('Cant open file from cache "%s"',1), 25117 => array('Can\'t open cached image "%s" for reading.',1), 25118 => array('Can\'t create directory "%s". Make sure PHP has write permission to this directory.',1), 25119 => array('Can\'t set permissions for "%s". Permission problems?',1), 25120 => array('Position for legend must be given as percentage in range 0-1',0), 25121 => array('Empty input data array specified for plot. Must have at least one data point.',0), 25122 => array('Stroke() must be implemented by concrete subclass to class Plot',0), 25123 => array('You can\'t use a text X-scale with specified X-coords. Use a "int" or "lin" scale instead.',0), 25124 => array('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)',0), 25125 => array('Illegal direction for static line',0), 25126 => array('Can\'t create truecolor image. Check that the GD2 library is properly setup with PHP.',0), /* **--------------------------------------------------------------------------------------------- ** Pro-version strings **--------------------------------------------------------------------------------------------- */ /* ** jpgraph_table */ 24001 => array('GTextTable: Invalid argument to Set(). Array argument must be 2 dimensional',0), 24002 => array('GTextTable: Invalid argument to Set()',0), 24003 => array('GTextTable: Wrong number of arguments to GTextTable::SetColor()',0), 24004 => array('GTextTable: Specified cell range to be merged is not valid.',0), 24005 => array('GTextTable: Cannot merge already merged cells in the range: (%d,%d) to (%d,%d)',4), 24006 => array('GTextTable: Column argument = %d is outside specified table size.',1), 24007 => array('GTextTable: Row argument = %d is outside specified table size.',1), 24008 => array('GTextTable: Column and row size arrays must match the dimensions of the table',0), 24009 => array('GTextTable: Number of table columns or rows are 0. Make sure Init() or Set() is called.',0), 24010 => array('GTextTable: No alignment specified in call to SetAlign()',0), 24011 => array('GTextTable: Unknown alignment specified in SetAlign(). Horizontal=%s, Vertical=%s',2), 24012 => array('GTextTable: Internal error. Invalid alignment specified =%s',1), 24013 => array('GTextTable: Argument to FormatNumber() must be a string.',0), 24014 => array('GTextTable: Table is not initilaized with either a call to Set() or Init()',0), 24015 => array('GTextTable: Cell image constrain type must be TIMG_WIDTH or TIMG_HEIGHT',0), /* ** jpgraph_windrose */ 22001 => array('Total percentage for all windrose legs in a windrose plot can not exceed 100% !\n(Current max is: %d)',1), 22002 => array('Graph is too small to have a scale. Please make the graph larger.',0), 22004 => array('Label specification for windrose directions must have 16 values (one for each compass direction).',0), 22005 => array('Line style for radial lines must be on of ("solid","dotted","dashed","longdashed") ',0), 22006 => array('Illegal windrose type specified.',0), 22007 => array('To few values for the range legend.',0), 22008 => array('Internal error: Trying to plot free Windrose even though type is not a free windrose',0), 22009 => array('You have specified the same direction twice, once with an angle and once with a compass direction (%f degrees)',0), 22010 => array('Direction must either be a numeric value or one of the 16 compass directions',0), 22011 => array('Windrose index must be numeric or direction label. You have specified index=%d',1), 22012 => array('Windrose radial axis specification contains a direction which is not enabled.',0), 22013 => array('You have specified the look&feel for the same compass direction twice, once with text and once with index (Index=%d)',1), 22014 => array('Index for compass direction must be between 0 and 15.',0), 22015 => array('You have specified an undefined Windrose plot type.',0), 22016 => array('Windrose leg index must be numeric or direction label.',0), 22017 => array('Windrose data contains a direction which is not enabled. Please adjust what labels are displayed.',0), 22018 => array('You have specified data for the same compass direction twice, once with text and once with index (Index=%d)',1), 22019 => array('Index for direction must be between 0 and 15. You can\'t specify angles for a Regular Windplot, only index and compass directions.',0), 22020 => array('Windrose plot is too large to fit the specified Graph size. Please use WindrosePlot::SetSize() to make the plot smaller or increase the size of the Graph in the initial WindroseGraph() call.',0), /* ** jpgraph_odometer */ 13001 => array('Unknown needle style (%d).',1), 13002 => array('Value for odometer (%f) is outside specified scale [%f,%f]',3), /* ** jpgraph_barcode */ 1001 => array('Unknown encoder specification: %s',1), 1002 => array('Data validation failed. Can\'t encode [%s] using encoding "%s"',2), 1003 => array('Internal encoding error. Trying to encode %s is not possible in Code 128',1), 1004 => array('Internal barcode error. Unknown UPC-E encoding type: %s',1), 1005 => array('Internal error. Can\'t encode character tuple (%s, %s) in Code-128 charset C',2), 1006 => array('Internal encoding error for CODE 128. Trying to encode control character in CHARSET != A',0), 1007 => array('Internal encoding error for CODE 128. Trying to encode DEL in CHARSET != B',0), 1008 => array('Internal encoding error for CODE 128. Trying to encode small letters in CHARSET != B',0), 1009 => array('Encoding using CODE 93 is not yet supported.',0), 1010 => array('Encoding using POSTNET is not yet supported.',0), 1011 => array('Non supported barcode backend for type %s',1), /* ** PDF417 */ 26001 => array('PDF417: Number of Columns must be >= 1 and <= 30',0), 26002 => array('PDF417: Error level must be between 0 and 8',0), 26003 => array('PDF417: Invalid format for input data to encode with PDF417',0), 26004 => array('PDF417: Can\'t encode given data with error level %d and %d columns since it results in too many symbols or more than 90 rows.',2), 26005 => array('PDF417: Can\'t open file "%s" for writing',1), 26006 => array('PDF417: Internal error. Data files for PDF417 cluster %d is corrupted.',1), 26007 => array('PDF417: Internal error. GetPattern: Illegal Code Value = %d (row=%d)',2), 26008 => array('PDF417: Internal error. Mode not found in mode list!! mode=%d',1), 26009 => array('PDF417: Encode error: Illegal character. Can\'t encode character with ASCII code=%d',1), 26010 => array('PDF417: Internal error: No input data in decode.',0), 26011 => array('PDF417: Encoding error. Can\'t use numeric encoding on non-numeric data.',0), 26012 => array('PDF417: Internal error. No input data to decode for Binary compressor.',0), 26013 => array('PDF417: Internal error. Checksum error. Coefficient tables corrupted.',0), 26014 => array('PDF417: Internal error. No data to calculate codewords on.',0), 26015 => array('PDF417: Internal error. State transition table entry 0 is NULL. Entry 1 = (%s)',1), 26016 => array('PDF417: Internal error: Unrecognized state transition mode in decode.',0), ); ?> ================================================ FILE: tools/server/admin/logs/empty.txt ================================================ Empty file, just to keep directory alive! ================================================ FILE: tools/server/admin/nel/admin_modules_itf.php ================================================ setName("GCMD"); $msg->serialString($command); return parent::sendMessage($msg); } function controlCmd($serviceAlias, $command) { $msg = new CMessage; $msg->setName("CCMD"); $msg->serialString($serviceAlias); $msg->serialString($command); return parent::sendMessage($msg); } function serviceCmd($serviceAlias, $command) { $msg = new CMessage; $msg->setName("SCMD"); $msg->serialString($serviceAlias); $msg->serialString($command); return parent::sendMessage($msg); } function getShardOrders() { $msg = new CMessage; $msg->setName("GSO"); $ret = ""; $ret = parent::sendMessage($msg); if ($ret == false) { // error during send $this->invokeError("getShardOrders", "Error in 'sendMessage'"); return false; } $retMsg = parent::waitMessage(); if ($ret == false) { // error during send $this->invokeError("getShardOrders", "Error in 'waitMessage'"); return false; } if (!($retMsg->MsgName === "R_GSO")) { // error during send $this->invokeError("getShardOrders", "Invalid response, awaited 'R_GSO', received '".$retMsg->MsgName."'"); return false; } // serial the return value $nbElem = 0; $retMsg->serialUInt32($nbElem); $retValue = array(); for ($i=0; $i<$nbElem;$i++) { $retMsg->serialString($item); $retValue[] = $item; } // return the return value return $retValue; } function getStates() { $msg = new CMessage; $msg->setName("GS"); $ret = ""; $ret = parent::sendMessage($msg); if ($ret == false) { // error during send $this->invokeError("getStates", "Error in 'sendMessage'"); return false; } $retMsg = parent::waitMessage(); if ($ret == false) { // error during send $this->invokeError("getStates", "Error in 'waitMessage'"); return false; } if (!($retMsg->MsgName === "R_GS")) { // error during send $this->invokeError("getStates", "Invalid response, awaited 'R_GS', received '".$retMsg->MsgName."'"); return false; } // serial the return value $nbElem = 0; $retMsg->serialUInt32($nbElem); $retValue = array(); for ($i=0; $i<$nbElem;$i++) { $retMsg->serialString($item); $retValue[] = $item; } // return the return value return $retValue; } function getHighRezGraph($varAddr, $startDate, $endDate, $milliStep) { $msg = new CMessage; $msg->setName("GHRG"); $msg->serialString($varAddr); $msg->serialUint32($startDate); $msg->serialUint32($endDate); $msg->serialUint32($milliStep); $ret = ""; $ret = parent::sendMessage($msg); if ($ret == false) { // error during send $this->invokeError("getHighRezGraph", "Error in 'sendMessage'"); return false; } $retMsg = parent::waitMessage(); if ($ret == false) { // error during send $this->invokeError("getHighRezGraph", "Error in 'waitMessage'"); return false; } if (!($retMsg->MsgName === "R_GHRG")) { // error during send $this->invokeError("getHighRezGraph", "Invalid response, awaited 'R_GHRG', received '".$retMsg->MsgName."'"); return false; } // serial the return value $nbElem = 0; $retMsg->serialUInt32($nbElem); $retValue = array(); for ($i=0; $i<$nbElem;$i++) { $retMsg->serialString($item); $retValue[] = $item; } // return the return value return $retValue; } function waitCallback() { $message = parent::waitMessage(); if ($message == false) return false; switch($message->MsgName) { case "CMDR": $this->commandResult_skel($message); break; default: return false; } return true; } function commandResult_skel(&$message) { $message->serialString($serviceAlias); $message->serialString($result); $this->commandResult($serviceAlias, $result); } ///////////////////////////////////////////////////////////////// // Copy paste this part of code in your derived class // and implement code to ract to incoming message ///////////////////////////////////////////////////////////////// function commandResult($serviceAlias, $result) { } } ?> ================================================ FILE: tools/server/admin/nel/nel_message.php ================================================ InputStream = false; $this->Pos = 0; $this->Buffer = ""; debug("A : ".gettype($this->Buffer)."
"); } function setBuffer ($Buffer) { $this->InputStream = true; $this->Buffer = $Buffer; $this->Pos = 0; } function isReading () { return $this->InputStream; } function serialUInt8 (&$val) { if ($this->isReading()) { $val = ord($this->Buffer{$this->Pos++}); debug(sprintf ("read uint8 '%d'
\n", $val)); } else { debug("B".gettype($this->Buffer)."
"); debug(sprintf ("write uint8 Buffer size before = %u
\n", strlen($this->Buffer))); $this->Buffer = $this->Buffer . chr($val & 0xFF); $this->Pos++; debug("C".gettype($this->Buffer)."
"); debug(sprintf ("write uint8 '%d' %d
\n", $val, $this->Pos)); debug(sprintf ("write uint8 Buffer size after = %u
\n", strlen($this->Buffer))); } } function serialUInt32 (&$val) { if ($this->isReading()) { $val = ord($this->Buffer{$this->Pos++}); $val += ord($this->Buffer{$this->Pos++})*256; $val += ord($this->Buffer{$this->Pos++})*(double)256*256; $val += ord($this->Buffer{$this->Pos++})*(double)256*256*256; debug(sprintf ("read uint32 '%d'
\n", $val)); // var_dump($val); } else { debug("D".gettype($this->Buffer)."
"); $this->Buffer .= chr($val & 0xFF); $this->Buffer .= chr(($val>>8) & 0xFF); $this->Buffer .= chr(($val>>16) & 0xFF); $this->Buffer .= chr(($val>>24) & 0xFF); $this->Pos += 4; debug("E".gettype($this->Buffer)."
"); debug(sprintf ("write uint32 '%d' %d
\n", $val, $this->Pos)); } } function serialString (&$val) { if ($this->isReading()) { $this->serialUInt32($size); debug(sprintf ("read string : size = %u
\n", $size)); $val = substr ($this->Buffer, $this->Pos, $size); debug(sprintf ("read string '%s'
\n", $val)); $this->Pos += strlen($val); } else { $lentmp = strlen($val); $this->serialUInt32($lentmp); $this->Buffer .= $val; $this->Pos += strlen($val); debug(sprintf ("write string '%s' %d
\n", $val, $this->Pos)); } } } class CMessage extends CMemStream { var $MsgName; function CMessage() { $this->CMemStream(); } function setName($name) { $this->MsgName = $name; } } class CCallbackClient { var $ConSock = false; var $MsgNum = 0; function connect($addr, $port, &$res) { global $SockTimeOut; debug(sprintf("Connect
")); $this->MsgNum = 0; $this->ConSock = fsockopen ($addr, $port, $errno, $errstr, $SockTimeOut); debug("H".gettype($this->ConSock)."
"); if (!$this->ConSock) { $errmsg = iconv('GBK', 'UTF-8', $errstr); $res = "Can't connect to the callback server '$addr:$port' ($errno: $errmsg)"; return false; } else { // set time out on the socket to 2 secondes stream_set_timeout($this->ConSock, $SockTimeOut); $res = ""; return true; } } function close() { if ($this->ConSock) { fclose($this->ConSock); debug(sprintf("Close
")); } else debug(sprintf("Already Closed !
")); } function sendMessage(&$message) { if (!$this->ConSock) { debug(sprintf ("Socket is not valid\n")); return false; } debug(sprintf ("sendMessage : message Buffer is '%d'
\n", $message->Pos)); debug(sprintf ("sendMessage : message Buffer is '%d'
\n", strlen($message->Buffer))); $hd = new CMemStream; debug(sprintf("SendMessage number %u
", $this->MsgNum)); $hd->serialUInt32 ($this->MsgNum); // number the packet $this->MsgNum += 1; debug(sprintf("After SendMessage, number %u
", $this->MsgNum)); $messageType = 0; $hd->serialUInt8 ($messageType); $hd->serialString ($message->MsgName); debug(sprintf ("sendMessage : header size is '%d'
\n", $hd->Pos)); // $sb .= $message->Buffer; $size = $hd->Pos + $message->Pos; $Buffer = (string) chr(($size>>24)&0xFF); $Buffer .= chr(($size>>16)&0xFF); $Buffer .= chr(($size>>8)&0xFF); $Buffer .= chr($size&0xFF); debug( "E".gettype($hd->Buffer)."
"); debug("F".gettype($message->Buffer)."
"); $Buffer .= (string) $hd->Buffer; $Buffer .= (string) $message->Buffer; debug("G".gettype($this->ConSock)."
"); if (!fwrite ($this->ConSock, $Buffer)) { debug(sprintf ("Error writing to socket\n")); return false; } debug(sprintf ("sent packet size '%d' (written size = %d)
\n", strlen($Buffer), $size)); fflush ($this->ConSock); return true; } function waitMessage() { if (!$this->ConSock) { debug(sprintf ("Socket is not valid\n")); return false; } $size = 0; $val = fread ($this->ConSock, 1); $info = stream_get_meta_data($this->ConSock); if ($info['timed_out']) { debug('Connection timed out!'); return false; } $size = ord($val) << 24; $val = fread ($this->ConSock, 1); $info = stream_get_meta_data($this->ConSock); if ($info['timed_out']) { debug('Connection timed out!'); return false; } $size = ord($val) << 16; $val = fread ($this->ConSock, 1); $info = stream_get_meta_data($this->ConSock); if ($info['timed_out']) { debug('Connection timed out!'); return false; } $size += ord($val) << 8; $val = fread ($this->ConSock, 1); $info = stream_get_meta_data($this->ConSock); if ($info['timed_out']) { debug('Connection timed out!'); return false; } $size += ord($val); debug(sprintf ("receive packet size '%d'
\n", $size)); $fake = fread ($this->ConSock, 5); $info = stream_get_meta_data($this->ConSock); if ($info['timed_out']) { debug('Connection timed out!'); return false; } $size -= 5; // remove the fake $Buffer = ""; while ($size > 0 && strlen($Buffer) != $size) { $Buffer .= fread ($this->ConSock, $size - strlen($Buffer)); $info = stream_get_meta_data($this->ConSock); if ($info['timed_out']) { debug('Connection timed out!'); return false; } } $msgin = new CMemStream; $msgin->setBuffer ($Buffer); // decode msg name $msgin->serialString($name); debug(sprintf("Message name = '%s'
", $name)); $message = new CMessage; $message->setBuffer(substr($msgin->Buffer, $msgin->Pos)); $message->setName($name); debug(sprintf("In message name = '%s'
", $message->MsgName)); return $message; } } // class CSessionManagerProxy // { // function createSession($userId, $sessionType, $callbackClient) // { // debug(sprintf("Creating session for user %u, type %s
", $userId, $sessionType)); // $msg = new CMessage; // $msg->setName("CSS"); // $msg->serialUInt32($userId); // $msg->serialString($sessionType); // // $callbackClient->sendMessage($msg); // } // } // class CSessionManagerClientSkel // { // function waitCallback($callbackClient) // { // $message = $callbackClient->waitMessage(); // // debug(sprintf("Received message '%s'
", $message->MsgName)); // // switch($message->MsgName) // { // case "CSSR": // debug(sprintf("Create session result
")); // $this->createSessionResult_skel($message); // break; // // case "CSNR": // debug(sprintf("Create scenario result
")); // $this->createScenarioResult_skel($message); // break; // }; // } // // function createSessionResult_skel($message) // { // $userId = 0; // $sessionId = 0; // $result = false; // // $message->serialUInt32($userId); // $message->serialUInt32($sessionId); // $message->serialUInt8($result); // // createSessionResult($userId, $sessionId, $result); // } // } // printf("creating callback client...
"); // // $cb = new CCallbackClient; // $ret = ""; // $cb->connect("192.168.0.1", "8060", $ret); // // $smp = new CSessionManagerProxy; // // printf("creating a new sessions...
"); // $smp->createSession(10, "st_edit", $cb); // // $smcs = new CSessionManagerClientSkel; // $smcs->waitCallback($cb); // // // function createSessionResult($userId, $sessionId, $result) // { // echo "The session result for user $userId is the session $sessionId with a result of $result\n"; // } // // This function connect to the AS. // If true, $res contains the url to connect. // If false, $res contains the reason why it s not okay. // function connectToAS(&$fp, &$res) // { // global $ASHost, $ASPort; ///* // $sid = session_id(); // $result = sqlquery("SELECT socket_id FROM resident_socket"); // if (!$result || sqlnumrows($result) == 0) // { // $fp = pfsockopen ($ASHost, $ASPort, $errno, $errstr, 30); // echo "opened resident socket '$fp'\n"; // // $result = sqlquery("SELECT socket_id FROM resident_socket WHERE socket_id='$fp'"); // if ($result && sqlnumrows($result)>0) // sqlquery("DELETE FROM resident_socket WHERE socket_id='$fp'"); // // sqlquery("INSERT INTO resident_socket SET socket_id='$fp', session_id='$sid', last_access=NOW()"); // } // else // { // $result = sqlfetch($result); // $fp = $result["socket_id"]; // } // // // remove too old sockets // sqlquery("SELECT socket_id FROM resident_socket WHERE NOW()-last_access > 1800"); // while ($result && ($arr=sqlfetch($result))) // { // fclose((int)($arr["socket_id"])); // sqlquery("DELETE FROM resident_socket WHERE socket_id='".$arr["socket_id"]."'"); // } // // // update current socket last access // sqlquery("UPDATE resident_socket SET last_access=NOW() WHERE socket_id='$fp' AND session_id='$sid'"); //*/ // // // connect to the login service that must be $ASHost:$ASPort // $fp = fsockopen ($ASHost, $ASPort, $errno, $errstr, 30); // if (!$fp) // { // $res = "Can't connect to the admin service '$ASHost:$ASPort' ($errno: $errstr)"; // } // else // { // $res = ""; // } // // } // // function disconnectFromAS(&$fp) // { ///* // $result = sqlquery("SELECT socket_id FROM resident_socket WHERE socket_id='$fp'"); // if (!$result || sqlnumrows($socket)==0) // fclose($fp); //*/ // fclose($fp); // } // // function sendMessage ($fp, $msgout) // { // $size = $msgout->Pos; // $Buffer = chr(($size>>24)&0xFF); // $Buffer .= chr(($size>>16)&0xFF); // $Buffer .= chr(($size>>8)&0xFF); // $Buffer .= chr($size&0xFF); // $Buffer .= $msgout->Buffer; // // fwrite ($fp, $Buffer); // // //printf ("sent packet size '%d'
", strlen($Buffer)); // // fflush ($fp); // } // // function waitMessage ($fp, &$msgin) // { // //echo "waiting a message"; // $size = 0; // $val = fread ($fp, 1); // $size = ord($val) << 24; // $val = fread ($fp, 1); // $size = ord($val) << 16; // $val = fread ($fp, 1); // $size += ord($val) << 8; // $val = fread ($fp, 1); // $size += ord($val); // //printf ("receive packet size '%d'
", $size); // $fake = fread ($fp, 4); // $size -= 4; // remove the fake // // $Buffer = fread ($fp, $size); // $msgin = new CMemStream; // $msgin->setBuffer ($Buffer); // } // // function logNelQuery($query) // { // global $uid; ///* // $f = fopen("./nel_queries.log", "a"); // fwrite($f, date("Y/m/d H:i:s")." ".sprintf("%-16s", $admlogin)." $query\n"); // fclose($f); //*/ // // logUser($uid, "QUERY=".$query); // } // // function nel_query($rawvarpath, &$result) // { // global $nel_queries; // // $nel_queries[] = $rawvarpath; // $ok = false; // //echo "rawvarpath=$rawvarpath
\n"; // // //logNelQuery($rawvarpath); // // connectToAS($fp, $result); // if(strlen($result) != 0) // return $ok; // // // send the message that say that we want to add a user // $msgout = new CMemStream; // $fake = 0; // $msgout->serialuint32 ($fake); // fake used to number the packet // $messageType = 0; // $msgout->serialuint8 ($messageType); // $msgout->serialstring ($rawvarpath); // // sendMessage ($fp, $msgout); // // waitMessage ($fp, $msgin); // // $msgin->serialstring($result); // // if(strlen($result) == 0) // { // // it failed // } // else // { // // it's ok // $ok = true; // } // // //printf("receive response '$result'
\n"); // // disconnectFromAS(&$fp); // //echo "sent OK.

\n"; // // return $ok; // } ?> ================================================ FILE: tools/server/admin/neltool.css ================================================ body { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; background-color: #FFFFFF; } td { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; } table { margin: 0px; padding: 0px; border-collapse: collapse; border-spacing: 0; } th { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; background-color: #999999; } input { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; } input.small { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 9px; width: 45px; } textarea { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; width:98%; border-left: 1px solid #000000; border-right: 1px solid #000000; border-top: 1px solid #000000; border-bottom: 1px solid #000000; } textarea.command { font-family: Terminal, Courier; font-size: 10pt; } a:link { color: #000088; text-decoration: none; } a:visited { color: #000088; text-decoration: none; } a:active { color: #000033; text-decoration: none; } a:hover { color: #8800CC; text-decoration: underline; } td.boxed { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; border-left: 1px solid #000000; border-right: 1px solid #000000; border-top: 1px solid #000000; border-bottom: 1px solid #000000; background-color: #eeeeee; padding-left: 5px; padding-right: 5px; text-align: center; vertical-align: middle; } td.line_left { border-left: 1px solid #000000; } td.line_right { border-right: 1px solid #000000; } td.line_top { border-top: 1px solid #000000; } td.line_bottom { border-bottom: 1px solid #000000; } table.viewlist { height:100%; } table.view { border-left: 1px solid #000000; border-right: 1px solid #000000; border-top: 1px solid #000000; border-bottom: 1px solid #000000; } td.offline { background-color: #FF0000; } td.unknown { background-color: #FFAA00; } tr.row0 { background-color: #CCCCCC; } tr.row1 { background-color: #DDDDDD; } tr.row0_static { background-color: #CCCCCC; } tr.row1_static { background-color: #DDDDDD; } tr.row_red { background-color: #C83C3C; } tr.row_orange_dark { background-color: #E4916F; } tr.row_orange_light { background-color: #F2D079; } tr.row_stopped { background-color: #AAAAAA; } tr.row_starting { background-color: #75D5A8; } tr.row0:hover, tr.row1:hover, tr.row_stopped:hover, tr.row_starting:hover, tr.row_red:hover, tr.row_orange_dark:hover, tr.row_orange_light:hover { background-color: #99BBDD; } tr.row_restart_active { background-color: #CC8899; border-left: 1px solid #000000; border-right: 1px solid #000000; border-top: 1px solid #000000; border-bottom: 1px solid #000000; } td.cell_inactive1 { color: #666666; } td.cell_inactive2 { color: #666666; font-style: italic; } td.heads { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; background-color: #999999; font-weight: bold; } input { border-left: 1px solid #000000; border-right: 1px solid #000000; border-top: 1px solid #000000; border-bottom: 1px solid #000000; } input.check { border-left: 0px solid #000000; border-right: 0px solid #000000; border-top: 0px solid #000000; border-bottom: 0px solid #000000; } input.refresh_counter { border-left: 0px solid #000000; border-right: 0px solid #000000; border-top: 0px solid #000000; border-bottom: 0px solid #000000; background-color: #cccccc; text-align: center; width: 100%; } input.restart { background-color: #CC8899; } span.alert { color: #FF0000; font-weight: bold; text-decoration: underline; } span.basicbold { color: #000000; font-weight: bold; } span.running { color: #38A167; font-weight: bold; } span.autostart_on { color: #38A167; font-weight: bold; } span.autostart_off { color: #C83C3C; font-weight: bold; } span.stopped { color: #C83C3C; font-weight: bold; } td.domainlist:hover { background-color: #7799BB; } td.domainlistselected { background-color: #99BBDD; font-weight: bold; } td.shardlist:hover { background-color: #7799BB; } td.shardlistselected { background-color: #99BBDD; font-weight: bold; } tr.varlist:hover { background-color: #7799BB; } tr.varlistselected { background-color: #99BBDD; } .ws_close { background-color: #888888; } .ws_dev { background-color: #DD8888; } .ws_restricted { background-color: #DDDD88; } .ws_open { background-color: #88DD88; } ================================================ FILE: tools/server/admin/overlib/makemini.pl ================================================ #!/usr/bin/perl my $doPlugin = 0; my $x = shift(@ARGV); if ($x !~ /^-p/) { unshift(@ARGV, $x); } else { $doPlugin=1; } my $injs = shift(@ARGV); my $outjs = shift(@ARGV); if ($injs eq '' or $outjs eq '') { print "Please use this script like this: makemini.pl [-p] in.js out.js\n"; exit(0); } open(INJS, $injs); open(OUTJS, ">$outjs"); my $output = ''; while () { my $line = $_; if ($line =~ /^\/\//) { # Remove lines that aren't important: //\ $line = "" if ($line !~ /^\/\/\\/); $line = "\n//\\ THIS IS A VERY MODIFIED VERSION. DO NOT EDIT OR PUBLISH. GET THE ORIGINAL!\n\n" if ($line =~ /\/\/\\mini/); } else { chop $line; $line =~ s/, /,/g unless ($line =~ /'\], '/); # ,{sp} -> , $line =~ s/; /;/g; # ;{sp} -> ; $line =~ s/ = /=/g; # {sp}={sp} -> = $line =~ s/ == /==/g; # {sp}=={sp} -> == $line =~ s/ < / < $line =~ s/ > />/g; # {sp}>{sp} -> > $line =~ s/ & /&/g; # {sp}&{sp} -> & $line =~ s/ \| /\|/g; # {sp}|{sp} -> | $line =~ s/ <= /<=/g; # {sp}<={sp} -> <= $line =~ s/ >= />=/g; # {sp}>={sp} -> >= $line =~ s/ \+ /\+/g; # {sp}+{sp} -> + $line =~ s/ - /-/g; # {sp}-{sp} -> - $line =~ s/ \/ /\//g; $line =~ s/ \|\| /\|\|/g; # {sp}||{sp} -> || $line =~ s/ && /&&/g; # {sp}&&{sp} -> && $line =~ s/ \? /\?/g; # {sp?{sp} -> ? $line =~ s/ \: /\:/g; # {sp}:{sp} -> : $line =~ s/ != /!=/g; # {sp}!={sp} -> != $line =~ s/ += /+=/g; # {sp}+={sp} -> += $line =~ s/ -= /-=/g; # {sp}-={sp} -> -= $line =~ s/ \*= /\*=/g; # {sp}*={sp} -> *= $line =~ s/ \|= /\|=/g; # {sp}|={sp} -> |= $line =~ s/ \^= /\^=/g; # {sp}^={sp} -> ^= $line =~ s/= /=/g; # ={sp} -> = $line =~ s/ =/=/g; # {sp}= -> = $line =~ s/\+ /\+/g; $line =~ s/ \+/\+/g; $line =~ s/- /-/g; $line =~ s/ -/-/g; $line =~ s/\/\/(.*)$//g if ($line !~ /\/\/-->(.*)$/ && $line !~ /http:\/\/(.*)$/); # remove trailing comments unless its part of a javascript insert or web address $line = '' if $line =~ /^[\n|\/\/]/; # skip blank lines or any line starting with // $line =~ s/^\s+//g; $line =~ s/\s+$//g; $line =~ s/(.+)\s+(.+)/$1 $2/g; $line =~ s/\{ (\w)/\{$1/g; $line =~ s/\) (\w)/\)$1/g; $line =~ s/\) var/\)var/g; $line =~ s/[ ]+\(/\(/g; $line =~ s/\) \{/\)\{/g; $line =~ s/\} else/\}else/g; $line =~ s/else \{/else\{/g; if ($line =~ /^\}$/) { if ($output =~ /;$/) { $output .= "}"; } else { $output = substr($output,0,length($output)-1) . "}"; } $line = ''; } } $output .= $line if ($line ne ''); $output .= "\n" unless ($line =~ /;\n*$/ or $line =~ /{\n*$/); } $output =~ s/\n+/\n/g; $output .= "}\n" if ($doPlugin && $output !~ /\}\s+$/); # replace multiple ;var xx to ,xx if the line contains var @lines = split(/^/,$output); foreach $line (@lines) { $line =~ s/;var /,/g if ($line =~ /^\s*var / && $line !~ /(turn|ment|Capture\(\)|Div'\)|1000\));var /); print OUTJS $line; } ================================================ FILE: tools/server/admin/overlib/overlib.js ================================================ //\///// //\ overLIB 4.21 - You may not remove or change this notice. //\ Copyright Erik Bosrup 1998-2004. All rights reserved. //\ //\ Contributors are listed on the homepage. //\ This file might be old, always check for the latest version at: //\ http://www.bosrup.com/web/overlib/ //\ //\ Please read the license agreement (available through the link above) //\ before using overLIB. Direct any licensing questions to erik@bosrup.com. //\ //\ Do not sell this as your own work or remove this copyright notice. //\ For full details on copying or changing this script please read the //\ license agreement at the link above. Please give credit on sites that //\ use overLIB and submit changes of the script so other people can use //\ them as well. // $Revision: 1.1 $ $Date: 2006/05/29 16:38:21 $ //\///// //\mini //////// // PRE-INIT // Ignore these lines, configuration is below. //////// var olLoaded = 0;var pmStart = 10000000; var pmUpper = 10001000; var pmCount = pmStart+1; var pmt=''; var pms = new Array(); var olInfo = new Info('4.21', 1); var FREPLACE = 0; var FBEFORE = 1; var FAFTER = 2; var FALTERNATE = 3; var FCHAIN=4; var olHideForm=0; // parameter for hiding SELECT and ActiveX elements in IE5.5+ var olHautoFlag = 0; // flags for over-riding VAUTO and HAUTO if corresponding var olVautoFlag = 0; // positioning commands are used on the command line var hookPts = new Array(), postParse = new Array(), cmdLine = new Array(), runTime = new Array(); // for plugins registerCommands('donothing,inarray,caparray,sticky,background,noclose,caption,left,right,center,offsetx,offsety,fgcolor,bgcolor,textcolor,capcolor,closecolor,width,border,cellpad,status,autostatus,autostatuscap,height,closetext,snapx,snapy,fixx,fixy,relx,rely,fgbackground,bgbackground,padx,pady,fullhtml,above,below,capicon,textfont,captionfont,closefont,textsize,captionsize,closesize,timeout,function,delay,hauto,vauto,closeclick,wrap,followmouse,mouseoff,closetitle,cssoff,compatmode,cssclass,fgclass,bgclass,textfontclass,captionfontclass,closefontclass'); //////// // DEFAULT CONFIGURATION // Settings you want everywhere are set here. All of this can also be // changed on your html page or through an overLIB call. //////// if (typeof ol_fgcolor=='undefined') var ol_fgcolor="#99BBDD"; if (typeof ol_bgcolor=='undefined') var ol_bgcolor="#7799BB"; if (typeof ol_textcolor=='undefined') var ol_textcolor="#000000"; if (typeof ol_capcolor=='undefined') var ol_capcolor="#000033"; if (typeof ol_closecolor=='undefined') var ol_closecolor="#000000"; if (typeof ol_textfont=='undefined') var ol_textfont="Verdana,Arial,Helvetica"; if (typeof ol_captionfont=='undefined') var ol_captionfont="Verdana,Arial,Helvetica"; if (typeof ol_closefont=='undefined') var ol_closefont="Verdana,Arial,Helvetica"; if (typeof ol_textsize=='undefined') var ol_textsize="1"; if (typeof ol_captionsize=='undefined') var ol_captionsize="1"; if (typeof ol_closesize=='undefined') var ol_closesize="1"; if (typeof ol_width=='undefined') var ol_width="200"; if (typeof ol_border=='undefined') var ol_border="1"; if (typeof ol_cellpad=='undefined') var ol_cellpad=2; if (typeof ol_offsetx=='undefined') var ol_offsetx=10; if (typeof ol_offsety=='undefined') var ol_offsety=10; if (typeof ol_text=='undefined') var ol_text="Default Text"; if (typeof ol_cap=='undefined') var ol_cap=""; if (typeof ol_sticky=='undefined') var ol_sticky=0; if (typeof ol_background=='undefined') var ol_background=""; if (typeof ol_close=='undefined') var ol_close="Close"; if (typeof ol_hpos=='undefined') var ol_hpos=RIGHT; if (typeof ol_status=='undefined') var ol_status=""; if (typeof ol_autostatus=='undefined') var ol_autostatus=0; if (typeof ol_height=='undefined') var ol_height=-1; if (typeof ol_snapx=='undefined') var ol_snapx=0; if (typeof ol_snapy=='undefined') var ol_snapy=0; if (typeof ol_fixx=='undefined') var ol_fixx=-1; if (typeof ol_fixy=='undefined') var ol_fixy=-1; if (typeof ol_relx=='undefined') var ol_relx=null; if (typeof ol_rely=='undefined') var ol_rely=null; if (typeof ol_fgbackground=='undefined') var ol_fgbackground=""; if (typeof ol_bgbackground=='undefined') var ol_bgbackground=""; if (typeof ol_padxl=='undefined') var ol_padxl=1; if (typeof ol_padxr=='undefined') var ol_padxr=1; if (typeof ol_padyt=='undefined') var ol_padyt=1; if (typeof ol_padyb=='undefined') var ol_padyb=1; if (typeof ol_fullhtml=='undefined') var ol_fullhtml=0; if (typeof ol_vpos=='undefined') var ol_vpos=BELOW; if (typeof ol_aboveheight=='undefined') var ol_aboveheight=0; if (typeof ol_capicon=='undefined') var ol_capicon=""; if (typeof ol_frame=='undefined') var ol_frame=self; if (typeof ol_timeout=='undefined') var ol_timeout=0; if (typeof ol_function=='undefined') var ol_function=null; if (typeof ol_delay=='undefined') var ol_delay=0; if (typeof ol_hauto=='undefined') var ol_hauto=0; if (typeof ol_vauto=='undefined') var ol_vauto=0; if (typeof ol_closeclick=='undefined') var ol_closeclick=0; if (typeof ol_wrap=='undefined') var ol_wrap=0; if (typeof ol_followmouse=='undefined') var ol_followmouse=1; if (typeof ol_mouseoff=='undefined') var ol_mouseoff=0; if (typeof ol_closetitle=='undefined') var ol_closetitle='Close'; if (typeof ol_compatmode=='undefined') var ol_compatmode=0; if (typeof ol_css=='undefined') var ol_css=CSSOFF; if (typeof ol_fgclass=='undefined') var ol_fgclass=""; if (typeof ol_bgclass=='undefined') var ol_bgclass=""; if (typeof ol_textfontclass=='undefined') var ol_textfontclass=""; if (typeof ol_captionfontclass=='undefined') var ol_captionfontclass=""; if (typeof ol_closefontclass=='undefined') var ol_closefontclass=""; //////// // ARRAY CONFIGURATION //////// // You can use these arrays to store popup text here instead of in the html. if (typeof ol_texts=='undefined') var ol_texts = new Array("Text 0", "Text 1"); if (typeof ol_caps=='undefined') var ol_caps = new Array("Caption 0", "Caption 1"); //////// // END OF CONFIGURATION // Don't change anything below this line, all configuration is above. //////// //////// // INIT //////// // Runtime variables init. Don't change for config! var o3_text=""; var o3_cap=""; var o3_sticky=0; var o3_background=""; var o3_close="Close"; var o3_hpos=RIGHT; var o3_offsetx=2; var o3_offsety=2; var o3_fgcolor=""; var o3_bgcolor=""; var o3_textcolor=""; var o3_capcolor=""; var o3_closecolor=""; var o3_width=100; var o3_border=1; var o3_cellpad=2; var o3_status=""; var o3_autostatus=0; var o3_height=-1; var o3_snapx=0; var o3_snapy=0; var o3_fixx=-1; var o3_fixy=-1; var o3_relx=null; var o3_rely=null; var o3_fgbackground=""; var o3_bgbackground=""; var o3_padxl=0; var o3_padxr=0; var o3_padyt=0; var o3_padyb=0; var o3_fullhtml=0; var o3_vpos=BELOW; var o3_aboveheight=0; var o3_capicon=""; var o3_textfont="Verdana,Arial,Helvetica"; var o3_captionfont="Verdana,Arial,Helvetica"; var o3_closefont="Verdana,Arial,Helvetica"; var o3_textsize="1"; var o3_captionsize="1"; var o3_closesize="1"; var o3_frame=self; var o3_timeout=0; var o3_timerid=0; var o3_allowmove=0; var o3_function=null; var o3_delay=0; var o3_delayid=0; var o3_hauto=0; var o3_vauto=0; var o3_closeclick=0; var o3_wrap=0; var o3_followmouse=1; var o3_mouseoff=0; var o3_closetitle=''; var o3_compatmode=0; var o3_css=CSSOFF; var o3_fgclass=""; var o3_bgclass=""; var o3_textfontclass=""; var o3_captionfontclass=""; var o3_closefontclass=""; // Display state variables var o3_x = 0; var o3_y = 0; var o3_showingsticky = 0; var o3_removecounter = 0; // Our layer var over = null; var fnRef, hoveringSwitch = false; var olHideDelay; // Decide browser version var isMac = (navigator.userAgent.indexOf("Mac") != -1); var olOp = (navigator.userAgent.toLowerCase().indexOf('opera') > -1 && document.createTextNode); // Opera 7 var olNs4 = (navigator.appName=='Netscape' && parseInt(navigator.appVersion) == 4); var olNs6 = (document.getElementById) ? true : false; var olKq = (olNs6 && /konqueror/i.test(navigator.userAgent)); var olIe4 = (document.all) ? true : false; var olIe5 = false; var olIe55 = false; // Added additional variable to identify IE5.5+ var docRoot = 'document.body'; // Resize fix for NS4.x to keep track of layer if (olNs4) { var oW = window.innerWidth; var oH = window.innerHeight; window.onresize = function() { if (oW != window.innerWidth || oH != window.innerHeight) location.reload(); } } // Microsoft Stupidity Check(tm). if (olIe4) { var agent = navigator.userAgent; if (/MSIE/.test(agent)) { var versNum = parseFloat(agent.match(/MSIE[ ](\d\.\d+)\.*/i)[1]); if (versNum >= 5){ olIe5=true; olIe55=(versNum>=5.5&&!olOp) ? true : false; if (olNs6) olNs6=false; } } if (olNs6) olIe4 = false; } // Check for compatability mode. if (document.compatMode && document.compatMode == 'CSS1Compat') { docRoot= ((olIe4 && !olOp) ? 'document.documentElement' : docRoot); } // Add window onload handlers to indicate when all modules have been loaded // For Netscape 6+ and Mozilla, uses addEventListener method on the window object // For IE it uses the attachEvent method of the window object and for Netscape 4.x // it sets the window.onload handler to the OLonload_handler function for Bubbling if(window.addEventListener) window.addEventListener("load",OLonLoad_handler,false); else if (window.attachEvent) window.attachEvent("onload",OLonLoad_handler); var capExtent; //////// // PUBLIC FUNCTIONS //////// // overlib(arg0,...,argN) // Loads parameters into global runtime variables. function overlib() { if (!olLoaded || isExclusive(overlib.arguments)) return true; if (olCheckMouseCapture) olMouseCapture(); if (over) { over = (typeof over.id != 'string') ? o3_frame.document.all['overDiv'] : over; cClick(); } // Load defaults to runtime. olHideDelay=0; o3_text=ol_text; o3_cap=ol_cap; o3_sticky=ol_sticky; o3_background=ol_background; o3_close=ol_close; o3_hpos=ol_hpos; o3_offsetx=ol_offsetx; o3_offsety=ol_offsety; o3_fgcolor=ol_fgcolor; o3_bgcolor=ol_bgcolor; o3_textcolor=ol_textcolor; o3_capcolor=ol_capcolor; o3_closecolor=ol_closecolor; o3_width=ol_width; o3_border=ol_border; o3_cellpad=ol_cellpad; o3_status=ol_status; o3_autostatus=ol_autostatus; o3_height=ol_height; o3_snapx=ol_snapx; o3_snapy=ol_snapy; o3_fixx=ol_fixx; o3_fixy=ol_fixy; o3_relx=ol_relx; o3_rely=ol_rely; o3_fgbackground=ol_fgbackground; o3_bgbackground=ol_bgbackground; o3_padxl=ol_padxl; o3_padxr=ol_padxr; o3_padyt=ol_padyt; o3_padyb=ol_padyb; o3_fullhtml=ol_fullhtml; o3_vpos=ol_vpos; o3_aboveheight=ol_aboveheight; o3_capicon=ol_capicon; o3_textfont=ol_textfont; o3_captionfont=ol_captionfont; o3_closefont=ol_closefont; o3_textsize=ol_textsize; o3_captionsize=ol_captionsize; o3_closesize=ol_closesize; o3_timeout=ol_timeout; o3_function=ol_function; o3_delay=ol_delay; o3_hauto=ol_hauto; o3_vauto=ol_vauto; o3_closeclick=ol_closeclick; o3_wrap=ol_wrap; o3_followmouse=ol_followmouse; o3_mouseoff=ol_mouseoff; o3_closetitle=ol_closetitle; o3_css=ol_css; o3_compatmode=ol_compatmode; o3_fgclass=ol_fgclass; o3_bgclass=ol_bgclass; o3_textfontclass=ol_textfontclass; o3_captionfontclass=ol_captionfontclass; o3_closefontclass=ol_closefontclass; setRunTimeVariables(); fnRef = ''; // Special for frame support, over must be reset... o3_frame = ol_frame; if(!(over=createDivContainer())) return false; parseTokens('o3_', overlib.arguments); if (!postParseChecks()) return false; if (o3_delay == 0) { return runHook("olMain", FREPLACE); } else { o3_delayid = setTimeout("runHook('olMain', FREPLACE)", o3_delay); return false; } } // Clears popups if appropriate function nd(time) { if (olLoaded && !isExclusive()) { hideDelay(time); // delay popup close if time specified if (o3_removecounter >= 1) { o3_showingsticky = 0 }; if (o3_showingsticky == 0) { o3_allowmove = 0; if (over != null && o3_timerid == 0) runHook("hideObject", FREPLACE, over); } else { o3_removecounter++; } } return true; } // The Close onMouseOver function for stickies function cClick() { if (olLoaded) { runHook("hideObject", FREPLACE, over); o3_showingsticky = 0; } return false; } // Method for setting page specific defaults. function overlib_pagedefaults() { parseTokens('ol_', overlib_pagedefaults.arguments); } //////// // OVERLIB MAIN FUNCTION //////// // This function decides what it is we want to display and how we want it done. function olMain() { var layerhtml, styleType; runHook("olMain", FBEFORE); if (o3_background!="" || o3_fullhtml) { // Use background instead of box. layerhtml = runHook('ol_content_background', FALTERNATE, o3_css, o3_text, o3_background, o3_fullhtml); } else { // They want a popup box. styleType = (pms[o3_css-1-pmStart] == "cssoff" || pms[o3_css-1-pmStart] == "cssclass"); // Prepare popup background if (o3_fgbackground != "") o3_fgbackground = "background=\""+o3_fgbackground+"\""; if (o3_bgbackground != "") o3_bgbackground = (styleType ? "background=\""+o3_bgbackground+"\"" : o3_bgbackground); // Prepare popup colors if (o3_fgcolor != "") o3_fgcolor = (styleType ? "bgcolor=\""+o3_fgcolor+"\"" : o3_fgcolor); if (o3_bgcolor != "") o3_bgcolor = (styleType ? "bgcolor=\""+o3_bgcolor+"\"" : o3_bgcolor); // Prepare popup height if (o3_height > 0) o3_height = (styleType ? "height=\""+o3_height+"\"" : o3_height); else o3_height = ""; // Decide which kinda box. if (o3_cap=="") { // Plain layerhtml = runHook('ol_content_simple', FALTERNATE, o3_css, o3_text); } else { // With caption if (o3_sticky) { // Show close text layerhtml = runHook('ol_content_caption', FALTERNATE, o3_css, o3_text, o3_cap, o3_close); } else { // No close text layerhtml = runHook('ol_content_caption', FALTERNATE, o3_css, o3_text, o3_cap, ""); } } } // We want it to stick! if (o3_sticky) { if (o3_timerid > 0) { clearTimeout(o3_timerid); o3_timerid = 0; } o3_showingsticky = 1; o3_removecounter = 0; } // Created a separate routine to generate the popup to make it easier // to implement a plugin capability if (!runHook("createPopup", FREPLACE, layerhtml)) return false; // Prepare status bar if (o3_autostatus > 0) { o3_status = o3_text; if (o3_autostatus > 1) o3_status = o3_cap; } // When placing the layer the first time, even stickies may be moved. o3_allowmove = 0; // Initiate a timer for timeout if (o3_timeout > 0) { if (o3_timerid > 0) clearTimeout(o3_timerid); o3_timerid = setTimeout("cClick()", o3_timeout); } // Show layer runHook("disp", FREPLACE, o3_status); runHook("olMain", FAFTER); return (olOp && event && event.type == 'mouseover' && !o3_status) ? '' : (o3_status != ''); } //////// // LAYER GENERATION FUNCTIONS //////// // These functions just handle popup content with tags that should adhere to the W3C standards specification. // Makes simple table without caption function ol_content_simple(text) { var cpIsMultiple = /,/.test(o3_cellpad); var txt = '
' : ((!olNs4&&cpIsMultiple) ? ' style="'+setCellPadStr(o3_cellpad)+'">' : '>'))+(o3_textfontclass ? '' : wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass ? '' : wrapStr(1,o3_textsize))+'
'; set_background(""); return txt; } // Makes table with caption and optional close link function ol_content_caption(text,title,close) { var nameId, txt, cpIsMultiple = /,/.test(o3_cellpad); var closing, closeevent; closing = ""; closeevent = "onmouseover"; if (o3_closeclick == 1) closeevent = (o3_closetitle ? "title='" + o3_closetitle +"'" : "") + " onclick"; if (o3_capicon != "") { nameId = ' hspace = \"5\"'+' align = \"middle\" alt = \"\"'; if (typeof o3_dragimg != 'undefined' && o3_dragimg) nameId =' hspace=\"5\"'+' name=\"'+o3_dragimg+'\" id=\"'+o3_dragimg+'\" align=\"middle\" alt=\"Drag Enabled\" title=\"Drag Enabled\"'; o3_capicon = ''; } if (close != "") closing = ''+(o3_closefontclass ? '' : wrapStr(0,o3_closesize,'close'))+close+(o3_closefontclass ? '' : wrapStr(1,o3_closesize,'close'))+''; txt = '
' : '>')+(o3_captionfontclass ? '' : ''+wrapStr(0,o3_captionsize,'caption'))+o3_capicon+title+(o3_captionfontclass ? '' : wrapStr(1,o3_captionsize)+'')+''+closing+'
' :((!olNs4&&cpIsMultiple) ? ' style="'+setCellPadStr(o3_cellpad)+'">' : '>'))+(o3_textfontclass ? '' : wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass ? '' : wrapStr(1,o3_textsize)) + '
'; set_background(""); return txt; } // Sets the background picture,padding and lots more. :) function ol_content_background(text,picture,hasfullhtml) { if (hasfullhtml) { txt=text; } else { txt='
'+(o3_textfontclass ? '' : wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass ? '' : wrapStr(1,o3_textsize))+'
'; } set_background(picture); return txt; } // Loads a picture into the div. function set_background(pic) { if (pic == "") { if (olNs4) { over.background.src = null; } else if (over.style) { over.style.backgroundImage = "none"; } } else { if (olNs4) { over.background.src = pic; } else if (over.style) { over.style.width=o3_width + 'px'; over.style.backgroundImage = "url("+pic+")"; } } } //////// // HANDLING FUNCTIONS //////// var olShowId=-1; // Displays the popup function disp(statustext) { runHook("disp", FBEFORE); if (o3_allowmove == 0) { runHook("placeLayer", FREPLACE); (olNs6&&olShowId<0) ? olShowId=setTimeout("runHook('showObject', FREPLACE, over)", 1) : runHook("showObject", FREPLACE, over); o3_allowmove = (o3_sticky || o3_followmouse==0) ? 0 : 1; } runHook("disp", FAFTER); if (statustext != "") self.status = statustext; } // Creates the actual popup structure function createPopup(lyrContent){ runHook("createPopup", FBEFORE); if (o3_wrap) { var wd,ww,theObj = (olNs4 ? over : over.style); theObj.top = theObj.left = ((olIe4&&!olOp) ? 0 : -10000) + (!olNs4 ? 'px' : 0); layerWrite(lyrContent); wd = (olNs4 ? over.clip.width : over.offsetWidth); if (wd > (ww=windowWidth())) { lyrContent=lyrContent.replace(/\ /g, ' '); o3_width=ww; o3_wrap=0; } } layerWrite(lyrContent); // Have to set o3_width for placeLayer() routine if o3_wrap is turned on if (o3_wrap) o3_width=(olNs4 ? over.clip.width : over.offsetWidth); runHook("createPopup", FAFTER, lyrContent); return true; } // Decides where we want the popup. function placeLayer() { var placeX, placeY, widthFix = 0; // HORIZONTAL PLACEMENT, re-arranged to work in Safari if (o3_frame.innerWidth) widthFix=18; iwidth = windowWidth(); // Horizontal scroll offset winoffset=(olIe4) ? eval('o3_frame.'+docRoot+'.scrollLeft') : o3_frame.pageXOffset; placeX = runHook('horizontalPlacement',FCHAIN,iwidth,winoffset,widthFix); // VERTICAL PLACEMENT, re-arranged to work in Safari if (o3_frame.innerHeight) { iheight=o3_frame.innerHeight; } else if (eval('o3_frame.'+docRoot)&&eval("typeof o3_frame."+docRoot+".clientHeight=='number'")&&eval('o3_frame.'+docRoot+'.clientHeight')) { iheight=eval('o3_frame.'+docRoot+'.clientHeight'); } // Vertical scroll offset scrolloffset=(olIe4) ? eval('o3_frame.'+docRoot+'.scrollTop') : o3_frame.pageYOffset; placeY = runHook('verticalPlacement',FCHAIN,iheight,scrolloffset); // Actually move the object. repositionTo(over, placeX, placeY); } // Moves the layer function olMouseMove(e) { var e = (e) ? e : event; if (e.pageX) { o3_x = e.pageX; o3_y = e.pageY; } else if (e.clientX) { o3_x = eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft'); o3_y = eval('e.clientY+o3_frame.'+docRoot+'.scrollTop'); } if (o3_allowmove == 1) runHook("placeLayer", FREPLACE); // MouseOut handler if (hoveringSwitch && !olNs4 && runHook("cursorOff", FREPLACE)) { (olHideDelay ? hideDelay(olHideDelay) : cClick()); hoveringSwitch = !hoveringSwitch; } } // Fake function for 3.0 users. function no_overlib() { return ver3fix; } // Capture the mouse and chain other scripts. function olMouseCapture() { capExtent = document; var fN, str = '', l, k, f, wMv, sS, mseHandler = olMouseMove; var re = /function[ ]*(\w*)\(/; wMv = (!olIe4 && window.onmousemove); if (document.onmousemove || wMv) { if (wMv) capExtent = window; f = capExtent.onmousemove.toString(); fN = f.match(re); if (fN == null) { str = f+'(e); '; } else if (fN[1] == 'anonymous' || fN[1] == 'olMouseMove' || (wMv && fN[1] == 'onmousemove')) { if (!olOp && wMv) { l = f.indexOf('{')+1; k = f.lastIndexOf('}'); sS = f.substring(l,k); if ((l = sS.indexOf('(')) != -1) { sS = sS.substring(0,l).replace(/^\s+/,'').replace(/\s+$/,''); if (eval("typeof " + sS + " == 'undefined'")) window.onmousemove = null; else str = sS + '(e);'; } } if (!str) { olCheckMouseCapture = false; return; } } else { if (fN[1]) str = fN[1]+'(e); '; else { l = f.indexOf('{')+1; k = f.lastIndexOf('}'); str = f.substring(l,k) + '\n'; } } str += 'olMouseMove(e); '; mseHandler = new Function('e', str); } capExtent.onmousemove = mseHandler; if (olNs4) capExtent.captureEvents(Event.MOUSEMOVE); } //////// // PARSING FUNCTIONS //////// // Does the actual command parsing. function parseTokens(pf, ar) { // What the next argument is expected to be. var v, i, mode=-1, par = (pf != 'ol_'); var fnMark = (par && !ar.length ? 1 : 0); for (i = 0; i < ar.length; i++) { if (mode < 0) { // Arg is maintext,unless its a number between pmStart and pmUpper // then its a command. if (typeof ar[i] == 'number' && ar[i] > pmStart && ar[i] < pmUpper) { fnMark = (par ? 1 : 0); i--; // backup one so that the next block can parse it } else { switch(pf) { case 'ol_': ol_text = ar[i].toString(); break; default: o3_text=ar[i].toString(); } } mode = 0; } else { // Note: NS4 doesn't like switch cases with vars. if (ar[i] >= pmCount || ar[i]==DONOTHING) { continue; } if (ar[i]==INARRAY) { fnMark = 0; eval(pf+'text=ol_texts['+ar[++i]+'].toString()'); continue; } if (ar[i]==CAPARRAY) { eval(pf+'cap=ol_caps['+ar[++i]+'].toString()'); continue; } if (ar[i]==STICKY) { if (pf!='ol_') eval(pf+'sticky=1'); continue; } if (ar[i]==BACKGROUND) { eval(pf+'background="'+ar[++i]+'"'); continue; } if (ar[i]==NOCLOSE) { if (pf!='ol_') opt_NOCLOSE(); continue; } if (ar[i]==CAPTION) { eval(pf+"cap='"+escSglQuote(ar[++i])+"'"); continue; } if (ar[i]==CENTER || ar[i]==LEFT || ar[i]==RIGHT) { eval(pf+'hpos='+ar[i]); if(pf!='ol_') olHautoFlag=1; continue; } if (ar[i]==OFFSETX) { eval(pf+'offsetx='+ar[++i]); continue; } if (ar[i]==OFFSETY) { eval(pf+'offsety='+ar[++i]); continue; } if (ar[i]==FGCOLOR) { eval(pf+'fgcolor="'+ar[++i]+'"'); continue; } if (ar[i]==BGCOLOR) { eval(pf+'bgcolor="'+ar[++i]+'"'); continue; } if (ar[i]==TEXTCOLOR) { eval(pf+'textcolor="'+ar[++i]+'"'); continue; } if (ar[i]==CAPCOLOR) { eval(pf+'capcolor="'+ar[++i]+'"'); continue; } if (ar[i]==CLOSECOLOR) { eval(pf+'closecolor="'+ar[++i]+'"'); continue; } if (ar[i]==WIDTH) { eval(pf+'width='+ar[++i]); continue; } if (ar[i]==BORDER) { eval(pf+'border='+ar[++i]); continue; } if (ar[i]==CELLPAD) { i=opt_MULTIPLEARGS(++i,ar,(pf+'cellpad')); continue; } if (ar[i]==STATUS) { eval(pf+"status='"+escSglQuote(ar[++i])+"'"); continue; } if (ar[i]==AUTOSTATUS) { eval(pf +'autostatus=('+pf+'autostatus == 1) ? 0 : 1'); continue; } if (ar[i]==AUTOSTATUSCAP) { eval(pf +'autostatus=('+pf+'autostatus == 2) ? 0 : 2'); continue; } if (ar[i]==HEIGHT) { eval(pf+'height='+pf+'aboveheight='+ar[++i]); continue; } // Same param again. if (ar[i]==CLOSETEXT) { eval(pf+"close='"+escSglQuote(ar[++i])+"'"); continue; } if (ar[i]==SNAPX) { eval(pf+'snapx='+ar[++i]); continue; } if (ar[i]==SNAPY) { eval(pf+'snapy='+ar[++i]); continue; } if (ar[i]==FIXX) { eval(pf+'fixx='+ar[++i]); continue; } if (ar[i]==FIXY) { eval(pf+'fixy='+ar[++i]); continue; } if (ar[i]==RELX) { eval(pf+'relx='+ar[++i]); continue; } if (ar[i]==RELY) { eval(pf+'rely='+ar[++i]); continue; } if (ar[i]==FGBACKGROUND) { eval(pf+'fgbackground="'+ar[++i]+'"'); continue; } if (ar[i]==BGBACKGROUND) { eval(pf+'bgbackground="'+ar[++i]+'"'); continue; } if (ar[i]==PADX) { eval(pf+'padxl='+ar[++i]); eval(pf+'padxr='+ar[++i]); continue; } if (ar[i]==PADY) { eval(pf+'padyt='+ar[++i]); eval(pf+'padyb='+ar[++i]); continue; } if (ar[i]==FULLHTML) { if (pf!='ol_') eval(pf+'fullhtml=1'); continue; } if (ar[i]==BELOW || ar[i]==ABOVE) { eval(pf+'vpos='+ar[i]); if (pf!='ol_') olVautoFlag=1; continue; } if (ar[i]==CAPICON) { eval(pf+'capicon="'+ar[++i]+'"'); continue; } if (ar[i]==TEXTFONT) { eval(pf+"textfont='"+escSglQuote(ar[++i])+"'"); continue; } if (ar[i]==CAPTIONFONT) { eval(pf+"captionfont='"+escSglQuote(ar[++i])+"'"); continue; } if (ar[i]==CLOSEFONT) { eval(pf+"closefont='"+escSglQuote(ar[++i])+"'"); continue; } if (ar[i]==TEXTSIZE) { eval(pf+'textsize="'+ar[++i]+'"'); continue; } if (ar[i]==CAPTIONSIZE) { eval(pf+'captionsize="'+ar[++i]+'"'); continue; } if (ar[i]==CLOSESIZE) { eval(pf+'closesize="'+ar[++i]+'"'); continue; } if (ar[i]==TIMEOUT) { eval(pf+'timeout='+ar[++i]); continue; } if (ar[i]==FUNCTION) { if (pf=='ol_') { if (typeof ar[i+1]!='number') { v=ar[++i]; ol_function=(typeof v=='function' ? v : null); }} else {fnMark = 0; v = null; if (typeof ar[i+1]!='number') v = ar[++i]; opt_FUNCTION(v); } continue; } if (ar[i]==DELAY) { eval(pf+'delay='+ar[++i]); continue; } if (ar[i]==HAUTO) { eval(pf+'hauto=('+pf+'hauto == 0) ? 1 : 0'); continue; } if (ar[i]==VAUTO) { eval(pf+'vauto=('+pf+'vauto == 0) ? 1 : 0'); continue; } if (ar[i]==CLOSECLICK) { eval(pf +'closeclick=('+pf+'closeclick == 0) ? 1 : 0'); continue; } if (ar[i]==WRAP) { eval(pf +'wrap=('+pf+'wrap == 0) ? 1 : 0'); continue; } if (ar[i]==FOLLOWMOUSE) { eval(pf +'followmouse=('+pf+'followmouse == 1) ? 0 : 1'); continue; } if (ar[i]==MOUSEOFF) { eval(pf +'mouseoff=('+pf+'mouseoff==0) ? 1 : 0'); v=ar[i+1]; if (pf != 'ol_' && eval(pf+'mouseoff') && typeof v == 'number' && (v < pmStart || v > pmUpper)) olHideDelay=ar[++i]; continue; } if (ar[i]==CLOSETITLE) { eval(pf+"closetitle='"+escSglQuote(ar[++i])+"'"); continue; } if (ar[i]==CSSOFF||ar[i]==CSSCLASS) { eval(pf+'css='+ar[i]); continue; } if (ar[i]==COMPATMODE) { eval(pf+'compatmode=('+pf+'compatmode==0) ? 1 : 0'); continue; } if (ar[i]==FGCLASS) { eval(pf+'fgclass="'+ar[++i]+'"'); continue; } if (ar[i]==BGCLASS) { eval(pf+'bgclass="'+ar[++i]+'"'); continue; } if (ar[i]==TEXTFONTCLASS) { eval(pf+'textfontclass="'+ar[++i]+'"'); continue; } if (ar[i]==CAPTIONFONTCLASS) { eval(pf+'captionfontclass="'+ar[++i]+'"'); continue; } if (ar[i]==CLOSEFONTCLASS) { eval(pf+'closefontclass="'+ar[++i]+'"'); continue; } i = parseCmdLine(pf, i, ar); } } if (fnMark && o3_function) o3_text = o3_function(); if ((pf == 'o3_') && o3_wrap) { o3_width = 0; var tReg=/<.*\n*>/ig; if (!tReg.test(o3_text)) o3_text = o3_text.replace(/[ ]+/g, ' '); if (!tReg.test(o3_cap))o3_cap = o3_cap.replace(/[ ]+/g, ' '); } if ((pf == 'o3_') && o3_sticky) { if (!o3_close && (o3_frame != ol_frame)) o3_close = ol_close; if (o3_mouseoff && (o3_frame == ol_frame)) opt_NOCLOSE(' '); } } //////// // LAYER FUNCTIONS //////// // Writes to a layer function layerWrite(txt) { txt += "\n"; if (olNs4) { var lyr = o3_frame.document.layers['overDiv'].document lyr.write(txt) lyr.close() } else if (typeof over.innerHTML != 'undefined') { if (olIe5 && isMac) over.innerHTML = ''; over.innerHTML = txt; } else { range = o3_frame.document.createRange(); range.setStartAfter(over); domfrag = range.createContextualFragment(txt); while (over.hasChildNodes()) { over.removeChild(over.lastChild); } over.appendChild(domfrag); } } // Make an object visible function showObject(obj) { runHook("showObject", FBEFORE); var theObj=(olNs4 ? obj : obj.style); theObj.visibility = 'visible'; runHook("showObject", FAFTER); } // Hides an object function hideObject(obj) { runHook("hideObject", FBEFORE); var theObj=(olNs4 ? obj : obj.style); if (olNs6 && olShowId>0) { clearTimeout(olShowId); olShowId=0; } theObj.visibility = 'hidden'; theObj.top = theObj.left = ((olIe4&&!olOp) ? 0 : -10000) + (!olNs4 ? 'px' : 0); if (o3_timerid > 0) clearTimeout(o3_timerid); if (o3_delayid > 0) clearTimeout(o3_delayid); o3_timerid = 0; o3_delayid = 0; self.status = ""; if (obj.onmouseout||obj.onmouseover) { if (olNs4) obj.releaseEvents(Event.MOUSEOUT || Event.MOUSEOVER); obj.onmouseout = obj.onmouseover = null; } runHook("hideObject", FAFTER); } // Move a layer function repositionTo(obj, xL, yL) { var theObj=(olNs4 ? obj : obj.style); theObj.left = xL + (!olNs4 ? 'px' : 0); theObj.top = yL + (!olNs4 ? 'px' : 0); } // Check position of cursor relative to overDiv DIVision; mouseOut function function cursorOff() { var left = parseInt(over.style.left); var top = parseInt(over.style.top); var right = left + (over.offsetWidth >= parseInt(o3_width) ? over.offsetWidth : parseInt(o3_width)); var bottom = top + (over.offsetHeight >= o3_aboveheight ? over.offsetHeight : o3_aboveheight); if (o3_x < left || o3_x > right || o3_y < top || o3_y > bottom) return true; return false; } //////// // COMMAND FUNCTIONS //////// // Calls callme or the default function. function opt_FUNCTION(callme) { o3_text = (callme ? (typeof callme=='string' ? (/.+\(.*\)/.test(callme) ? eval(callme) : callme) : callme()) : (o3_function ? o3_function() : 'No Function')); return 0; } // Handle hovering function opt_NOCLOSE(unused) { if (!unused) o3_close = ""; if (olNs4) { over.captureEvents(Event.MOUSEOUT || Event.MOUSEOVER); over.onmouseover = function () { if (o3_timerid > 0) { clearTimeout(o3_timerid); o3_timerid = 0; } } over.onmouseout = function (e) { if (olHideDelay) hideDelay(olHideDelay); else cClick(e); } } else { over.onmouseover = function () {hoveringSwitch = true; if (o3_timerid > 0) { clearTimeout(o3_timerid); o3_timerid =0; } } } return 0; } // Function to scan command line arguments for multiples function opt_MULTIPLEARGS(i, args, parameter) { var k=i, re, pV, str=''; for(k=i; kpmStart) break; str += args[k] + ','; } if (str) str = str.substring(0,--str.length); k--; // reduce by one so the for loop this is in works correctly pV=(olNs4 && /cellpad/i.test(parameter)) ? str.split(',')[0] : str; eval(parameter + '="' + pV + '"'); return k; } // Remove   in texts when done. function nbspCleanup() { if (o3_wrap) { o3_text = o3_text.replace(/\ /g, ' '); o3_cap = o3_cap.replace(/\ /g, ' '); } } // Escape embedded single quotes in text strings function escSglQuote(str) { return str.toString().replace(/'/g,"\\'"); } // Onload handler for window onload event function OLonLoad_handler(e) { var re = /\w+\(.*\)[;\s]+/g, olre = /overlib\(|nd\(|cClick\(/, fn, l, i; if(!olLoaded) olLoaded=1; // Remove it for Gecko based browsers if(window.removeEventListener && e.eventPhase == 3) window.removeEventListener("load",OLonLoad_handler,false); else if(window.detachEvent) { // and for IE and Opera 4.x but execute calls to overlib, nd, or cClick() window.detachEvent("onload",OLonLoad_handler); var fN = document.body.getAttribute('onload'); if (fN) { fN=fN.toString().match(re); if (fN && fN.length) { for (i=0; i' : '') : ''; else { fontStr='o3_'+whichString+'font'; fontColor='o3_'+((whichString=='caption')? 'cap' : whichString)+'color'; return (hasDims&&!olNs4) ? (isClose ? '' : '

') : ''; } } // Quotes Multi word font names; needed for CSS Standards adherence in font-family function quoteMultiNameFonts(theFont) { var v, pM=theFont.split(','); for (var i=0; i 0) clearTimeout(o3_timerid); o3_timerid=setTimeout("cClick()",(o3_timeout=time)); } } // Was originally in the placeLayer() routine; separated out for future ease function horizontalPlacement(browserWidth, horizontalScrollAmount, widthFix) { var placeX, iwidth=browserWidth, winoffset=horizontalScrollAmount; var parsedWidth = parseInt(o3_width); if (o3_fixx > -1 || o3_relx != null) { // Fixed position placeX=(o3_relx != null ? ( o3_relx < 0 ? winoffset +o3_relx+ iwidth - parsedWidth - widthFix : winoffset+o3_relx) : o3_fixx); } else { // If HAUTO, decide what to use. if (o3_hauto == 1) { if ((o3_x - winoffset) > (iwidth / 2)) { o3_hpos = LEFT; } else { o3_hpos = RIGHT; } } // From mouse if (o3_hpos == CENTER) { // Center placeX = o3_x+o3_offsetx-(parsedWidth/2); if (placeX < winoffset) placeX = winoffset; } if (o3_hpos == RIGHT) { // Right placeX = o3_x+o3_offsetx; if ((placeX+parsedWidth) > (winoffset+iwidth - widthFix)) { placeX = iwidth+winoffset - parsedWidth - widthFix; if (placeX < 0) placeX = 0; } } if (o3_hpos == LEFT) { // Left placeX = o3_x-o3_offsetx-parsedWidth; if (placeX < winoffset) placeX = winoffset; } // Snapping! if (o3_snapx > 1) { var snapping = placeX % o3_snapx; if (o3_hpos == LEFT) { placeX = placeX - (o3_snapx+snapping); } else { // CENTER and RIGHT placeX = placeX+(o3_snapx - snapping); } if (placeX < winoffset) placeX = winoffset; } } return placeX; } // was originally in the placeLayer() routine; separated out for future ease function verticalPlacement(browserHeight,verticalScrollAmount) { var placeY, iheight=browserHeight, scrolloffset=verticalScrollAmount; var parsedHeight=(o3_aboveheight ? parseInt(o3_aboveheight) : (olNs4 ? over.clip.height : over.offsetHeight)); if (o3_fixy > -1 || o3_rely != null) { // Fixed position placeY=(o3_rely != null ? (o3_rely < 0 ? scrolloffset+o3_rely+iheight - parsedHeight : scrolloffset+o3_rely) : o3_fixy); } else { // If VAUTO, decide what to use. if (o3_vauto == 1) { if ((o3_y - scrolloffset) > (iheight / 2) && o3_vpos == BELOW && (o3_y + parsedHeight + o3_offsety - (scrolloffset + iheight) > 0)) { o3_vpos = ABOVE; } else if (o3_vpos == ABOVE && (o3_y - (parsedHeight + o3_offsety) - scrolloffset < 0)) { o3_vpos = BELOW; } } // From mouse if (o3_vpos == ABOVE) { if (o3_aboveheight == 0) o3_aboveheight = parsedHeight; placeY = o3_y - (o3_aboveheight+o3_offsety); if (placeY < scrolloffset) placeY = scrolloffset; } else { // BELOW placeY = o3_y+o3_offsety; } // Snapping! if (o3_snapy > 1) { var snapping = placeY % o3_snapy; if (o3_aboveheight > 0 && o3_vpos == ABOVE) { placeY = placeY - (o3_snapy+snapping); } else { placeY = placeY+(o3_snapy - snapping); } if (placeY < scrolloffset) placeY = scrolloffset; } } return placeY; } // checks positioning flags function checkPositionFlags() { if (olHautoFlag) olHautoFlag = o3_hauto=0; if (olVautoFlag) olVautoFlag = o3_vauto=0; return true; } // get Browser window width function windowWidth() { var w; if (o3_frame.innerWidth) w=o3_frame.innerWidth; else if (eval('o3_frame.'+docRoot)&&eval("typeof o3_frame."+docRoot+".clientWidth=='number'")&&eval('o3_frame.'+docRoot+'.clientWidth')) w=eval('o3_frame.'+docRoot+'.clientWidth'); return w; } // create the div container for popup content if it doesn't exist function createDivContainer(id,frm,zValue) { id = (id || 'overDiv'), frm = (frm || o3_frame), zValue = (zValue || 1000); var objRef, divContainer = layerReference(id); if (divContainer == null) { if (olNs4) { divContainer = frm.document.layers[id] = new Layer(window.innerWidth, frm); objRef = divContainer; } else { var body = (olIe4 ? frm.document.all.tags('BODY')[0] : frm.document.getElementsByTagName("BODY")[0]); if (olIe4&&!document.getElementById) { body.insertAdjacentHTML("beforeEnd",'
'); divContainer=layerReference(id); } else { divContainer = frm.document.createElement("DIV"); divContainer.id = id; body.appendChild(divContainer); } objRef = divContainer.style; } objRef.position = 'absolute'; objRef.visibility = 'hidden'; objRef.zIndex = zValue; if (olIe4&&!olOp) objRef.left = objRef.top = '0px'; else objRef.left = objRef.top = -10000 + (!olNs4 ? 'px' : 0); } return divContainer; } // get reference to a layer with ID=id function layerReference(id) { return (olNs4 ? o3_frame.document.layers[id] : (document.all ? o3_frame.document.all[id] : o3_frame.document.getElementById(id))); } //////// // UTILITY FUNCTIONS //////// // Checks if something is a function. function isFunction(fnRef) { var rtn = true; if (typeof fnRef == 'object') { for (var i = 0; i < fnRef.length; i++) { if (typeof fnRef[i]=='function') continue; rtn = false; break; } } else if (typeof fnRef != 'function') { rtn = false; } return rtn; } // Converts an array into an argument string for use in eval. function argToString(array, strtInd, argName) { var jS = strtInd, aS = '', ar = array; argName=(argName ? argName : 'ar'); if (ar.length > jS) { for (var k = jS; k < ar.length; k++) aS += argName+'['+k+'], '; aS = aS.substring(0, aS.length-2); } return aS; } // Places a hook in the correct position in a hook point. function reOrder(hookPt, fnRef, order) { var newPt = new Array(), match, i, j; if (!order || typeof order == 'undefined' || typeof order == 'number') return hookPt; if (typeof order=='function') { if (typeof fnRef=='object') { newPt = newPt.concat(fnRef); } else { newPt[newPt.length++]=fnRef; } for (i = 0; i < hookPt.length; i++) { match = false; if (typeof fnRef == 'function' && hookPt[i] == fnRef) { continue; } else { for(j = 0; j < fnRef.length; j++) if (hookPt[i] == fnRef[j]) { match = true; break; } } if (!match) newPt[newPt.length++] = hookPt[i]; } newPt[newPt.length++] = order; } else if (typeof order == 'object') { if (typeof fnRef == 'object') { newPt = newPt.concat(fnRef); } else { newPt[newPt.length++] = fnRef; } for (j = 0; j < hookPt.length; j++) { match = false; if (typeof fnRef == 'function' && hookPt[j] == fnRef) { continue; } else { for (i = 0; i < fnRef.length; i++) if (hookPt[j] == fnRef[i]) { match = true; break; } } if (!match) newPt[newPt.length++]=hookPt[j]; } for (i = 0; i < newPt.length; i++) hookPt[i] = newPt[i]; newPt.length = 0; for (j = 0; j < hookPt.length; j++) { match = false; for (i = 0; i < order.length; i++) { if (hookPt[j] == order[i]) { match = true; break; } } if (!match) newPt[newPt.length++] = hookPt[j]; } newPt = newPt.concat(order); } hookPt = newPt; return hookPt; } //////// // PLUGIN ACTIVATION FUNCTIONS //////// // Runs plugin functions to set runtime variables. function setRunTimeVariables(){ if (typeof runTime != 'undefined' && runTime.length) { for (var k = 0; k < runTime.length; k++) { runTime[k](); } } } // Runs plugin functions to parse commands. function parseCmdLine(pf, i, args) { if (typeof cmdLine != 'undefined' && cmdLine.length) { for (var k = 0; k < cmdLine.length; k++) { var j = cmdLine[k](pf, i, args); if (j >- 1) { i = j; break; } } } return i; } // Runs plugin functions to do things after parse. function postParseChecks(pf,args){ if (typeof postParse != 'undefined' && postParse.length) { for (var k = 0; k < postParse.length; k++) { if (postParse[k](pf,args)) continue; return false; // end now since have an error } } return true; } //////// // PLUGIN REGISTRATION FUNCTIONS //////// // Registers commands and creates constants. function registerCommands(cmdStr) { if (typeof cmdStr!='string') return; var pM = cmdStr.split(','); pms = pms.concat(pM); for (var i = 0; i< pM.length; i++) { eval(pM[i].toUpperCase()+'='+pmCount++); } } // Registers no-parameter commands function registerNoParameterCommands(cmdStr) { if (!cmdStr && typeof cmdStr != 'string') return; pmt=(!pmt) ? cmdStr : pmt + ',' + cmdStr; } // Register a function to hook at a certain point. function registerHook(fnHookTo, fnRef, hookType, optPm) { var hookPt, last = typeof optPm; if (fnHookTo == 'plgIn'||fnHookTo == 'postParse') return; if (typeof hookPts[fnHookTo] == 'undefined') hookPts[fnHookTo] = new FunctionReference(); hookPt = hookPts[fnHookTo]; if (hookType != null) { if (hookType == FREPLACE) { hookPt.ovload = fnRef; // replace normal overlib routine if (fnHookTo.indexOf('ol_content_') > -1) hookPt.alt[pms[CSSOFF-1-pmStart]]=fnRef; } else if (hookType == FBEFORE || hookType == FAFTER) { var hookPt=(hookType == 1 ? hookPt.before : hookPt.after); if (typeof fnRef == 'object') { hookPt = hookPt.concat(fnRef); } else { hookPt[hookPt.length++] = fnRef; } if (optPm) hookPt = reOrder(hookPt, fnRef, optPm); } else if (hookType == FALTERNATE) { if (last=='number') hookPt.alt[pms[optPm-1-pmStart]] = fnRef; } else if (hookType == FCHAIN) { hookPt = hookPt.chain; if (typeof fnRef=='object') hookPt=hookPt.concat(fnRef); // add other functions else hookPt[hookPt.length++]=fnRef; } return; } } // Register a function that will set runtime variables. function registerRunTimeFunction(fn) { if (isFunction(fn)) { if (typeof fn == 'object') { runTime = runTime.concat(fn); } else { runTime[runTime.length++] = fn; } } } // Register a function that will handle command parsing. function registerCmdLineFunction(fn){ if (isFunction(fn)) { if (typeof fn == 'object') { cmdLine = cmdLine.concat(fn); } else { cmdLine[cmdLine.length++] = fn; } } } // Register a function that does things after command parsing. function registerPostParseFunction(fn){ if (isFunction(fn)) { if (typeof fn == 'object') { postParse = postParse.concat(fn); } else { postParse[postParse.length++] = fn; } } } //////// // PLUGIN REGISTRATION FUNCTIONS //////// // Runs any hooks registered. function runHook(fnHookTo, hookType) { var l = hookPts[fnHookTo], k, rtnVal = null, optPm, arS, ar = runHook.arguments; if (hookType == FREPLACE) { arS = argToString(ar, 2); if (typeof l == 'undefined' || !(l = l.ovload)) rtnVal = eval(fnHookTo+'('+arS+')'); else rtnVal = eval('l('+arS+')'); } else if (hookType == FBEFORE || hookType == FAFTER) { if (typeof l != 'undefined') { l=(hookType == 1 ? l.before : l.after); if (l.length) { arS = argToString(ar, 2); for (var k = 0; k < l.length; k++) eval('l[k]('+arS+')'); } } } else if (hookType == FALTERNATE) { optPm = ar[2]; arS = argToString(ar, 3); if (typeof l == 'undefined' || (l = l.alt[pms[optPm-1-pmStart]]) == 'undefined') { rtnVal = eval(fnHookTo+'('+arS+')'); } else { rtnVal = eval('l('+arS+')'); } } else if (hookType == FCHAIN) { arS=argToString(ar,2); l=l.chain; for (k=l.length; k > 0; k--) if((rtnVal=eval('l[k-1]('+arS+')'))!=void(0)) break; } return rtnVal; } //////// // OBJECT CONSTRUCTORS //////// // Object for handling hooks. function FunctionReference() { this.ovload = null; this.before = new Array(); this.after = new Array(); this.alt = new Array(); this.chain = new Array(); } // Object for simple access to the overLIB version used. // Examples: simpleversion:351 major:3 minor:5 revision:1 function Info(version, prerelease) { this.version = version; this.prerelease = prerelease; this.simpleversion = Math.round(this.version*100); this.major = parseInt(this.simpleversion / 100); this.minor = parseInt(this.simpleversion / 10) - this.major * 10; this.revision = parseInt(this.simpleversion) - this.major * 100 - this.minor * 10; this.meets = meets; } // checks for Core Version required function meets(reqdVersion) { return (!reqdVersion) ? false : this.simpleversion >= Math.round(100*parseFloat(reqdVersion)); } //////// // STANDARD REGISTRATIONS //////// registerHook("ol_content_simple", ol_content_simple, FALTERNATE, CSSOFF); registerHook("ol_content_caption", ol_content_caption, FALTERNATE, CSSOFF); registerHook("ol_content_background", ol_content_background, FALTERNATE, CSSOFF); registerHook("ol_content_simple", ol_content_simple, FALTERNATE, CSSCLASS); registerHook("ol_content_caption", ol_content_caption, FALTERNATE, CSSCLASS); registerHook("ol_content_background", ol_content_background, FALTERNATE, CSSCLASS); registerPostParseFunction(checkPositionFlags); registerHook("hideObject", nbspCleanup, FAFTER); registerHook("horizontalPlacement", horizontalPlacement, FCHAIN); registerHook("verticalPlacement", verticalPlacement, FCHAIN); if (olNs4||(olIe5&&isMac)||olKq) olLoaded=1; registerNoParameterCommands('sticky,autostatus,autostatuscap,fullhtml,hauto,vauto,closeclick,wrap,followmouse,mouseoff,compatmode'); /////// // ESTABLISH MOUSECAPTURING /////// // Capture events, alt. diffuses the overlib function. var olCheckMouseCapture=true; if ((olNs4 || olNs6 || olIe4)) { olMouseCapture(); } else { overlib = no_overlib; nd = no_overlib; ver3fix = true; } ================================================ FILE: tools/server/admin/overlib/overlib_anchor.js ================================================ //\///// //\ overLIB Anchor Plugin //\ This file requires overLIB 4.10 or later. //\ //\ overLIB 4.10 - You may not remove or change this notice. //\ Copyright Erik Bosrup 1998-2004. All rights reserved. //\ Contributors are listed on the homepage. //\ See http://www.bosrup.com/web/overlib/ for details. // $Revision: 1.1 $ $Date: 2006/05/29 16:38:21 $ //\///// //\mini //////// // PRE-INIT // Ignore these lines, configuration is below. //////// if (typeof olInfo == 'undefined' || typeof olInfo.meets == 'undefined' || !olInfo.meets(4.10)) alert('overLIB 4.10 or later is required for the Anchor Plugin.'); else { registerCommands('anchor,anchorx,anchory,noanchorwarn,anchoralign'); //////// // DEFAULT CONFIGURATION // Settings you want everywhere are set here. All of this can also be // changed on your html page or through an overLIB call. //////// if (typeof ol_anchor == 'undefined') var ol_anchor = ''; if (typeof ol_anchorx == 'undefined') var ol_anchorx = 0; if (typeof ol_anchory == 'undefined') var ol_anchory = 0; if (typeof ol_noanchorwarn == 'undefined') var ol_noanchorwarn = 1; if (typeof ol_anchoralign == 'undefined') var ol_anchoralign = 'UL'; //////// // END OF CONFIGURATION // Don't change anything below this line, all configuration is above. //////// //////// // INIT //////// // Runtime variables init. Don't change for config! var o3_anchor = ""; var o3_anchorx = 0; var o3_anchory = 0; var o3_noanchorwarn = 1; var o3_anchoralign = 'UL'; var mrkObj, rmrkPosition; //reference mark object, reference mark position, an array; //////// // PLUGIN FUNCTIONS //////// function setAnchorVariables() { o3_anchor = ol_anchor; o3_anchorx = ol_anchorx; o3_anchory = ol_anchory; o3_noanchorwarn = ol_noanchorwarn; o3_anchoralign = ol_anchoralign; mrkObj = null; // initialize this variable } // Parses Reference Mark commands function parseAnchorExtras(pf,i,ar) { var v, k=i; if (k < ar.length) { if (ar[k] == ANCHOR) { eval(pf + "anchor = '" + escSglQuote(ar[++k]) + "'"); return k; } if (ar[k] == ANCHORX) { eval(pf + 'anchorx = ' + ar[++k]); return k; } if (ar[k] == ANCHORY) { eval(pf + 'anchory = ' + ar[++k]); return k; } if (ar[k] == NOANCHORWARN) { eval(pf + 'noanchorwarn = (' + pf + 'noanchorwarn==1) ? 0 : 1'); return k; } if (ar[k] == ANCHORALIGN) { k = opt_MULTIPLEARGS(++k, ar, (pf + 'anchoralign')); return k; } } return -1; } /////// // FUNCTION WHICH CHECKS FOR THE EXISTENCE OF A REFERENCE MARKER /////// function checkAnchorObject() { var w = o3_anchor; if (w) { if (!(mrkObj = getAnchorObjectRef(w))) { if (o3_noanchorwarn) { alert('WARNING! Reference mark "' + w + '" not found.'); return false; } else w = ''; } } return true; } /////// // EXTERNAL SUPPORT FUNCTIONS TO HANDLE ANCHOR PROPERTIES /////// // Horizontal placement routine with anchors function anchorHorizontal(browserWidth, horizontalScrollAmount, widthFix) { var hasAnchor = (typeof o3_anchor != 'undefined' && o3_anchor); if (!hasAnchor) return void(0); // set o3_relx for follow scroll if defined if (typeof o3_followscroll != 'undefined' && o3_followscroll && o3_sticky) o3_relx = rmrkPosition[0]; return rmrkPosition[0]; } // Vertical placement routine with anchors function anchorVertical(browserHeight,verticalScrollAmount) { var hasAnchor = (typeof o3_anchor != 'undefined' && o3_anchor); if (!hasAnchor) return void(0); // set o3_rely for follow scroll if defined if (typeof o3_followscroll != 'undefined' && o3_followscroll && o3_sticky) o3_rely = rmrkPosition[1]; return rmrkPosition[1]; } // Stub function for the runHook routine function anchorPreface() { if (!mrkObj) return; rmrkPosition = getAnchorLocation(mrkObj); } // Get Reference Mark object function getAnchorObjectRef(aObj) { return getRefById(aObj, o3_frame.document) || getRefByName(aObj, o3_frame.document) } // Adapted to overlib from jwin by Jason Anderson -- http://www.jwinlib.com function getAnchorLocation(objRef){ var mkObj, of, offsets, mlyr mkObj = mlyr = objRef offsets = [o3_anchorx, o3_anchory] if (document.layers){ if (typeof mlyr.length != 'undefined' && mlyr.length > 1) { mkObj = mlyr[0] offsets[0] += mlyr[0].x + mlyr[1].pageX offsets[1] += mlyr[0].y + mlyr[1].pageY } else { if(mlyr.toString().indexOf('Image') != -1 || mlyr.toString().indexOf('Anchor') != -1){ offsets[0] += mlyr.x offsets[1] += mlyr.y } else { offsets[0] += mlyr.pageX offsets[1] += mlyr.pageY } } } else { offsets[0] += pageLocation(mlyr, 'Left') offsets[1] += pageLocation(mlyr, 'Top') } of = getAnchorOffsets(mkObj) if (typeof o3_dragimg != 'undefined' && o3_dragimg) { olImgLeft = offsets[0]; olImgTop = offsets[1]; } offsets[0] += of[0] offsets[1] += of[1] if (typeof o3_dragimg != 'undefined' && o3_dragimg) { olImgRight = offsets[0]; olImgBottom = offsets[1]; return; } return offsets; } // Adapted to overlib from jwin by Jason Anderson -- http://www.jwinlib.com function getAnchorOffsets(mkObj){ var fx = fy = 0, mp, puc, mkAry, sx = sy = 0, w = o3_anchoralign var mW = mH = pW = pH = 0 var off = [0, 0] mkAry = w.split(','); if (mkAry.length < 3) { mp = mkAry[0].toUpperCase(); puc = (mkAry.length == 1) ? mp : mkAry[1].toUpperCase(); } else if (mkAry.length == 3) { if (!isNaN(mkAry[0])) { mp = mkAry.slice(0, 2); puc = mkAry[2].toUpperCase(); } else { mp = mkAry[0].toUpperCase(); puc = mkAry.slice(1); } } else { mp = mkAry.slice(0, 2); puc = mkAry.slice(2); } var shdwPresent = typeof o3_shadow != 'undefined' && o3_shadow if (shdwPresent) { sx = Math.abs(o3_shadowx); sy = Math.abs(o3_shadowy); } pW = (shdwPresent ? parseInt(o3_width) : (olNs4 ? over.clip.width : over.offsetWidth)) pH = (shdwPresent ? parseInt(o3_aboveheight) : (olNs4 ? over.clip.height : over.offsetHeight)) if (olOp && o3_wrap) { pW = (shdwPresent ? parseInt(o3_width) : (olNs4 ? over.clip.width : over.offsetWidth)) pH = (shdwPresent ? parseInt(o3_aboveheight) : (olNs4 ? over.clip.height : over.offsetHeight)) } if (!olOp && mkObj.toString().indexOf('Image') != -1){ mW = mkObj.width mH = mkObj.height } else if (!olOp && mkObj.toString().indexOf('Anchor') != -1) { // enforced only for NS4 mp = 'UL' } else { mW = (olNs4) ? mkObj.clip.width : mkObj.offsetWidth mH = (olNs4) ? mkObj.clip.height : mkObj.offsetHeight } if (!isNaN(mp) || typeof mp == 'object') { if (typeof mp == 'object') { fx = parseFloat(mp[0]); fy = parseFloat(mp[1]); } else fx = fy = parseFloat(mp); off = [Math.round(fx*mW), Math.round(fy*mH)]; } else { if (mp == 'UR') off = [mW, 0] else if (mp == 'LL') off = [0, mH] else if (mp == 'LR') off = [mW, mH] } if (typeof o3_dragimg != 'undefined' && o3_dragimg) return off; else { if (!isNaN(puc) || typeof puc == 'object' ) { if (typeof puc == 'object') { fx = parseFloat(puc[0]); fy = parseFloat(puc[1]); } else fx = fy = parseFloat(puc); off[0] -= Math.round(fx*(pW - sx)); off[1] -= Math.round(fy*(pH - sy)); } else { if (puc == 'UR') { off[0] -= (pW - sx); off[1] -= sy } else if (puc == 'LL') { off[0] -= sx; off[1] -= (pH - sy) } else if (puc == 'LR') { off[0] -= (pW-sx); off[1] -= (pH - sy) } } return off } } // Adapted to overlib from jwin by Jason Anderson -- http://www.jwinlib.com function pageLocation(o, t){ var x = 0 while(o.offsetParent){ x += o['offset' + t] o = o.offsetParent } x += o['offset' + t] return x } // Adapted to overlib from jwin by Jason Anderson -- http://www.jwinlib.com function getRefById(l, d){ var r = "", j d = (d || document) if (d.all) return d.all[l] else if (d.getElementById) return d.getElementById(l) else if (d.layers && d.layers.length > 0) { if (d.layers[l]) return d.layers[l] for (j=0; j < d.layers.length; j++) { r = getRefById(l, d.layers[j].document) if(r) return r } } return false } // Adapted to overlib from jwin by Jason Anderson -- http://www.jwinlib.com function getRefByName(l, d) { var r = null, j d = (d || document) if (d.images[l]) return d.images[l] else if (d.anchors[l]) return d.anchors[l]; else if (d.layers && d.layers.length > 0) { for (j=0; j < d.layers.length; j++) { r = getRefByName(l, d.layers[j].document) if (r && r.length > 0) return r else if (r) return [r, d.layers[j]] } } return null } //////// // PLUGIN REGISTRATIONS //////// registerRunTimeFunction(setAnchorVariables); registerCmdLineFunction(parseAnchorExtras); registerPostParseFunction(checkAnchorObject); registerHook("createPopup", anchorPreface, FAFTER); registerHook("horizontalPlacement", anchorHorizontal, FCHAIN); registerHook("verticalPlacement", anchorVertical, FCHAIN); if(olInfo.meets(4.10)) registerNoParameterCommands('noanchorwarn'); } ================================================ FILE: tools/server/admin/overlib/overlib_anchor_mini.js ================================================ //\///// //\ overLIB Anchor Plugin //\ This file requires overLIB 4.10 or later. //\ //\ overLIB 4.10 - You may not remove or change this notice. //\ Copyright Erik Bosrup 1998-2004. All rights reserved. //\ Contributors are listed on the homepage. //\ See http://www.bosrup.com/web/overlib/ for details. //\///// //\ THIS IS A VERY MODIFIED VERSION. DO NOT EDIT OR PUBLISH. GET THE ORIGINAL! if(typeof olInfo=='undefined'||typeof olInfo.meets=='undefined'||!olInfo.meets(4.10))alert('overLIB 4.10 or later is required for the Anchor Plugin.');else{registerCommands('anchor,anchorx,anchory,noanchorwarn,anchoralign'); if(typeof ol_anchor=='undefined')var ol_anchor='';if(typeof ol_anchorx=='undefined')var ol_anchorx=0;if(typeof ol_anchory=='undefined')var ol_anchory=0;if(typeof ol_noanchorwarn=='undefined')var ol_noanchorwarn=1;if(typeof ol_anchoralign=='undefined')var ol_anchoralign='UL'; var o3_anchor="",o3_anchorx=0,o3_anchory=0,o3_noanchorwarn=1,o3_anchoralign='UL',mrkObj,rmrkPosition; function setAnchorVariables(){o3_anchor=ol_anchor;o3_anchorx=ol_anchorx;o3_anchory=ol_anchory;o3_noanchorwarn=ol_noanchorwarn;o3_anchoralign=ol_anchoralign;mrkObj=null;} function parseAnchorExtras(pf,i,ar){var v,k=i; if(k1){mkObj=mlyr[0] offsets[0]+=mlyr[0].x+mlyr[1].pageX offsets[1]+=mlyr[0].y+mlyr[1].pageY }else{if(mlyr.toString().indexOf('Image')!=-1||mlyr.toString().indexOf('Anchor')!=-1){offsets[0]+=mlyr.x offsets[1]+=mlyr.y }else{offsets[0]+=mlyr.pageX offsets[1]+=mlyr.pageY}} }else{offsets[0]+=pageLocation(mlyr,'Left') offsets[1]+=pageLocation(mlyr,'Top')} of=getAnchorOffsets(mkObj) if(typeof o3_dragimg!='undefined'&& o3_dragimg){olImgLeft=offsets[0];olImgTop=offsets[1];} offsets[0]+=of[0] offsets[1]+=of[1] if(typeof o3_dragimg!='undefined'&& o3_dragimg){olImgRight=offsets[0];olImgBottom=offsets[1];return;} return offsets;} function getAnchorOffsets(mkObj){var fx=fy=0, mp,puc,mkAry,sx=sy=0,w=o3_anchoralign var mW=mH=pW=pH=0 var off=[0,0] mkAry=w.split(','); if(mkAry.length<3){mp=mkAry[0].toUpperCase();puc=(mkAry.length==1)?mp:mkAry[1].toUpperCase();}else if(mkAry.length==3){if(!isNaN(mkAry[0])){mp=mkAry.slice(0,2);puc=mkAry[2].toUpperCase();}else{mp=mkAry[0].toUpperCase();puc=mkAry.slice(1);} }else{mp=mkAry.slice(0,2);puc=mkAry.slice(2);} var shdwPresent=typeof o3_shadow!='undefined'&& o3_shadow if(shdwPresent){sx=Math.abs(o3_shadowx);sy=Math.abs(o3_shadowy);} pW=(shdwPresent?parseInt(o3_width):(olNs4?over.clip.width:over.offsetWidth)) pH=(shdwPresent?parseInt(o3_aboveheight):(olNs4?over.clip.height:over.offsetHeight)) if(olOp&& o3_wrap){pW=(shdwPresent?parseInt(o3_width):(olNs4?over.clip.width:over.offsetWidth)) pH=(shdwPresent?parseInt(o3_aboveheight):(olNs4?over.clip.height:over.offsetHeight))} if(!olOp&& mkObj.toString().indexOf('Image')!=-1){mW=mkObj.width mH=mkObj.height }else if(!olOp&& mkObj.toString().indexOf('Anchor')!=-1){mp='UL' }else{mW=(olNs4)?mkObj.clip.width:mkObj.offsetWidth mH=(olNs4)?mkObj.clip.height:mkObj.offsetHeight} if(!isNaN(mp)||typeof mp=='object'){if(typeof mp=='object'){fx=parseFloat(mp[0]);fy=parseFloat(mp[1]);}else fx=fy=parseFloat(mp);off=[Math.round(fx*mW),Math.round(fy*mH)];}else{if(mp=='UR')off=[mW,0] else if(mp=='LL')off=[0,mH] else if(mp=='LR')off=[mW,mH]} if(typeof o3_dragimg!='undefined'&& o3_dragimg)return off;else{if(!isNaN(puc)||typeof puc=='object' ){if(typeof puc=='object'){fx=parseFloat(puc[0]);fy=parseFloat(puc[1]);}else fx=fy=parseFloat(puc);off[0]-=Math.round(fx*(pW-sx));off[1]-=Math.round(fy*(pH-sy));}else{if(puc=='UR'){off[0]-=(pW-sx);off[1]-=sy }else if(puc=='LL'){off[0]-=sx;off[1]-=(pH-sy) }else if(puc=='LR'){off[0]-=(pW-sx);off[1]-=(pH-sy)}} return off}} function pageLocation(o,t){var x=0 while(o.offsetParent){x+=o['offset'+t] o=o.offsetParent} x+=o['offset'+t] return x} function getRefById(l,d){var r="",j d=(d||document) if(d.all)return d.all[l] else if(d.getElementById)return d.getElementById(l) else if(d.layers&& d.layers.length>0){if(d.layers[l])return d.layers[l] for(j=0;j0){for(j=0;j0)return r else if(r)return [r,d.layers[j]]}} return null} registerRunTimeFunction(setAnchorVariables);registerCmdLineFunction(parseAnchorExtras);registerPostParseFunction(checkAnchorObject);registerHook("createPopup",anchorPreface,FAFTER);registerHook("horizontalPlacement",anchorHorizontal,FCHAIN);registerHook("verticalPlacement",anchorVertical,FCHAIN);if(olInfo.meets(4.10))registerNoParameterCommands('noanchorwarn'); } ================================================ FILE: tools/server/admin/overlib/overlib_draggable.js ================================================ //\///// //\ overLIB Draggable Plugin //\ //\ You may not remove or change this notice. //\ Copyright Erik Bosrup 1998-2003. All rights reserved. //\ Contributors are listed on the homepage. //\ See http://www.bosrup.com/web/overlib/ for details. //\///// //////// // PRE-INIT // Ignore these lines, configuration is below. //////// if (typeof olInfo == 'undefined' || typeof olInfo.meets == 'undefined' || !olInfo.meets(4.14)) alert('overLIB 4.14 or later is required for the Draggable Plugin.'); else { registerCommands('draggable,altcut,dragimg'); //////// // DEFAULT CONFIGURATION // Settings you want everywhere are set here. All of this can also be // changed on your html page or through an overLIB call. //////// if (typeof ol_draggable=='undefined') var ol_draggable=0; if (typeof ol_altcut=='undefined') var ol_altcut=0; if (typeof ol_dragimg=='undefined') var ol_dragimg=''; //////// // END OF CONFIGURATION // Don't change anything below this line, all configuration is above. //////// //////// // INIT //////// // Runtime variables init. Don't change for config! var o3_draggable=0; var o3_altcut=0; var o3_dragimg=''; var olImgLeft,olImgTop; var olImgObj; var olMseMv; // hold old mouseMove routine //////// // PLUGIN FUNCTIONS //////// function setDragVariables() { o3_draggable=ol_draggable; o3_altcut=ol_altcut; o3_dragimg=ol_dragimg; olImgObj=null; } // Parses Draggable commands function parseDragExtras(pf,i,ar) { var k=i; if (k < ar.length) { if (ar[k]==DRAGGABLE) { eval(pf+'draggable=('+pf+'draggable==0) ? 1 : 0'); return k; } if (ar[k]==ALTCUT) { eval(pf+'altcut=('+pf+'altcut==0) ? 1 : 0'); return k; } if (ar[k]==DRAGIMG) { eval(pf+'dragimg="'+ar[++k]+'"'); return k; } } return -1; } ////// // PRESHOW PROCESSING FOR DRAGGABLE POPUPS ////// function startDrag() { // Initiate dragging if in same frame and its a sticky if (o3_draggable) { if (o3_sticky&&(o3_frame==ol_frame)) initDrag(); else o3_draggable=0; } } ////// // POSTHIDE PROCESSING FOR DRAGGABLE POPUPS ////// function stopDrag() { if (o3_draggable) endDrag(); } ////// // DRAGGABLE FUNCTIONS ////// function initDrag() { olMseMv=capExtent.onmousemove; if(olNs4) { document.captureEvents(Event.MOUSEDOWN | Event.CLICK); document.onmousedown=grabEl; document.onclick=function(e) {return routeEvent(e);} } else { over.onmousedown=grabEl; } if (o3_dragimg) chkForImgSupport(o3_dragimg); return true; } // Checks for image for dragging function chkForImgSupport(dragImg) { if (dragImg) { if (typeof getAnchorObjRef!='undefined') olImgObj=getAnchorObjRef(dragImg); if (olImgObj==null) o3_dragimg=''; } } // Sets cursor symbol function setCursor(on) { if (olNs4) return; over.style.cursor=(on ? 'move' : 'auto'); } // Checks cursor position relative to image function chkCursorPosition(Obj,XPos,YPos) { if (Obj) { o3_anchorx=o3_anchory=0; o3_anchoralign='UL'; getAnchorLocation(Obj); if (XPos < olImgLeft||XPos > (olImgLeft+Obj.width)||YPos < olImgTop||YPos > (olImgTop+Obj.height)) return false; } return true; } // Sets up mouse grab for moving function grabEl(e) { var e=(e) ? e : event; var X,Y; var cKy=(olNs4 ? e.modifiers & Event.ALT_MASK : (!olOp ? e.altKey : e.ctrlKey)); if ((o3_altcut ? !cKy : cKy)) { // get mouse's current x,y location X=(e.pageX || eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft')); Y=(e.pageY || eval('e.clientY+o3_frame.'+docRoot+'.scrollTop')); if (chkCursorPosition(olImgObj,X,Y)) { if (olNs4) document.captureEvents(Event.MOUSEUP); capExtent.onmousemove=moveEl; document.onmouseup=function() {setCursor(0); if (olIe4) over.onselectstart=null; capExtent.onmousemove=olMseMv;} setCursor(1); if (olIe4) over.onselectstart=function() {return false;} if (olNs4) { cX=X cY=Y } else { // get offsets from upper left hand corner of popup to keep popup from jummping // when first starting to drag cX=X-(olNs4 ? over.left : parseInt(over.style.left)); cY=Y-(olNs4 ? over.top : parseInt(over.style.top)); } return (olNs4 ? routeEvent(e) : false); } } else setCursor(0); } // Moves popup to follow mouse function moveEl(e) { var e=(e) ? e : event; var dX,dY,X,Y; // get new mouse location X=(e.pageX || eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft')); Y=(e.pageY || eval('e.clientY+o3_frame.'+docRoot+'.scrollTop')); if (chkCursorPosition(olImgObj,X,Y)){ if (olNs4) { dX=X-cX; cX=X; dY=Y-cY; cY=Y; over.moveBy(dX,dY); } else repositionTo(over,X-cX,Y-cY); // move popup to that position } } // Cleanup for Drag end function endDrag(obj) { if (olNs4) { document.releaseEvents(Event.MOUSEDOWN | Event.MOUSEUP | Event.CLICK); document.onmousedown=document.onclick=null; } else { if(!obj) obj=over; obj.onmousedown=null; } document.onmouseup= null; } //////// // PLUGIN REGISTRATIONS //////// registerRunTimeFunction(setDragVariables); registerCmdLineFunction(parseDragExtras); registerHook("disp",startDrag,FBEFORE); registerHook("hideObject",stopDrag,FAFTER); if (olInfo.meets(4.14)) registerNoParameterCommands('draggable,altcut'); } //end ================================================ FILE: tools/server/admin/overlib/overlib_draggable_mini.js ================================================ //\///// //\ overLIB Draggable Plugin //\ //\ You may not remove or change this notice. //\ Copyright Erik Bosrup 1998-2003. All rights reserved. //\ Contributors are listed on the homepage. //\ See http://www.bosrup.com/web/overlib/ for details. //\///// if(typeof olInfo=='undefined'||typeof olInfo.meets=='undefined'||!olInfo.meets(4.14))alert('overLIB 4.14 or later is required for the Draggable Plugin.');else{registerCommands('draggable,altcut,dragimg'); if(typeof ol_draggable=='undefined')var ol_draggable=0;if(typeof ol_altcut=='undefined')var ol_altcut=0;if(typeof ol_dragimg=='undefined')var ol_dragimg=''; var o3_draggable=0,o3_altcut=0,o3_dragimg='',olImgLeft,olImgTop,olImgObj,olMseMv; function setDragVariables(){o3_draggable=ol_draggable;o3_altcut=ol_altcut;o3_dragimg=ol_dragimg;olImgObj=null;} function parseDragExtras(pf,i,ar){var k=i;if(k(olImgLeft+Obj.width)||YPos(olImgTop+Obj.height))return false;} return true;} function grabEl(e){var e=(e)?e:event;var X,Y;var cKy=(olNs4?e.modifiers&Event.ALT_MASK:(!olOp?e.altKey:e.ctrlKey));if((o3_altcut?!cKy:cKy)){ X=(e.pageX||eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft'));Y=(e.pageY||eval('e.clientY+o3_frame.'+docRoot+'.scrollTop'));if(chkCursorPosition(olImgObj,X,Y)){if(olNs4)document.captureEvents(Event.MOUSEUP);capExtent.onmousemove=moveEl;document.onmouseup=function(){setCursor(0);if(olIe4)over.onselectstart=null;capExtent.onmousemove=olMseMv;} setCursor(1);if(olIe4)over.onselectstart=function(){return false;} if(olNs4){cX=X cY=Y }else{ cX=X-(olNs4?over.left:parseInt(over.style.left));cY=Y-(olNs4?over.top:parseInt(over.style.top));} return(olNs4?routeEvent(e):false);} }else setCursor(0);} function moveEl(e){var e=(e)?e:event;var dX,dY,X,Y; X=(e.pageX||eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft'));Y=(e.pageY||eval('e.clientY+o3_frame.'+docRoot+'.scrollTop'));if(chkCursorPosition(olImgObj,X,Y)){if(olNs4){dX=X-cX;cX=X;dY=Y-cY;cY=Y;over.moveBy(dX,dY);}else repositionTo(over,X-cX,Y-cY);}} function endDrag(obj){if(olNs4){document.releaseEvents(Event.MOUSEDOWN|Event.MOUSEUP|Event.CLICK);document.onmousedown=document.onclick=null;}else{if(!obj)obj=over;obj.onmousedown=null;} document.onmouseup=null;} registerRunTimeFunction(setDragVariables);registerCmdLineFunction(parseDragExtras);registerHook("disp",startDrag,FBEFORE);registerHook("hideObject",stopDrag,FAFTER);if(olInfo.meets(4.14))registerNoParameterCommands('draggable,altcut');} ================================================ FILE: tools/server/admin/overlib/overlib_mini.js ================================================ //\///// //\ overLIB 4.21 - You may not remove or change this notice. //\ Copyright Erik Bosrup 1998-2004. All rights reserved. //\ //\ Contributors are listed on the homepage. //\ This file might be old, always check for the latest version at: //\ http://www.bosrup.com/web/overlib/ //\ //\ Please read the license agreement (available through the link above) //\ before using overLIB. Direct any licensing questions to erik@bosrup.com. //\ //\ Do not sell this as your own work or remove this copyright notice. //\ For full details on copying or changing this script please read the //\ license agreement at the link above. Please give credit on sites that //\ use overLIB and submit changes of the script so other people can use //\ them as well. //\///// //\ THIS IS A VERY MODIFIED VERSION. DO NOT EDIT OR PUBLISH. GET THE ORIGINAL! var olLoaded=0,pmStart=10000000,pmUpper=10001000,pmCount=pmStart+1,pmt='',pms=new Array(),olInfo=new Info('4.21',1),FREPLACE=0,FBEFORE=1,FAFTER=2,FALTERNATE=3,FCHAIN=4,olHideForm=0,olHautoFlag=0,olVautoFlag=0,hookPts=new Array(),postParse=new Array(),cmdLine=new Array(),runTime=new Array(); registerCommands('donothing,inarray,caparray,sticky,background,noclose,caption,left,right,center,offsetx,offsety,fgcolor,bgcolor,textcolor,capcolor,closecolor,width,border,cellpad,status,autostatus,autostatuscap,height,closetext,snapx,snapy,fixx,fixy,relx,rely,fgbackground,bgbackground,padx,pady,fullhtml,above,below,capicon,textfont,captionfont,closefont,textsize,captionsize,closesize,timeout,function,delay,hauto,vauto,closeclick,wrap,followmouse,mouseoff,closetitle,cssoff,compatmode,cssclass,fgclass,bgclass,textfontclass,captionfontclass,closefontclass'); if(typeof ol_fgcolor=='undefined')var ol_fgcolor="#99BBDD";if(typeof ol_bgcolor=='undefined')var ol_bgcolor="#7799BB";if(typeof ol_textcolor=='undefined')var ol_textcolor="#000000";if(typeof ol_capcolor=='undefined')var ol_capcolor="#000033";if(typeof ol_closecolor=='undefined')var ol_closecolor="#000000";if(typeof ol_textfont=='undefined')var ol_textfont="Verdana,Arial,Helvetica";if(typeof ol_captionfont=='undefined')var ol_captionfont="Verdana,Arial,Helvetica";if(typeof ol_closefont=='undefined')var ol_closefont="Verdana,Arial,Helvetica";if(typeof ol_textsize=='undefined')var ol_textsize="1";if(typeof ol_captionsize=='undefined')var ol_captionsize="1";if(typeof ol_closesize=='undefined')var ol_closesize="1";if(typeof ol_width=='undefined')var ol_width="200";if(typeof ol_border=='undefined')var ol_border="1";if(typeof ol_cellpad=='undefined')var ol_cellpad=2;if(typeof ol_offsetx=='undefined')var ol_offsetx=10;if(typeof ol_offsety=='undefined')var ol_offsety=10;if(typeof ol_text=='undefined')var ol_text="Default Text";if(typeof ol_cap=='undefined')var ol_cap="";if(typeof ol_sticky=='undefined')var ol_sticky=0;if(typeof ol_background=='undefined')var ol_background="";if(typeof ol_close=='undefined')var ol_close="Close";if(typeof ol_hpos=='undefined')var ol_hpos=RIGHT;if(typeof ol_status=='undefined')var ol_status="";if(typeof ol_autostatus=='undefined')var ol_autostatus=0;if(typeof ol_height=='undefined')var ol_height=-1;if(typeof ol_snapx=='undefined')var ol_snapx=0;if(typeof ol_snapy=='undefined')var ol_snapy=0;if(typeof ol_fixx=='undefined')var ol_fixx=-1;if(typeof ol_fixy=='undefined')var ol_fixy=-1;if(typeof ol_relx=='undefined')var ol_relx=null;if(typeof ol_rely=='undefined')var ol_rely=null;if(typeof ol_fgbackground=='undefined')var ol_fgbackground="";if(typeof ol_bgbackground=='undefined')var ol_bgbackground="";if(typeof ol_padxl=='undefined')var ol_padxl=1;if(typeof ol_padxr=='undefined')var ol_padxr=1;if(typeof ol_padyt=='undefined')var ol_padyt=1;if(typeof ol_padyb=='undefined')var ol_padyb=1;if(typeof ol_fullhtml=='undefined')var ol_fullhtml=0;if(typeof ol_vpos=='undefined')var ol_vpos=BELOW;if(typeof ol_aboveheight=='undefined')var ol_aboveheight=0;if(typeof ol_capicon=='undefined')var ol_capicon="";if(typeof ol_frame=='undefined')var ol_frame=self;if(typeof ol_timeout=='undefined')var ol_timeout=0;if(typeof ol_function=='undefined')var ol_function=null;if(typeof ol_delay=='undefined')var ol_delay=0;if(typeof ol_hauto=='undefined')var ol_hauto=0;if(typeof ol_vauto=='undefined')var ol_vauto=0;if(typeof ol_closeclick=='undefined')var ol_closeclick=0;if(typeof ol_wrap=='undefined')var ol_wrap=0;if(typeof ol_followmouse=='undefined')var ol_followmouse=1;if(typeof ol_mouseoff=='undefined')var ol_mouseoff=0;if(typeof ol_closetitle=='undefined')var ol_closetitle='Close';if(typeof ol_compatmode=='undefined')var ol_compatmode=0;if(typeof ol_css=='undefined')var ol_css=CSSOFF;if(typeof ol_fgclass=='undefined')var ol_fgclass="";if(typeof ol_bgclass=='undefined')var ol_bgclass="";if(typeof ol_textfontclass=='undefined')var ol_textfontclass="";if(typeof ol_captionfontclass=='undefined')var ol_captionfontclass="";if(typeof ol_closefontclass=='undefined')var ol_closefontclass=""; if(typeof ol_texts=='undefined')var ol_texts=new Array("Text 0","Text 1");if(typeof ol_caps=='undefined')var ol_caps=new Array("Caption 0","Caption 1"); var o3_text="",o3_cap="",o3_sticky=0,o3_background="",o3_close="Close",o3_hpos=RIGHT,o3_offsetx=2,o3_offsety=2,o3_fgcolor="",o3_bgcolor="",o3_textcolor="",o3_capcolor="",o3_closecolor="",o3_width=100,o3_border=1,o3_cellpad=2,o3_status="",o3_autostatus=0,o3_height=-1,o3_snapx=0,o3_snapy=0,o3_fixx=-1,o3_fixy=-1,o3_relx=null,o3_rely=null,o3_fgbackground="",o3_bgbackground="",o3_padxl=0,o3_padxr=0,o3_padyt=0,o3_padyb=0,o3_fullhtml=0,o3_vpos=BELOW,o3_aboveheight=0,o3_capicon="",o3_textfont="Verdana,Arial,Helvetica",o3_captionfont="Verdana,Arial,Helvetica",o3_closefont="Verdana,Arial,Helvetica",o3_textsize="1",o3_captionsize="1",o3_closesize="1",o3_frame=self,o3_timeout=0,o3_timerid=0,o3_allowmove=0,o3_function=null,o3_delay=0,o3_delayid=0,o3_hauto=0,o3_vauto=0,o3_closeclick=0,o3_wrap=0,o3_followmouse=1,o3_mouseoff=0,o3_closetitle='',o3_compatmode=0,o3_css=CSSOFF,o3_fgclass="",o3_bgclass="",o3_textfontclass="",o3_captionfontclass="",o3_closefontclass=""; var o3_x=0,o3_y=0,o3_showingsticky=0,o3_removecounter=0; var over=null,fnRef,hoveringSwitch=false,olHideDelay; var isMac=(navigator.userAgent.indexOf("Mac")!=-1),olOp=(navigator.userAgent.toLowerCase().indexOf('opera')>-1&&document.createTextNode),olNs4=(navigator.appName=='Netscape'&&parseInt(navigator.appVersion)==4),olNs6=(document.getElementById)?true:false,olKq=(olNs6&&/konqueror/i.test(navigator.userAgent)),olIe4=(document.all)?true:false,olIe5=false,olIe55=false,docRoot='document.body'; if(olNs4){var oW=window.innerWidth;var oH=window.innerHeight;window.onresize=function(){if(oW!=window.innerWidth||oH!=window.innerHeight)location.reload();}} if(olIe4){var agent=navigator.userAgent;if(/MSIE/.test(agent)){var versNum=parseFloat(agent.match(/MSIE[ ](\d\.\d+)\.*/i)[1]);if(versNum>=5){olIe5=true;olIe55=(versNum>=5.5&&!olOp)?true:false;if(olNs6)olNs6=false;}} if(olNs6)olIe4=false;} if(document.compatMode&&document.compatMode=='CSS1Compat'){docRoot=((olIe4&&!olOp)?'document.documentElement':docRoot);} if(window.addEventListener)window.addEventListener("load",OLonLoad_handler,false);else if(window.attachEvent)window.attachEvent("onload",OLonLoad_handler); var capExtent; function overlib(){if(!olLoaded||isExclusive(overlib.arguments))return true;if(olCheckMouseCapture)olMouseCapture();if(over){over=(typeof over.id!='string')?o3_frame.document.all['overDiv']:over;cClick();} olHideDelay=0;o3_text=ol_text;o3_cap=ol_cap;o3_sticky=ol_sticky;o3_background=ol_background;o3_close=ol_close;o3_hpos=ol_hpos;o3_offsetx=ol_offsetx;o3_offsety=ol_offsety;o3_fgcolor=ol_fgcolor;o3_bgcolor=ol_bgcolor;o3_textcolor=ol_textcolor;o3_capcolor=ol_capcolor;o3_closecolor=ol_closecolor;o3_width=ol_width;o3_border=ol_border;o3_cellpad=ol_cellpad;o3_status=ol_status;o3_autostatus=ol_autostatus;o3_height=ol_height;o3_snapx=ol_snapx;o3_snapy=ol_snapy;o3_fixx=ol_fixx;o3_fixy=ol_fixy;o3_relx=ol_relx;o3_rely=ol_rely;o3_fgbackground=ol_fgbackground;o3_bgbackground=ol_bgbackground;o3_padxl=ol_padxl;o3_padxr=ol_padxr;o3_padyt=ol_padyt;o3_padyb=ol_padyb;o3_fullhtml=ol_fullhtml;o3_vpos=ol_vpos;o3_aboveheight=ol_aboveheight;o3_capicon=ol_capicon;o3_textfont=ol_textfont;o3_captionfont=ol_captionfont;o3_closefont=ol_closefont;o3_textsize=ol_textsize;o3_captionsize=ol_captionsize;o3_closesize=ol_closesize;o3_timeout=ol_timeout;o3_function=ol_function;o3_delay=ol_delay;o3_hauto=ol_hauto;o3_vauto=ol_vauto;o3_closeclick=ol_closeclick;o3_wrap=ol_wrap;o3_followmouse=ol_followmouse;o3_mouseoff=ol_mouseoff;o3_closetitle=ol_closetitle;o3_css=ol_css;o3_compatmode=ol_compatmode;o3_fgclass=ol_fgclass;o3_bgclass=ol_bgclass;o3_textfontclass=ol_textfontclass;o3_captionfontclass=ol_captionfontclass;o3_closefontclass=ol_closefontclass; setRunTimeVariables(); fnRef=''; o3_frame=ol_frame; if(!(over=createDivContainer()))return false; parseTokens('o3_',overlib.arguments);if(!postParseChecks())return false; if(o3_delay==0){return runHook("olMain",FREPLACE);}else{o3_delayid=setTimeout("runHook('olMain',FREPLACE)",o3_delay);return false;}} function nd(time){if(olLoaded&&!isExclusive()){hideDelay(time); if(o3_removecounter>=1){o3_showingsticky=0 }; if(o3_showingsticky==0){o3_allowmove=0;if(over!=null&&o3_timerid==0)runHook("hideObject",FREPLACE,over);}else{o3_removecounter++;}} return true;} function cClick(){if(olLoaded){runHook("hideObject",FREPLACE,over);o3_showingsticky=0;} return false;} function overlib_pagedefaults(){parseTokens('ol_',overlib_pagedefaults.arguments);} function olMain(){var layerhtml,styleType;runHook("olMain",FBEFORE); if(o3_background!=""||o3_fullhtml){ layerhtml=runHook('ol_content_background',FALTERNATE,o3_css,o3_text,o3_background,o3_fullhtml);}else{ styleType=(pms[o3_css-1-pmStart]=="cssoff"||pms[o3_css-1-pmStart]=="cssclass"); if(o3_fgbackground!="")o3_fgbackground="background=\""+o3_fgbackground+"\"";if(o3_bgbackground!="")o3_bgbackground=(styleType?"background=\""+o3_bgbackground+"\"":o3_bgbackground); if(o3_fgcolor!="")o3_fgcolor=(styleType?"bgcolor=\""+o3_fgcolor+"\"":o3_fgcolor);if(o3_bgcolor!="")o3_bgcolor=(styleType?"bgcolor=\""+o3_bgcolor+"\"":o3_bgcolor); if(o3_height>0)o3_height=(styleType?"height=\""+o3_height+"\"":o3_height);else o3_height=""; if(o3_cap==""){ layerhtml=runHook('ol_content_simple',FALTERNATE,o3_css,o3_text);}else{ if(o3_sticky){ layerhtml=runHook('ol_content_caption',FALTERNATE,o3_css,o3_text,o3_cap,o3_close);}else{ layerhtml=runHook('ol_content_caption',FALTERNATE,o3_css,o3_text,o3_cap,"");}}} if(o3_sticky){if(o3_timerid>0){clearTimeout(o3_timerid);o3_timerid=0;} o3_showingsticky=1;o3_removecounter=0;} if(!runHook("createPopup",FREPLACE,layerhtml))return false; if(o3_autostatus>0){o3_status=o3_text;if(o3_autostatus>1)o3_status=o3_cap;} o3_allowmove=0; if(o3_timeout>0){if(o3_timerid>0)clearTimeout(o3_timerid);o3_timerid=setTimeout("cClick()",o3_timeout);} runHook("disp",FREPLACE,o3_status);runHook("olMain",FAFTER); return(olOp&&event&&event.type=='mouseover'&&!o3_status)?'':(o3_status!='');} function ol_content_simple(text){var cpIsMultiple=/,/.test(o3_cellpad);var txt='
':((!olNs4&&cpIsMultiple)?' style="'+setCellPadStr(o3_cellpad)+'">':'>'))+(o3_textfontclass?'':wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass?'':wrapStr(1,o3_textsize))+'
'; set_background("");return txt;} function ol_content_caption(text,title,close){var nameId,txt,cpIsMultiple=/,/.test(o3_cellpad);var closing,closeevent; closing="";closeevent="onmouseover";if(o3_closeclick==1)closeevent=(o3_closetitle?"title='"+o3_closetitle+"'":"")+" onclick";if(o3_capicon!=""){nameId=' hspace=\"5\"'+' align=\"middle\" alt=\"\"';if(typeof o3_dragimg!='undefined'&&o3_dragimg)nameId=' hspace=\"5\"'+' name=\"'+o3_dragimg+'\" id=\"'+o3_dragimg+'\" align=\"middle\" alt=\"Drag Enabled\" title=\"Drag Enabled\"';o3_capicon='';} if(close!="") closing=''+(o3_closefontclass?'':wrapStr(0,o3_closesize,'close'))+close+(o3_closefontclass?'':wrapStr(1,o3_closesize,'close'))+'';txt='
':'>')+(o3_captionfontclass?'':''+wrapStr(0,o3_captionsize,'caption'))+o3_capicon+title+(o3_captionfontclass?'':wrapStr(1,o3_captionsize)+'')+''+closing+'
' :((!olNs4&&cpIsMultiple)?' style="'+setCellPadStr(o3_cellpad)+'">':'>'))+(o3_textfontclass?'':wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass?'':wrapStr(1,o3_textsize))+'
'; set_background("");return txt;} function ol_content_background(text,picture,hasfullhtml){if(hasfullhtml){txt=text;}else{txt='
'+(o3_textfontclass?'':wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass?'':wrapStr(1,o3_textsize))+'
';} set_background(picture);return txt;} function set_background(pic){if(pic==""){if(olNs4){over.background.src=null;}else if(over.style){over.style.backgroundImage="none";} }else{if(olNs4){over.background.src=pic;}else if(over.style){over.style.width=o3_width+'px';over.style.backgroundImage="url("+pic+")";}}} var olShowId=-1; function disp(statustext){runHook("disp",FBEFORE); if(o3_allowmove==0){runHook("placeLayer",FREPLACE);(olNs6&&olShowId<0)?olShowId=setTimeout("runHook('showObject',FREPLACE,over)",1):runHook("showObject",FREPLACE,over);o3_allowmove=(o3_sticky||o3_followmouse==0)?0:1;} runHook("disp",FAFTER); if(statustext!="")self.status=statustext;} function createPopup(lyrContent){runHook("createPopup",FBEFORE); if(o3_wrap){var wd,ww,theObj=(olNs4?over:over.style);theObj.top=theObj.left=((olIe4&&!olOp)?0:-10000)+(!olNs4?'px':0);layerWrite(lyrContent);wd=(olNs4?over.clip.width:over.offsetWidth);if(wd>(ww=windowWidth())){lyrContent=lyrContent.replace(/\ /g,' ');o3_width=ww;o3_wrap=0;}} layerWrite(lyrContent); if(o3_wrap)o3_width=(olNs4?over.clip.width:over.offsetWidth); runHook("createPopup",FAFTER,lyrContent); return true;} function placeLayer(){var placeX,placeY,widthFix=0; if(o3_frame.innerWidth)widthFix=18;iwidth=windowWidth(); winoffset=(olIe4)?eval('o3_frame.'+docRoot+'.scrollLeft'):o3_frame.pageXOffset; placeX=runHook('horizontalPlacement',FCHAIN,iwidth,winoffset,widthFix); if(o3_frame.innerHeight){iheight=o3_frame.innerHeight;}else if(eval('o3_frame.'+docRoot)&&eval("typeof o3_frame."+docRoot+".clientHeight=='number'")&&eval('o3_frame.'+docRoot+'.clientHeight')){iheight=eval('o3_frame.'+docRoot+'.clientHeight');} scrolloffset=(olIe4)?eval('o3_frame.'+docRoot+'.scrollTop'):o3_frame.pageYOffset;placeY=runHook('verticalPlacement',FCHAIN,iheight,scrolloffset); repositionTo(over,placeX,placeY);} function olMouseMove(e){var e=(e)?e:event; if(e.pageX){o3_x=e.pageX;o3_y=e.pageY;}else if(e.clientX){o3_x=eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft');o3_y=eval('e.clientY+o3_frame.'+docRoot+'.scrollTop');} if(o3_allowmove==1)runHook("placeLayer",FREPLACE); if(hoveringSwitch&&!olNs4&&runHook("cursorOff",FREPLACE)){(olHideDelay?hideDelay(olHideDelay):cClick());hoveringSwitch=!hoveringSwitch;}} function no_overlib(){return ver3fix;} function olMouseCapture(){capExtent=document;var fN,str='',l,k,f,wMv,sS,mseHandler=olMouseMove;var re=/function[ ]*(\w*)\(/; wMv=(!olIe4&&window.onmousemove);if(document.onmousemove||wMv){if(wMv)capExtent=window;f=capExtent.onmousemove.toString();fN=f.match(re);if(fN==null){str=f+'(e);';}else if(fN[1]=='anonymous'||fN[1]=='olMouseMove'||(wMv&&fN[1]=='onmousemove')){if(!olOp&&wMv){l=f.indexOf('{')+1;k=f.lastIndexOf('}');sS=f.substring(l,k);if((l=sS.indexOf('('))!=-1){sS=sS.substring(0,l).replace(/^\s+/,'').replace(/\s+$/,'');if(eval("typeof "+sS+"=='undefined'"))window.onmousemove=null;else str=sS+'(e);';}} if(!str){olCheckMouseCapture=false;return;} }else{if(fN[1])str=fN[1]+'(e);';else{l=f.indexOf('{')+1;k=f.lastIndexOf('}');str=f.substring(l,k)+'\n';}} str+='olMouseMove(e);';mseHandler=new Function('e',str);} capExtent.onmousemove=mseHandler;if(olNs4)capExtent.captureEvents(Event.MOUSEMOVE);} function parseTokens(pf,ar){ var v,i,mode=-1,par=(pf!='ol_'),fnMark=(par&&!ar.length?1:0); for(i=0;ipmStart&&ar[i]=pmCount||ar[i]==DONOTHING){continue;} if(ar[i]==INARRAY){fnMark=0;eval(pf+'text=ol_texts['+ar[++i]+'].toString()');continue;} if(ar[i]==CAPARRAY){eval(pf+'cap=ol_caps['+ar[++i]+'].toString()');continue;} if(ar[i]==STICKY){if(pf!='ol_')eval(pf+'sticky=1');continue;} if(ar[i]==BACKGROUND){eval(pf+'background="'+ar[++i]+'"');continue;} if(ar[i]==NOCLOSE){if(pf!='ol_')opt_NOCLOSE();continue;} if(ar[i]==CAPTION){eval(pf+"cap='"+escSglQuote(ar[++i])+"'");continue;} if(ar[i]==CENTER||ar[i]==LEFT||ar[i]==RIGHT){eval(pf+'hpos='+ar[i]);if(pf!='ol_')olHautoFlag=1;continue;} if(ar[i]==OFFSETX){eval(pf+'offsetx='+ar[++i]);continue;} if(ar[i]==OFFSETY){eval(pf+'offsety='+ar[++i]);continue;} if(ar[i]==FGCOLOR){eval(pf+'fgcolor="'+ar[++i]+'"');continue;} if(ar[i]==BGCOLOR){eval(pf+'bgcolor="'+ar[++i]+'"');continue;} if(ar[i]==TEXTCOLOR){eval(pf+'textcolor="'+ar[++i]+'"');continue;} if(ar[i]==CAPCOLOR){eval(pf+'capcolor="'+ar[++i]+'"');continue;} if(ar[i]==CLOSECOLOR){eval(pf+'closecolor="'+ar[++i]+'"');continue;} if(ar[i]==WIDTH){eval(pf+'width='+ar[++i]);continue;} if(ar[i]==BORDER){eval(pf+'border='+ar[++i]);continue;} if(ar[i]==CELLPAD){i=opt_MULTIPLEARGS(++i,ar,(pf+'cellpad'));continue;} if(ar[i]==STATUS){eval(pf+"status='"+escSglQuote(ar[++i])+"'");continue;} if(ar[i]==AUTOSTATUS){eval(pf+'autostatus=('+pf+'autostatus==1)?0:1');continue;} if(ar[i]==AUTOSTATUSCAP){eval(pf+'autostatus=('+pf+'autostatus==2)?0:2');continue;} if(ar[i]==HEIGHT){eval(pf+'height='+pf+'aboveheight='+ar[++i]);continue;} if(ar[i]==CLOSETEXT){eval(pf+"close='"+escSglQuote(ar[++i])+"'");continue;} if(ar[i]==SNAPX){eval(pf+'snapx='+ar[++i]);continue;} if(ar[i]==SNAPY){eval(pf+'snapy='+ar[++i]);continue;} if(ar[i]==FIXX){eval(pf+'fixx='+ar[++i]);continue;} if(ar[i]==FIXY){eval(pf+'fixy='+ar[++i]);continue;} if(ar[i]==RELX){eval(pf+'relx='+ar[++i]);continue;} if(ar[i]==RELY){eval(pf+'rely='+ar[++i]);continue;} if(ar[i]==FGBACKGROUND){eval(pf+'fgbackground="'+ar[++i]+'"');continue;} if(ar[i]==BGBACKGROUND){eval(pf+'bgbackground="'+ar[++i]+'"');continue;} if(ar[i]==PADX){eval(pf+'padxl='+ar[++i]);eval(pf+'padxr='+ar[++i]);continue;} if(ar[i]==PADY){eval(pf+'padyt='+ar[++i]);eval(pf+'padyb='+ar[++i]);continue;} if(ar[i]==FULLHTML){if(pf!='ol_')eval(pf+'fullhtml=1');continue;} if(ar[i]==BELOW||ar[i]==ABOVE){eval(pf+'vpos='+ar[i]);if(pf!='ol_')olVautoFlag=1;continue;} if(ar[i]==CAPICON){eval(pf+'capicon="'+ar[++i]+'"');continue;} if(ar[i]==TEXTFONT){eval(pf+"textfont='"+escSglQuote(ar[++i])+"'");continue;} if(ar[i]==CAPTIONFONT){eval(pf+"captionfont='"+escSglQuote(ar[++i])+"'");continue;} if(ar[i]==CLOSEFONT){eval(pf+"closefont='"+escSglQuote(ar[++i])+"'");continue;} if(ar[i]==TEXTSIZE){eval(pf+'textsize="'+ar[++i]+'"');continue;} if(ar[i]==CAPTIONSIZE){eval(pf+'captionsize="'+ar[++i]+'"');continue;} if(ar[i]==CLOSESIZE){eval(pf+'closesize="'+ar[++i]+'"');continue;} if(ar[i]==TIMEOUT){eval(pf+'timeout='+ar[++i]);continue;} if(ar[i]==FUNCTION){if(pf=='ol_'){if(typeof ar[i+1]!='number'){v=ar[++i];ol_function=(typeof v=='function'?v:null);}}else{fnMark=0;v=null;if(typeof ar[i+1]!='number')v=ar[++i]; opt_FUNCTION(v);} continue;} if(ar[i]==DELAY){eval(pf+'delay='+ar[++i]);continue;} if(ar[i]==HAUTO){eval(pf+'hauto=('+pf+'hauto==0)?1:0');continue;} if(ar[i]==VAUTO){eval(pf+'vauto=('+pf+'vauto==0)?1:0');continue;} if(ar[i]==CLOSECLICK){eval(pf+'closeclick=('+pf+'closeclick==0)?1:0');continue;} if(ar[i]==WRAP){eval(pf+'wrap=('+pf+'wrap==0)?1:0');continue;} if(ar[i]==FOLLOWMOUSE){eval(pf+'followmouse=('+pf+'followmouse==1)?0:1');continue;} if(ar[i]==MOUSEOFF){eval(pf+'mouseoff=('+pf+'mouseoff==0)?1:0');v=ar[i+1];if(pf!='ol_'&&eval(pf+'mouseoff')&&typeof v=='number'&&(vpmUpper))olHideDelay=ar[++i];continue;} if(ar[i]==CLOSETITLE){eval(pf+"closetitle='"+escSglQuote(ar[++i])+"'");continue;} if(ar[i]==CSSOFF||ar[i]==CSSCLASS){eval(pf+'css='+ar[i]);continue;} if(ar[i]==COMPATMODE){eval(pf+'compatmode=('+pf+'compatmode==0)?1:0');continue;} if(ar[i]==FGCLASS){eval(pf+'fgclass="'+ar[++i]+'"');continue;} if(ar[i]==BGCLASS){eval(pf+'bgclass="'+ar[++i]+'"');continue;} if(ar[i]==TEXTFONTCLASS){eval(pf+'textfontclass="'+ar[++i]+'"');continue;} if(ar[i]==CAPTIONFONTCLASS){eval(pf+'captionfontclass="'+ar[++i]+'"');continue;} if(ar[i]==CLOSEFONTCLASS){eval(pf+'closefontclass="'+ar[++i]+'"');continue;} i=parseCmdLine(pf,i,ar);}} if(fnMark&&o3_function)o3_text=o3_function(); if((pf=='o3_')&&o3_wrap){o3_width=0; var tReg=/<.*\n*>/ig;if(!tReg.test(o3_text))o3_text=o3_text.replace(/[ ]+/g,' ');if(!tReg.test(o3_cap))o3_cap=o3_cap.replace(/[ ]+/g,' ');} if((pf=='o3_')&&o3_sticky){if(!o3_close&&(o3_frame!=ol_frame))o3_close=ol_close;if(o3_mouseoff&&(o3_frame==ol_frame))opt_NOCLOSE(' ');}} function layerWrite(txt){txt+="\n";if(olNs4){var lyr=o3_frame.document.layers['overDiv'].document lyr.write(txt) lyr.close() }else if(typeof over.innerHTML!='undefined'){if(olIe5&&isMac)over.innerHTML='';over.innerHTML=txt;}else{range=o3_frame.document.createRange();range.setStartAfter(over);domfrag=range.createContextualFragment(txt); while(over.hasChildNodes()){over.removeChild(over.lastChild);} over.appendChild(domfrag);}} function showObject(obj){runHook("showObject",FBEFORE); var theObj=(olNs4?obj:obj.style);theObj.visibility='visible'; runHook("showObject",FAFTER);} function hideObject(obj){runHook("hideObject",FBEFORE); var theObj=(olNs4?obj:obj.style);if(olNs6&&olShowId>0){clearTimeout(olShowId);olShowId=0;} theObj.visibility='hidden';theObj.top=theObj.left=((olIe4&&!olOp)?0:-10000)+(!olNs4?'px':0); if(o3_timerid>0)clearTimeout(o3_timerid);if(o3_delayid>0)clearTimeout(o3_delayid); o3_timerid=0;o3_delayid=0;self.status=""; if(obj.onmouseout||obj.onmouseover){if(olNs4)obj.releaseEvents(Event.MOUSEOUT||Event.MOUSEOVER);obj.onmouseout=obj.onmouseover=null;} runHook("hideObject",FAFTER);} function repositionTo(obj,xL,yL){var theObj=(olNs4?obj:obj.style);theObj.left=xL+(!olNs4?'px':0);theObj.top=yL+(!olNs4?'px':0);} function cursorOff(){var left=parseInt(over.style.left);var top=parseInt(over.style.top);var right=left+(over.offsetWidth>=parseInt(o3_width)?over.offsetWidth:parseInt(o3_width));var bottom=top+(over.offsetHeight>=o3_aboveheight?over.offsetHeight:o3_aboveheight); if(o3_xright||o3_ybottom)return true; return false;} function opt_FUNCTION(callme){o3_text=(callme?(typeof callme=='string'?(/.+\(.*\)/.test(callme)?eval(callme):callme):callme()):(o3_function?o3_function():'No Function')); return 0;} function opt_NOCLOSE(unused){if(!unused)o3_close=""; if(olNs4){over.captureEvents(Event.MOUSEOUT||Event.MOUSEOVER);over.onmouseover=function(){if(o3_timerid>0){clearTimeout(o3_timerid);o3_timerid=0;} } over.onmouseout=function(e){if(olHideDelay)hideDelay(olHideDelay);else cClick(e);} }else{over.onmouseover=function(){hoveringSwitch=true;if(o3_timerid>0){clearTimeout(o3_timerid);o3_timerid=0;} }} return 0;} function opt_MULTIPLEARGS(i,args,parameter){var k=i,re,pV,str=''; for(k=i;kpmStart)break;str+=args[k]+',';} if(str)str=str.substring(0,--str.length); k--;pV=(olNs4&&/cellpad/i.test(parameter))?str.split(',')[0]:str;eval(parameter+'="'+pV+'"'); return k;} function nbspCleanup(){if(o3_wrap){o3_text=o3_text.replace(/\ /g,' ');o3_cap=o3_cap.replace(/\ /g,' ');}} function escSglQuote(str){return str.toString().replace(/'/g,"\\'");} function OLonLoad_handler(e){var re=/\w+\(.*\)[;\s]+/g,olre=/overlib\(|nd\(|cClick\(/,fn,l,i; if(!olLoaded)olLoaded=1; if(window.removeEventListener&&e.eventPhase==3)window.removeEventListener("load",OLonLoad_handler,false);else if(window.detachEvent){window.detachEvent("onload",OLonLoad_handler);var fN=document.body.getAttribute('onload');if(fN){fN=fN.toString().match(re);if(fN&&fN.length){for(i=0;i':'
'):'';else{fontStr='o3_'+whichString+'font';fontColor='o3_'+((whichString=='caption')? 'cap':whichString)+'color';return(hasDims&&!olNs4)?(isClose?'':'
'):'';}} function quoteMultiNameFonts(theFont){var v,pM=theFont.split(',');for(var i=0;i0)clearTimeout(o3_timerid); o3_timerid=setTimeout("cClick()",(o3_timeout=time));}} function horizontalPlacement(browserWidth,horizontalScrollAmount,widthFix){var placeX,iwidth=browserWidth,winoffset=horizontalScrollAmount;var parsedWidth=parseInt(o3_width); if(o3_fixx>-1||o3_relx!=null){ placeX=(o3_relx!=null?( o3_relx<0?winoffset+o3_relx+iwidth-parsedWidth-widthFix:winoffset+o3_relx):o3_fixx);}else{ if(o3_hauto==1){if((o3_x-winoffset)>(iwidth/2)){o3_hpos=LEFT;}else{o3_hpos=RIGHT;}} if(o3_hpos==CENTER){placeX=o3_x+o3_offsetx-(parsedWidth/2); if(placeX(winoffset+iwidth-widthFix)){placeX=iwidth+winoffset-parsedWidth-widthFix;if(placeX<0)placeX=0;}} if(o3_hpos==LEFT){placeX=o3_x-o3_offsetx-parsedWidth;if(placeX1){var snapping=placeX % o3_snapx; if(o3_hpos==LEFT){placeX=placeX-(o3_snapx+snapping);}else{ placeX=placeX+(o3_snapx-snapping);} if(placeX-1||o3_rely!=null){ placeY=(o3_rely!=null?(o3_rely<0?scrolloffset+o3_rely+iheight-parsedHeight:scrolloffset+o3_rely):o3_fixy);}else{ if(o3_vauto==1){if((o3_y-scrolloffset)>(iheight/2)&&o3_vpos==BELOW&&(o3_y+parsedHeight+o3_offsety-(scrolloffset+iheight)>0)){o3_vpos=ABOVE;}else if(o3_vpos==ABOVE&&(o3_y-(parsedHeight+o3_offsety)-scrolloffset<0)){o3_vpos=BELOW;}} if(o3_vpos==ABOVE){if(o3_aboveheight==0)o3_aboveheight=parsedHeight; placeY=o3_y-(o3_aboveheight+o3_offsety);if(placeY1){var snapping=placeY % o3_snapy; if(o3_aboveheight>0&&o3_vpos==ABOVE){placeY=placeY-(o3_snapy+snapping);}else{placeY=placeY+(o3_snapy-snapping);} if(placeY
');divContainer=layerReference(id);}else{divContainer=frm.document.createElement("DIV");divContainer.id=id;body.appendChild(divContainer);} objRef=divContainer.style;} objRef.position='absolute';objRef.visibility='hidden';objRef.zIndex=zValue;if(olIe4&&!olOp)objRef.left=objRef.top='0px';else objRef.left=objRef.top=-10000+(!olNs4?'px':0);} return divContainer;} function layerReference(id){return(olNs4?o3_frame.document.layers[id]:(document.all?o3_frame.document.all[id]:o3_frame.document.getElementById(id)));} function isFunction(fnRef){var rtn=true; if(typeof fnRef=='object'){for(var i=0;ijS){for(var k=jS;k-1){i=j;break;}}} return i;} function postParseChecks(pf,args){if(typeof postParse!='undefined'&&postParse.length){for(var k=0;k-1)hookPt.alt[pms[CSSOFF-1-pmStart]]=fnRef; }else if(hookType==FBEFORE||hookType==FAFTER){var hookPt=(hookType==1?hookPt.before:hookPt.after); if(typeof fnRef=='object'){hookPt=hookPt.concat(fnRef);}else{hookPt[hookPt.length++]=fnRef;} if(optPm)hookPt=reOrder(hookPt,fnRef,optPm); }else if(hookType==FALTERNATE){if(last=='number')hookPt.alt[pms[optPm-1-pmStart]]=fnRef;}else if(hookType==FCHAIN){hookPt=hookPt.chain;if(typeof fnRef=='object')hookPt=hookPt.concat(fnRef);else hookPt[hookPt.length++]=fnRef;} return;}} function registerRunTimeFunction(fn){if(isFunction(fn)){if(typeof fn=='object'){runTime=runTime.concat(fn);}else{runTime[runTime.length++]=fn;}}} function registerCmdLineFunction(fn){if(isFunction(fn)){if(typeof fn=='object'){cmdLine=cmdLine.concat(fn);}else{cmdLine[cmdLine.length++]=fn;}}} function registerPostParseFunction(fn){if(isFunction(fn)){if(typeof fn=='object'){postParse=postParse.concat(fn);}else{postParse[postParse.length++]=fn;}}} function runHook(fnHookTo,hookType){var l=hookPts[fnHookTo],k,rtnVal=null,optPm,arS,ar=runHook.arguments; if(hookType==FREPLACE){arS=argToString(ar,2); if(typeof l=='undefined'||!(l=l.ovload))rtnVal=eval(fnHookTo+'('+arS+')');else rtnVal=eval('l('+arS+')'); }else if(hookType==FBEFORE||hookType==FAFTER){if(typeof l!='undefined'){l=(hookType==1?l.before:l.after); if(l.length){arS=argToString(ar,2);for(var k=0;k0;k--)if((rtnVal=eval('l[k-1]('+arS+')'))!=void(0))break;} return rtnVal;} function FunctionReference(){this.ovload=null;this.before=new Array();this.after=new Array();this.alt=new Array();this.chain=new Array();} function Info(version,prerelease){this.version=version;this.prerelease=prerelease; this.simpleversion=Math.round(this.version*100);this.major=parseInt(this.simpleversion/100);this.minor=parseInt(this.simpleversion/10)-this.major * 10;this.revision=parseInt(this.simpleversion)-this.major * 100-this.minor * 10;this.meets=meets;} function meets(reqdVersion){return(!reqdVersion)?false:this.simpleversion>=Math.round(100*parseFloat(reqdVersion));} registerHook("ol_content_simple",ol_content_simple,FALTERNATE,CSSOFF);registerHook("ol_content_caption",ol_content_caption,FALTERNATE,CSSOFF);registerHook("ol_content_background",ol_content_background,FALTERNATE,CSSOFF);registerHook("ol_content_simple",ol_content_simple,FALTERNATE,CSSCLASS);registerHook("ol_content_caption",ol_content_caption,FALTERNATE,CSSCLASS);registerHook("ol_content_background",ol_content_background,FALTERNATE,CSSCLASS);registerPostParseFunction(checkPositionFlags);registerHook("hideObject",nbspCleanup,FAFTER);registerHook("horizontalPlacement",horizontalPlacement,FCHAIN);registerHook("verticalPlacement",verticalPlacement,FCHAIN);if(olNs4||(olIe5&&isMac)||olKq)olLoaded=1;registerNoParameterCommands('sticky,autostatus,autostatuscap,fullhtml,hauto,vauto,closeclick,wrap,followmouse,mouseoff,compatmode'); var olCheckMouseCapture=true;if((olNs4||olNs6||olIe4)){olMouseCapture();}else{overlib=no_overlib;nd=no_overlib;ver3fix=true;} ================================================ FILE: tools/server/admin/scripts/index.html ================================================ ================================================ FILE: tools/server/admin/scripts/restart_sequence.php ================================================ ================================================ FILE: tools/server/admin/scripts/run_script.sh ================================================ #!/bin/bash # we might want to add some security here, in order to check the parameters cd /home/atrium-admin/public_html/scripts nohup /usr/bin/php4 $* >/dev/null & ================================================ FILE: tools/server/admin/smarty/Config_File.class.php ================================================ * @access public * @package Smarty */ /* $Id: Config_File.class.php,v 1.1 2006/05/29 16:38:21 powles Exp $ */ /** * Config file reading class * @package Smarty */ class Config_File { /**#@+ * Options * @var boolean */ /** * Controls whether variables with the same name overwrite each other. */ var $overwrite = true; /** * Controls whether config values of on/true/yes and off/false/no get * converted to boolean values automatically. */ var $booleanize = true; /** * Controls whether hidden config sections/vars are read from the file. */ var $read_hidden = true; /** * Controls whether or not to fix mac or dos formatted newlines. * If set to true, \r or \r\n will be changed to \n. */ var $fix_newlines = true; /**#@-*/ /** @access private */ var $_config_path = ""; var $_config_data = array(); /**#@-*/ /** * Constructs a new config file class. * * @param string $config_path (optional) path to the config files */ function Config_File($config_path = NULL) { if (isset($config_path)) $this->set_path($config_path); } /** * Set the path where configuration files can be found. * * @param string $config_path path to the config files */ function set_path($config_path) { if (!empty($config_path)) { if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) { $this->_trigger_error_msg("Bad config file path '$config_path'"); return; } if(substr($config_path, -1) != DIRECTORY_SEPARATOR) { $config_path .= DIRECTORY_SEPARATOR; } $this->_config_path = $config_path; } } /** * Retrieves config info based on the file, section, and variable name. * * @param string $file_name config file to get info for * @param string $section_name (optional) section to get info for * @param string $var_name (optional) variable to get info for * @return string|array a value or array of values */ function &get($file_name, $section_name = NULL, $var_name = NULL) { if (empty($file_name)) { $this->_trigger_error_msg('Empty config file name'); return; } else { $file_name = $this->_config_path . $file_name; if (!isset($this->_config_data[$file_name])) $this->load_file($file_name, false); } if (!empty($var_name)) { if (empty($section_name)) { return $this->_config_data[$file_name]["vars"][$var_name]; } else { if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name])) return $this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name]; else return array(); } } else { if (empty($section_name)) { return (array)$this->_config_data[$file_name]["vars"]; } else { if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"])) return (array)$this->_config_data[$file_name]["sections"][$section_name]["vars"]; else return array(); } } } /** * Retrieves config info based on the key. * * @param $file_name string config key (filename/section/var) * @return string|array same as get() * @uses get() retrieves information from config file and returns it */ function &get_key($config_key) { list($file_name, $section_name, $var_name) = explode('/', $config_key, 3); $result = &$this->get($file_name, $section_name, $var_name); return $result; } /** * Get all loaded config file names. * * @return array an array of loaded config file names */ function get_file_names() { return array_keys($this->_config_data); } /** * Get all section names from a loaded file. * * @param string $file_name config file to get section names from * @return array an array of section names from the specified file */ function get_section_names($file_name) { $file_name = $this->_config_path . $file_name; if (!isset($this->_config_data[$file_name])) { $this->_trigger_error_msg("Unknown config file '$file_name'"); return; } return array_keys($this->_config_data[$file_name]["sections"]); } /** * Get all global or section variable names. * * @param string $file_name config file to get info for * @param string $section_name (optional) section to get info for * @return array an array of variables names from the specified file/section */ function get_var_names($file_name, $section = NULL) { if (empty($file_name)) { $this->_trigger_error_msg('Empty config file name'); return; } else if (!isset($this->_config_data[$file_name])) { $this->_trigger_error_msg("Unknown config file '$file_name'"); return; } if (empty($section)) return array_keys($this->_config_data[$file_name]["vars"]); else return array_keys($this->_config_data[$file_name]["sections"][$section]["vars"]); } /** * Clear loaded config data for a certain file or all files. * * @param string $file_name file to clear config data for */ function clear($file_name = NULL) { if ($file_name === NULL) $this->_config_data = array(); else if (isset($this->_config_data[$file_name])) $this->_config_data[$file_name] = array(); } /** * Load a configuration file manually. * * @param string $file_name file name to load * @param boolean $prepend_path whether current config path should be * prepended to the filename */ function load_file($file_name, $prepend_path = true) { if ($prepend_path && $this->_config_path != "") $config_file = $this->_config_path . $file_name; else $config_file = $file_name; ini_set('track_errors', true); $fp = @fopen($config_file, "r"); if (!is_resource($fp)) { $this->_trigger_error_msg("Could not open config file '$config_file'"); return false; } $contents = ($size = filesize($config_file)) ? fread($fp, $size) : ''; fclose($fp); $this->_config_data[$config_file] = $this->parse_contents($contents); return true; } /** * Store the contents of a file manually. * * @param string $config_file file name of the related contents * @param string $contents the file-contents to parse */ function set_file_contents($config_file, $contents) { $this->_config_data[$config_file] = $this->parse_contents($contents); return true; } /** * parse the source of a configuration file manually. * * @param string $contents the file-contents to parse */ function parse_contents($contents) { if($this->fix_newlines) { // fix mac/dos formatted newlines $contents = preg_replace('!\r\n?!', "\n", $contents); } $config_data = array(); $config_data['sections'] = array(); $config_data['vars'] = array(); /* reference to fill with data */ $vars =& $config_data['vars']; /* parse file line by line */ preg_match_all('!^.*\r?\n?!m', $contents, $match); $lines = $match[0]; for ($i=0, $count=count($lines); $i<$count; $i++) { $line = $lines[$i]; if (empty($line)) continue; if ( $line{0} == '[' && preg_match('!^\[(.*?)\]!', $line, $match) ) { /* section found */ if ($match[1]{0} == '.') { /* hidden section */ if ($this->read_hidden) { $section_name = substr($match[1], 1); } else { /* break reference to $vars to ignore hidden section */ unset($vars); $vars = array(); continue; } } else { $section_name = $match[1]; } if (!isset($config_data['sections'][$section_name])) $config_data['sections'][$section_name] = array('vars' => array()); $vars =& $config_data['sections'][$section_name]['vars']; continue; } if (preg_match('/^\s*(\.?\w+)\s*=\s*(.*)/s', $line, $match)) { /* variable found */ $var_name = rtrim($match[1]); if (strpos($match[2], '"""') === 0) { /* handle multiline-value */ $lines[$i] = substr($match[2], 3); $var_value = ''; while ($i<$count) { if (($pos = strpos($lines[$i], '"""')) === false) { $var_value .= $lines[$i++]; } else { /* end of multiline-value */ $var_value .= substr($lines[$i], 0, $pos); break; } } $booleanize = false; } else { /* handle simple value */ $var_value = preg_replace('/^([\'"])(.*)\1$/', '\2', rtrim($match[2])); $booleanize = $this->booleanize; } $this->_set_config_var($vars, $var_name, $var_value, $booleanize); } /* else unparsable line / means it is a comment / means ignore it */ } return $config_data; } /**#@+ @access private */ /** * @param array &$container * @param string $var_name * @param mixed $var_value * @param boolean $booleanize determines whether $var_value is converted to * to true/false */ function _set_config_var(&$container, $var_name, $var_value, $booleanize) { if ($var_name{0} == '.') { if (!$this->read_hidden) return; else $var_name = substr($var_name, 1); } if (!preg_match("/^[a-zA-Z_]\w*$/", $var_name)) { $this->_trigger_error_msg("Bad variable name '$var_name'"); return; } if ($booleanize) { if (preg_match("/^(on|true|yes)$/i", $var_value)) $var_value = true; else if (preg_match("/^(off|false|no)$/i", $var_value)) $var_value = false; } if (!isset($container[$var_name]) || $this->overwrite) $container[$var_name] = $var_value; else { settype($container[$var_name], 'array'); $container[$var_name][] = $var_value; } } /** * @uses trigger_error() creates a PHP warning/error * @param string $error_msg * @param integer $error_type one of */ function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING) { trigger_error("Config_File error: $error_msg", $error_type); } /**#@-*/ } ?> ================================================ FILE: tools/server/admin/smarty/Smarty.class.php ================================================ * @author Andrei Zmievski * @package Smarty * @version 2.6.9 */ /* $Id: Smarty.class.php,v 1.1 2006/05/29 16:38:21 powles Exp $ */ /** * DIR_SEP isn't used anymore, but third party apps might */ if(!defined('DIR_SEP')) { define('DIR_SEP', DIRECTORY_SEPARATOR); } /** * set SMARTY_DIR to absolute path to Smarty library files. * if not defined, include_path will be used. Sets SMARTY_DIR only if user * application has not already defined it. */ if (!defined('SMARTY_DIR')) { define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); } if (!defined('SMARTY_CORE_DIR')) { define('SMARTY_CORE_DIR', SMARTY_DIR . 'internals' . DIRECTORY_SEPARATOR); } define('SMARTY_PHP_PASSTHRU', 0); define('SMARTY_PHP_QUOTE', 1); define('SMARTY_PHP_REMOVE', 2); define('SMARTY_PHP_ALLOW', 3); /** * @package Smarty */ class Smarty { /**#@+ * Smarty Configuration Section */ /** * The name of the directory where templates are located. * * @var string */ var $template_dir = 'templates'; /** * The directory where compiled templates are located. * * @var string */ var $compile_dir = 'templates_c'; /** * The directory where config files are located. * * @var string */ var $config_dir = 'configs'; /** * An array of directories searched for plugins. * * @var array */ var $plugins_dir = array('plugins'); /** * If debugging is enabled, a debug console window will display * when the page loads (make sure your browser allows unrequested * popup windows) * * @var boolean */ var $debugging = false; /** * When set, smarty does uses this value as error_reporting-level. * * @var boolean */ var $error_reporting = null; /** * This is the path to the debug console template. If not set, * the default one will be used. * * @var string */ var $debug_tpl = ''; /** * This determines if debugging is enable-able from the browser. *
    *
  • NONE => no debugging control allowed
  • *
  • URL => enable debugging when SMARTY_DEBUG is found in the URL.
  • *
* @link http://www.foo.dom/index.php?SMARTY_DEBUG * @var string */ var $debugging_ctrl = 'NONE'; /** * This tells Smarty whether to check for recompiling or not. Recompiling * does not need to happen unless a template or config file is changed. * Typically you enable this during development, and disable for * production. * * @var boolean */ var $compile_check = true; /** * This forces templates to compile every time. Useful for development * or debugging. * * @var boolean */ var $force_compile = false; /** * This enables template caching. *
    *
  • 0 = no caching
  • *
  • 1 = use class cache_lifetime value
  • *
  • 2 = use cache_lifetime in cache file
  • *
* @var integer */ var $caching = 0; /** * The name of the directory for cache files. * * @var string */ var $cache_dir = 'cache'; /** * This is the number of seconds cached content will persist. *
    *
  • 0 = always regenerate cache
  • *
  • -1 = never expires
  • *
* * @var integer */ var $cache_lifetime = 3600; /** * Only used when $caching is enabled. If true, then If-Modified-Since headers * are respected with cached content, and appropriate HTTP headers are sent. * This way repeated hits to a cached page do not send the entire page to the * client every time. * * @var boolean */ var $cache_modified_check = false; /** * This determines how Smarty handles "" tags in templates. * possible values: *
    *
  • SMARTY_PHP_PASSTHRU -> print tags as plain text
  • *
  • SMARTY_PHP_QUOTE -> escape tags as entities
  • *
  • SMARTY_PHP_REMOVE -> remove php tags
  • *
  • SMARTY_PHP_ALLOW -> execute php tags
  • *
* * @var integer */ var $php_handling = SMARTY_PHP_PASSTHRU; /** * This enables template security. When enabled, many things are restricted * in the templates that normally would go unchecked. This is useful when * untrusted parties are editing templates and you want a reasonable level * of security. (no direct execution of PHP in templates for example) * * @var boolean */ var $security = false; /** * This is the list of template directories that are considered secure. This * is used only if {@link $security} is enabled. One directory per array * element. {@link $template_dir} is in this list implicitly. * * @var array */ var $secure_dir = array(); /** * These are the security settings for Smarty. They are used only when * {@link $security} is enabled. * * @var array */ var $security_settings = array( 'PHP_HANDLING' => false, 'IF_FUNCS' => array('array', 'list', 'isset', 'empty', 'count', 'sizeof', 'in_array', 'is_array', 'true', 'false', 'null'), 'INCLUDE_ANY' => false, 'PHP_TAGS' => false, 'MODIFIER_FUNCS' => array('count'), 'ALLOW_CONSTANTS' => false ); /** * This is an array of directories where trusted php scripts reside. * {@link $security} is disabled during their inclusion/execution. * * @var array */ var $trusted_dir = array(); /** * The left delimiter used for the template tags. * * @var string */ var $left_delimiter = '{'; /** * The right delimiter used for the template tags. * * @var string */ var $right_delimiter = '}'; /** * The order in which request variables are registered, similar to * variables_order in php.ini E = Environment, G = GET, P = POST, * C = Cookies, S = Server * * @var string */ var $request_vars_order = 'EGPCS'; /** * Indicates wether $HTTP_*_VARS[] (request_use_auto_globals=false) * are uses as request-vars or $_*[]-vars. note: if * request_use_auto_globals is true, then $request_vars_order has * no effect, but the php-ini-value "gpc_order" * * @var boolean */ var $request_use_auto_globals = true; /** * Set this if you want different sets of compiled files for the same * templates. This is useful for things like different languages. * Instead of creating separate sets of templates per language, you * set different compile_ids like 'en' and 'de'. * * @var string */ var $compile_id = null; /** * This tells Smarty whether or not to use sub dirs in the cache/ and * templates_c/ directories. sub directories better organized, but * may not work well with PHP safe mode enabled. * * @var boolean * */ var $use_sub_dirs = false; /** * This is a list of the modifiers to apply to all template variables. * Put each modifier in a separate array element in the order you want * them applied. example: array('escape:"htmlall"'); * * @var array */ var $default_modifiers = array(); /** * This is the resource type to be used when not specified * at the beginning of the resource path. examples: * $smarty->display('file:index.tpl'); * $smarty->display('db:index.tpl'); * $smarty->display('index.tpl'); // will use default resource type * {include file="file:index.tpl"} * {include file="db:index.tpl"} * {include file="index.tpl"} {* will use default resource type *} * * @var array */ var $default_resource_type = 'file'; /** * The function used for cache file handling. If not set, built-in caching is used. * * @var null|string function name */ var $cache_handler_func = null; /** * This indicates which filters are automatically loaded into Smarty. * * @var array array of filter names */ var $autoload_filters = array(); /**#@+ * @var boolean */ /** * This tells if config file vars of the same name overwrite each other or not. * if disabled, same name variables are accumulated in an array. */ var $config_overwrite = true; /** * This tells whether or not to automatically booleanize config file variables. * If enabled, then the strings "on", "true", and "yes" are treated as boolean * true, and "off", "false" and "no" are treated as boolean false. */ var $config_booleanize = true; /** * This tells whether hidden sections [.foobar] are readable from the * tempalates or not. Normally you would never allow this since that is * the point behind hidden sections: the application can access them, but * the templates cannot. */ var $config_read_hidden = false; /** * This tells whether or not automatically fix newlines in config files. * It basically converts \r (mac) or \r\n (dos) to \n */ var $config_fix_newlines = true; /**#@-*/ /** * If a template cannot be found, this PHP function will be executed. * Useful for creating templates on-the-fly or other special action. * * @var string function name */ var $default_template_handler_func = ''; /** * The file that contains the compiler class. This can a full * pathname, or relative to the php_include path. * * @var string */ var $compiler_file = 'Smarty_Compiler.class.php'; /** * The class used for compiling templates. * * @var string */ var $compiler_class = 'Smarty_Compiler'; /** * The class used to load config vars. * * @var string */ var $config_class = 'Config_File'; /**#@+ * END Smarty Configuration Section * There should be no need to touch anything below this line. * @access private */ /** * where assigned template vars are kept * * @var array */ var $_tpl_vars = array(); /** * stores run-time $smarty.* vars * * @var null|array */ var $_smarty_vars = null; /** * keeps track of sections * * @var array */ var $_sections = array(); /** * keeps track of foreach blocks * * @var array */ var $_foreach = array(); /** * keeps track of tag hierarchy * * @var array */ var $_tag_stack = array(); /** * configuration object * * @var Config_file */ var $_conf_obj = null; /** * loaded configuration settings * * @var array */ var $_config = array(array('vars' => array(), 'files' => array())); /** * md5 checksum of the string 'Smarty' * * @var string */ var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; /** * Smarty version number * * @var string */ var $_version = '2.6.9'; /** * current template inclusion depth * * @var integer */ var $_inclusion_depth = 0; /** * for different compiled templates * * @var string */ var $_compile_id = null; /** * text in URL to enable debug mode * * @var string */ var $_smarty_debug_id = 'SMARTY_DEBUG'; /** * debugging information for debug console * * @var array */ var $_smarty_debug_info = array(); /** * info that makes up a cache file * * @var array */ var $_cache_info = array(); /** * default file permissions * * @var integer */ var $_file_perms = 0644; /** * default dir permissions * * @var integer */ var $_dir_perms = 0771; /** * registered objects * * @var array */ var $_reg_objects = array(); /** * table keeping track of plugins * * @var array */ var $_plugins = array( 'modifier' => array(), 'function' => array(), 'block' => array(), 'compiler' => array(), 'prefilter' => array(), 'postfilter' => array(), 'outputfilter' => array(), 'resource' => array(), 'insert' => array()); /** * cache serials * * @var array */ var $_cache_serials = array(); /** * name of optional cache include file * * @var string */ var $_cache_include = null; /** * indicate if the current code is used in a compiled * include * * @var string */ var $_cache_including = false; /**#@-*/ /** * The class constructor. */ function Smarty() { $this->assign('SCRIPT_NAME', isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : @$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_NAME']); } /** * assigns values to template variables * * @param array|string $tpl_var the template variable name(s) * @param mixed $value the value to assign */ function assign($tpl_var, $value = null) { if (is_array($tpl_var)){ foreach ($tpl_var as $key => $val) { if ($key != '') { $this->_tpl_vars[$key] = $val; } } } else { if ($tpl_var != '') $this->_tpl_vars[$tpl_var] = $value; } } /** * assigns values to template variables by reference * * @param string $tpl_var the template variable name * @param mixed $value the referenced value to assign */ function assign_by_ref($tpl_var, &$value) { if ($tpl_var != '') $this->_tpl_vars[$tpl_var] = &$value; } /** * appends values to template variables * * @param array|string $tpl_var the template variable name(s) * @param mixed $value the value to append */ function append($tpl_var, $value=null, $merge=false) { if (is_array($tpl_var)) { // $tpl_var is an array, ignore $value foreach ($tpl_var as $_key => $_val) { if ($_key != '') { if(!@is_array($this->_tpl_vars[$_key])) { settype($this->_tpl_vars[$_key],'array'); } if($merge && is_array($_val)) { foreach($_val as $_mkey => $_mval) { $this->_tpl_vars[$_key][$_mkey] = $_mval; } } else { $this->_tpl_vars[$_key][] = $_val; } } } } else { if ($tpl_var != '' && isset($value)) { if(!@is_array($this->_tpl_vars[$tpl_var])) { settype($this->_tpl_vars[$tpl_var],'array'); } if($merge && is_array($value)) { foreach($value as $_mkey => $_mval) { $this->_tpl_vars[$tpl_var][$_mkey] = $_mval; } } else { $this->_tpl_vars[$tpl_var][] = $value; } } } } /** * appends values to template variables by reference * * @param string $tpl_var the template variable name * @param mixed $value the referenced value to append */ function append_by_ref($tpl_var, &$value, $merge=false) { if ($tpl_var != '' && isset($value)) { if(!@is_array($this->_tpl_vars[$tpl_var])) { settype($this->_tpl_vars[$tpl_var],'array'); } if ($merge && is_array($value)) { foreach($value as $_key => $_val) { $this->_tpl_vars[$tpl_var][$_key] = &$value[$_key]; } } else { $this->_tpl_vars[$tpl_var][] = &$value; } } } /** * clear the given assigned template variable. * * @param string $tpl_var the template variable to clear */ function clear_assign($tpl_var) { if (is_array($tpl_var)) foreach ($tpl_var as $curr_var) unset($this->_tpl_vars[$curr_var]); else unset($this->_tpl_vars[$tpl_var]); } /** * Registers custom function to be used in templates * * @param string $function the name of the template function * @param string $function_impl the name of the PHP function to register */ function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null) { $this->_plugins['function'][$function] = array($function_impl, null, null, false, $cacheable, $cache_attrs); } /** * Unregisters custom function * * @param string $function name of template function */ function unregister_function($function) { unset($this->_plugins['function'][$function]); } /** * Registers object to be used in templates * * @param string $object name of template object * @param object &$object_impl the referenced PHP object to register * @param null|array $allowed list of allowed methods (empty = all) * @param boolean $smarty_args smarty argument format, else traditional * @param null|array $block_functs list of methods that are block format */ function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) { settype($allowed, 'array'); settype($smarty_args, 'boolean'); $this->_reg_objects[$object] = array(&$object_impl, $allowed, $smarty_args, $block_methods); } /** * Unregisters object * * @param string $object name of template object */ function unregister_object($object) { unset($this->_reg_objects[$object]); } /** * Registers block function to be used in templates * * @param string $block name of template block * @param string $block_impl PHP function to register */ function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null) { $this->_plugins['block'][$block] = array($block_impl, null, null, false, $cacheable, $cache_attrs); } /** * Unregisters block function * * @param string $block name of template function */ function unregister_block($block) { unset($this->_plugins['block'][$block]); } /** * Registers compiler function * * @param string $function name of template function * @param string $function_impl name of PHP function to register */ function register_compiler_function($function, $function_impl, $cacheable=true) { $this->_plugins['compiler'][$function] = array($function_impl, null, null, false, $cacheable); } /** * Unregisters compiler function * * @param string $function name of template function */ function unregister_compiler_function($function) { unset($this->_plugins['compiler'][$function]); } /** * Registers modifier to be used in templates * * @param string $modifier name of template modifier * @param string $modifier_impl name of PHP function to register */ function register_modifier($modifier, $modifier_impl) { $this->_plugins['modifier'][$modifier] = array($modifier_impl, null, null, false); } /** * Unregisters modifier * * @param string $modifier name of template modifier */ function unregister_modifier($modifier) { unset($this->_plugins['modifier'][$modifier]); } /** * Registers a resource to fetch a template * * @param string $type name of resource * @param array $functions array of functions to handle resource */ function register_resource($type, $functions) { if (count($functions)==4) { $this->_plugins['resource'][$type] = array($functions, false); } elseif (count($functions)==5) { $this->_plugins['resource'][$type] = array(array(array(&$functions[0], $functions[1]) ,array(&$functions[0], $functions[2]) ,array(&$functions[0], $functions[3]) ,array(&$functions[0], $functions[4])) ,false); } else { $this->trigger_error("malformed function-list for '$type' in register_resource"); } } /** * Unregisters a resource * * @param string $type name of resource */ function unregister_resource($type) { unset($this->_plugins['resource'][$type]); } /** * Registers a prefilter function to apply * to a template before compiling * * @param string $function name of PHP function to register */ function register_prefilter($function) { $_name = (is_array($function)) ? $function[1] : $function; $this->_plugins['prefilter'][$_name] = array($function, null, null, false); } /** * Unregisters a prefilter function * * @param string $function name of PHP function */ function unregister_prefilter($function) { unset($this->_plugins['prefilter'][$function]); } /** * Registers a postfilter function to apply * to a compiled template after compilation * * @param string $function name of PHP function to register */ function register_postfilter($function) { $_name = (is_array($function)) ? $function[1] : $function; $this->_plugins['postfilter'][$_name] = array($function, null, null, false); } /** * Unregisters a postfilter function * * @param string $function name of PHP function */ function unregister_postfilter($function) { unset($this->_plugins['postfilter'][$function]); } /** * Registers an output filter function to apply * to a template output * * @param string $function name of PHP function */ function register_outputfilter($function) { $_name = (is_array($function)) ? $function[1] : $function; $this->_plugins['outputfilter'][$_name] = array($function, null, null, false); } /** * Unregisters an outputfilter function * * @param string $function name of PHP function */ function unregister_outputfilter($function) { unset($this->_plugins['outputfilter'][$function]); } /** * load a filter of specified type and name * * @param string $type filter type * @param string $name filter name */ function load_filter($type, $name) { switch ($type) { case 'output': $_params = array('plugins' => array(array($type . 'filter', $name, null, null, false))); require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); smarty_core_load_plugins($_params, $this); break; case 'pre': case 'post': if (!isset($this->_plugins[$type . 'filter'][$name])) $this->_plugins[$type . 'filter'][$name] = false; break; } } /** * clear cached content for the given template and cache id * * @param string $tpl_file name of template file * @param string $cache_id name of cache_id * @param string $compile_id name of compile_id * @param string $exp_time expiration time * @return boolean */ function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null) { if (!isset($compile_id)) $compile_id = $this->compile_id; if (!isset($tpl_file)) $compile_id = null; $_auto_id = $this->_get_auto_id($cache_id, $compile_id); if (!empty($this->cache_handler_func)) { return call_user_func_array($this->cache_handler_func, array('clear', &$this, &$dummy, $tpl_file, $cache_id, $compile_id, $exp_time)); } else { $_params = array('auto_base' => $this->cache_dir, 'auto_source' => $tpl_file, 'auto_id' => $_auto_id, 'exp_time' => $exp_time); require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); return smarty_core_rm_auto($_params, $this); } } /** * clear the entire contents of cache (all templates) * * @param string $exp_time expire time * @return boolean results of {@link smarty_core_rm_auto()} */ function clear_all_cache($exp_time = null) { return $this->clear_cache(null, null, null, $exp_time); } /** * test to see if valid cache exists for this template * * @param string $tpl_file name of template file * @param string $cache_id * @param string $compile_id * @return string|false results of {@link _read_cache_file()} */ function is_cached($tpl_file, $cache_id = null, $compile_id = null) { if (!$this->caching) return false; if (!isset($compile_id)) $compile_id = $this->compile_id; $_params = array( 'tpl_file' => $tpl_file, 'cache_id' => $cache_id, 'compile_id' => $compile_id ); require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); return smarty_core_read_cache_file($_params, $this); } /** * clear all the assigned template variables. * */ function clear_all_assign() { $this->_tpl_vars = array(); } /** * clears compiled version of specified template resource, * or all compiled template files if one is not specified. * This function is for advanced use only, not normally needed. * * @param string $tpl_file * @param string $compile_id * @param string $exp_time * @return boolean results of {@link smarty_core_rm_auto()} */ function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null) { if (!isset($compile_id)) { $compile_id = $this->compile_id; } $_params = array('auto_base' => $this->compile_dir, 'auto_source' => $tpl_file, 'auto_id' => $compile_id, 'exp_time' => $exp_time, 'extensions' => array('.inc', '.php')); require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); return smarty_core_rm_auto($_params, $this); } /** * Checks whether requested template exists. * * @param string $tpl_file * @return boolean */ function template_exists($tpl_file) { $_params = array('resource_name' => $tpl_file, 'quiet'=>true, 'get_source'=>false); return $this->_fetch_resource_info($_params); } /** * Returns an array containing template variables * * @param string $name * @param string $type * @return array */ function &get_template_vars($name=null) { if(!isset($name)) { return $this->_tpl_vars; } if(isset($this->_tpl_vars[$name])) { return $this->_tpl_vars[$name]; } } /** * Returns an array containing config variables * * @param string $name * @param string $type * @return array */ function &get_config_vars($name=null) { if(!isset($name) && is_array($this->_config[0])) { return $this->_config[0]['vars']; } else if(isset($this->_config[0]['vars'][$name])) { return $this->_config[0]['vars'][$name]; } } /** * trigger Smarty error * * @param string $error_msg * @param integer $error_type */ function trigger_error($error_msg, $error_type = E_USER_WARNING) { trigger_error("Smarty error: $error_msg", $error_type); } /** * executes & displays the template results * * @param string $resource_name * @param string $cache_id * @param string $compile_id */ function display($resource_name, $cache_id = null, $compile_id = null) { $this->fetch($resource_name, $cache_id, $compile_id, true); } /** * executes & returns or displays the template results * * @param string $resource_name * @param string $cache_id * @param string $compile_id * @param boolean $display */ function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false) { static $_cache_info = array(); $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting) ? $this->error_reporting : error_reporting() & ~E_NOTICE); if (!$this->debugging && $this->debugging_ctrl == 'URL') { $_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']; if (@strstr($_query_string, $this->_smarty_debug_id)) { if (@strstr($_query_string, $this->_smarty_debug_id . '=on')) { // enable debugging for this browser session @setcookie('SMARTY_DEBUG', true); $this->debugging = true; } elseif (@strstr($_query_string, $this->_smarty_debug_id . '=off')) { // disable debugging for this browser session @setcookie('SMARTY_DEBUG', false); $this->debugging = false; } else { // enable debugging for this page $this->debugging = true; } } else { $this->debugging = (bool)($this->request_use_auto_globals ? @$_COOKIE['SMARTY_DEBUG'] : @$GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG']); } } if ($this->debugging) { // capture time for debugging info $_params = array(); require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); $_debug_start_time = smarty_core_get_microtime($_params, $this); $this->_smarty_debug_info[] = array('type' => 'template', 'filename' => $resource_name, 'depth' => 0); $_included_tpls_idx = count($this->_smarty_debug_info) - 1; } if (!isset($compile_id)) { $compile_id = $this->compile_id; } $this->_compile_id = $compile_id; $this->_inclusion_depth = 0; if ($this->caching) { // save old cache_info, initialize cache_info array_push($_cache_info, $this->_cache_info); $this->_cache_info = array(); $_params = array( 'tpl_file' => $resource_name, 'cache_id' => $cache_id, 'compile_id' => $compile_id, 'results' => null ); require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); if (smarty_core_read_cache_file($_params, $this)) { $_smarty_results = $_params['results']; if (!empty($this->_cache_info['insert_tags'])) { $_params = array('plugins' => $this->_cache_info['insert_tags']); require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); smarty_core_load_plugins($_params, $this); $_params = array('results' => $_smarty_results); require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); $_smarty_results = smarty_core_process_cached_inserts($_params, $this); } if (!empty($this->_cache_info['cache_serials'])) { $_params = array('results' => $_smarty_results); require_once(SMARTY_CORE_DIR . 'core.process_compiled_include.php'); $_smarty_results = smarty_core_process_compiled_include($_params, $this); } if ($display) { if ($this->debugging) { // capture time for debugging info $_params = array(); require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $_debug_start_time; require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); $_smarty_results .= smarty_core_display_debug_console($_params, $this); } if ($this->cache_modified_check) { $_server_vars = ($this->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; $_last_modified_date = @substr($_server_vars['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_server_vars['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3); $_gmt_mtime = gmdate('D, d M Y H:i:s', $this->_cache_info['timestamp']).' GMT'; if (@count($this->_cache_info['insert_tags']) == 0 && !$this->_cache_serials && $_gmt_mtime == $_last_modified_date) { if (php_sapi_name()=='cgi') header('Status: 304 Not Modified'); else header('HTTP/1.1 304 Not Modified'); } else { header('Last-Modified: '.$_gmt_mtime); echo $_smarty_results; } } else { echo $_smarty_results; } error_reporting($_smarty_old_error_level); // restore initial cache_info $this->_cache_info = array_pop($_cache_info); return true; } else { error_reporting($_smarty_old_error_level); // restore initial cache_info $this->_cache_info = array_pop($_cache_info); return $_smarty_results; } } else { $this->_cache_info['template'][$resource_name] = true; if ($this->cache_modified_check && $display) { header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT'); } } } // load filters that are marked as autoload if (count($this->autoload_filters)) { foreach ($this->autoload_filters as $_filter_type => $_filters) { foreach ($_filters as $_filter) { $this->load_filter($_filter_type, $_filter); } } } $_smarty_compile_path = $this->_get_compile_path($resource_name); // if we just need to display the results, don't perform output // buffering - for speed $_cache_including = $this->_cache_including; $this->_cache_including = false; if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) { if ($this->_is_compiled($resource_name, $_smarty_compile_path) || $this->_compile_resource($resource_name, $_smarty_compile_path)) { include($_smarty_compile_path); } } else { ob_start(); if ($this->_is_compiled($resource_name, $_smarty_compile_path) || $this->_compile_resource($resource_name, $_smarty_compile_path)) { include($_smarty_compile_path); } $_smarty_results = ob_get_contents(); ob_end_clean(); foreach ((array)$this->_plugins['outputfilter'] as $_output_filter) { $_smarty_results = call_user_func_array($_output_filter[0], array($_smarty_results, &$this)); } } if ($this->caching) { $_params = array('tpl_file' => $resource_name, 'cache_id' => $cache_id, 'compile_id' => $compile_id, 'results' => $_smarty_results); require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php'); smarty_core_write_cache_file($_params, $this); require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); $_smarty_results = smarty_core_process_cached_inserts($_params, $this); if ($this->_cache_serials) { // strip nocache-tags from output $_smarty_results = preg_replace('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!s' ,'' ,$_smarty_results); } // restore initial cache_info $this->_cache_info = array_pop($_cache_info); } $this->_cache_including = $_cache_including; if ($display) { if (isset($_smarty_results)) { echo $_smarty_results; } if ($this->debugging) { // capture time for debugging info $_params = array(); require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = (smarty_core_get_microtime($_params, $this) - $_debug_start_time); require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); echo smarty_core_display_debug_console($_params, $this); } error_reporting($_smarty_old_error_level); return; } else { error_reporting($_smarty_old_error_level); if (isset($_smarty_results)) { return $_smarty_results; } } } /** * load configuration values * * @param string $file * @param string $section * @param string $scope */ function config_load($file, $section = null, $scope = 'global') { require_once($this->_get_plugin_filepath('function', 'config_load')); smarty_function_config_load(array('file' => $file, 'section' => $section, 'scope' => $scope), $this); } /** * return a reference to a registered object * * @param string $name * @return object */ function &get_registered_object($name) { if (!isset($this->_reg_objects[$name])) $this->_trigger_fatal_error("'$name' is not a registered object"); if (!is_object($this->_reg_objects[$name][0])) $this->_trigger_fatal_error("registered '$name' is not an object"); return $this->_reg_objects[$name][0]; } /** * clear configuration values * * @param string $var */ function clear_config($var = null) { if(!isset($var)) { // clear all values $this->_config = array(array('vars' => array(), 'files' => array())); } else { unset($this->_config[0]['vars'][$var]); } } /** * get filepath of requested plugin * * @param string $type * @param string $name * @return string|false */ function _get_plugin_filepath($type, $name) { $_params = array('type' => $type, 'name' => $name); require_once(SMARTY_CORE_DIR . 'core.assemble_plugin_filepath.php'); return smarty_core_assemble_plugin_filepath($_params, $this); } /** * test if resource needs compiling * * @param string $resource_name * @param string $compile_path * @return boolean */ function _is_compiled($resource_name, $compile_path) { if (!$this->force_compile && file_exists($compile_path)) { if (!$this->compile_check) { // no need to check compiled file return true; } else { // get file source and timestamp $_params = array('resource_name' => $resource_name, 'get_source'=>false); if (!$this->_fetch_resource_info($_params)) { return false; } if ($_params['resource_timestamp'] <= filemtime($compile_path)) { // template not expired, no recompile return true; } else { // compile template return false; } } } else { // compiled template does not exist, or forced compile return false; } } /** * compile the template * * @param string $resource_name * @param string $compile_path * @return boolean */ function _compile_resource($resource_name, $compile_path) { $_params = array('resource_name' => $resource_name); if (!$this->_fetch_resource_info($_params)) { return false; } $_source_content = $_params['source_content']; $_cache_include = substr($compile_path, 0, -4).'.inc'; if ($this->_compile_source($resource_name, $_source_content, $_compiled_content, $_cache_include)) { // if a _cache_serial was set, we also have to write an include-file: if ($this->_cache_include_info) { require_once(SMARTY_CORE_DIR . 'core.write_compiled_include.php'); smarty_core_write_compiled_include(array_merge($this->_cache_include_info, array('compiled_content'=>$_compiled_content, 'resource_name'=>$resource_name)), $this); } $_params = array('compile_path'=>$compile_path, 'compiled_content' => $_compiled_content); require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); smarty_core_write_compiled_resource($_params, $this); return true; } else { return false; } } /** * compile the given source * * @param string $resource_name * @param string $source_content * @param string $compiled_content * @return boolean */ function _compile_source($resource_name, &$source_content, &$compiled_content, $cache_include_path=null) { if (file_exists(SMARTY_DIR . $this->compiler_file)) { require_once(SMARTY_DIR . $this->compiler_file); } else { // use include_path require_once($this->compiler_file); } $smarty_compiler = new $this->compiler_class; $smarty_compiler->template_dir = $this->template_dir; $smarty_compiler->compile_dir = $this->compile_dir; $smarty_compiler->plugins_dir = $this->plugins_dir; $smarty_compiler->config_dir = $this->config_dir; $smarty_compiler->force_compile = $this->force_compile; $smarty_compiler->caching = $this->caching; $smarty_compiler->php_handling = $this->php_handling; $smarty_compiler->left_delimiter = $this->left_delimiter; $smarty_compiler->right_delimiter = $this->right_delimiter; $smarty_compiler->_version = $this->_version; $smarty_compiler->security = $this->security; $smarty_compiler->secure_dir = $this->secure_dir; $smarty_compiler->security_settings = $this->security_settings; $smarty_compiler->trusted_dir = $this->trusted_dir; $smarty_compiler->use_sub_dirs = $this->use_sub_dirs; $smarty_compiler->_reg_objects = &$this->_reg_objects; $smarty_compiler->_plugins = &$this->_plugins; $smarty_compiler->_tpl_vars = &$this->_tpl_vars; $smarty_compiler->default_modifiers = $this->default_modifiers; $smarty_compiler->compile_id = $this->_compile_id; $smarty_compiler->_config = $this->_config; $smarty_compiler->request_use_auto_globals = $this->request_use_auto_globals; if (isset($cache_include_path) && isset($this->_cache_serials[$cache_include_path])) { $smarty_compiler->_cache_serial = $this->_cache_serials[$cache_include_path]; } $smarty_compiler->_cache_include = $cache_include_path; $_results = $smarty_compiler->_compile_file($resource_name, $source_content, $compiled_content); if ($smarty_compiler->_cache_serial) { $this->_cache_include_info = array( 'cache_serial'=>$smarty_compiler->_cache_serial ,'plugins_code'=>$smarty_compiler->_plugins_code ,'include_file_path' => $cache_include_path); } else { $this->_cache_include_info = null; } return $_results; } /** * Get the compile path for this resource * * @param string $resource_name * @return string results of {@link _get_auto_filename()} */ function _get_compile_path($resource_name) { return $this->_get_auto_filename($this->compile_dir, $resource_name, $this->_compile_id) . '.php'; } /** * fetch the template info. Gets timestamp, and source * if get_source is true * * sets $source_content to the source of the template, and * $resource_timestamp to its time stamp * @param string $resource_name * @param string $source_content * @param integer $resource_timestamp * @param boolean $get_source * @param boolean $quiet * @return boolean */ function _fetch_resource_info(&$params) { if(!isset($params['get_source'])) { $params['get_source'] = true; } if(!isset($params['quiet'])) { $params['quiet'] = false; } $_return = false; $_params = array('resource_name' => $params['resource_name']) ; if (isset($params['resource_base_path'])) $_params['resource_base_path'] = $params['resource_base_path']; else $_params['resource_base_path'] = $this->template_dir; if ($this->_parse_resource_name($_params)) { $_resource_type = $_params['resource_type']; $_resource_name = $_params['resource_name']; switch ($_resource_type) { case 'file': if ($params['get_source']) { $params['source_content'] = $this->_read_file($_resource_name); } $params['resource_timestamp'] = filemtime($_resource_name); $_return = is_file($_resource_name); break; default: // call resource functions to fetch the template source and timestamp if ($params['get_source']) { $_source_return = isset($this->_plugins['resource'][$_resource_type]) && call_user_func_array($this->_plugins['resource'][$_resource_type][0][0], array($_resource_name, &$params['source_content'], &$this)); } else { $_source_return = true; } $_timestamp_return = isset($this->_plugins['resource'][$_resource_type]) && call_user_func_array($this->_plugins['resource'][$_resource_type][0][1], array($_resource_name, &$params['resource_timestamp'], &$this)); $_return = $_source_return && $_timestamp_return; break; } } if (!$_return) { // see if we can get a template with the default template handler if (!empty($this->default_template_handler_func)) { if (!is_callable($this->default_template_handler_func)) { $this->trigger_error("default template handler function \"$this->default_template_handler_func\" doesn't exist."); } else { $_return = call_user_func_array( $this->default_template_handler_func, array($_params['resource_type'], $_params['resource_name'], &$params['source_content'], &$params['resource_timestamp'], &$this)); } } } if (!$_return) { if (!$params['quiet']) { $this->trigger_error('unable to read resource: "' . $params['resource_name'] . '"'); } } else if ($_return && $this->security) { require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); if (!smarty_core_is_secure($_params, $this)) { if (!$params['quiet']) $this->trigger_error('(secure mode) accessing "' . $params['resource_name'] . '" is not allowed'); $params['source_content'] = null; $params['resource_timestamp'] = null; return false; } } return $_return; } /** * parse out the type and name from the resource * * @param string $resource_base_path * @param string $resource_name * @param string $resource_type * @param string $resource_name * @return boolean */ function _parse_resource_name(&$params) { // split tpl_path by the first colon $_resource_name_parts = explode(':', $params['resource_name'], 2); if (count($_resource_name_parts) == 1) { // no resource type given $params['resource_type'] = $this->default_resource_type; $params['resource_name'] = $_resource_name_parts[0]; } else { if(strlen($_resource_name_parts[0]) == 1) { // 1 char is not resource type, but part of filepath $params['resource_type'] = $this->default_resource_type; $params['resource_name'] = $params['resource_name']; } else { $params['resource_type'] = $_resource_name_parts[0]; $params['resource_name'] = $_resource_name_parts[1]; } } if ($params['resource_type'] == 'file') { if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $params['resource_name'])) { // relative pathname to $params['resource_base_path'] // use the first directory where the file is found foreach ((array)$params['resource_base_path'] as $_curr_path) { $_fullpath = $_curr_path . DIRECTORY_SEPARATOR . $params['resource_name']; if (file_exists($_fullpath) && is_file($_fullpath)) { $params['resource_name'] = $_fullpath; return true; } // didn't find the file, try include_path $_params = array('file_path' => $_fullpath); require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); if(smarty_core_get_include_path($_params, $this)) { $params['resource_name'] = $_params['new_file_path']; return true; } } return false; } else { /* absolute path */ return file_exists($params['resource_name']); } } elseif (empty($this->_plugins['resource'][$params['resource_type']])) { $_params = array('type' => $params['resource_type']); require_once(SMARTY_CORE_DIR . 'core.load_resource_plugin.php'); smarty_core_load_resource_plugin($_params, $this); } return true; } /** * Handle modifiers * * @param string|null $modifier_name * @param array|null $map_array * @return string result of modifiers */ function _run_mod_handler() { $_args = func_get_args(); list($_modifier_name, $_map_array) = array_splice($_args, 0, 2); list($_func_name, $_tpl_file, $_tpl_line) = $this->_plugins['modifier'][$_modifier_name]; $_var = $_args[0]; foreach ($_var as $_key => $_val) { $_args[0] = $_val; $_var[$_key] = call_user_func_array($_func_name, $_args); } return $_var; } /** * Remove starting and ending quotes from the string * * @param string $string * @return string */ function _dequote($string) { if (($string{0} == "'" || $string{0} == '"') && $string{strlen($string)-1} == $string{0}) return substr($string, 1, -1); else return $string; } /** * read in a file * * @param string $filename * @return string */ function _read_file($filename) { if ( file_exists($filename) && ($fd = @fopen($filename, 'rb')) ) { $contents = ($size = filesize($filename)) ? fread($fd, $size) : ''; fclose($fd); return $contents; } else { return false; } } /** * get a concrete filename for automagically created content * * @param string $auto_base * @param string $auto_source * @param string $auto_id * @return string * @staticvar string|null * @staticvar string|null */ function _get_auto_filename($auto_base, $auto_source = null, $auto_id = null) { $_compile_dir_sep = $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'; $_return = $auto_base . DIRECTORY_SEPARATOR; if(isset($auto_id)) { // make auto_id safe for directory names $auto_id = str_replace('%7C',$_compile_dir_sep,(urlencode($auto_id))); // split into separate directories $_return .= $auto_id . $_compile_dir_sep; } if(isset($auto_source)) { // make source name safe for filename $_filename = urlencode(basename($auto_source)); $_crc32 = sprintf('%08X', crc32($auto_source)); // prepend %% to avoid name conflicts with // with $params['auto_id'] names $_crc32 = substr($_crc32, 0, 2) . $_compile_dir_sep . substr($_crc32, 0, 3) . $_compile_dir_sep . $_crc32; $_return .= '%%' . $_crc32 . '%%' . $_filename; } return $_return; } /** * unlink a file, possibly using expiration time * * @param string $resource * @param integer $exp_time */ function _unlink($resource, $exp_time = null) { if(isset($exp_time)) { if(time() - @filemtime($resource) >= $exp_time) { return @unlink($resource); } } else { return @unlink($resource); } } /** * returns an auto_id for auto-file-functions * * @param string $cache_id * @param string $compile_id * @return string|null */ function _get_auto_id($cache_id=null, $compile_id=null) { if (isset($cache_id)) return (isset($compile_id)) ? $cache_id . '|' . $compile_id : $cache_id; elseif(isset($compile_id)) return $compile_id; else return null; } /** * trigger Smarty plugin error * * @param string $error_msg * @param string $tpl_file * @param integer $tpl_line * @param string $file * @param integer $line * @param integer $error_type */ function _trigger_fatal_error($error_msg, $tpl_file = null, $tpl_line = null, $file = null, $line = null, $error_type = E_USER_ERROR) { if(isset($file) && isset($line)) { $info = ' ('.basename($file).", line $line)"; } else { $info = ''; } if (isset($tpl_line) && isset($tpl_file)) { $this->trigger_error('[in ' . $tpl_file . ' line ' . $tpl_line . "]: $error_msg$info", $error_type); } else { $this->trigger_error($error_msg . $info, $error_type); } } /** * callback function for preg_replace, to call a non-cacheable block * @return string */ function _process_compiled_include_callback($match) { $_func = '_smarty_tplfunc_'.$match[2].'_'.$match[3]; ob_start(); $_func($this); $_ret = ob_get_contents(); ob_end_clean(); return $_ret; } /** * called for included templates * * @param string $_smarty_include_tpl_file * @param string $_smarty_include_vars */ // $_smarty_include_tpl_file, $_smarty_include_vars function _smarty_include($params) { if ($this->debugging) { $_params = array(); require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); $debug_start_time = smarty_core_get_microtime($_params, $this); $this->_smarty_debug_info[] = array('type' => 'template', 'filename' => $params['smarty_include_tpl_file'], 'depth' => ++$this->_inclusion_depth); $included_tpls_idx = count($this->_smarty_debug_info) - 1; } $this->_tpl_vars = array_merge($this->_tpl_vars, $params['smarty_include_vars']); // config vars are treated as local, so push a copy of the // current ones onto the front of the stack array_unshift($this->_config, $this->_config[0]); $_smarty_compile_path = $this->_get_compile_path($params['smarty_include_tpl_file']); if ($this->_is_compiled($params['smarty_include_tpl_file'], $_smarty_compile_path) || $this->_compile_resource($params['smarty_include_tpl_file'], $_smarty_compile_path)) { include($_smarty_compile_path); } // pop the local vars off the front of the stack array_shift($this->_config); $this->_inclusion_depth--; if ($this->debugging) { // capture time for debugging info $_params = array(); require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); $this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $debug_start_time; } if ($this->caching) { $this->_cache_info['template'][$params['smarty_include_tpl_file']] = true; } } /** * get or set an array of cached attributes for function that is * not cacheable * @return array */ function &_smarty_cache_attrs($cache_serial, $count) { $_cache_attrs =& $this->_cache_info['cache_attrs'][$cache_serial][$count]; if ($this->_cache_including) { /* return next set of cache_attrs */ $_return =& current($_cache_attrs); next($_cache_attrs); return $_return; } else { /* add a reference to a new set of cache_attrs */ $_cache_attrs[] = array(); return $_cache_attrs[count($_cache_attrs)-1]; } } /** * wrapper for include() retaining $this * @return mixed */ function _include($filename, $once=false, $params=null) { if ($once) { return include_once($filename); } else { return include($filename); } } /** * wrapper for eval() retaining $this * @return mixed */ function _eval($code, $params=null) { return eval($code); } /**#@-*/ } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/Smarty_Compiler.class.php ================================================ * @author Andrei Zmievski * @version 2.6.9 * @copyright 2001-2005 New Digital Group, Inc. * @package Smarty */ /* $Id: Smarty_Compiler.class.php,v 1.1 2006/05/29 16:38:21 powles Exp $ */ /** * Template compiling class * @package Smarty */ class Smarty_Compiler extends Smarty { // internal vars /**#@+ * @access private */ var $_folded_blocks = array(); // keeps folded template blocks var $_current_file = null; // the current template being compiled var $_current_line_no = 1; // line number for error messages var $_capture_stack = array(); // keeps track of nested capture buffers var $_plugin_info = array(); // keeps track of plugins to load var $_init_smarty_vars = false; var $_permitted_tokens = array('true','false','yes','no','on','off','null'); var $_db_qstr_regexp = null; // regexps are setup in the constructor var $_si_qstr_regexp = null; var $_qstr_regexp = null; var $_func_regexp = null; var $_reg_obj_regexp = null; var $_var_bracket_regexp = null; var $_num_const_regexp = null; var $_dvar_guts_regexp = null; var $_dvar_regexp = null; var $_cvar_regexp = null; var $_svar_regexp = null; var $_avar_regexp = null; var $_mod_regexp = null; var $_var_regexp = null; var $_parenth_param_regexp = null; var $_func_call_regexp = null; var $_obj_ext_regexp = null; var $_obj_start_regexp = null; var $_obj_params_regexp = null; var $_obj_call_regexp = null; var $_cacheable_state = 0; var $_cache_attrs_count = 0; var $_nocache_count = 0; var $_cache_serial = null; var $_cache_include = null; var $_strip_depth = 0; var $_additional_newline = "\n"; /**#@-*/ /** * The class constructor. */ function Smarty_Compiler() { // matches double quoted strings: // "foobar" // "foo\"bar" $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'; // matches single quoted strings: // 'foobar' // 'foo\'bar' $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''; // matches single or double quoted strings $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')'; // matches bracket portion of vars // [0] // [foo] // [$bar] $this->_var_bracket_regexp = '\[\$?[\w\.]+\]'; // matches numerical constants // 30 // -12 // 13.22 $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)'; // matches $ vars (not objects): // $foo // $foo.bar // $foo.bar.foobar // $foo[0] // $foo[$bar] // $foo[5][blah] // $foo[5].bar[$foobar][4] $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))'; $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]'; $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?'; $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp; // matches config vars: // #foo# // #foobar123_foo# $this->_cvar_regexp = '\#\w+\#'; // matches section vars: // %foo.bar% $this->_svar_regexp = '\%\w+\.\w+\%'; // matches all valid variables (no quotes, no modifiers) $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|' . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')'; // matches valid variable syntax: // $foo // $foo // #foo# // #foo# // "text" // "text" $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')'; // matches valid object call (one level of object nesting allowed in parameters): // $foo->bar // $foo->bar() // $foo->bar("text") // $foo->bar($foo, $bar, "text") // $foo->bar($foo, "foo") // $foo->bar->foo() // $foo->bar->foo->bar() // $foo->bar($foo->bar) // $foo->bar($foo->bar()) // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar)) $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')'; $this->_obj_restricted_param_regexp = '(?:' . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')' . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)'; $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|' . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)'; $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)'; $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)'; $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)'; // matches valid modifier syntax: // |foo // |@foo // |foo:"bar" // |foo:$bar // |foo:"bar":$foobar // |foo|bar // |foo:$foo->bar $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)'; // matches valid function name: // foo123 // _foo_bar $this->_func_regexp = '[a-zA-Z_]\w*'; // matches valid registered object: // foo->bar $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*'; // matches valid parameter values: // true // $foo // $foo|bar // #foo# // #foo#|bar // "text" // "text"|bar // $foo->bar $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '|' . $this->_num_const_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)'; // matches valid parenthesised function parameters: // // "text" // $foo, $bar, "text" // $foo|bar, "foo"|bar, $foo->bar($foo)|bar $this->_parenth_param_regexp = '(?:\((?:\w+|' . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|' . $this->_param_regexp . ')))*)?\))'; // matches valid function call: // foo() // foo_bar($foo) // _foo_bar($foo,"bar") // foo123($foo,$foo->bar(),"foo") $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:' . $this->_parenth_param_regexp . '))'; } /** * compile a resource * * sets $compiled_content to the compiled source * @param string $resource_name * @param string $source_content * @param string $compiled_content * @return true */ function _compile_file($resource_name, $source_content, &$compiled_content) { if ($this->security) { // do not allow php syntax to be executed unless specified if ($this->php_handling == SMARTY_PHP_ALLOW && !$this->security_settings['PHP_HANDLING']) { $this->php_handling = SMARTY_PHP_PASSTHRU; } } $this->_load_filters(); $this->_current_file = $resource_name; $this->_current_line_no = 1; $ldq = preg_quote($this->left_delimiter, '~'); $rdq = preg_quote($this->right_delimiter, '~'); // run template source through prefilter functions if (count($this->_plugins['prefilter']) > 0) { foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { if ($prefilter === false) continue; if ($prefilter[3] || is_callable($prefilter[0])) { $source_content = call_user_func_array($prefilter[0], array($source_content, &$this)); $this->_plugins['prefilter'][$filter_name][3] = true; } else { $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented"); } } } /* fetch all special blocks */ $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s"; preg_match_all($search, $source_content, $match, PREG_SET_ORDER); $this->_folded_blocks = $match; reset($this->_folded_blocks); /* replace special blocks by "{php}" */ $source_content = preg_replace($search.'e', "'" . $this->_quote_replace($this->left_delimiter) . 'php' . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'" . $this->_quote_replace($this->right_delimiter) . "'" , $source_content); /* Gather all template tags. */ preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match); $template_tags = $_match[1]; /* Split content by template tags to obtain non-template content. */ $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content); /* loop through text blocks */ for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) { /* match anything resembling php tags */ if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) { /* replace tags with placeholders to prevent recursive replacements */ $sp_match[1] = array_unique($sp_match[1]); usort($sp_match[1], '_smarty_sort_length'); for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]); } /* process each one */ for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { if ($this->php_handling == SMARTY_PHP_PASSTHRU) { /* echo php contents */ $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', ''."\n", $text_blocks[$curr_tb]); } else if ($this->php_handling == SMARTY_PHP_QUOTE) { /* quote php tags */ $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]); } else if ($this->php_handling == SMARTY_PHP_REMOVE) { /* remove php tags */ $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]); } else { /* SMARTY_PHP_ALLOW, but echo non php starting tags */ $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', ''."\n", $sp_match[1][$curr_sp]); $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]); } } } } /* Compile the template tags into PHP code. */ $compiled_tags = array(); for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) { $this->_current_line_no += substr_count($text_blocks[$i], "\n"); $compiled_tags[] = $this->_compile_tag($template_tags[$i]); $this->_current_line_no += substr_count($template_tags[$i], "\n"); } if (count($this->_tag_stack)>0) { list($_open_tag, $_line_no) = end($this->_tag_stack); $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__); return; } /* Reformat $text_blocks between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */ $strip = false; for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { if ($compiled_tags[$i] == '{strip}') { $compiled_tags[$i] = ''; $strip = true; /* remove leading whitespaces */ $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]); } if ($strip) { /* strip all $text_blocks before the next '/strip' */ for ($j = $i + 1; $j < $for_max; $j++) { /* remove leading and trailing whitespaces of each line */ $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]); if ($compiled_tags[$j] == '{/strip}') { /* remove trailing whitespaces from the last text_block */ $text_blocks[$j] = rtrim($text_blocks[$j]); } $text_blocks[$j] = ""\'", "\\"=>"\\\\")) . "'; ?>"; if ($compiled_tags[$j] == '{/strip}') { $compiled_tags[$j] = "\n"; /* slurped by php, but necessary if a newline is following the closing strip-tag */ $strip = false; $i = $j; break; } } } } $compiled_content = ''; /* Interleave the compiled contents and text blocks to get the final result. */ for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { if ($compiled_tags[$i] == '') { // tag result empty, remove first newline from following text block $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]); } $compiled_content .= $text_blocks[$i].$compiled_tags[$i]; } $compiled_content .= $text_blocks[$i]; // remove \n from the end of the file, if any if (($_len=strlen($compiled_content)) && ($compiled_content{$_len - 1} == "\n" )) { $compiled_content = substr($compiled_content, 0, -1); } if (!empty($this->_cache_serial)) { $compiled_content = "_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content; } // remove unnecessary close/open tags $compiled_content = preg_replace('~\?>\n?<\?php~', '', $compiled_content); // run compiled template through postfilter functions if (count($this->_plugins['postfilter']) > 0) { foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { if ($postfilter === false) continue; if ($postfilter[3] || is_callable($postfilter[0])) { $compiled_content = call_user_func_array($postfilter[0], array($compiled_content, &$this)); $this->_plugins['postfilter'][$filter_name][3] = true; } else { $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented"); } } } // put header at the top of the compiled template $template_header = "_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n"; /* Emit code to load needed plugins. */ $this->_plugins_code = ''; if (count($this->_plugin_info)) { $_plugins_params = "array('plugins' => array("; foreach ($this->_plugin_info as $plugin_type => $plugins) { foreach ($plugins as $plugin_name => $plugin_info) { $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], "; $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),'; } } $_plugins_params .= '))'; $plugins_code = "\n"; $template_header .= $plugins_code; $this->_plugin_info = array(); $this->_plugins_code = $plugins_code; } if ($this->_init_smarty_vars) { $template_header .= "\n"; $this->_init_smarty_vars = false; } $compiled_content = $template_header . $compiled_content; return true; } /** * Compile a template tag * * @param string $template_tag * @return string */ function _compile_tag($template_tag) { /* Matched comment. */ if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*') return ''; /* Split tag into two three parts: command, command modifiers and the arguments. */ if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)) (?:\s+(.*))?$ ~xs', $template_tag, $match)) { $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__); } $tag_command = $match[1]; $tag_modifier = isset($match[2]) ? $match[2] : null; $tag_args = isset($match[3]) ? $match[3] : null; if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) { /* tag name is a variable or object */ $_return = $this->_parse_var_props($tag_command . $tag_modifier); return "" . $this->_additional_newline; } /* If the tag name is a registered object, we process it. */ if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) { return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier); } switch ($tag_command) { case 'include': return $this->_compile_include_tag($tag_args); case 'include_php': return $this->_compile_include_php_tag($tag_args); case 'if': $this->_push_tag('if'); return $this->_compile_if_tag($tag_args); case 'else': list($_open_tag) = end($this->_tag_stack); if ($_open_tag != 'if' && $_open_tag != 'elseif') $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__); else $this->_push_tag('else'); return ''; case 'elseif': list($_open_tag) = end($this->_tag_stack); if ($_open_tag != 'if' && $_open_tag != 'elseif') $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__); if ($_open_tag == 'if') $this->_push_tag('elseif'); return $this->_compile_if_tag($tag_args, true); case '/if': $this->_pop_tag('if'); return ''; case 'capture': return $this->_compile_capture_tag(true, $tag_args); case '/capture': return $this->_compile_capture_tag(false); case 'ldelim': return $this->left_delimiter; case 'rdelim': return $this->right_delimiter; case 'section': $this->_push_tag('section'); return $this->_compile_section_start($tag_args); case 'sectionelse': $this->_push_tag('sectionelse'); return ""; break; case '/section': $_open_tag = $this->_pop_tag('section'); if ($_open_tag == 'sectionelse') return ""; else return ""; case 'foreach': $this->_push_tag('foreach'); return $this->_compile_foreach_start($tag_args); break; case 'foreachelse': $this->_push_tag('foreachelse'); return ""; case '/foreach': $_open_tag = $this->_pop_tag('foreach'); if ($_open_tag == 'foreachelse') return ""; else return ""; break; case 'strip': case '/strip': if ($tag_command{0}=='/') { $this->_pop_tag('strip'); if (--$this->_strip_depth==0) { /* outermost closing {/strip} */ $this->_additional_newline = "\n"; return '{' . $tag_command . '}'; } } else { $this->_push_tag('strip'); if ($this->_strip_depth++==0) { /* outermost opening {strip} */ $this->_additional_newline = ""; return '{' . $tag_command . '}'; } } return ''; case 'php': /* handle folded tags replaced by {php} */ list(, $block) = each($this->_folded_blocks); $this->_current_line_no += substr_count($block[0], "\n"); /* the number of matched elements in the regexp in _compile_file() determins the type of folded tag that was found */ switch (count($block)) { case 2: /* comment */ return ''; case 3: /* literal */ return ""\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline; case 4: /* php */ if ($this->security && !$this->security_settings['PHP_TAGS']) { $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__); return; } return ''; } break; case 'insert': return $this->_compile_insert_tag($tag_args); default: if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) { return $output; } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) { return $output; } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) { return $output; } else { $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__); } } } /** * compile the custom compiler tag * * sets $output to the compiled custom compiler tag * @param string $tag_command * @param string $tag_args * @param string $output * @return boolean */ function _compile_compiler_tag($tag_command, $tag_args, &$output) { $found = false; $have_function = true; /* * First we check if the compiler function has already been registered * or loaded from a plugin file. */ if (isset($this->_plugins['compiler'][$tag_command])) { $found = true; $plugin_func = $this->_plugins['compiler'][$tag_command][0]; if (!is_callable($plugin_func)) { $message = "compiler function '$tag_command' is not implemented"; $have_function = false; } } /* * Otherwise we need to load plugin file and look for the function * inside it. */ else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) { $found = true; include_once $plugin_file; $plugin_func = 'smarty_compiler_' . $tag_command; if (!is_callable($plugin_func)) { $message = "plugin function $plugin_func() not found in $plugin_file\n"; $have_function = false; } else { $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true); } } /* * True return value means that we either found a plugin or a * dynamically registered function. False means that we didn't and the * compiler should now emit code to load custom function plugin for this * tag. */ if ($found) { if ($have_function) { $output = call_user_func_array($plugin_func, array($tag_args, &$this)); if($output != '') { $output = '_push_cacheable_state('compiler', $tag_command) . $output . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>'; } } else { $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); } return true; } else { return false; } } /** * compile block function tag * * sets $output to compiled block function tag * @param string $tag_command * @param string $tag_args * @param string $tag_modifier * @param string $output * @return boolean */ function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output) { if ($tag_command{0} == '/') { $start_tag = false; $tag_command = substr($tag_command, 1); } else $start_tag = true; $found = false; $have_function = true; /* * First we check if the block function has already been registered * or loaded from a plugin file. */ if (isset($this->_plugins['block'][$tag_command])) { $found = true; $plugin_func = $this->_plugins['block'][$tag_command][0]; if (!is_callable($plugin_func)) { $message = "block function '$tag_command' is not implemented"; $have_function = false; } } /* * Otherwise we need to load plugin file and look for the function * inside it. */ else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) { $found = true; include_once $plugin_file; $plugin_func = 'smarty_block_' . $tag_command; if (!function_exists($plugin_func)) { $message = "plugin function $plugin_func() not found in $plugin_file\n"; $have_function = false; } else { $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true); } } if (!$found) { return false; } else if (!$have_function) { $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); return true; } /* * Even though we've located the plugin function, compilation * happens only once, so the plugin will still need to be loaded * at runtime for future requests. */ $this->_add_plugin('block', $tag_command); if ($start_tag) $this->_push_tag($tag_command); else $this->_pop_tag($tag_command); if ($start_tag) { $output = '_push_cacheable_state('block', $tag_command); $attrs = $this->_parse_attrs($tag_args); $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs=''); $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); '; $output .= $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat=true);'; $output .= 'while ($_block_repeat) { ob_start(); ?>'; } else { $output = '_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat=false)'; if ($tag_modifier != '') { $this->_parse_modifiers($_out_tag_text, $tag_modifier); } $output .= 'echo '.$_out_tag_text.'; } '; $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>'; } return true; } /** * compile custom function tag * * @param string $tag_command * @param string $tag_args * @param string $tag_modifier * @return string */ function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output) { $found = false; $have_function = true; /* * First we check if the custom function has already been registered * or loaded from a plugin file. */ if (isset($this->_plugins['function'][$tag_command])) { $found = true; $plugin_func = $this->_plugins['function'][$tag_command][0]; if (!is_callable($plugin_func)) { $message = "custom function '$tag_command' is not implemented"; $have_function = false; } } /* * Otherwise we need to load plugin file and look for the function * inside it. */ else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) { $found = true; include_once $plugin_file; $plugin_func = 'smarty_function_' . $tag_command; if (!function_exists($plugin_func)) { $message = "plugin function $plugin_func() not found in $plugin_file\n"; $have_function = false; } else { $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true); } } if (!$found) { return false; } else if (!$have_function) { $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); return true; } /* declare plugin to be loaded on display of the template that we compile right now */ $this->_add_plugin('function', $tag_command); $_cacheable_state = $this->_push_cacheable_state('function', $tag_command); $attrs = $this->_parse_attrs($tag_args); $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs=''); $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)"; if($tag_modifier != '') { $this->_parse_modifiers($output, $tag_modifier); } if($output != '') { $output = '_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline; } return true; } /** * compile a registered object tag * * @param string $tag_command * @param array $attrs * @param string $tag_modifier * @return string */ function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier) { if ($tag_command{0} == '/') { $start_tag = false; $tag_command = substr($tag_command, 1); } else { $start_tag = true; } list($object, $obj_comp) = explode('->', $tag_command); $arg_list = array(); if(count($attrs)) { $_assign_var = false; foreach ($attrs as $arg_name => $arg_value) { if($arg_name == 'assign') { $_assign_var = $arg_value; unset($attrs['assign']); continue; } if (is_bool($arg_value)) $arg_value = $arg_value ? 'true' : 'false'; $arg_list[] = "'$arg_name' => $arg_value"; } } if($this->_reg_objects[$object][2]) { // smarty object argument format $args = "array(".implode(',', (array)$arg_list)."), \$this"; } else { // traditional argument format $args = implode(',', array_values($attrs)); if (empty($args)) { $args = 'null'; } } $prefix = ''; $postfix = ''; $newline = ''; if(!is_object($this->_reg_objects[$object][0])) { $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) { $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) { // method if(in_array($obj_comp, $this->_reg_objects[$object][3])) { // block method if ($start_tag) { $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); "; $prefix .= "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat=true); "; $prefix .= "while (\$_block_repeat) { ob_start();"; $return = null; $postfix = ''; } else { $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); "; $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat=false)"; $postfix = "} array_pop(\$this->_tag_stack);"; } } else { // non-block method $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)"; } } else { // property $return = "\$this->_reg_objects['$object'][0]->$obj_comp"; } if($return != null) { if($tag_modifier != '') { $this->_parse_modifiers($return, $tag_modifier); } if(!empty($_assign_var)) { $output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);"; } else { $output = 'echo ' . $return . ';'; $newline = $this->_additional_newline; } } else { $output = ''; } return '" . $newline; } /** * Compile {insert ...} tag * * @param string $tag_args * @return string */ function _compile_insert_tag($tag_args) { $attrs = $this->_parse_attrs($tag_args); $name = $this->_dequote($attrs['name']); if (empty($name)) { $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__); } if (!empty($attrs['script'])) { $delayed_loading = true; } else { $delayed_loading = false; } foreach ($attrs as $arg_name => $arg_value) { if (is_bool($arg_value)) $arg_value = $arg_value ? 'true' : 'false'; $arg_list[] = "'$arg_name' => $arg_value"; } $this->_add_plugin('insert', $name, $delayed_loading); $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))"; return "" . $this->_additional_newline; } /** * Compile {include ...} tag * * @param string $tag_args * @return string */ function _compile_include_tag($tag_args) { $attrs = $this->_parse_attrs($tag_args); $arg_list = array(); if (empty($attrs['file'])) { $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__); } foreach ($attrs as $arg_name => $arg_value) { if ($arg_name == 'file') { $include_file = $arg_value; continue; } else if ($arg_name == 'assign') { $assign_var = $arg_value; continue; } if (is_bool($arg_value)) $arg_value = $arg_value ? 'true' : 'false'; $arg_list[] = "'$arg_name' => $arg_value"; } $output = '_tpl_vars;\n"; $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))"; $output .= "\$this->_smarty_include($_params);\n" . "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . "unset(\$_smarty_tpl_vars);\n"; if (isset($assign_var)) { $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n"; } $output .= ' ?>'; return $output; } /** * Compile {include ...} tag * * @param string $tag_args * @return string */ function _compile_include_php_tag($tag_args) { $attrs = $this->_parse_attrs($tag_args); if (empty($attrs['file'])) { $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__); } $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']); $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true'; $arg_list = array(); foreach($attrs as $arg_name => $arg_value) { if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') { if(is_bool($arg_value)) $arg_value = $arg_value ? 'true' : 'false'; $arg_list[] = "'$arg_name' => $arg_value"; } } $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))"; return "" . $this->_additional_newline; } /** * Compile {section ...} tag * * @param string $tag_args * @return string */ function _compile_section_start($tag_args) { $attrs = $this->_parse_attrs($tag_args); $arg_list = array(); $output = '_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__); } $output .= "unset(\$this->_sections[$section_name]);\n"; $section_props = "\$this->_sections[$section_name]"; foreach ($attrs as $attr_name => $attr_value) { switch ($attr_name) { case 'loop': $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n"; break; case 'show': if (is_bool($attr_value)) $show_attr_value = $attr_value ? 'true' : 'false'; else $show_attr_value = "(bool)$attr_value"; $output .= "{$section_props}['show'] = $show_attr_value;\n"; break; case 'name': $output .= "{$section_props}['$attr_name'] = $attr_value;\n"; break; case 'max': case 'start': $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n"; break; case 'step': $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n"; break; default: $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__); break; } } if (!isset($attrs['show'])) $output .= "{$section_props}['show'] = true;\n"; if (!isset($attrs['loop'])) $output .= "{$section_props}['loop'] = 1;\n"; if (!isset($attrs['max'])) $output .= "{$section_props}['max'] = {$section_props}['loop'];\n"; else $output .= "if ({$section_props}['max'] < 0)\n" . " {$section_props}['max'] = {$section_props}['loop'];\n"; if (!isset($attrs['step'])) $output .= "{$section_props}['step'] = 1;\n"; if (!isset($attrs['start'])) $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n"; else { $output .= "if ({$section_props}['start'] < 0)\n" . " {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" . "else\n" . " {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n"; } $output .= "if ({$section_props}['show']) {\n"; if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) { $output .= " {$section_props}['total'] = {$section_props}['loop'];\n"; } else { $output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n"; } $output .= " if ({$section_props}['total'] == 0)\n" . " {$section_props}['show'] = false;\n" . "} else\n" . " {$section_props}['total'] = 0;\n"; $output .= "if ({$section_props}['show']):\n"; $output .= " for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1; {$section_props}['iteration'] <= {$section_props}['total']; {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n"; $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n"; $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n"; $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n"; $output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n"; $output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n"; $output .= "?>"; return $output; } /** * Compile {foreach ...} tag. * * @param string $tag_args * @return string */ function _compile_foreach_start($tag_args) { $attrs = $this->_parse_attrs($tag_args); $arg_list = array(); if (empty($attrs['from'])) { return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__); } $from = $attrs['from']; if (empty($attrs['item'])) { return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__); } $item = $this->_dequote($attrs['item']); if (!preg_match('~^\w+$~', $item)) { return $this->_syntax_error("'foreach: item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); } if (isset($attrs['key'])) { $key = $this->_dequote($attrs['key']); if (!preg_match('~^\w+$~', $key)) { return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); } $key_part = "\$this->_tpl_vars['$key'] => "; } else { $key = null; $key_part = ''; } if (isset($attrs['name'])) { $name = $attrs['name']; } else { $name = null; } $output = '_foreach[$name]"; $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n"; $output .= "if ({$foreach_props}['total'] > 0):\n"; $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; $output .= " {$foreach_props}['iteration']++;\n"; } else { $output .= "if (count(\$_from)):\n"; $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; } $output .= '?>'; return $output; } /** * Compile {capture} .. {/capture} tags * * @param boolean $start true if this is the {capture} tag * @param string $tag_args * @return string */ function _compile_capture_tag($start, $tag_args = '') { $attrs = $this->_parse_attrs($tag_args); if ($start) { if (isset($attrs['name'])) $buffer = $attrs['name']; else $buffer = "'default'"; if (isset($attrs['assign'])) $assign = $attrs['assign']; else $assign = null; $output = ""; $this->_capture_stack[] = array($buffer, $assign); } else { list($buffer, $assign) = array_pop($this->_capture_stack); $output = "_smarty_vars['capture'][$buffer] = ob_get_contents(); "; if (isset($assign)) { $output .= " \$this->assign($assign, ob_get_contents());"; } $output .= "ob_end_clean(); ?>"; } return $output; } /** * Compile {if ...} tag * * @param string $tag_args * @param boolean $elseif if true, uses elseif instead of if * @return string */ function _compile_if_tag($tag_args, $elseif = false) { /* Tokenize args for 'if' tag. */ preg_match_all('~(?> ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token \b\w+\b | # valid word token \S+ # anything else )~x', $tag_args, $match); $tokens = $match[0]; // make sure we have balanced parenthesis $token_count = array_count_values($tokens); if(isset($token_count['(']) && $token_count['('] != $token_count[')']) { $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__); } $is_arg_stack = array(); for ($i = 0; $i < count($tokens); $i++) { $token = &$tokens[$i]; switch (strtolower($token)) { case '!': case '%': case '!==': case '==': case '===': case '>': case '<': case '!=': case '<>': case '<<': case '>>': case '<=': case '>=': case '&&': case '||': case '|': case '^': case '&': case '~': case ')': case ',': case '+': case '-': case '*': case '/': case '@': break; case 'eq': $token = '=='; break; case 'ne': case 'neq': $token = '!='; break; case 'lt': $token = '<'; break; case 'le': case 'lte': $token = '<='; break; case 'gt': $token = '>'; break; case 'ge': case 'gte': $token = '>='; break; case 'and': $token = '&&'; break; case 'or': $token = '||'; break; case 'not': $token = '!'; break; case 'mod': $token = '%'; break; case '(': array_push($is_arg_stack, $i); break; case 'is': /* If last token was a ')', we operate on the parenthesized expression. The start of the expression is on the stack. Otherwise, we operate on the last encountered token. */ if ($tokens[$i-1] == ')') $is_arg_start = array_pop($is_arg_stack); else $is_arg_start = $i-1; /* Construct the argument for 'is' expression, so it knows what to operate on. */ $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); /* Pass all tokens from next one until the end to the 'is' expression parsing function. The function will return modified tokens, where the first one is the result of the 'is' expression and the rest are the tokens it didn't touch. */ $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); /* Replace the old tokens with the new ones. */ array_splice($tokens, $is_arg_start, count($tokens), $new_tokens); /* Adjust argument start so that it won't change from the current position for the next iteration. */ $i = $is_arg_start; break; default: if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) { // function call if($this->security && !in_array($token, $this->security_settings['IF_FUNCS'])) { $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); } } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') { // variable function call $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) { // object or variable $token = $this->_parse_var_props($token); } elseif(is_numeric($token)) { // number, skip it } else { $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__); } break; } } if ($elseif) return ''; else return ''; } function _compile_arg_list($type, $name, $attrs, &$cache_code) { $arg_list = array(); if (isset($type) && isset($name) && isset($this->_plugins[$type]) && isset($this->_plugins[$type][$name]) && empty($this->_plugins[$type][$name][4]) && is_array($this->_plugins[$type][$name][5]) ) { /* we have a list of parameters that should be cached */ $_cache_attrs = $this->_plugins[$type][$name][5]; $_count = $this->_cache_attrs_count++; $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');"; } else { /* no parameters are cached */ $_cache_attrs = null; } foreach ($attrs as $arg_name => $arg_value) { if (is_bool($arg_value)) $arg_value = $arg_value ? 'true' : 'false'; if (is_null($arg_value)) $arg_value = 'null'; if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) { $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)"; } else { $arg_list[] = "'$arg_name' => $arg_value"; } } return $arg_list; } /** * Parse is expression * * @param string $is_arg * @param array $tokens * @return array */ function _parse_is_expr($is_arg, $tokens) { $expr_end = 0; $negate_expr = false; if (($first_token = array_shift($tokens)) == 'not') { $negate_expr = true; $expr_type = array_shift($tokens); } else $expr_type = $first_token; switch ($expr_type) { case 'even': if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { $expr_end++; $expr_arg = $tokens[$expr_end++]; $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; } else $expr = "!(1 & $is_arg)"; break; case 'odd': if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { $expr_end++; $expr_arg = $tokens[$expr_end++]; $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; } else $expr = "(1 & $is_arg)"; break; case 'div': if (@$tokens[$expr_end] == 'by') { $expr_end++; $expr_arg = $tokens[$expr_end++]; $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")"; } else { $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__); } break; default: $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__); break; } if ($negate_expr) { $expr = "!($expr)"; } array_splice($tokens, 0, $expr_end, $expr); return $tokens; } /** * Parse attribute string * * @param string $tag_args * @return array */ function _parse_attrs($tag_args) { /* Tokenize tag attributes. */ preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) )+ | [=] ~x', $tag_args, $match); $tokens = $match[0]; $attrs = array(); /* Parse state: 0 - expecting attribute name 1 - expecting '=' 2 - expecting attribute value (not '=') */ $state = 0; foreach ($tokens as $token) { switch ($state) { case 0: /* If the token is a valid identifier, we set attribute name and go to state 1. */ if (preg_match('~^\w+$~', $token)) { $attr_name = $token; $state = 1; } else $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); break; case 1: /* If the token is '=', then we go to state 2. */ if ($token == '=') { $state = 2; } else $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); break; case 2: /* If token is not '=', we set the attribute value and go to state 0. */ if ($token != '=') { /* We booleanize the token if it's a non-quoted possible boolean value. */ if (preg_match('~^(on|yes|true)$~', $token)) { $token = 'true'; } else if (preg_match('~^(off|no|false)$~', $token)) { $token = 'false'; } else if ($token == 'null') { $token = 'null'; } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) { /* treat integer literally */ } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) { /* treat as a string, double-quote it escaping quotes */ $token = '"'.addslashes($token).'"'; } $attrs[$attr_name] = $token; $state = 0; } else $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); break; } $last_token = $token; } if($state != 0) { if($state == 1) { $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); } else { $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); } } $this->_parse_vars_props($attrs); return $attrs; } /** * compile multiple variables and section properties tokens into * PHP code * * @param array $tokens */ function _parse_vars_props(&$tokens) { foreach($tokens as $key => $val) { $tokens[$key] = $this->_parse_var_props($val); } } /** * compile single variable and section properties token into * PHP code * * @param string $val * @param string $tag_attrs * @return string */ function _parse_var_props($val) { $val = trim($val); if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) { // $ variable or object $return = $this->_parse_var($match[1]); $modifiers = $match[2]; if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) { $_default_mod_string = implode('|',(array)$this->default_modifiers); $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers; } $this->_parse_modifiers($return, $modifiers); return $return; } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { // double quoted text preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); $return = $this->_expand_quoted_text($match[1]); if($match[2] != '') { $this->_parse_modifiers($return, $match[2]); } return $return; } elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { // numerical constant preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); if($match[2] != '') { $this->_parse_modifiers($match[1], $match[2]); return $match[1]; } } elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { // single quoted text preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); if($match[2] != '') { $this->_parse_modifiers($match[1], $match[2]); return $match[1]; } } elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { // config var return $this->_parse_conf_var($val); } elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { // section var return $this->_parse_section_prop($val); } elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) { // literal string return $this->_expand_quoted_text('"' . $val .'"'); } return $val; } /** * expand quoted text with embedded variables * * @param string $var_expr * @return string */ function _expand_quoted_text($var_expr) { // if contains unescaped $, expand it if(preg_match_all('~(?:\`(?_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?_parse_var(str_replace('`','',$_var)) . ')."', $var_expr); } $_return = preg_replace('~\.""|(?_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE); if(count($_math_vars) > 1) { $_first_var = ""; $_complete_var = ""; $_output = ""; // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter) foreach($_math_vars as $_k => $_math_var) { $_math_var = $_math_vars[$_k]; if(!empty($_math_var) || is_numeric($_math_var)) { // hit a math operator, so process the stuff which came before it if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) { $_has_math = true; if(!empty($_complete_var) || is_numeric($_complete_var)) { $_output .= $this->_parse_var($_complete_var); } // just output the math operator to php $_output .= $_math_var; if(empty($_first_var)) $_first_var = $_complete_var; $_complete_var = ""; } else { $_complete_var .= $_math_var; } } } if($_has_math) { if(!empty($_complete_var) || is_numeric($_complete_var)) $_output .= $this->_parse_var($_complete_var); // get the modifiers working (only the last var from math + modifier is left) $var_expr = $_complete_var; } } // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit) if(is_numeric($var_expr{0})) $_var_ref = $var_expr; else $_var_ref = substr($var_expr, 1); if(!$_has_math) { // get [foo] and .foo and ->foo and (...) pieces preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match); $_indexes = $match[0]; $_var_name = array_shift($_indexes); /* Handle $smarty.* variable references as a special case. */ if ($_var_name == 'smarty') { /* * If the reference could be compiled, use the compiled output; * otherwise, fall back on the $smarty variable generated at * run-time. */ if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) { $_output = $smarty_ref; } else { $_var_name = substr(array_shift($_indexes), 1); $_output = "\$this->_smarty_vars['$_var_name']"; } } elseif(is_numeric($_var_name) && is_numeric($var_expr{0})) { // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers if(count($_indexes) > 0) { $_var_name .= implode("", $_indexes); $_indexes = array(); } $_output = $_var_name; } else { $_output = "\$this->_tpl_vars['$_var_name']"; } foreach ($_indexes as $_index) { if ($_index{0} == '[') { $_index = substr($_index, 1, -1); if (is_numeric($_index)) { $_output .= "[$_index]"; } elseif ($_index{0} == '$') { if (strpos($_index, '.') !== false) { $_output .= '[' . $this->_parse_var($_index) . ']'; } else { $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]"; } } else { $_var_parts = explode('.', $_index); $_var_section = $_var_parts[0]; $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index'; $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]"; } } else if ($_index{0} == '.') { if ($_index{1} == '$') $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]"; else $_output .= "['" . substr($_index, 1) . "']"; } else if (substr($_index,0,2) == '->') { if(substr($_index,2,2) == '__') { $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); } elseif($this->security && substr($_index, 2, 1) == '_') { $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); } elseif ($_index{2} == '$') { if ($this->security) { $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); } else { $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}'; } } else { $_output .= $_index; } } elseif ($_index{0} == '(') { $_index = $this->_parse_parenth_args($_index); $_output .= $_index; } else { $_output .= $_index; } } } return $_output; } /** * parse arguments in function call parenthesis * * @param string $parenth_args * @return string */ function _parse_parenth_args($parenth_args) { preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match); $orig_vals = $match = $match[0]; $this->_parse_vars_props($match); $replace = array(); for ($i = 0, $count = count($match); $i < $count; $i++) { $replace[$orig_vals[$i]] = $match[$i]; } return strtr($parenth_args, $replace); } /** * parse configuration variable expression into PHP code * * @param string $conf_var_expr */ function _parse_conf_var($conf_var_expr) { $parts = explode('|', $conf_var_expr, 2); $var_ref = $parts[0]; $modifiers = isset($parts[1]) ? $parts[1] : ''; $var_name = substr($var_ref, 1, -1); $output = "\$this->_config[0]['vars']['$var_name']"; $this->_parse_modifiers($output, $modifiers); return $output; } /** * parse section property expression into PHP code * * @param string $section_prop_expr * @return string */ function _parse_section_prop($section_prop_expr) { $parts = explode('|', $section_prop_expr, 2); $var_ref = $parts[0]; $modifiers = isset($parts[1]) ? $parts[1] : ''; preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); $section_name = $match[1]; $prop_name = $match[2]; $output = "\$this->_sections['$section_name']['$prop_name']"; $this->_parse_modifiers($output, $modifiers); return $output; } /** * parse modifier chain into PHP code * * sets $output to parsed modified chain * @param string $output * @param string $modifier_string */ function _parse_modifiers(&$output, $modifier_string) { preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match); list(, $_modifiers, $modifier_arg_strings) = $_match; for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) { $_modifier_name = $_modifiers[$_i]; if($_modifier_name == 'smarty') { // skip smarty modifier continue; } preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match); $_modifier_args = $_match[1]; if ($_modifier_name{0} == '@') { $_map_array = false; $_modifier_name = substr($_modifier_name, 1); } else { $_map_array = true; } if (empty($this->_plugins['modifier'][$_modifier_name]) && !$this->_get_plugin_filepath('modifier', $_modifier_name) && function_exists($_modifier_name)) { if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); } else { $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false); } } $this->_add_plugin('modifier', $_modifier_name); $this->_parse_vars_props($_modifier_args); if($_modifier_name == 'default') { // supress notifications of default modifier vars and args if($output{0} == '$') { $output = '@' . $output; } if(isset($_modifier_args[0]) && $_modifier_args[0]{0} == '$') { $_modifier_args[0] = '@' . $_modifier_args[0]; } } if (count($_modifier_args) > 0) $_modifier_args = ', '.implode(', ', $_modifier_args); else $_modifier_args = ''; if ($_map_array) { $output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))"; } else { $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)"; } } } /** * add plugin * * @param string $type * @param string $name * @param boolean? $delayed_loading */ function _add_plugin($type, $name, $delayed_loading = null) { if (!isset($this->_plugin_info[$type])) { $this->_plugin_info[$type] = array(); } if (!isset($this->_plugin_info[$type][$name])) { $this->_plugin_info[$type][$name] = array($this->_current_file, $this->_current_line_no, $delayed_loading); } } /** * Compiles references of type $smarty.foo * * @param string $indexes * @return string */ function _compile_smarty_ref(&$indexes) { /* Extract the reference name. */ $_ref = substr($indexes[0], 1); foreach($indexes as $_index_no=>$_index) { if ($_index{0} != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) { $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); } } switch ($_ref) { case 'now': $compiled_ref = 'time()'; $_max_index = 1; break; case 'foreach': array_shift($indexes); $_var = $this->_parse_var_props(substr($indexes[0], 1)); $_propname = substr($indexes[1], 1); $_max_index = 1; switch ($_propname) { case 'index': array_shift($indexes); $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)"; break; case 'first': array_shift($indexes); $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)"; break; case 'last': array_shift($indexes); $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])"; break; case 'show': array_shift($indexes); $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)"; break; default: unset($_max_index); $compiled_ref = "\$this->_foreach[$_var]"; } break; case 'section': array_shift($indexes); $_var = $this->_parse_var_props(substr($indexes[0], 1)); $compiled_ref = "\$this->_sections[$_var]"; break; case 'get': $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']"; break; case 'post': $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']"; break; case 'cookies': $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']"; break; case 'env': $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']"; break; case 'server': $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']"; break; case 'session': $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']"; break; /* * These cases are handled either at run-time or elsewhere in the * compiler. */ case 'request': if ($this->request_use_auto_globals) { $compiled_ref = '$_REQUEST'; break; } else { $this->_init_smarty_vars = true; } return null; case 'capture': return null; case 'template': $compiled_ref = "'$this->_current_file'"; $_max_index = 1; break; case 'version': $compiled_ref = "'$this->_version'"; $_max_index = 1; break; case 'const': if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) { $this->_syntax_error("(secure mode) constants not permitted", E_USER_WARNING, __FILE__, __LINE__); return; } array_shift($indexes); if (preg_match('!^\.\w+$!', $indexes[0])) { $compiled_ref = '@' . substr($indexes[0], 1); } else { $_val = $this->_parse_var_props(substr($indexes[0], 1)); $compiled_ref = '@constant(' . $_val . ')'; } $_max_index = 1; break; case 'config': $compiled_ref = "\$this->_config[0]['vars']"; $_max_index = 3; break; case 'ldelim': $compiled_ref = "'$this->left_delimiter'"; break; case 'rdelim': $compiled_ref = "'$this->right_delimiter'"; break; default: $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__); break; } if (isset($_max_index) && count($indexes) > $_max_index) { $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); } array_shift($indexes); return $compiled_ref; } /** * compiles call to plugin of type $type with name $name * returns a string containing the function-name or method call * without the paramter-list that would have follow to make the * call valid php-syntax * * @param string $type * @param string $name * @return string */ function _compile_plugin_call($type, $name) { if (isset($this->_plugins[$type][$name])) { /* plugin loaded */ if (is_array($this->_plugins[$type][$name][0])) { return ((is_object($this->_plugins[$type][$name][0][0])) ? "\$this->_plugins['$type']['$name'][0][0]->" /* method callback */ : (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */ ). $this->_plugins[$type][$name][0][1]; } else { /* function callback */ return $this->_plugins[$type][$name][0]; } } else { /* plugin not loaded -> auto-loadable-plugin */ return 'smarty_'.$type.'_'.$name; } } /** * load pre- and post-filters */ function _load_filters() { if (count($this->_plugins['prefilter']) > 0) { foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { if ($prefilter === false) { unset($this->_plugins['prefilter'][$filter_name]); $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false))); require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); smarty_core_load_plugins($_params, $this); } } } if (count($this->_plugins['postfilter']) > 0) { foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { if ($postfilter === false) { unset($this->_plugins['postfilter'][$filter_name]); $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false))); require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); smarty_core_load_plugins($_params, $this); } } } } /** * Quote subpattern references * * @param string $string * @return string */ function _quote_replace($string) { return strtr($string, array('\\' => '\\\\', '$' => '\\$')); } /** * display Smarty syntax error * * @param string $error_msg * @param integer $error_type * @param string $file * @param integer $line */ function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null) { $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type); } /** * check if the compilation changes from cacheable to * non-cacheable state with the beginning of the current * plugin. return php-code to reflect the transition. * @return string */ function _push_cacheable_state($type, $name) { $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; if ($_cacheable || 0<$this->_cacheable_state++) return ''; if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty')); $_ret = 'if ($this->caching && !$this->_cache_including) { echo \'{nocache:' . $this->_cache_serial . '#' . $this->_nocache_count . '}\';}'; return $_ret; } /** * check if the compilation changes from non-cacheable to * cacheable state with the end of the current plugin return * php-code to reflect the transition. * @return string */ function _pop_cacheable_state($type, $name) { $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; if ($_cacheable || --$this->_cacheable_state>0) return ''; return 'if ($this->caching && !$this->_cache_including) { echo \'{/nocache:' . $this->_cache_serial . '#' . ($this->_nocache_count++) . '}\';}'; } /** * push opening tag-name, file-name and line-number on the tag-stack * @param string the opening tag's name */ function _push_tag($open_tag) { array_push($this->_tag_stack, array($open_tag, $this->_current_line_no)); } /** * pop closing tag-name * raise an error if this stack-top doesn't match with the closing tag * @param string the closing tag's name * @return string the opening tag's name */ function _pop_tag($close_tag) { $message = ''; if (count($this->_tag_stack)>0) { list($_open_tag, $_line_no) = array_pop($this->_tag_stack); if ($close_tag == $_open_tag) { return $_open_tag; } if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) { return $this->_pop_tag($close_tag); } if ($close_tag == 'section' && $_open_tag == 'sectionelse') { $this->_pop_tag($close_tag); return $_open_tag; } if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') { $this->_pop_tag($close_tag); return $_open_tag; } if ($_open_tag == 'else' || $_open_tag == 'elseif') { $_open_tag = 'if'; } elseif ($_open_tag == 'sectionelse') { $_open_tag = 'section'; } elseif ($_open_tag == 'foreachelse') { $_open_tag = 'foreach'; } $message = " expected {/$_open_tag} (opened line $_line_no)."; } $this->_syntax_error("mismatched tag {/$close_tag}.$message", E_USER_ERROR, __FILE__, __LINE__); } } /** * compare to values by their string length * * @access private * @param string $a * @param string $b * @return 0|-1|1 */ function _smarty_sort_length($a, $b) { if($a == $b) return 0; if(strlen($a) == strlen($b)) return ($a > $b) ? -1 : 1; return (strlen($a) > strlen($b)) ? -1 : 1; } /* vim: set et: */ ?> ================================================ FILE: tools/server/admin/smarty/debug.tpl ================================================ {* Smarty *} {* debug.tpl, last updated version 2.0.1 *} {assign_debug_info} {if isset($_smarty_debug_output) and $_smarty_debug_output eq "html"} {section name=templates loop=$_debug_tpls} {sectionelse} {/section} {section name=vars loop=$_debug_keys} {sectionelse} {/section} {section name=config_vars loop=$_debug_config_keys} {sectionelse} {/section}
Smarty Debug Console
included templates & config files (load time in seconds):
{section name=indent loop=$_debug_tpls[templates].depth}   {/section}{$_debug_tpls[templates].filename|escape:html}{if isset($_debug_tpls[templates].exec_time)} ({$_debug_tpls[templates].exec_time|string_format:"%.5f"}){if %templates.index% eq 0} (total){/if}{/if}
no templates included
assigned template variables:
{ldelim}${$_debug_keys[vars]}{rdelim}{$_debug_vals[vars]|@debug_print_var}
no template variables assigned
assigned config file variables (outer template scope):
{ldelim}#{$_debug_config_keys[config_vars]}#{rdelim}{$_debug_config_vals[config_vars]|@debug_print_var}
no config vars assigned
{else} {/if} ================================================ FILE: tools/server/admin/smarty/internals/core.assemble_plugin_filepath.php ================================================ plugins_dir as $_plugin_dir) { $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename; // see if path is relative if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/", $_plugin_dir)) { $_relative_paths[] = $_plugin_dir; // relative path, see if it is in the SMARTY_DIR if (@is_readable(SMARTY_DIR . $_plugin_filepath)) { $_return = SMARTY_DIR . $_plugin_filepath; break; } } // try relative to cwd (or absolute) if (@is_readable($_plugin_filepath)) { $_return = $_plugin_filepath; break; } } if($_return === false) { // still not found, try PHP include_path if(isset($_relative_paths)) { foreach ((array)$_relative_paths as $_plugin_dir) { $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename; $_params = array('file_path' => $_plugin_filepath); require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); if(smarty_core_get_include_path($_params, $smarty)) { $_return = $_params['new_file_path']; break; } } } } $_filepaths_cache[$_plugin_filename] = $_return; return $_return; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.assign_smarty_interface.php ================================================ * Name: assign_smarty_interface
* Purpose: assign the $smarty interface variable * @param array Format: null * @param Smarty */ function smarty_core_assign_smarty_interface($params, &$smarty) { if (isset($smarty->_smarty_vars) && isset($smarty->_smarty_vars['request'])) { return; } $_globals_map = array('g' => 'HTTP_GET_VARS', 'p' => 'HTTP_POST_VARS', 'c' => 'HTTP_COOKIE_VARS', 's' => 'HTTP_SERVER_VARS', 'e' => 'HTTP_ENV_VARS'); $_smarty_vars_request = array(); foreach (preg_split('!!', strtolower($smarty->request_vars_order)) as $_c) { if (isset($_globals_map[$_c])) { $_smarty_vars_request = array_merge($_smarty_vars_request, $GLOBALS[$_globals_map[$_c]]); } } $_smarty_vars_request = @array_merge($_smarty_vars_request, $GLOBALS['HTTP_SESSION_VARS']); $smarty->_smarty_vars['request'] = $_smarty_vars_request; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.create_dir_structure.php ================================================ _dir_perms) && !is_dir($_new_dir)) { $smarty->trigger_error("problem creating directory '" . $_new_dir . "'"); return false; } $_new_dir .= '/'; } } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.display_debug_console.php ================================================ * Name: display_debug_console
* Purpose: display the javascript debug console window * @param array Format: null * @param Smarty */ function smarty_core_display_debug_console($params, &$smarty) { // we must force compile the debug template in case the environment // changed between separate applications. if(empty($smarty->debug_tpl)) { // set path to debug template from SMARTY_DIR $smarty->debug_tpl = SMARTY_DIR . 'debug.tpl'; if($smarty->security && is_file($smarty->debug_tpl)) { $smarty->secure_dir[] = dirname(realpath($smarty->debug_tpl)); } $smarty->debug_tpl = 'file:' . SMARTY_DIR . 'debug.tpl'; } $_ldelim_orig = $smarty->left_delimiter; $_rdelim_orig = $smarty->right_delimiter; $smarty->left_delimiter = '{'; $smarty->right_delimiter = '}'; $_compile_id_orig = $smarty->_compile_id; $smarty->_compile_id = null; $_compile_path = $smarty->_get_compile_path($smarty->debug_tpl); if ($smarty->_compile_resource($smarty->debug_tpl, $_compile_path)) { ob_start(); $smarty->_include($_compile_path); $_results = ob_get_contents(); ob_end_clean(); } else { $_results = ''; } $smarty->_compile_id = $_compile_id_orig; $smarty->left_delimiter = $_ldelim_orig; $smarty->right_delimiter = $_rdelim_orig; return $_results; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.get_include_path.php ================================================ ================================================ FILE: tools/server/admin/smarty/internals/core.get_microtime.php ================================================ ================================================ FILE: tools/server/admin/smarty/internals/core.get_php_resource.php ================================================ trusted_dir; $smarty->_parse_resource_name($params, $smarty); /* * Find out if the resource exists. */ if ($params['resource_type'] == 'file') { $_readable = false; if(file_exists($params['resource_name']) && is_readable($params['resource_name'])) { $_readable = true; } else { // test for file in include_path $_params = array('file_path' => $params['resource_name']); require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); if(smarty_core_get_include_path($_params, $smarty)) { $_include_path = $_params['new_file_path']; $_readable = true; } } } else if ($params['resource_type'] != 'file') { $_template_source = null; $_readable = is_callable($smarty->_plugins['resource'][$params['resource_type']][0][0]) && call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][0], array($params['resource_name'], &$_template_source, &$smarty)); } /* * Set the error function, depending on which class calls us. */ if (method_exists($smarty, '_syntax_error')) { $_error_funcc = '_syntax_error'; } else { $_error_funcc = 'trigger_error'; } if ($_readable) { if ($smarty->security) { require_once(SMARTY_CORE_DIR . 'core.is_trusted.php'); if (!smarty_core_is_trusted($params, $smarty)) { $smarty->$_error_funcc('(secure mode) ' . $params['resource_type'] . ':' . $params['resource_name'] . ' is not trusted'); return false; } } } else { $smarty->$_error_funcc($params['resource_type'] . ':' . $params['resource_name'] . ' is not readable'); return false; } if ($params['resource_type'] == 'file') { $params['php_resource'] = $params['resource_name']; } else { $params['php_resource'] = $_template_source; } return true; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.is_secure.php ================================================ security || $smarty->security_settings['INCLUDE_ANY']) { return true; } if ($params['resource_type'] == 'file') { $_rp = realpath($params['resource_name']); if (isset($params['resource_base_path'])) { foreach ((array)$params['resource_base_path'] as $curr_dir) { if ( ($_cd = realpath($curr_dir)) !== false && strncmp($_rp, $_cd, strlen($_cd)) == 0 && $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) { return true; } } } if (!empty($smarty->secure_dir)) { foreach ((array)$smarty->secure_dir as $curr_dir) { if ( ($_cd = realpath($curr_dir)) !== false && strncmp($_rp, $_cd, strlen($_cd)) == 0 && $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) { return true; } } } } else { // resource is not on local file system return call_user_func_array( $smarty->_plugins['resource'][$params['resource_type']][0][2], array($params['resource_name'], &$smarty)); } return false; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.is_trusted.php ================================================ trusted_dir)) { $_rp = realpath($params['resource_name']); foreach ((array)$smarty->trusted_dir as $curr_dir) { if (!empty($curr_dir) && is_readable ($curr_dir)) { $_cd = realpath($curr_dir); if (strncmp($_rp, $_cd, strlen($_cd)) == 0 && $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) { $_smarty_trusted = true; break; } } } } } else { // resource is not on local file system $_smarty_trusted = call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][3], array($params['resource_name'], $smarty)); } return $_smarty_trusted; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.load_plugins.php ================================================ _plugins[$_type][$_name]; /* * We do not load plugin more than once for each instance of Smarty. * The following code checks for that. The plugin can also be * registered dynamically at runtime, in which case template file * and line number will be unknown, so we fill them in. * * The final element of the info array is a flag that indicates * whether the dynamically registered plugin function has been * checked for existence yet or not. */ if (isset($_plugin)) { if (empty($_plugin[3])) { if (!is_callable($_plugin[0])) { $smarty->_trigger_fatal_error("[plugin] $_type '$_name' is not implemented", $_tpl_file, $_tpl_line, __FILE__, __LINE__); } else { $_plugin[1] = $_tpl_file; $_plugin[2] = $_tpl_line; $_plugin[3] = true; if (!isset($_plugin[4])) $_plugin[4] = true; /* cacheable */ } } continue; } else if ($_type == 'insert') { /* * For backwards compatibility, we check for insert functions in * the symbol table before trying to load them as a plugin. */ $_plugin_func = 'insert_' . $_name; if (function_exists($_plugin_func)) { $_plugin = array($_plugin_func, $_tpl_file, $_tpl_line, true, false); continue; } } $_plugin_file = $smarty->_get_plugin_filepath($_type, $_name); if (! $_found = ($_plugin_file != false)) { $_message = "could not load plugin file '$_type.$_name.php'\n"; } /* * If plugin file is found, it -must- provide the properly named * plugin function. In case it doesn't, simply output the error and * do not fall back on any other method. */ if ($_found) { include_once $_plugin_file; $_plugin_func = 'smarty_' . $_type . '_' . $_name; if (!function_exists($_plugin_func)) { $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", $_tpl_file, $_tpl_line, __FILE__, __LINE__); continue; } } /* * In case of insert plugins, their code may be loaded later via * 'script' attribute. */ else if ($_type == 'insert' && $_delayed_loading) { $_plugin_func = 'smarty_' . $_type . '_' . $_name; $_found = true; } /* * Plugin specific processing and error checking. */ if (!$_found) { if ($_type == 'modifier') { /* * In case modifier falls back on using PHP functions * directly, we only allow those specified in the security * context. */ if ($smarty->security && !in_array($_name, $smarty->security_settings['MODIFIER_FUNCS'])) { $_message = "(secure mode) modifier '$_name' is not allowed"; } else { if (!function_exists($_name)) { $_message = "modifier '$_name' is not implemented"; } else { $_plugin_func = $_name; $_found = true; } } } else if ($_type == 'function') { /* * This is a catch-all situation. */ $_message = "unknown tag - '$_name'"; } } if ($_found) { $smarty->_plugins[$_type][$_name] = array($_plugin_func, $_tpl_file, $_tpl_line, true, true); } else { // output error $smarty->_trigger_fatal_error('[plugin] ' . $_message, $_tpl_file, $_tpl_line, __FILE__, __LINE__); } } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.load_resource_plugin.php ================================================ _plugins['resource'][$params['type']]; if (isset($_plugin)) { if (!$_plugin[1] && count($_plugin[0])) { $_plugin[1] = true; foreach ($_plugin[0] as $_plugin_func) { if (!is_callable($_plugin_func)) { $_plugin[1] = false; break; } } } if (!$_plugin[1]) { $smarty->_trigger_fatal_error("[plugin] resource '" . $params['type'] . "' is not implemented", null, null, __FILE__, __LINE__); } return; } $_plugin_file = $smarty->_get_plugin_filepath('resource', $params['type']); $_found = ($_plugin_file != false); if ($_found) { /* * If the plugin file is found, it -must- provide the properly named * plugin functions. */ include_once($_plugin_file); /* * Locate functions that we require the plugin to provide. */ $_resource_ops = array('source', 'timestamp', 'secure', 'trusted'); $_resource_funcs = array(); foreach ($_resource_ops as $_op) { $_plugin_func = 'smarty_resource_' . $params['type'] . '_' . $_op; if (!function_exists($_plugin_func)) { $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", null, null, __FILE__, __LINE__); return; } else { $_resource_funcs[] = $_plugin_func; } } $smarty->_plugins['resource'][$params['type']] = array($_resource_funcs, true); } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.process_cached_inserts.php ================================================ _smarty_md5.'{insert_cache (.*)}'.$smarty->_smarty_md5.'!Uis', $params['results'], $match); list($cached_inserts, $insert_args) = $match; for ($i = 0, $for_max = count($cached_inserts); $i < $for_max; $i++) { if ($smarty->debugging) { $_params = array(); require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); $debug_start_time = smarty_core_get_microtime($_params, $smarty); } $args = unserialize($insert_args[$i]); $name = $args['name']; if (isset($args['script'])) { $_params = array('resource_name' => $smarty->_dequote($args['script'])); require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); if(!smarty_core_get_php_resource($_params, $smarty)) { return false; } $resource_type = $_params['resource_type']; $php_resource = $_params['php_resource']; if ($resource_type == 'file') { $smarty->_include($php_resource, true); } else { $smarty->_eval($php_resource); } } $function_name = $smarty->_plugins['insert'][$name][0]; if (empty($args['assign'])) { $replace = $function_name($args, $smarty); } else { $smarty->assign($args['assign'], $function_name($args, $smarty)); $replace = ''; } $params['results'] = str_replace($cached_inserts[$i], $replace, $params['results']); if ($smarty->debugging) { $_params = array(); require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); $smarty->_smarty_debug_info[] = array('type' => 'insert', 'filename' => 'insert_'.$name, 'depth' => $smarty->_inclusion_depth, 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $debug_start_time); } } return $params['results']; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.process_compiled_include.php ================================================ _cache_including; $smarty->_cache_including = true; $_return = $params['results']; foreach ($smarty->_cache_serials as $_include_file_path=>$_cache_serial) { $_return = preg_replace_callback('!(\{nocache\:('.$_cache_serial.')#(\d+)\})!s', array(&$smarty, '_process_compiled_include_callback'), $_return); } $smarty->_cache_including = $_cache_including; return $_return; } ?> ================================================ FILE: tools/server/admin/smarty/internals/core.read_cache_file.php ================================================ force_compile) { // force compile enabled, always regenerate return false; } if (isset($content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']])) { list($params['results'], $smarty->_cache_info) = $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']]; return true; } if (!empty($smarty->cache_handler_func)) { // use cache_handler function call_user_func_array($smarty->cache_handler_func, array('read', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null)); } else { // use local cache file $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']); $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id); $params['results'] = $smarty->_read_file($_cache_file); } if (empty($params['results'])) { // nothing to parse (error?), regenerate cache return false; } $_contents = $params['results']; $_info_start = strpos($_contents, "\n") + 1; $_info_len = (int)substr($_contents, 0, $_info_start - 1); $_cache_info = unserialize(substr($_contents, $_info_start, $_info_len)); $params['results'] = substr($_contents, $_info_start + $_info_len); if ($smarty->caching == 2 && isset ($_cache_info['expires'])){ // caching by expiration time if ($_cache_info['expires'] > -1 && (time() > $_cache_info['expires'])) { // cache expired, regenerate return false; } } else { // caching by lifetime if ($smarty->cache_lifetime > -1 && (time() - $_cache_info['timestamp'] > $smarty->cache_lifetime)) { // cache expired, regenerate return false; } } if ($smarty->compile_check) { $_params = array('get_source' => false, 'quiet'=>true); foreach (array_keys($_cache_info['template']) as $_template_dep) { $_params['resource_name'] = $_template_dep; if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) { // template file has changed, regenerate cache return false; } } if (isset($_cache_info['config'])) { $_params = array('resource_base_path' => $smarty->config_dir, 'get_source' => false, 'quiet'=>true); foreach (array_keys($_cache_info['config']) as $_config_dep) { $_params['resource_name'] = $_config_dep; if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) { // config file has changed, regenerate cache return false; } } } } foreach ($_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) { if (empty($smarty->_cache_serials[$_include_file_path])) { $smarty->_include($_include_file_path, true); } if ($smarty->_cache_serials[$_include_file_path] != $_cache_serial) { /* regenerate */ return false; } } $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']] = array($params['results'], $_cache_info); $smarty->_cache_info = $_cache_info; return true; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.rm_auto.php ================================================ $params['auto_base'], 'level' => 0, 'exp_time' => $params['exp_time'] ); require_once(SMARTY_CORE_DIR . 'core.rmdir.php'); $_res = smarty_core_rmdir($_params, $smarty); } else { $_tname = $smarty->_get_auto_filename($params['auto_base'], $params['auto_source'], $params['auto_id']); if(isset($params['auto_source'])) { if (isset($params['extensions'])) { $_res = false; foreach ((array)$params['extensions'] as $_extension) $_res |= $smarty->_unlink($_tname.$_extension, $params['exp_time']); } else { $_res = $smarty->_unlink($_tname, $params['exp_time']); } } elseif ($smarty->use_sub_dirs) { $_params = array( 'dirname' => $_tname, 'level' => 1, 'exp_time' => $params['exp_time'] ); require_once(SMARTY_CORE_DIR . 'core.rmdir.php'); $_res = smarty_core_rmdir($_params, $smarty); } else { // remove matching file names $_handle = opendir($params['auto_base']); $_res = true; while (false !== ($_filename = readdir($_handle))) { if($_filename == '.' || $_filename == '..') { continue; } elseif (substr($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, 0, strlen($_tname)) == $_tname) { $_res &= (bool)$smarty->_unlink($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, $params['exp_time']); } } } } return $_res; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.rmdir.php ================================================ keep root) * WARNING: no tests, it will try to remove what you tell it! * * @param string $dirname * @param integer $level * @param integer $exp_time * @return boolean */ // $dirname, $level = 1, $exp_time = null function smarty_core_rmdir($params, &$smarty) { if(!isset($params['level'])) { $params['level'] = 1; } if(!isset($params['exp_time'])) { $params['exp_time'] = null; } if($_handle = @opendir($params['dirname'])) { while (false !== ($_entry = readdir($_handle))) { if ($_entry != '.' && $_entry != '..') { if (@is_dir($params['dirname'] . DIRECTORY_SEPARATOR . $_entry)) { $_params = array( 'dirname' => $params['dirname'] . DIRECTORY_SEPARATOR . $_entry, 'level' => $params['level'] + 1, 'exp_time' => $params['exp_time'] ); require_once(SMARTY_CORE_DIR . 'core.rmdir.php'); smarty_core_rmdir($_params, $smarty); } else { $smarty->_unlink($params['dirname'] . DIRECTORY_SEPARATOR . $_entry, $params['exp_time']); } } } closedir($_handle); } if ($params['level']) { return @rmdir($params['dirname']); } return (bool)$_handle; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.run_insert_handler.php ================================================ debugging) { $_params = array(); $_debug_start_time = smarty_core_get_microtime($_params, $smarty); } if ($smarty->caching) { $_arg_string = serialize($params['args']); $_name = $params['args']['name']; if (!isset($smarty->_cache_info['insert_tags'][$_name])) { $smarty->_cache_info['insert_tags'][$_name] = array('insert', $_name, $smarty->_plugins['insert'][$_name][1], $smarty->_plugins['insert'][$_name][2], !empty($params['args']['script']) ? true : false); } return $smarty->_smarty_md5."{insert_cache $_arg_string}".$smarty->_smarty_md5; } else { if (isset($params['args']['script'])) { $_params = array('resource_name' => $smarty->_dequote($params['args']['script'])); require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); if(!smarty_core_get_php_resource($_params, $smarty)) { return false; } if ($_params['resource_type'] == 'file') { $smarty->_include($_params['php_resource'], true); } else { $smarty->_eval($_params['php_resource']); } unset($params['args']['script']); } $_funcname = $smarty->_plugins['insert'][$params['args']['name']][0]; $_content = $_funcname($params['args'], $smarty); if ($smarty->debugging) { $_params = array(); require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); $smarty->_smarty_debug_info[] = array('type' => 'insert', 'filename' => 'insert_'.$params['args']['name'], 'depth' => $smarty->_inclusion_depth, 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); } if (!empty($params['args']["assign"])) { $smarty->assign($params['args']["assign"], $_content); } else { return $_content; } } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.smarty_include_php.php ================================================ $params['smarty_file']); require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); smarty_core_get_php_resource($_params, $smarty); $_smarty_resource_type = $_params['resource_type']; $_smarty_php_resource = $_params['php_resource']; if (!empty($params['smarty_assign'])) { ob_start(); if ($_smarty_resource_type == 'file') { $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']); } else { $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']); } $smarty->assign($params['smarty_assign'], ob_get_contents()); ob_end_clean(); } else { if ($_smarty_resource_type == 'file') { $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']); } else { $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']); } } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.write_cache_file.php ================================================ _cache_info['timestamp'] = time(); if ($smarty->cache_lifetime > -1){ // expiration set $smarty->_cache_info['expires'] = $smarty->_cache_info['timestamp'] + $smarty->cache_lifetime; } else { // cache will never expire $smarty->_cache_info['expires'] = -1; } // collapse nocache.../nocache-tags if (preg_match_all('!\{(/?)nocache\:[0-9a-f]{32}#\d+\}!', $params['results'], $match, PREG_PATTERN_ORDER)) { // remove everything between every pair of outermost noache.../nocache-tags // and replace it by a single nocache-tag // this new nocache-tag will be replaced by dynamic contents in // smarty_core_process_compiled_includes() on a cache-read $match_count = count($match[0]); $results = preg_split('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!', $params['results'], -1, PREG_SPLIT_DELIM_CAPTURE); $level = 0; $j = 0; for ($i=0, $results_count = count($results); $i < $results_count && $j < $match_count; $i++) { if ($results[$i] == $match[0][$j]) { // nocache tag if ($match[1][$j]) { // closing tag $level--; unset($results[$i]); } else { // opening tag if ($level++ > 0) unset($results[$i]); } $j++; } elseif ($level > 0) { unset($results[$i]); } } $params['results'] = implode('', $results); } $smarty->_cache_info['cache_serials'] = $smarty->_cache_serials; // prepend the cache header info into cache file $_cache_info = serialize($smarty->_cache_info); $params['results'] = strlen($_cache_info) . "\n" . $_cache_info . $params['results']; if (!empty($smarty->cache_handler_func)) { // use cache_handler function call_user_func_array($smarty->cache_handler_func, array('write', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null)); } else { // use local cache file if(!@is_writable($smarty->cache_dir)) { // cache_dir not writable, see if it exists if(!@is_dir($smarty->cache_dir)) { $smarty->trigger_error('the $cache_dir \'' . $smarty->cache_dir . '\' does not exist, or is not a directory.', E_USER_ERROR); return false; } $smarty->trigger_error('unable to write to $cache_dir \'' . realpath($smarty->cache_dir) . '\'. Be sure $cache_dir is writable by the web server user.', E_USER_ERROR); return false; } $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']); $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id); $_params = array('filename' => $_cache_file, 'contents' => $params['results'], 'create_dirs' => true); require_once(SMARTY_CORE_DIR . 'core.write_file.php'); smarty_core_write_file($_params, $smarty); return true; } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.write_compiled_include.php ================================================ caching && \!\$this->_cache_including\) \{ echo \'\{nocache\:('.$params['cache_serial'].')#(\d+)\}\';\}'; $_tag_end = 'if \(\$this->caching && \!\$this->_cache_including\) \{ echo \'\{/nocache\:(\\2)#(\\3)\}\';\}'; preg_match_all('!('.$_tag_start.'(.*)'.$_tag_end.')!Us', $params['compiled_content'], $_match_source, PREG_SET_ORDER); // no nocache-parts found: done if (count($_match_source)==0) return; // convert the matched php-code to functions $_include_compiled = "_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; $_include_compiled .= " compiled from " . strtr(urlencode($params['resource_name']), array('%2F'=>'/', '%3A'=>':')) . " */\n\n"; $_compile_path = $params['include_file_path']; $smarty->_cache_serials[$_compile_path] = $params['cache_serial']; $_include_compiled .= "\$this->_cache_serials['".$_compile_path."'] = '".$params['cache_serial']."';\n\n?>"; $_include_compiled .= $params['plugins_code']; $_include_compiled .= "= 5.0) ? '_smarty' : 'this'; for ($_i = 0, $_for_max = count($_match_source); $_i < $_for_max; $_i++) { $_match =& $_match_source[$_i]; $source = $_match[4]; if ($this_varname == '_smarty') { /* rename $this to $_smarty in the sourcecode */ $tokens = token_get_all('\n"; $_params = array('filename' => $_compile_path, 'contents' => $_include_compiled, 'create_dirs' => true); require_once(SMARTY_CORE_DIR . 'core.write_file.php'); smarty_core_write_file($_params, $smarty); return true; } ?> ================================================ FILE: tools/server/admin/smarty/internals/core.write_compiled_resource.php ================================================ compile_dir)) { // compile_dir not writable, see if it exists if(!@is_dir($smarty->compile_dir)) { $smarty->trigger_error('the $compile_dir \'' . $smarty->compile_dir . '\' does not exist, or is not a directory.', E_USER_ERROR); return false; } $smarty->trigger_error('unable to write to $compile_dir \'' . realpath($smarty->compile_dir) . '\'. Be sure $compile_dir is writable by the web server user.', E_USER_ERROR); return false; } $_params = array('filename' => $params['compile_path'], 'contents' => $params['compiled_content'], 'create_dirs' => true); require_once(SMARTY_CORE_DIR . 'core.write_file.php'); smarty_core_write_file($_params, $smarty); return true; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/internals/core.write_file.php ================================================ $_dirname); require_once(SMARTY_CORE_DIR . 'core.create_dir_structure.php'); smarty_core_create_dir_structure($_params, $smarty); } // write to tmp file, then rename it to avoid // file locking race condition $_tmp_file = tempnam($_dirname, 'wrt'); if (!($fd = @fopen($_tmp_file, 'wb'))) { $_tmp_file = $_dirname . DIRECTORY_SEPARATOR . uniqid('wrt'); if (!($fd = @fopen($_tmp_file, 'wb'))) { $smarty->trigger_error("problem writing temporary file '$_tmp_file'"); return false; } } fwrite($fd, $params['contents']); fclose($fd); // Delete the file if it allready exists (this is needed on Win, // because it cannot overwrite files with rename() if (file_exists($params['filename'])) { @unlink($params['filename']); } @rename($_tmp_file, $params['filename']); @chmod($params['filename'], $smarty->_file_perms); return true; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/block.textformat.php ================================================ * Name: textformat
* Purpose: format text a certain way with preset styles * or custom wrap/indent settings
* @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat} * (Smarty online manual) * @param array *
 * Params:   style: string (email)
 *           indent: integer (0)
 *           wrap: integer (80)
 *           wrap_char string ("\n")
 *           indent_char: string (" ")
 *           wrap_boundary: boolean (true)
 * 
* @param string contents of the block * @param Smarty clever simulation of a method * @return string string $content re-formatted */ function smarty_block_textformat($params, $content, &$smarty) { if (is_null($content)) { return; } $style = null; $indent = 0; $indent_first = 0; $indent_char = ' '; $wrap = 80; $wrap_char = "\n"; $wrap_cut = false; $assign = null; foreach ($params as $_key => $_val) { switch ($_key) { case 'style': case 'indent_char': case 'wrap_char': case 'assign': $$_key = (string)$_val; break; case 'indent': case 'indent_first': case 'wrap': $$_key = (int)$_val; break; case 'wrap_cut': $$_key = (bool)$_val; break; default: $smarty->trigger_error("textformat: unknown attribute '$_key'"); } } if ($style == 'email') { $wrap = 72; } // split into paragraphs $_paragraphs = preg_split('![\r\n][\r\n]!',$content); $_output = ''; for($_x = 0, $_y = count($_paragraphs); $_x < $_y; $_x++) { if ($_paragraphs[$_x] == '') { continue; } // convert mult. spaces & special chars to single space $_paragraphs[$_x] = preg_replace(array('!\s+!','!(^\s+)|(\s+$)!'), array(' ',''), $_paragraphs[$_x]); // indent first line if($indent_first > 0) { $_paragraphs[$_x] = str_repeat($indent_char, $indent_first) . $_paragraphs[$_x]; } // wordwrap sentences $_paragraphs[$_x] = wordwrap($_paragraphs[$_x], $wrap - $indent, $wrap_char, $wrap_cut); // indent lines if($indent > 0) { $_paragraphs[$_x] = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraphs[$_x]); } } $_output = implode($wrap_char . $wrap_char, $_paragraphs); return $assign ? $smarty->assign($assign, $_output) : $_output; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/compiler.assign.php ================================================ * Name: assign
* Purpose: assign a value to a template variable * @link http://smarty.php.net/manual/en/language.custom.functions.php#LANGUAGE.FUNCTION.ASSIGN {assign} * (Smarty online manual) * @param string containing var-attribute and value-attribute * @param Smarty_Compiler */ function smarty_compiler_assign($tag_attrs, &$compiler) { $_params = $compiler->_parse_attrs($tag_attrs); if (!isset($_params['var'])) { $compiler->_syntax_error("assign: missing 'var' parameter", E_USER_WARNING); return; } if (!isset($_params['value'])) { $compiler->_syntax_error("assign: missing 'value' parameter", E_USER_WARNING); return; } return "\$this->assign({$_params['var']}, {$_params['value']});"; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.assign_debug_info.php ================================================ * Name: assign_debug_info
* Purpose: assign debug info to the template
* @param array unused in this plugin, this plugin uses {@link Smarty::$_config}, * {@link Smarty::$_tpl_vars} and {@link Smarty::$_smarty_debug_info} * @param Smarty */ function smarty_function_assign_debug_info($params, &$smarty) { $assigned_vars = $smarty->_tpl_vars; ksort($assigned_vars); if (@is_array($smarty->_config[0])) { $config_vars = $smarty->_config[0]; ksort($config_vars); $smarty->assign("_debug_config_keys", array_keys($config_vars)); $smarty->assign("_debug_config_vals", array_values($config_vars)); } $included_templates = $smarty->_smarty_debug_info; $smarty->assign("_debug_keys", array_keys($assigned_vars)); $smarty->assign("_debug_vals", array_values($assigned_vars)); $smarty->assign("_debug_tpls", $included_templates); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.config_load.php ================================================ * Name: config_load
* Purpose: load config file vars * @link http://smarty.php.net/manual/en/language.function.config.load.php {config_load} * (Smarty online manual) * @param array Format: *
 * array('file' => required config file name,
 *       'section' => optional config file section to load
 *       'scope' => local/parent/global
 *       'global' => overrides scope, setting to parent if true)
 * 
* @param Smarty */ function smarty_function_config_load($params, &$smarty) { if ($smarty->debugging) { $_params = array(); require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); $_debug_start_time = smarty_core_get_microtime($_params, $smarty); } $_file = isset($params['file']) ? $smarty->_dequote($params['file']) : null; $_section = isset($params['section']) ? $smarty->_dequote($params['section']) : null; $_scope = isset($params['scope']) ? $smarty->_dequote($params['scope']) : 'global'; $_global = isset($params['global']) ? $smarty->_dequote($params['global']) : false; if (!isset($_file) || strlen($_file) == 0) { $smarty->trigger_error("missing 'file' attribute in config_load tag", E_USER_ERROR, __FILE__, __LINE__); } if (isset($_scope)) { if ($_scope != 'local' && $_scope != 'parent' && $_scope != 'global') { $smarty->trigger_error("invalid 'scope' attribute value", E_USER_ERROR, __FILE__, __LINE__); } } else { if ($_global) { $_scope = 'parent'; } else { $_scope = 'local'; } } $_params = array('resource_name' => $_file, 'resource_base_path' => $smarty->config_dir, 'get_source' => false); $smarty->_parse_resource_name($_params); $_file_path = $_params['resource_type'] . ':' . $_params['resource_name']; if (isset($_section)) $_compile_file = $smarty->_get_compile_path($_file_path.'|'.$_section); else $_compile_file = $smarty->_get_compile_path($_file_path); if($smarty->force_compile || !file_exists($_compile_file)) { $_compile = true; } elseif ($smarty->compile_check) { $_params = array('resource_name' => $_file, 'resource_base_path' => $smarty->config_dir, 'get_source' => false); $_compile = $smarty->_fetch_resource_info($_params) && $_params['resource_timestamp'] > filemtime($_compile_file); } else { $_compile = false; } if($_compile) { // compile config file if(!is_object($smarty->_conf_obj)) { require_once SMARTY_DIR . $smarty->config_class . '.class.php'; $smarty->_conf_obj = new $smarty->config_class(); $smarty->_conf_obj->overwrite = $smarty->config_overwrite; $smarty->_conf_obj->booleanize = $smarty->config_booleanize; $smarty->_conf_obj->read_hidden = $smarty->config_read_hidden; $smarty->_conf_obj->fix_newlines = $smarty->config_fix_newlines; } $_params = array('resource_name' => $_file, 'resource_base_path' => $smarty->config_dir, $_params['get_source'] = true); if (!$smarty->_fetch_resource_info($_params)) { return; } $smarty->_conf_obj->set_file_contents($_file, $_params['source_content']); $_config_vars = array_merge($smarty->_conf_obj->get($_file), $smarty->_conf_obj->get($_file, $_section)); if(function_exists('var_export')) { $_output = ''; } else { $_output = ''\\\'', '\\'=>'\\\\')) . '\'); ?>'; } $_params = (array('compile_path' => $_compile_file, 'compiled_content' => $_output, 'resource_timestamp' => $_params['resource_timestamp'])); require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); smarty_core_write_compiled_resource($_params, $smarty); } else { include($_compile_file); } if ($smarty->caching) { $smarty->_cache_info['config'][$_file] = true; } $smarty->_config[0]['vars'] = @array_merge($smarty->_config[0]['vars'], $_config_vars); $smarty->_config[0]['files'][$_file] = true; if ($_scope == 'parent') { $smarty->_config[1]['vars'] = @array_merge($smarty->_config[1]['vars'], $_config_vars); $smarty->_config[1]['files'][$_file] = true; } else if ($_scope == 'global') { for ($i = 1, $for_max = count($smarty->_config); $i < $for_max; $i++) { $smarty->_config[$i]['vars'] = @array_merge($smarty->_config[$i]['vars'], $_config_vars); $smarty->_config[$i]['files'][$_file] = true; } } if ($smarty->debugging) { $_params = array(); require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); $smarty->_smarty_debug_info[] = array('type' => 'config', 'filename' => $_file.' ['.$_section.'] '.$_scope, 'depth' => $smarty->_inclusion_depth, 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.counter.php ================================================ * Name: counter
* Purpose: print out a counter value * @link http://smarty.php.net/manual/en/language.function.counter.php {counter} * (Smarty online manual) * @param array parameters * @param Smarty * @return string|null */ function smarty_function_counter($params, &$smarty) { static $counters = array(); $name = (isset($params['name'])) ? $params['name'] : 'default'; if (!isset($counters[$name])) { $counters[$name] = array( 'start'=>1, 'skip'=>1, 'direction'=>'up', 'count'=>1 ); } $counter =& $counters[$name]; if (isset($params['start'])) { $counter['start'] = $counter['count'] = (int)$params['start']; } if (!empty($params['assign'])) { $counter['assign'] = $params['assign']; } if (isset($counter['assign'])) { $smarty->assign($counter['assign'], $counter['count']); } if (isset($params['print'])) { $print = (bool)$params['print']; } else { $print = empty($counter['assign']); } if ($print) { $retval = $counter['count']; } else { $retval = null; } if (isset($params['skip'])) { $counter['skip'] = $params['skip']; } if (isset($params['direction'])) { $counter['direction'] = $params['direction']; } if ($counter['direction'] == "down") $counter['count'] -= $counter['skip']; else $counter['count'] += $counter['skip']; return $retval; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.cycle.php ================================================ * Name: cycle
* Date: May 3, 2002
* Purpose: cycle through given values
* Input: * - name = name of cycle (optional) * - values = comma separated list of values to cycle, * or an array of values to cycle * (this can be left out for subsequent calls) * - reset = boolean - resets given var to true * - print = boolean - print var or not. default is true * - advance = boolean - whether or not to advance the cycle * - delimiter = the value delimiter, default is "," * - assign = boolean, assigns to template var instead of * printed. * * Examples:
*
 * {cycle values="#eeeeee,#d0d0d0d"}
 * {cycle name=row values="one,two,three" reset=true}
 * {cycle name=row}
 * 
* @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle} * (Smarty online manual) * @author Monte Ohrt * @author credit to Mark Priatel * @author credit to Gerard * @author credit to Jason Sweat * @version 1.3 * @param array * @param Smarty * @return string|null */ function smarty_function_cycle($params, &$smarty) { static $cycle_vars; $name = (empty($params['name'])) ? 'default' : $params['name']; $print = (isset($params['print'])) ? (bool)$params['print'] : true; $advance = (isset($params['advance'])) ? (bool)$params['advance'] : true; $reset = (isset($params['reset'])) ? (bool)$params['reset'] : false; if (!in_array('values', array_keys($params))) { if(!isset($cycle_vars[$name]['values'])) { $smarty->trigger_error("cycle: missing 'values' parameter"); return; } } else { if(isset($cycle_vars[$name]['values']) && $cycle_vars[$name]['values'] != $params['values'] ) { $cycle_vars[$name]['index'] = 0; } $cycle_vars[$name]['values'] = $params['values']; } $cycle_vars[$name]['delimiter'] = (isset($params['delimiter'])) ? $params['delimiter'] : ','; if(is_array($cycle_vars[$name]['values'])) { $cycle_array = $cycle_vars[$name]['values']; } else { $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']); } if(!isset($cycle_vars[$name]['index']) || $reset ) { $cycle_vars[$name]['index'] = 0; } if (isset($params['assign'])) { $print = false; $smarty->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]); } if($print) { $retval = $cycle_array[$cycle_vars[$name]['index']]; } else { $retval = null; } if($advance) { if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) { $cycle_vars[$name]['index'] = 0; } else { $cycle_vars[$name]['index']++; } } return $retval; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.debug.php ================================================ * Name: debug
* Date: July 1, 2002
* Purpose: popup debug window * @link http://smarty.php.net/manual/en/language.function.debug.php {debug} * (Smarty online manual) * @author Monte Ohrt * @version 1.0 * @param array * @param Smarty * @return string output from {@link Smarty::_generate_debug_output()} */ function smarty_function_debug($params, &$smarty) { if (isset($params['output'])) { $smarty->assign('_smarty_debug_output', $params['output']); } require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); return smarty_core_display_debug_console(null, $smarty); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.eval.php ================================================ * Name: eval
* Purpose: evaluate a template variable as a template
* @link http://smarty.php.net/manual/en/language.function.eval.php {eval} * (Smarty online manual) * @param array * @param Smarty */ function smarty_function_eval($params, &$smarty) { if (!isset($params['var'])) { $smarty->trigger_error("eval: missing 'var' parameter"); return; } if($params['var'] == '') { return; } $smarty->_compile_source('evaluated template', $params['var'], $_var_compiled); ob_start(); $smarty->_eval('?>' . $_var_compiled); $_contents = ob_get_contents(); ob_end_clean(); if (!empty($params['assign'])) { $smarty->assign($params['assign'], $_contents); } else { return $_contents; } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.fetch.php ================================================ * Name: fetch
* Purpose: fetch file, web or ftp data and display results * @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch} * (Smarty online manual) * @param array * @param Smarty * @return string|null if the assign parameter is passed, Smarty assigns the * result to a template variable */ function smarty_function_fetch($params, &$smarty) { if (empty($params['file'])) { $smarty->_trigger_fatal_error("[plugin] parameter 'file' cannot be empty"); return; } $content = ''; if ($smarty->security && !preg_match('!^(http|ftp)://!i', $params['file'])) { $_params = array('resource_type' => 'file', 'resource_name' => $params['file']); require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); if(!smarty_core_is_secure($_params, $smarty)) { $smarty->_trigger_fatal_error('[plugin] (secure mode) fetch \'' . $params['file'] . '\' is not allowed'); return; } // fetch the file if($fp = @fopen($params['file'],'r')) { while(!feof($fp)) { $content .= fgets ($fp,4096); } fclose($fp); } else { $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] . '\''); return; } } else { // not a local file if(preg_match('!^http://!i',$params['file'])) { // http fetch if($uri_parts = parse_url($params['file'])) { // set defaults $host = $server_name = $uri_parts['host']; $timeout = 30; $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; $agent = "Smarty Template Engine ".$smarty->_version; $referer = ""; $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/'; $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : ''; $_is_proxy = false; if(empty($uri_parts['port'])) { $port = 80; } else { $port = $uri_parts['port']; } if(!empty($uri_parts['user'])) { $user = $uri_parts['user']; } if(!empty($uri_parts['pass'])) { $pass = $uri_parts['pass']; } // loop through parameters, setup headers foreach($params as $param_key => $param_value) { switch($param_key) { case "file": case "assign": case "assign_headers": break; case "user": if(!empty($param_value)) { $user = $param_value; } break; case "pass": if(!empty($param_value)) { $pass = $param_value; } break; case "accept": if(!empty($param_value)) { $accept = $param_value; } break; case "header": if(!empty($param_value)) { if(!preg_match('![\w\d-]+: .+!',$param_value)) { $smarty->_trigger_fatal_error("[plugin] invalid header format '".$param_value."'"); return; } else { $extra_headers[] = $param_value; } } break; case "proxy_host": if(!empty($param_value)) { $proxy_host = $param_value; } break; case "proxy_port": if(!preg_match('!\D!', $param_value)) { $proxy_port = (int) $param_value; } else { $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); return; } break; case "agent": if(!empty($param_value)) { $agent = $param_value; } break; case "referer": if(!empty($param_value)) { $referer = $param_value; } break; case "timeout": if(!preg_match('!\D!', $param_value)) { $timeout = (int) $param_value; } else { $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); return; } break; default: $smarty->_trigger_fatal_error("[plugin] unrecognized attribute '".$param_key."'"); return; } } if(!empty($proxy_host) && !empty($proxy_port)) { $_is_proxy = true; $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout); } else { $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout); } if(!$fp) { $errmsg = iconv('GBK', 'UTF-8', $errstr); $smarty->_trigger_fatal_error("[plugin] unable to fetch: $errmsg ($errno)"); return; } else { if($_is_proxy) { fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n"); } else { fputs($fp, "GET $uri HTTP/1.0\r\n"); } if(!empty($host)) { fputs($fp, "Host: $host\r\n"); } if(!empty($accept)) { fputs($fp, "Accept: $accept\r\n"); } if(!empty($agent)) { fputs($fp, "User-Agent: $agent\r\n"); } if(!empty($referer)) { fputs($fp, "Referer: $referer\r\n"); } if(isset($extra_headers) && is_array($extra_headers)) { foreach($extra_headers as $curr_header) { fputs($fp, $curr_header."\r\n"); } } if(!empty($user) && !empty($pass)) { fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n"); } fputs($fp, "\r\n"); while(!feof($fp)) { $content .= fgets($fp,4096); } fclose($fp); $csplit = split("\r\n\r\n",$content,2); $content = $csplit[1]; if(!empty($params['assign_headers'])) { $smarty->assign($params['assign_headers'],split("\r\n",$csplit[0])); } } } else { $smarty->_trigger_fatal_error("[plugin] unable to parse URL, check syntax"); return; } } else { // ftp fetch if($fp = @fopen($params['file'],'r')) { while(!feof($fp)) { $content .= fgets ($fp,4096); } fclose($fp); } else { $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] .'\''); return; } } } if (!empty($params['assign'])) { $smarty->assign($params['assign'],$content); } else { return $content; } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.html_checkboxes.php ================================================ * Type: function
* Name: html_checkboxes
* Date: 24.Feb.2003
* Purpose: Prints out a list of checkbox input types
* Input:
* - name (optional) - string default "checkbox" * - values (required) - array * - options (optional) - associative array * - checked (optional) - array default not set * - separator (optional) - ie
or   * - output (optional) - the output next to each checkbox * - assign (optional) - assign the output as an array to this variable * Examples: *
 * {html_checkboxes values=$ids output=$names}
 * {html_checkboxes values=$ids name='box' separator='
' output=$names} * {html_checkboxes values=$ids checked=$checked separator='
' output=$names} *
* @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} * (Smarty online manual) * @author Christopher Kvarme * @author credits to Monte Ohrt * @version 1.0 * @param array * @param Smarty * @return string * @uses smarty_function_escape_special_chars() */ function smarty_function_html_checkboxes($params, &$smarty) { require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); $name = 'checkbox'; $values = null; $options = null; $selected = null; $separator = ''; $labels = true; $output = null; $extra = ''; foreach($params as $_key => $_val) { switch($_key) { case 'name': case 'separator': $$_key = $_val; break; case 'labels': $$_key = (bool)$_val; break; case 'options': $$_key = (array)$_val; break; case 'values': case 'output': $$_key = array_values((array)$_val); break; case 'checked': case 'selected': $selected = array_map('strval', array_values((array)$_val)); break; case 'checkboxes': $smarty->trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING); $options = (array)$_val; break; case 'assign': break; default: if(!is_array($_val)) { $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; } else { $smarty->trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE); } break; } } if (!isset($options) && !isset($values)) return ''; /* raise error here? */ settype($selected, 'array'); $_html_result = array(); if (isset($options)) { foreach ($options as $_key=>$_val) $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); } else { foreach ($values as $_i=>$_key) { $_val = isset($output[$_i]) ? $output[$_i] : ''; $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); } } if(!empty($params['assign'])) { $smarty->assign($params['assign'], $_html_result); } else { return implode("\n",$_html_result); } } function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) { $_output = ''; if ($labels) $_output .= ''; $_output .= $separator; return $_output; } ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.html_image.php ================================================ * Name: html_image
* Date: Feb 24, 2003
* Purpose: format HTML tags for the image
* Input:
* - file = file (and path) of image (required) * - height = image height (optional, default actual height) * - width = image width (optional, default actual width) * - basedir = base directory for absolute paths, default * is environment variable DOCUMENT_ROOT * * Examples: {html_image file="images/masthead.gif"} * Output: * @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image} * (Smarty online manual) * @author Monte Ohrt * @author credits to Duda - wrote first image function * in repository, helped with lots of functionality * @version 1.0 * @param array * @param Smarty * @return string * @uses smarty_function_escape_special_chars() */ function smarty_function_html_image($params, &$smarty) { require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); $alt = ''; $file = ''; $height = ''; $width = ''; $extra = ''; $prefix = ''; $suffix = ''; $server_vars = ($smarty->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; $basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : ''; foreach($params as $_key => $_val) { switch($_key) { case 'file': case 'height': case 'width': case 'dpi': case 'basedir': $$_key = $_val; break; case 'alt': if(!is_array($_val)) { $$_key = smarty_function_escape_special_chars($_val); } else { $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); } break; case 'link': case 'href': $prefix = ''; $suffix = ''; break; default: if(!is_array($_val)) { $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; } else { $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); } break; } } if (empty($file)) { $smarty->trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE); return; } if (substr($file,0,1) == '/') { $_image_path = $basedir . $file; } else { $_image_path = $file; } if(!isset($params['width']) || !isset($params['height'])) { if ($smarty->security && ($_params = array('resource_type' => 'file', 'resource_name' => $_image_path)) && (require_once(SMARTY_CORE_DIR . 'core.is_secure.php')) && (!smarty_core_is_secure($_params, $smarty)) ) { $smarty->trigger_error("html_image: (secure) '$_image_path' not in secure directory", E_USER_NOTICE); } elseif (!$_image_data = @getimagesize($_image_path)) { if(!file_exists($_image_path)) { $smarty->trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE); return; } else if(!is_readable($_image_path)) { $smarty->trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE); return; } else { $smarty->trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE); return; } } if(!isset($params['width'])) { $width = $_image_data[0]; } if(!isset($params['height'])) { $height = $_image_data[1]; } } if(isset($params['dpi'])) { if(strstr($server_vars['HTTP_USER_AGENT'], 'Mac')) { $dpi_default = 72; } else { $dpi_default = 96; } $_resize = $dpi_default/$params['dpi']; $width = round($width * $_resize); $height = round($height * $_resize); } return $prefix . ''.$alt.'' . $suffix; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.html_options.php ================================================ * Name: html_options
* Input:
* - name (optional) - string default "select" * - values (required if no options supplied) - array * - options (required if no values supplied) - associative array * - selected (optional) - string default not set * - output (required if not options supplied) - array * - disabled (optional) - string default not set (added by Yogin) * Purpose: Prints the list of ' . "\n"; foreach ($values as $key => $value) { $optgroup_html .= smarty_function_html_options_optoutput($key, $value, $selected, $disabled); } $optgroup_html .= "\n"; return $optgroup_html; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.html_radios.php ================================================ * Type: function
* Name: html_radios
* Date: 24.Feb.2003
* Purpose: Prints out a list of radio input types
* Input:
* - name (optional) - string default "radio" * - values (required) - array * - options (optional) - associative array * - checked (optional) - array default not set * - separator (optional) - ie
or   * - output (optional) - the output next to each radio button * - assign (optional) - assign the output as an array to this variable * Examples: *
 * {html_radios values=$ids output=$names}
 * {html_radios values=$ids name='box' separator='
' output=$names} * {html_radios values=$ids checked=$checked separator='
' output=$names} *
* @link http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios} * (Smarty online manual) * @author Christopher Kvarme * @author credits to Monte Ohrt * @version 1.0 * @param array * @param Smarty * @return string * @uses smarty_function_escape_special_chars() */ function smarty_function_html_radios($params, &$smarty) { require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); $name = 'radio'; $values = null; $options = null; $selected = null; $separator = ''; $labels = true; $output = null; $extra = ''; foreach($params as $_key => $_val) { switch($_key) { case 'name': case 'separator': $$_key = (string)$_val; break; case 'checked': case 'selected': if(is_array($_val)) { $smarty->trigger_error('html_radios: the "' . $_key . '" attribute cannot be an array', E_USER_WARNING); } else { $selected = (string)$_val; } break; case 'labels': $$_key = (bool)$_val; break; case 'options': $$_key = (array)$_val; break; case 'values': case 'output': $$_key = array_values((array)$_val); break; case 'radios': $smarty->trigger_error('html_radios: the use of the "radios" attribute is deprecated, use "options" instead', E_USER_WARNING); $options = (array)$_val; break; case 'assign': break; default: if(!is_array($_val)) { $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; } else { $smarty->trigger_error("html_radios: extra attribute '$_key' cannot be an array", E_USER_NOTICE); } break; } } if (!isset($options) && !isset($values)) return ''; /* raise error here? */ $_html_result = array(); if (isset($options)) { foreach ($options as $_key=>$_val) $_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels); } else { foreach ($values as $_i=>$_key) { $_val = isset($output[$_i]) ? $output[$_i] : ''; $_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels); } } if(!empty($params['assign'])) { $smarty->assign($params['assign'], $_html_result); } else { return implode("\n",$_html_result); } } function smarty_function_html_radios_output($name, $value, $output, $selected, $extra, $separator, $labels) { $_output = ''; if ($labels) { $_id = smarty_function_escape_special_chars($name . '_' . $value); $_output .= ''; $_output .= $separator; return $_output; } ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.html_select_date.php ================================================ * Name: html_select_date
* Purpose: Prints the dropdowns for date selection. * * ChangeLog:
* - 1.0 initial release * - 1.1 added support for +/- N syntax for begin * and end year values. (Monte) * - 1.2 added support for yyyy-mm-dd syntax for * time value. (Jan Rosier) * - 1.3 added support for choosing format for * month values (Gary Loescher) * - 1.3.1 added support for choosing format for * day values (Marcus Bointon) * - 1.3.2 suppport negative timestamps, force year * dropdown to include given date unless explicitly set (Monte) * @link http://smarty.php.net/manual/en/language.function.html.select.date.php {html_select_date} * (Smarty online manual) * @version 1.3.2 * @author Andrei Zmievski * @param array * @param Smarty * @return string */ function smarty_function_html_select_date($params, &$smarty) { require_once $smarty->_get_plugin_filepath('shared','make_timestamp'); require_once $smarty->_get_plugin_filepath('function','html_options'); /* Default values. */ $prefix = "Date_"; $start_year = strftime("%Y"); $end_year = $start_year; $display_days = true; $display_months = true; $display_years = true; $month_format = "%B"; /* Write months as numbers by default GL */ $month_value_format = "%m"; $day_format = "%02d"; /* Write day values using this format MB */ $day_value_format = "%d"; $year_as_text = false; /* Display years in reverse order? Ie. 2000,1999,.... */ $reverse_years = false; /* Should the select boxes be part of an array when returned from PHP? e.g. setting it to "birthday", would create "birthday[Day]", "birthday[Month]" & "birthday[Year]". Can be combined with prefix */ $field_array = null; /* tags. If not set, uses default dropdown. */ $day_size = null; $month_size = null; $year_size = null; /* Unparsed attributes common to *ALL* the tags. An example might be in the template: all_extra ='class ="foo"'. */ $all_extra = null; /* Separate attributes for the tags. */ $day_extra = null; $month_extra = null; $year_extra = null; /* Order in which to display the fields. "D" -> day, "M" -> month, "Y" -> year. */ $field_order = 'MDY'; /* String printed between the different fields. */ $field_separator = "\n"; $time = time(); $all_empty = null; $day_empty = null; $month_empty = null; $year_empty = null; foreach ($params as $_key=>$_value) { switch ($_key) { case 'prefix': case 'time': case 'start_year': case 'end_year': case 'month_format': case 'day_format': case 'day_value_format': case 'field_array': case 'day_size': case 'month_size': case 'year_size': case 'all_extra': case 'day_extra': case 'month_extra': case 'year_extra': case 'field_order': case 'field_separator': case 'month_value_format': case 'month_empty': case 'day_empty': case 'year_empty': $$_key = (string)$_value; break; case 'all_empty': $$_key = (string)$_value; $day_empty = $month_empty = $year_empty = $all_empty; break; case 'display_days': case 'display_months': case 'display_years': case 'year_as_text': case 'reverse_years': $$_key = (bool)$_value; break; default: $smarty->trigger_error("[html_select_date] unknown parameter $_key", E_USER_WARNING); } } if(preg_match('!^-\d+$!',$time)) { // negative timestamp, use date() $time = date('Y-m-d',$time); } // If $time is not in format yyyy-mm-dd if (!preg_match('/^\d{0,4}-\d{0,2}-\d{0,2}$/', $time)) { // use smarty_make_timestamp to get an unix timestamp and // strftime to make yyyy-mm-dd $time = strftime('%Y-%m-%d', smarty_make_timestamp($time)); } // Now split this in pieces, which later can be used to set the select $time = explode("-", $time); // make syntax "+N" or "-N" work with start_year and end_year if (preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match)) { if ($match[1] == '+') { $end_year = strftime('%Y') + $match[2]; } else { $end_year = strftime('%Y') - $match[2]; } } if (preg_match('!^(\+|\-)\s*(\d+)$!', $start_year, $match)) { if ($match[1] == '+') { $start_year = strftime('%Y') + $match[2]; } else { $start_year = strftime('%Y') - $match[2]; } } if (strlen($time[0]) > 0) { if ($start_year > $time[0] && !isset($params['start_year'])) { // force start year to include given date if not explicitly set $start_year = $time[0]; } if($end_year < $time[0] && !isset($params['end_year'])) { // force end year to include given date if not explicitly set $end_year = $time[0]; } } $field_order = strtoupper($field_order); $html_result = $month_result = $day_result = $year_result = ""; if ($display_months) { $month_names = array(); $month_values = array(); if(isset($month_empty)) { $month_names[''] = $month_empty; $month_values[''] = ''; } for ($i = 1; $i <= 12; $i++) { $month_names[$i] = strftime($month_format, mktime(0, 0, 0, $i, 1, 2000)); $month_values[$i] = strftime($month_value_format, mktime(0, 0, 0, $i, 1, 2000)); } $month_result .= ''; } if ($display_days) { $days = array(); if (isset($day_empty)) { $days[''] = $day_empty; $day_values[''] = ''; } for ($i = 1; $i <= 31; $i++) { $days[] = sprintf($day_format, $i); $day_values[] = sprintf($day_value_format, $i); } $day_result .= ''; } if ($display_years) { if (null !== $field_array){ $year_name = $field_array . '[' . $prefix . 'Year]'; } else { $year_name = $prefix . 'Year'; } if ($year_as_text) { $year_result .= ' $years, 'values' => $yearvals, 'selected' => $time[0], 'print_result' => false), $smarty); $year_result .= ''; } } // Loop thru the field_order field for ($i = 0; $i <= 2; $i++){ $c = substr($field_order, $i, 1); switch ($c){ case 'D': $html_result .= $day_result; break; case 'M': $html_result .= $month_result; break; case 'Y': $html_result .= $year_result; break; } // Add the field seperator if($i != 2) { $html_result .= $field_separator; } } return $html_result; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.html_select_time.php ================================================ * Name: html_select_time
* Purpose: Prints the dropdowns for time selection * @link http://smarty.php.net/manual/en/language.function.html.select.time.php {html_select_time} * (Smarty online manual) * @param array * @param Smarty * @return string * @uses smarty_make_timestamp() */ function smarty_function_html_select_time($params, &$smarty) { require_once $smarty->_get_plugin_filepath('shared','make_timestamp'); require_once $smarty->_get_plugin_filepath('function','html_options'); /* Default values. */ $prefix = "Time_"; $time = time(); $display_hours = true; $display_minutes = true; $display_seconds = true; $display_meridian = true; $use_24_hours = true; $minute_interval = 1; $second_interval = 1; /* Should the select boxes be part of an array when returned from PHP? e.g. setting it to "birthday", would create "birthday[Hour]", "birthday[Minute]", "birthday[Seconds]" & "birthday[Meridian]". Can be combined with prefix. */ $field_array = null; $all_extra = null; $hour_extra = null; $minute_extra = null; $second_extra = null; $meridian_extra = null; foreach ($params as $_key=>$_value) { switch ($_key) { case 'prefix': case 'time': case 'field_array': case 'all_extra': case 'hour_extra': case 'minute_extra': case 'second_extra': case 'meridian_extra': $$_key = (string)$_value; break; case 'display_hours': case 'display_minutes': case 'display_seconds': case 'display_meridian': case 'use_24_hours': $$_key = (bool)$_value; break; case 'minute_interval': case 'second_interval': $$_key = (int)$_value; break; default: $smarty->trigger_error("[html_select_time] unknown parameter $_key", E_USER_WARNING); } } $time = smarty_make_timestamp($time); $html_result = ''; if ($display_hours) { $hours = $use_24_hours ? range(0, 23) : range(1, 12); $hour_fmt = $use_24_hours ? '%H' : '%I'; for ($i = 0, $for_max = count($hours); $i < $for_max; $i++) $hours[$i] = sprintf('%02d', $hours[$i]); $html_result .= '\n"; } if ($display_minutes) { $all_minutes = range(0, 59); for ($i = 0, $for_max = count($all_minutes); $i < $for_max; $i+= $minute_interval) $minutes[] = sprintf('%02d', $all_minutes[$i]); $selected = intval(floor(strftime('%M', $time) / $minute_interval) * $minute_interval); $html_result .= '\n"; } if ($display_seconds) { $all_seconds = range(0, 59); for ($i = 0, $for_max = count($all_seconds); $i < $for_max; $i+= $second_interval) $seconds[] = sprintf('%02d', $all_seconds[$i]); $selected = intval(floor(strftime('%S', $time) / $second_interval) * $second_interval); $html_result .= '\n"; } if ($display_meridian && !$use_24_hours) { $html_result .= '\n"; } return $html_result; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.html_table.php ================================================ * Name: html_table
* Date: Feb 17, 2003
* Purpose: make an html table from an array of data
* Input:
* - loop = array to loop through * - cols = number of columns * - rows = number of rows * - table_attr = table attributes * - tr_attr = table row attributes (arrays are cycled) * - td_attr = table cell attributes (arrays are cycled) * - trailpad = value to pad trailing cells with * - vdir = vertical direction (default: "down", means top-to-bottom) * - hdir = horizontal direction (default: "right", means left-to-right) * - inner = inner loop (default "cols": print $loop line by line, * $loop will be printed column by column otherwise) * * * Examples: *
 * {table loop=$data}
 * {table loop=$data cols=4 tr_attr='"bgcolor=red"'}
 * {table loop=$data cols=4 tr_attr=$colors}
 * 
* @author Monte Ohrt * @version 1.0 * @link http://smarty.php.net/manual/en/language.function.html.table.php {html_table} * (Smarty online manual) * @param array * @param Smarty * @return string */ function smarty_function_html_table($params, &$smarty) { $table_attr = 'border="1"'; $tr_attr = ''; $td_attr = ''; $cols = 3; $rows = 3; $trailpad = ' '; $vdir = 'down'; $hdir = 'right'; $inner = 'cols'; if (!isset($params['loop'])) { $smarty->trigger_error("html_table: missing 'loop' parameter"); return; } foreach ($params as $_key=>$_value) { switch ($_key) { case 'loop': $$_key = (array)$_value; break; case 'cols': case 'rows': $$_key = (int)$_value; break; case 'table_attr': case 'trailpad': case 'hdir': case 'vdir': case 'inner': $$_key = (string)$_value; break; case 'tr_attr': case 'td_attr': $$_key = $_value; break; } } $loop_count = count($loop); if (empty($params['rows'])) { /* no rows specified */ $rows = ceil($loop_count/$cols); } elseif (empty($params['cols'])) { if (!empty($params['rows'])) { /* no cols specified, but rows */ $cols = ceil($loop_count/$rows); } } $output = "\n"; for ($r=0; $r<$rows; $r++) { $output .= "\n"; $rx = ($vdir == 'down') ? $r*$cols : ($rows-1-$r)*$cols; for ($c=0; $c<$cols; $c++) { $x = ($hdir == 'right') ? $rx+$c : $rx+$cols-1-$c; if ($inner!='cols') { /* shuffle x to loop over rows*/ $x = floor($x/$cols) + ($x%$cols)*$rows; } if ($x<$loop_count) { $output .= "" . $loop[$x] . "\n"; } else { $output .= "$trailpad\n"; } } $output .= "\n"; } $output .= "
\n"; return $output; } function smarty_function_html_table_cycle($name, $var, $no) { if(!is_array($var)) { $ret = $var; } else { $ret = $var[$no % count($var)]; } return ($ret) ? ' '.$ret : ''; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.mailto.php ================================================ * Name: mailto
* Date: May 21, 2002 * Purpose: automate mailto address link creation, and optionally * encode them.
* Input:
* - address = e-mail address * - text = (optional) text to display, default is address * - encode = (optional) can be one of: * * none : no encoding (default) * * javascript : encode with javascript * * javascript_charcode : encode with javascript charcode * * hex : encode with hexidecimal (no javascript) * - cc = (optional) address(es) to carbon copy * - bcc = (optional) address(es) to blind carbon copy * - subject = (optional) e-mail subject * - newsgroups = (optional) newsgroup(s) to post to * - followupto = (optional) address(es) to follow up to * - extra = (optional) extra tags for the href link * * Examples: *
 * {mailto address="me@domain.com"}
 * {mailto address="me@domain.com" encode="javascript"}
 * {mailto address="me@domain.com" encode="hex"}
 * {mailto address="me@domain.com" subject="Hello to you!"}
 * {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"}
 * {mailto address="me@domain.com" extra='class="mailto"'}
 * 
* @link http://smarty.php.net/manual/en/language.function.mailto.php {mailto} * (Smarty online manual) * @version 1.2 * @author Monte Ohrt * @author credits to Jason Sweat (added cc, bcc and subject functionality) * @param array * @param Smarty * @return string */ function smarty_function_mailto($params, &$smarty) { $extra = ''; if (empty($params['address'])) { $smarty->trigger_error("mailto: missing 'address' parameter"); return; } else { $address = $params['address']; } $text = $address; // netscape and mozilla do not decode %40 (@) in BCC field (bug?) // so, don't encode it. $mail_parms = array(); foreach ($params as $var=>$value) { switch ($var) { case 'cc': case 'bcc': case 'followupto': if (!empty($value)) $mail_parms[] = $var.'='.str_replace('%40','@',rawurlencode($value)); break; case 'subject': case 'newsgroups': $mail_parms[] = $var.'='.rawurlencode($value); break; case 'extra': case 'text': $$var = $value; default: } } $mail_parm_vals = ''; for ($i=0; $itrigger_error("mailto: 'encode' parameter must be none, javascript or hex"); return; } if ($encode == 'javascript' ) { $string = 'document.write(\''.$text.'\');'; $js_encode = ''; for ($x=0; $x < strlen($string); $x++) { $js_encode .= '%' . bin2hex($string[$x]); } return ''; } elseif ($encode == 'javascript_charcode' ) { $string = ''.$text.''; for($x = 0, $y = strlen($string); $x < $y; $x++ ) { $ord[] = ord($string[$x]); } $_ret = "\n"; return $_ret; } elseif ($encode == 'hex') { preg_match('!^(.*)(\?.*)$!',$address,$match); if(!empty($match[2])) { $smarty->trigger_error("mailto: hex encoding does not work with extra attributes. Try javascript."); return; } $address_encode = ''; for ($x=0; $x < strlen($address); $x++) { if(preg_match('!\w!',$address[$x])) { $address_encode .= '%' . bin2hex($address[$x]); } else { $address_encode .= $address[$x]; } } $text_encode = ''; for ($x=0; $x < strlen($text); $x++) { $text_encode .= '&#x' . bin2hex($text[$x]).';'; } $mailto = "mailto:"; return ''.$text_encode.''; } else { // no encoding return ''.$text.''; } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.math.php ================================================ * Name: math
* Purpose: handle math computations in template
* @link http://smarty.php.net/manual/en/language.function.math.php {math} * (Smarty online manual) * @param array * @param Smarty * @return string */ function smarty_function_math($params, &$smarty) { // be sure equation parameter is present if (empty($params['equation'])) { $smarty->trigger_error("math: missing equation parameter"); return; } $equation = $params['equation']; // make sure parenthesis are balanced if (substr_count($equation,"(") != substr_count($equation,")")) { $smarty->trigger_error("math: unbalanced parenthesis"); return; } // match all vars in equation, make sure all are passed preg_match_all("!(?:0x[a-fA-F0-9]+)|([a-zA-Z][a-zA-Z0-9_]+)!",$equation, $match); $allowed_funcs = array('int','abs','ceil','cos','exp','floor','log','log10', 'max','min','pi','pow','rand','round','sin','sqrt','srand','tan'); foreach($match[1] as $curr_var) { if ($curr_var && !in_array($curr_var, array_keys($params)) && !in_array($curr_var, $allowed_funcs)) { $smarty->trigger_error("math: function call $curr_var not allowed"); return; } } foreach($params as $key => $val) { if ($key != "equation" && $key != "format" && $key != "assign") { // make sure value is not empty if (strlen($val)==0) { $smarty->trigger_error("math: parameter $key is empty"); return; } if (!is_numeric($val)) { $smarty->trigger_error("math: parameter $key: is not numeric"); return; } $equation = preg_replace("/\b$key\b/",$val, $equation); } } eval("\$smarty_math_result = ".$equation.";"); if (empty($params['format'])) { if (empty($params['assign'])) { return $smarty_math_result; } else { $smarty->assign($params['assign'],$smarty_math_result); } } else { if (empty($params['assign'])){ printf($params['format'],$smarty_math_result); } else { $smarty->assign($params['assign'],sprintf($params['format'],$smarty_math_result)); } } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.popup.php ================================================ * Name: popup
* Purpose: make text pop up in windows via overlib * @link http://smarty.php.net/manual/en/language.function.popup.php {popup} * (Smarty online manual) * @param array * @param Smarty * @return string */ function smarty_function_popup($params, &$smarty) { $append = ''; foreach ($params as $_key=>$_value) { switch ($_key) { case 'text': case 'trigger': case 'function': case 'inarray': $$_key = (string)$_value; if ($_key == 'function' || $_key == 'inarray') $append .= ',' . strtoupper($_key) . ",'$_value'"; break; case 'caption': case 'closetext': case 'status': $append .= ',' . strtoupper($_key) . ",'" . str_replace("'","\'",$_value) . "'"; break; case 'fgcolor': case 'bgcolor': case 'textcolor': case 'capcolor': case 'closecolor': case 'textfont': case 'captionfont': case 'closefont': case 'fgbackground': case 'bgbackground': case 'caparray': case 'capicon': case 'background': case 'frame': $append .= ',' . strtoupper($_key) . ",'$_value'"; break; case 'textsize': case 'captionsize': case 'closesize': case 'width': case 'height': case 'border': case 'offsetx': case 'offsety': case 'snapx': case 'snapy': case 'fixx': case 'fixy': case 'padx': case 'pady': case 'timeout': case 'delay': $append .= ',' . strtoupper($_key) . ",$_value"; break; case 'sticky': case 'left': case 'right': case 'center': case 'above': case 'below': case 'noclose': case 'autostatus': case 'autostatuscap': case 'fullhtml': case 'hauto': case 'vauto': case 'mouseoff': case 'followmouse': if ($_value) $append .= ',' . strtoupper($_key); break; default: $smarty->trigger_error("[popup] unknown parameter $_key", E_USER_WARNING); } } if (empty($text) && !isset($inarray) && empty($function)) { $smarty->trigger_error("overlib: attribute 'text' or 'inarray' or 'function' required"); return false; } if (empty($trigger)) { $trigger = "onmouseover"; } $retval = $trigger . '="return overlib(\''.preg_replace(array("!'!","![\r\n]!"),array("\'",'\r'),$text).'\''; $retval .= $append . ');"'; if ($trigger == 'onmouseover') $retval .= ' onmouseout="nd();"'; return $retval; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.popup_init.php ================================================ * Name: popup_init
* Purpose: initialize overlib * @link http://smarty.php.net/manual/en/language.function.popup.init.php {popup_init} * (Smarty online manual) * @param array * @param Smarty * @return string */ function smarty_function_popup_init($params, &$smarty) { $zindex = 1000; if (!empty($params['zindex'])) { $zindex = $params['zindex']; } if (!empty($params['src'])) { return '' . "\n" . '' . "\n"; } else { $smarty->trigger_error("popup_init: missing src parameter"); } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/function.substr.php ================================================ trigger_error("substr: missing 'src' parameter"); return; } if (!isset($params['var'])) { $smarty->trigger_error("substr: missing 'var' parameter"); return; } $tmp = ""; if (isset($params['start']) && isset($params['length'])) { $tmp = substr($params['src'], $params['start'], $params['length']); } elseif (isset($params['start']) && isset($params['delim'])) { $tmp = substr($params['src'], $params['start'], strpos($params['src'], $params['delim'])); } elseif (isset($params['delim'])) { $tmp = substr($params['src'], strpos($params['src'], $params['delim'])); } elseif (isset($params['start'])) { $tmp = substr($params['src'], $params['start']); } elseif (isset($params['length'])) { $tmp = substr($params['src'], 0, $params['length']); } else { $smarty->trigger_error("substr: missing start/stop/delim parameters"); return; } $smarty->assign($params['var'], $tmp); } ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.capitalize.php ================================================ * Name: capitalize
* Purpose: capitalize words in the string * @link http://smarty.php.net/manual/en/language.modifiers.php#LANGUAGE.MODIFIER.CAPITALIZE * capitalize (Smarty online manual) * @param string * @return string */ function smarty_modifier_capitalize($string, $uc_digits = false) { smarty_modifier_capitalize_ucfirst(null, $uc_digits); return preg_replace_callback('!\b\w+\b!', 'smarty_modifier_capitalize_ucfirst', $string); } function smarty_modifier_capitalize_ucfirst($string, $uc_digits = null) { static $_uc_digits = false; if(isset($uc_digits)) { $_uc_digits = $uc_digits; return; } if(!preg_match('!\d!',$string[0]) || $_uc_digits) return ucfirst($string[0]); else return $string[0]; } ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.cat.php ================================================ * Name: cat
* Date: Feb 24, 2003 * Purpose: catenate a value to a variable * Input: string to catenate * Example: {$var|cat:"foo"} * @link http://smarty.php.net/manual/en/language.modifier.cat.php cat * (Smarty online manual) * @author Monte Ohrt * @version 1.0 * @param string * @param string * @return string */ function smarty_modifier_cat($string, $cat) { return $string . $cat; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.count_characters.php ================================================ * Name: count_characteres
* Purpose: count the number of characters in a text * @link http://smarty.php.net/manual/en/language.modifier.count.characters.php * count_characters (Smarty online manual) * @param string * @param boolean include whitespace in the character count * @return integer */ function smarty_modifier_count_characters($string, $include_spaces = false) { if ($include_spaces) return(strlen($string)); return preg_match_all("/[^\s]/",$string, $match); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.count_paragraphs.php ================================================ * Name: count_paragraphs
* Purpose: count the number of paragraphs in a text * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php * count_paragraphs (Smarty online manual) * @param string * @return integer */ function smarty_modifier_count_paragraphs($string) { // count \r or \n characters return count(preg_split('/[\r\n]+/', $string)); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.count_sentences.php ================================================ * Name: count_sentences * Purpose: count the number of sentences in a text * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php * count_sentences (Smarty online manual) * @param string * @return integer */ function smarty_modifier_count_sentences($string) { // find periods with a word before but not after. return preg_match_all('/[^\s]\.(?!\w)/', $string, $match); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.count_words.php ================================================ * Name: count_words
* Purpose: count the number of words in a text * @link http://smarty.php.net/manual/en/language.modifier.count.words.php * count_words (Smarty online manual) * @param string * @return integer */ function smarty_modifier_count_words($string) { // split text by ' ',\r,\n,\f,\t $split_array = preg_split('/\s+/',$string); // count matches that contain alphanumerics $word_count = preg_grep('/[a-zA-Z0-9\\x80-\\xff]/', $split_array); return count($word_count); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.date_format.php ================================================ _get_plugin_filepath('shared','make_timestamp'); /** * Smarty date_format modifier plugin * * Type: modifier
* Name: date_format
* Purpose: format datestamps via strftime
* Input:
* - string: input date string * - format: strftime format for output * - default_date: default date if $string is empty * @link http://smarty.php.net/manual/en/language.modifier.date.format.php * date_format (Smarty online manual) * @param string * @param string * @param string * @return string|void * @uses smarty_make_timestamp() */ function smarty_modifier_date_format($string, $format="%b %e, %Y", $default_date=null) { if (substr(PHP_OS,0,3) == 'WIN') { $_win_from = array ('%e', '%T', '%D'); $_win_to = array ('%#d', '%H:%M:%S', '%m/%d/%y'); $format = str_replace($_win_from, $_win_to, $format); } if($string != '') { return strftime($format, smarty_make_timestamp($string)); } elseif (isset($default_date) && $default_date != '') { return strftime($format, smarty_make_timestamp($default_date)); } else { return; } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.debug_print_var.php ================================================ * Name: debug_print_var
* Purpose: formats variable contents for display in the console * @link http://smarty.php.net/manual/en/language.modifier.debug.print.var.php * debug_print_var (Smarty online manual) * @param array|object * @param integer * @param integer * @return string */ function smarty_modifier_debug_print_var($var, $depth = 0, $length = 40) { $_replace = array("\n"=>'\n', "\r"=>'\r', "\t"=>'\t'); if (is_array($var)) { $results = "Array (".count($var).")"; foreach ($var as $curr_key => $curr_val) { $return = smarty_modifier_debug_print_var($curr_val, $depth+1, $length); $results .= "
".str_repeat(' ', $depth*2)."".strtr($curr_key, $_replace)." => $return"; } } else if (is_object($var)) { $object_vars = get_object_vars($var); $results = "".get_class($var)." Object (".count($object_vars).")"; foreach ($object_vars as $curr_key => $curr_val) { $return = smarty_modifier_debug_print_var($curr_val, $depth+1, $length); $results .= "
".str_repeat(' ', $depth*2)."$curr_key => $return"; } } else if (is_resource($var)) { $results = ''.(string)$var.''; } else if (empty($var) && $var != "0") { $results = 'empty'; } else { if (strlen($var) > $length ) { $results = substr($var, 0, $length-3).'...'; } else { $results = $var; } $results = htmlspecialchars($results); $results = strtr($results, $_replace); } return $results; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.default.php ================================================ * Name: default
* Purpose: designate default value for empty variables * @link http://smarty.php.net/manual/en/language.modifier.default.php * default (Smarty online manual) * @param string * @param string * @return string */ function smarty_modifier_default($string, $default = '') { if (!isset($string) || $string === '') return $default; else return $string; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.escape.php ================================================ * Name: escape
* Purpose: Escape the string according to escapement type * @link http://smarty.php.net/manual/en/language.modifier.escape.php * escape (Smarty online manual) * @param string * @param html|htmlall|url|quotes|hex|hexentity|javascript * @return string */ function smarty_modifier_escape($string, $esc_type = 'html') { switch ($esc_type) { case 'html': return htmlspecialchars($string, ENT_QUOTES); case 'htmlall': return htmlentities($string, ENT_QUOTES); case 'url': return rawurlencode($string); case 'quotes': // escape unescaped single quotes return preg_replace("%(?'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n',''<\/')); case 'mail': // safe way to display e-mail address on a web page return str_replace(array('@', '.'),array(' [AT] ', ' [DOT] '), $string); case 'nonstd': // escape non-standard chars, such as ms document quotes $_res = ''; for($_i = 0, $_len = strlen($string); $_i < $_len; $_i++) { $_ord = ord($string{$_i}); // non-standard char, escape it if($_ord >= 126){ $_res .= '&#' . $_ord . ';'; } else { $_res .= $string{$_i}; } } return $_res; default: return $string; } } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.indent.php ================================================ * Name: indent
* Purpose: indent lines of text * @link http://smarty.php.net/manual/en/language.modifier.indent.php * indent (Smarty online manual) * @param string * @param integer * @param string * @return string */ function smarty_modifier_indent($string,$chars=4,$char=" ") { return preg_replace('!^!m',str_repeat($char,$chars),$string); } ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.lower.php ================================================ * Name: lower
* Purpose: convert string to lowercase * @link http://smarty.php.net/manual/en/language.modifier.lower.php * lower (Smarty online manual) * @param string * @return string */ function smarty_modifier_lower($string) { return strtolower($string); } ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.nl2br.php ================================================ * Name: nl2br
* Date: Feb 26, 2003 * Purpose: convert \r\n, \r or \n to <
> * Input:
* - contents = contents to replace * - preceed_test = if true, includes preceeding break tags * in replacement * Example: {$text|nl2br} * @link http://smarty.php.net/manual/en/language.modifier.nl2br.php * nl2br (Smarty online manual) * @version 1.0 * @author Monte Ohrt * @param string * @return string */ function smarty_modifier_nl2br($string) { return nl2br($string); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.regex_replace.php ================================================ * Name: regex_replace
* Purpose: regular epxression search/replace * @link http://smarty.php.net/manual/en/language.modifier.regex.replace.php * regex_replace (Smarty online manual) * @param string * @param string|array * @param string|array * @return string */ function smarty_modifier_regex_replace($string, $search, $replace) { if (preg_match('!\W(\w+)$!s', $search, $match) && (strpos($match[1], 'e') !== false)) { /* remove eval-modifier from $search */ $search = substr($search, 0, -strlen($match[1])) . str_replace('e', '', $match[1]); } return preg_replace($search, $replace, $string); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.replace.php ================================================ * Name: replace
* Purpose: simple search/replace * @link http://smarty.php.net/manual/en/language.modifier.replace.php * replace (Smarty online manual) * @param string * @param string * @param string * @return string */ function smarty_modifier_replace($string, $search, $replace) { return str_replace($search, $replace, $string); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.spacify.php ================================================ * Name: spacify
* Purpose: add spaces between characters in a string * @link http://smarty.php.net/manual/en/language.modifier.spacify.php * spacify (Smarty online manual) * @param string * @param string * @return string */ function smarty_modifier_spacify($string, $spacify_char = ' ') { return implode($spacify_char, preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY)); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.string_format.php ================================================ * Name: string_format
* Purpose: format strings via sprintf * @link http://smarty.php.net/manual/en/language.modifier.string.format.php * string_format (Smarty online manual) * @param string * @param string * @return string */ function smarty_modifier_string_format($string, $format) { return sprintf($format, $string); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.strip.php ================================================ * Name: strip
* Purpose: Replace all repeated spaces, newlines, tabs * with a single space or supplied replacement string.
* Example: {$var|strip} {$var|strip:" "} * Date: September 25th, 2002 * @link http://smarty.php.net/manual/en/language.modifier.strip.php * strip (Smarty online manual) * @author Monte Ohrt * @version 1.0 * @param string * @param string * @return string */ function smarty_modifier_strip($text, $replace = ' ') { return preg_replace('!\s+!', $replace, $text); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.strip_tags.php ================================================ * Name: strip_tags
* Purpose: strip html tags from text * @link http://smarty.php.net/manual/en/language.modifier.strip.tags.php * strip_tags (Smarty online manual) * @param string * @param boolean * @return string */ function smarty_modifier_strip_tags($string, $replace_with_space = true) { if ($replace_with_space) return preg_replace('!<[^>]*?>!', ' ', $string); else return strip_tags($string); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.truncate.php ================================================ * Name: truncate
* Purpose: Truncate a string to a certain length if necessary, * optionally splitting in the middle of a word, and * appending the $etc string. * @link http://smarty.php.net/manual/en/language.modifier.truncate.php * truncate (Smarty online manual) * @param string * @param integer * @param string * @param boolean * @return string */ function smarty_modifier_truncate($string, $length = 80, $etc = '...', $break_words = false) { if ($length == 0) return ''; if (strlen($string) > $length) { $length -= strlen($etc); if (!$break_words) $string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length+1)); return substr($string, 0, $length).$etc; } else return $string; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.upper.php ================================================ * Name: upper
* Purpose: convert string to uppercase * @link http://smarty.php.net/manual/en/language.modifier.upper.php * upper (Smarty online manual) * @param string * @return string */ function smarty_modifier_upper($string) { return strtoupper($string); } ?> ================================================ FILE: tools/server/admin/smarty/plugins/modifier.wordwrap.php ================================================ * Name: wordwrap
* Purpose: wrap a string of text at a given length * @link http://smarty.php.net/manual/en/language.modifier.wordwrap.php * wordwrap (Smarty online manual) * @param string * @param integer * @param string * @param boolean * @return string */ function smarty_modifier_wordwrap($string,$length=80,$break="\n",$cut=false) { return wordwrap($string,$length,$break,$cut); } ?> ================================================ FILE: tools/server/admin/smarty/plugins/outputfilter.trimwhitespace.php ================================================ * Type: outputfilter
* Name: trimwhitespace
* Date: Jan 25, 2003
* Purpose: trim leading white space and blank lines from * template source after it gets interpreted, cleaning * up code and saving bandwidth. Does not affect * <
>
and blocks.
* Install: Drop into the plugin directory, call * $smarty->load_filter('output','trimwhitespace'); * from application. * @author Monte Ohrt * @author Contributions from Lars Noschinski * @version 1.3 * @param string * @param Smarty */ function smarty_outputfilter_trimwhitespace($source, &$smarty) { // Pull out the script blocks preg_match_all("!]+>.*?!is", $source, $match); $_script_blocks = $match[0]; $source = preg_replace("!]+>.*?!is", '@@@SMARTY:TRIM:SCRIPT@@@', $source); // Pull out the pre blocks preg_match_all("!
.*?
!is", $source, $match); $_pre_blocks = $match[0]; $source = preg_replace("!
.*?
!is", '@@@SMARTY:TRIM:PRE@@@', $source); // Pull out the textarea blocks preg_match_all("!]+>.*?!is", $source, $match); $_textarea_blocks = $match[0]; $source = preg_replace("!]+>.*?!is", '@@@SMARTY:TRIM:TEXTAREA@@@', $source); // remove all leading spaces, tabs and carriage returns NOT // preceeded by a php close tag. $source = trim(preg_replace('/((?)\n)[\s]+/m', '\1', $source)); // replace script blocks smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:SCRIPT@@@",$_script_blocks, $source); // replace pre blocks smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:PRE@@@",$_pre_blocks, $source); // replace textarea blocks smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:TEXTAREA@@@",$_textarea_blocks, $source); return $source; } function smarty_outputfilter_trimwhitespace_replace($search_str, $replace, &$subject) { $_len = strlen($search_str); $_pos = 0; for ($_i=0, $_count=count($replace); $_i<$_count; $_i++) if (($_pos=strpos($subject, $search_str, $_pos))!==false) $subject = substr_replace($subject, $replace[$_i], $_pos, $_len); else break; } ?> ================================================ FILE: tools/server/admin/smarty/plugins/shared.escape_special_chars.php ================================================ * Purpose: used by other smarty functions to escape * special chars except for already escaped ones * @param string * @return string */ function smarty_function_escape_special_chars($string) { if(!is_array($string)) { $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string); $string = htmlspecialchars($string); $string = str_replace(array('%%%SMARTY_START%%%','%%%SMARTY_END%%%'), array('&',';'), $string); } return $string; } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/smarty/plugins/shared.make_timestamp.php ================================================ * Purpose: used by other smarty functions to make a timestamp * from a string. * @param string * @return string */ function smarty_make_timestamp($string) { if(empty($string)) { $string = "now"; } $time = strtotime($string); if (is_numeric($time) && $time != -1) return $time; // is mysql timestamp format of YYYYMMDDHHMMSS? if (preg_match('/^\d{14}$/', $string)) { $time = mktime(substr($string,8,2),substr($string,10,2),substr($string,12,2), substr($string,4,2),substr($string,6,2),substr($string,0,4)); return $time; } // couldn't recognize it, try to return a time $time = (int) $string; if ($time > 0) return $time; else return time(); } /* vim: set expandtab: */ ?> ================================================ FILE: tools/server/admin/templates/default/_index.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{if $tool_domain_selected && $tool_shard_selected} {if $tool_refresh_rate > 0} {/if}
Refresh

{/if} {section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=shard loop=$tool_shard_list} {if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id} {/if} {/section}
Shards
{$tool_shard_list[shard].shard_name}
{/if} {if $restriction_tool_notes && $tool_note_list}
{section name=note loop=$tool_note_list} {if $tool_note_list[note].note_mode == 0} {elseif $tool_note_list[note].note_mode == 1} {/if} {/section}
Notes
{$tool_note_list[note].note_title}{$tool_note_list[note].note_title}
{/if} {if $tool_hd_list}
{section name=hd loop=$tool_hd_list} {if $tool_hd_list[hd].hd_percent >= 85}{assign var="hdtrclass" value="row_red"} {elseif $tool_hd_list[hd].hd_percent >= 75}{assign var="hdtrclass" value="row_orange_light"} {else}{assign var="hdtrclass" value="row0"}{/if} {/section}
HardDrives
{$tool_hd_list[hd].hd_server} {$tool_hd_list[hd].hd_percent}%
{$tool_hd_time|date_format:"%Y/%m/%d %H:%M:%S"}
{/if}
  {if tool_domain_selected && $tool_shard_selected} {if $tool_annotation_info || $tool_has_lock} {/if}
Annotation {if $tool_has_lock}{/if} {if $tool_annotation_info} ({$tool_annotation_info.annotation_user_name} @ {$tool_annotation_info.annotation_date|date_format:"%Y/%m/%d %H:%M:%S"}) {/if}
Lock {if $tool_no_lock} {* if (!$tool_lock_info || $tool_lock_info.lock_shard_id) && !$tool_cant_lock && ($tool_shard_restart_status == 0) && !$tool_no_domain_lock *} {if (!$tool_lock_info || $tool_lock_info.lock_shard_id) && !$tool_cant_lock && !$tool_no_domain_lock} {if $restriction_tool_main_lock_shard}{/if} {else} Lock unavailable, a restart sequence is active ! {/if} {if ($tool_shard_restart_status == 0) && ($tool_domain_has_shard_restart == 0)} {if $restriction_tool_main_lock_domain}{/if} {/if} {elseif $tool_has_shard_lock} {if $tool_shard_restart_status == 0} {/if} {if ($tool_shard_restart_status == 0) && ($tool_domain_has_shard_restart == 0)} {if $restriction_tool_main_lock_domain}{/if} {elseif $tool_shard_restart_status > 0} Restart Sequence is active ! {/if} {if $restriction_tool_main_easy_restart && ($tool_shard_restart_status == 0)} {/if} {elseif $tool_has_domain_lock} {/if} {if $tool_lock_info} {if $tool_lock_info.lock_domain_id} Domain{elseif $tool_lock_info.lock_shard_id} Shard{/if} Locked by {$tool_lock_info.lock_user_name} @ {$tool_lock_info.lock_date|date_format:"%Y/%m/%d %H:%M:%S"} {else} Unlocked. {/if}

{/if} {if !$tool_domain_selected}
You need to select a domain.
{elseif !$tool_shard_selected}
You need to select a shard.
{elseif $tool_domain_error}
{$tool_domain_error}
{else} {if $tool_as_error}
{$tool_as_error}

{/if}
{**} {**} {section name=service loop=$tool_services_list} {assign var="service_shard_id" value=$tool_services_list[service].ShardName} {if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)} {cycle assign="trclass" values="row0,row1"} {assign var="tdclass1" value=""} {assign var="tdclass2" value=""} {if $tool_services_list[service]._flags_.rs_stopped}{assign var="tdclass1" value="class=\"cell_inactive1\""}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_stopped"}{/if} {if $tool_services_list[service]._flags_.rs_starting}{* assign var="tdclass1" value="class=\"cell_inactive1\"" *}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_starting"}{/if} {if $tool_services_list[service]._flags_.alert_red && ($tool_services_list[service]._flags_.rs_starting || $tool_services_list[service]._flags_.rs_online)}{assign var="trclass" value="row_red"} {elseif $tool_services_list[service]._flags_.alert_orange_dark && ($tool_services_list[service]._flags_.rs_starting || $tool_services_list[service]._flags_.rs_online)}{assign var="trclass" value="row_orange_dark"} {elseif $tool_services_list[service]._flags_.alert_orange_light && ($tool_services_list[service]._flags_.rs_starting || $tool_services_list[service]._flags_.rs_online)}{assign var="trclass" value="row_orange_light"}{/if} {assign var="check_name" value=$tool_services_list[service].AliasName} {**} {**} {/if} {/section}
AliasName ShardLongNameShortNameServiceAliasHostname Running State Running Orders Running Tags State Report Start Counters User SL Tick SL Memory NbPlayers UpTime
{$tool_services_list[service].AliasName} {if $tool_services_list[service].ShardName != ""}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != ""}/{$tool_services_list[service].ShardId}{/if}{$tool_services_list[service].LongName}{$tool_services_list[service].ShortName}{$tool_services_list[service].ServiceAlias}{$tool_services_list[service].Hostname} {$tool_services_list[service].RunningState} {$tool_services_list[service].RunningOrders} {$tool_services_list[service].RunningTags} {$tool_services_list[service].State} {$tool_services_list[service].NoReportSince} {$tool_services_list[service].StartCounter} {$tool_services_list[service].UserSpeedLoop} {$tool_services_list[service].TickSpeedLoop} {$tool_services_list[service].ProcessUsedMemory} {$tool_services_list[service].NbPlayers} {$tool_services_list[service].UpTime}
{if $restriction_tool_main_easy_restart && ($tool_shard_restart_status > 0)} {include file="index_restart_sequence.tpl"} {else} {if $restriction_tool_main_ws}
WS : {if $restriction_tool_main_ws_old}
new/old{/if}
{if $restriction_tool_main_ws_old} {/if}
{section name=shard loop=$tool_shard_run_list} {assign var="sname" value=$tool_shard_run_list[shard]} {if $tool_shard_infos[$sname] && $tool_shard_su_name} {/if} {/section}
 {$tool_shard_run_list[shard]}  
{/if} {if $restriction_tool_main_start || $restriction_tool_main_stop || $restriction_tool_main_restart || $restriction_tool_main_kill || $restriction_tool_main_abort || $restriction_tool_main_reset_counters || $restriction_tool_main_service_autostart}
Services :   {if $restriction_tool_main_start}   {/if} {if $restriction_tool_main_stop}   {/if} {if $restriction_tool_main_restart}   {/if} {if $restriction_tool_main_kill}   {/if} {if $restriction_tool_main_abort}   {/if} {if $restriction_tool_main_service_autostart}     {/if} {if $restriction_tool_main_reset_counters}   {/if}
{/if} {if $restriction_tool_main_shard_autostart && $tool_shard_run_list}
Shards : {section name=shard loop=$tool_shard_run_list} {assign var="sname" value=$tool_shard_run_list[shard]} {/section}
 {$tool_shard_run_list[shard]} {if $sname != ""}{$tool_shard_orders[$sname]|replace:'_':' '}{/if}     
{/if} {if $restriction_tool_main_execute}
Command :     
{if $tool_execute_command}
Command Results for '{$tool_execute_command}' :
{/if} {/if} {* end of: if $restriction_tool_main_easy_restart && ($tool_shard_restart_status > 0) *} {/if}
{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/index.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{if $tool_domain_selected && $tool_shard_selected} {if $tool_refresh_rate > 0} {/if}
Refresh

{/if} {section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=shard loop=$tool_shard_list} {if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id} {/if} {/section}
Shards
{$tool_shard_list[shard].shard_name}
{/if} {if $restriction_tool_notes && $tool_note_list}
{section name=note loop=$tool_note_list} {if $tool_note_list[note].note_mode == 0} {elseif $tool_note_list[note].note_mode == 1} {/if} {/section}
Notes
{$tool_note_list[note].note_title}{$tool_note_list[note].note_title}
{/if} {if $tool_hd_list}
{section name=hd loop=$tool_hd_list} {if $tool_hd_list[hd].hd_percent >= 85}{assign var="hdtrclass" value="row_red"} {elseif $tool_hd_list[hd].hd_percent >= 75}{assign var="hdtrclass" value="row_orange_light"} {else}{assign var="hdtrclass" value="row0"}{/if} {/section}
HardDrives
{$tool_hd_list[hd].hd_server} {$tool_hd_list[hd].hd_percent}%
{$tool_hd_time|date_format:"%Y/%m/%d %H:%M:%S"}
{/if}
  {if tool_domain_selected && $tool_shard_selected} {if $tool_annotation_info || $tool_has_lock} {/if}
Annotation {if $tool_has_lock}{/if} {if $tool_annotation_info} ({$tool_annotation_info.annotation_user_name} @ {$tool_annotation_info.annotation_date|date_format:"%Y/%m/%d %H:%M:%S"}) {/if}
Lock {if $tool_no_lock} {* if (!$tool_lock_info || $tool_lock_info.lock_shard_id) && !$tool_cant_lock && ($tool_shard_restart_status == 0) && !$tool_no_domain_lock *} {if (!$tool_lock_info || $tool_lock_info.lock_shard_id) && !$tool_cant_lock && !$tool_no_domain_lock} {if $restriction_tool_main_lock_shard}{/if} {else} Lock unavailable, a restart sequence is active ! {/if} {if ($tool_shard_restart_status == 0) && ($tool_domain_has_shard_restart == 0)} {if $restriction_tool_main_lock_domain}{/if} {/if} {elseif $tool_has_shard_lock} {if $tool_shard_restart_status == 0} {/if} {if ($tool_shard_restart_status == 0) && ($tool_domain_has_shard_restart == 0)} {if $restriction_tool_main_lock_domain}{/if} {elseif $tool_shard_restart_status > 0} Restart Sequence is active ! {/if} {if $restriction_tool_main_easy_restart && ($tool_shard_restart_status == 0)} {/if} {elseif $tool_has_domain_lock} {/if} {if $tool_lock_info} {if $tool_lock_info.lock_domain_id} Domain{elseif $tool_lock_info.lock_shard_id} Shard{/if} Locked by {$tool_lock_info.lock_user_name} @ {$tool_lock_info.lock_date|date_format:"%Y/%m/%d %H:%M:%S"} {else} Unlocked. {/if}

{/if} {if !$tool_domain_selected}
You need to select a domain.
{elseif !$tool_shard_selected}
You need to select a shard.
{elseif $tool_domain_error}
{$tool_domain_error}
{else} {if $tool_as_error}
{$tool_as_error}

{/if}
{if !$iPhone} {**} {**} {/if} {if !$iPhone} {/if} {section name=service loop=$tool_services_list} {assign var="service_shard_id" value=$tool_services_list[service].ShardName} {if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)} {cycle assign="trclass" values="row0,row1"} {assign var="tdclass1" value=""} {assign var="tdclass2" value=""} {if $tool_services_list[service]._flags_.rs_stopped}{assign var="tdclass1" value="class=\"cell_inactive1\""}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_stopped"}{/if} {if $tool_services_list[service]._flags_.rs_starting}{* assign var="tdclass1" value="class=\"cell_inactive1\"" *}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_starting"}{/if} {if $tool_services_list[service]._flags_.alert_red && ($tool_services_list[service]._flags_.rs_starting || $tool_services_list[service]._flags_.rs_online)}{assign var="trclass" value="row_red"} {elseif $tool_services_list[service]._flags_.alert_orange_dark && ($tool_services_list[service]._flags_.rs_starting || $tool_services_list[service]._flags_.rs_online)}{assign var="trclass" value="row_orange_dark"} {elseif $tool_services_list[service]._flags_.alert_orange_light && ($tool_services_list[service]._flags_.rs_starting || $tool_services_list[service]._flags_.rs_online)}{assign var="trclass" value="row_orange_light"}{/if} {assign var="check_name" value=$tool_services_list[service].AliasName} {if !$iPhone} {**} {**} {/if} {if !$iPhone} {/if} {/if} {/section}
AliasNameShardLongNameShortNameServiceAliasHostname Running State Running Orders Running TagsState Rep Start CntrsUser SLTick SL Mem Nb Play UpTime
{$tool_services_list[service].AliasName}{if $tool_services_list[service].ShardName != ""}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != ""}/{$tool_services_list[service].ShardId}{/if}{$tool_services_list[service].LongName}{$tool_services_list[service].ShortName}{$tool_services_list[service].ServiceAlias}{$tool_services_list[service].Hostname} {$tool_services_list[service].RunningState} {$tool_services_list[service].RunningOrders} {$tool_services_list[service].RunningTags}{$tool_services_list[service].State} {$tool_services_list[service].NoReportSince} {$tool_services_list[service].StartCounter}{$tool_services_list[service].UserSpeedLoop}{$tool_services_list[service].TickSpeedLoop} {$tool_services_list[service].ProcessUsedMemory} {$tool_services_list[service].NbPlayers} {$tool_services_list[service].UpTime}
{if $restriction_tool_main_easy_restart && ($tool_shard_restart_status > 0)} {include file="index_restart_sequence.tpl"} {else} {* if $restriction_tool_main_ws *}
WS : {if $restriction_tool_main_ws_old && $restriction_tool_main_ws}
new/old{/if}
{if $restriction_tool_main_ws_old && $restriction_tool_main_ws} {/if}
{if $restriction_tool_main_ws} {/if} {section name=shard loop=$tool_shard_run_list} {assign var="sname" value=$tool_shard_run_list[shard]} {if $tool_shard_infos[$sname] && $tool_shard_su_name} {/if} {/section}
 {$tool_shard_run_list[shard]} {if $restriction_tool_main_ws} {/if}    
{* /if *} {if $restriction_tool_main_start || $restriction_tool_main_stop || $restriction_tool_main_restart || $restriction_tool_main_kill || $restriction_tool_main_abort || $restriction_tool_main_reset_counters || $restriction_tool_main_service_autostart}
Services :   {if $restriction_tool_main_start}   {/if} {if $restriction_tool_main_stop}   {/if} {if $restriction_tool_main_restart}   {/if} {if $restriction_tool_main_kill}   {/if} {if $restriction_tool_main_abort}   {/if} {if $restriction_tool_main_service_autostart}     {/if} {if $restriction_tool_main_reset_counters}   {/if}
{/if} {if $restriction_tool_main_shard_autostart && $tool_shard_run_list}
Shards : {section name=shard loop=$tool_shard_run_list} {assign var="sname" value=$tool_shard_run_list[shard]} {/section}
 {$tool_shard_run_list[shard]} {if $sname != ""}{$tool_shard_orders[$sname]|replace:'_':' '}{/if}     
{/if} {if $restriction_tool_main_execute}
Command :     
{if $tool_execute_command}
Command Results for '{$tool_execute_command}' :
{/if} {/if} {* end of: if $restriction_tool_main_easy_restart && ($tool_shard_restart_status > 0) *} {/if}
{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/index_login.tpl ================================================ {include file="page_header_light.tpl"}

Shard Administration Website

Use login: guest and password: guest to login.

Login:
Password:
 
{include file="page_footer_light.tpl"} ================================================ FILE: tools/server/admin/templates/default/index_restart_sequence.tpl ================================================ {* this closes the global service form *} {* due to incompatibilities with jscript functions with moz/ie i need to do individiual forms :( *} {literal} {/literal}
Restart Sequence {* **** STEP 0 **** *} {* **** STEP 1 **** *} {* **** STEP 2 **** *} {* **** STEP 3 **** *} {* **** STEP 4 **** *}
Step 0

{if $tool_restart_info.restart_sequence_step == 0} {/if}

Step 1 {if $tool_restart_info.restart_sequence_step == 1}{math assign="restart_timer" equation="x - y" x=$tool_restart_info.restart_sequence_timer y=$system_time}{else}{assign var=restart_timer value='-1'}{/if} {if $restart_timer >= 0} {else} {if $tool_restart_info.restart_sequence_step == 1} {/if} {/if} {if $tool_restart_info.restart_sequence_step == 1} {/if}

Step 2 {if $tool_restart_info.restart_sequence_step == 2}{math assign="restart_timer2" equation="x - y" x=$tool_restart_info.restart_sequence_timer y=$system_time}{else}{assign var=restart_timer2 value='-1'}{/if} {if $restart_timer2 >= 0} {else} {if $tool_restart_info.restart_sequence_step == 2} {/if} {/if}  

Step 3 {* The following services will be stopped : {$tool_restart_stop_actions} *}

{section name=start loop=$tool_restart_start_actions} The following services will be started : {$tool_restart_start_actions[start].restart_group_list}

{/section}
{if $tool_restart_info.restart_sequence_step == 3} {/if}

Step 4 Success, the Shard is now in the hands of the Customer Support Team. {if $tool_restart_info.restart_sequence_step == 4} {/if}
{* this is just a dummy form to match the global services end form tag *}
================================================ FILE: tools/server/admin/templates/default/page_footer.tpl ================================================ {if !$iPhone}


{* DEBUG INFORMATION *} {if $NELTOOL_DEBUG != null}
DEBUG
{php}
global $nel_debug;
foreach ($nel_debug as $dbgline) echo "  $dbgline\n";
{/php}
{/if} {/if} ================================================ FILE: tools/server/admin/templates/default/page_footer_light.tpl ================================================ ================================================ FILE: tools/server/admin/templates/default/page_header.tpl ================================================ {$nel_tool_title}{if $tool_page_title != ''} - {$tool_page_title}{/if} {*$nel_tool_notes_meta*} {$nel_tool_refresh} {$nel_tool_extra_css} {if $iPhone} {/if} {if !$iPhone} {/if}
{$tool_title} {$user_info}
{section name=onemenu loop=$nel_menu} {/section} {if !$iPhone} {/if}
{if $menu_style == 1 && !$iPhone} {elseif $menu_style == 2 && !$iPhone}
{$nel_menu[onemenu].application_name}
{else} {$nel_menu[onemenu].application_name} {/if}
================================================ FILE: tools/server/admin/templates/default/page_header_light.tpl ================================================ {$tool_login_title} {if $iPhone} {/if} ================================================ FILE: tools/server/admin/templates/default/tool_actions.tpl ================================================ {include file="page_header.tpl"} {include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_administration.tpl ================================================ {include file="page_header.tpl"}
{section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

Admin Tool v2.0

Author: Anthony 'YoGiN' Powles <yogin@nevrax.com>
Copyright © Nevrax 2000 - 2006


{if $ie_check}
This part of the tool uses some features that Internet Explorer does NOT support.
Therefore, if you need to access them, i would recommend using Mozilla Firefox! {/if}

{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_administration_applications.tpl ================================================ {include file="page_header.tpl"}
{$tool_alert_message} {section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

{section name=application loop=$tool_application_list} {cycle assign="trclass" values="row1,row0"} {/section}
Applications
ID Name URI Restriction Icon Order Visible
{$tool_application_list[application].application_id} {$tool_application_list[application].application_name} {$tool_application_list[application].application_uri} {$tool_application_list[application].application_restriction} {$tool_application_list[application].application_icon} {$tool_application_list[application].application_order} {if $tool_application_list[application].application_visible == 1}Yes{else}No{/if}
{if $tool_application_edit_data.application_id} {/if}
Applications Details
Id :
Name :
URI :
Restriction :
Icon :
Order :
Visible :
  {if $tool_application_edit_data.application_id} {else} {/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_administration_domains.tpl ================================================ {include file="page_header.tpl"}
{$tool_alert_message} {section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

{section name=domain loop=$tool_domain_list} {cycle assign="trclass" values="row1,row0"} {/section}
Domains
ID Name Application AS Host AS Port MFS Web RRD Path LAS Admin Path LAS Local Path Ring DB CS DB HD Check
{$tool_domain_list[domain].domain_id} {$tool_domain_list[domain].domain_name} {$tool_domain_list[domain].domain_application} {$tool_domain_list[domain].domain_as_host} {$tool_domain_list[domain].domain_as_port} {$tool_domain_list[domain].domain_mfs_web} {$tool_domain_list[domain].domain_rrd_path} {$tool_domain_list[domain].domain_las_admin_path} {$tool_domain_list[domain].domain_las_local_path} {if $tool_domain_list[domain].domain_sql_string != ''}True{else}False{/if} {if $tool_domain_list[domain].domain_cs_sql_string != ''}True{else}False{/if} {if $tool_domain_list[domain].domain_hd_check == 1}Yes{else}No{/if}
{if $tool_domain_edit_data.domain_id} {/if}
Domain Details
Id :
Name :
Application :
AS Host :
AS Port :
MFS Web :
RRD Path :
LAS Admin Path :
LAS Local Path :
Ring DB String :
CS DB String :
HD Check :
  {if $tool_domain_edit_data.domain_id} {else} {/if}
{if $tool_domain_nel_data}
Domain Data
ID :
Name :
Status :
 
{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_administration_groups.tpl ================================================ {include file="page_header.tpl"}
{$tool_alert_message} {section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

{section name=group loop=$tool_group_list} {cycle assign="trclass" values="row1,row0"} {/section}
Groups
ID Name Level Default Active
{$tool_group_list[group].group_id} {$tool_group_list[group].group_name} {$tool_group_list[group].group_level_name} {if $tool_group_list[group].group_default == 1}Yes{else}No{/if} {if $tool_group_list[group].group_active == 1}Yes{else}No{/if}
{if $tool_group_user_list}
{section name=user loop=$tool_group_user_list} {cycle assign="trclass2" values="row1,row0"} {if $tool_group_user_list[user].user_logged_last > 0} {else} {/if} {/section}
Accounts
ID Login Created Last Logged Num Logs Active
{$tool_group_user_list[user].user_id} {$tool_group_user_list[user].user_name} {$tool_group_user_list[user].user_created|date_format:"%Y/%m/%d %H:%M:%S"}{$tool_group_user_list[user].user_logged_last|date_format:"%Y/%m/%d %H:%M:%S"}never{$tool_group_user_list[user].user_logged_count} {if $tool_group_user_list[user].user_active == 1}Yes{else}No{/if}
{/if}
{if $tool_group_edit_data.group_id} {/if}
Group Details
Id :
Name :
Level :
Default :
Active :
  {if $tool_group_edit_data.group_id} {else} {/if}
{if $tool_group_edit_data.group_id}
Default Domain
Domains :
 
{if $tool_group_edit_data.group_default_domain_id > 0}
Default Shard
Shards :
 
{/if}
Default Application
Application :
 

Application Access
Applications :
 

Domain Access
Domains :
 

Shard Access
Shards :
 
{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_administration_logs.tpl ================================================ {include file="page_header.tpl"}
{$tool_alert_message} {section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

{section name=log loop=$tool_log_list} {/section}
Logs
ID User Date Action
{$tool_log_list[log].logs_id} {$tool_log_list[log].logs_user_name} {$tool_log_list[log].logs_date|date_format:"%Y/%m/%d %H:%M:%S"} {$tool_log_list[log].logs_data}
|<    <    Page {$tool_log_page_current} / {$tool_log_page_total}    >    >|
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_administration_restarts.tpl ================================================ {include file="page_header.tpl"}
{$tool_alert_message} {section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

{section name=restart loop=$tool_restart_list} {cycle assign="trclass" values="row1,row0"} {/section}
Restart Groups
ID Name List Order
{$tool_restart_list[restart].restart_group_id} {$tool_restart_list[restart].restart_group_name} {$tool_restart_list[restart].restart_group_list} {$tool_restart_list[restart].restart_group_order}
{if $tool_restart_edit_data.restart_group_id} {/if}
Restart Group Details
Id :
Name :
Services :
Order :
  {if $tool_restart_edit_data.restart_group_id} {else} {/if}

{section name=msg loop=$tool_message_list} {cycle assign="trclass" values="row1,row0"} {/section}
Restart Messages
ID Language Name Value
{$tool_message_list[msg].restart_message_id} {$tool_message_list[msg].restart_message_lang} {$tool_message_list[msg].restart_message_name} {$tool_message_list[msg].restart_message_value}
{if $tool_message_edit_data.restart_message_id} {/if}
Restart Message Details
Id :
Name :
Value :
Language :
  {if $tool_message_edit_data.restart_message_id } {else} {/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_administration_shards.tpl ================================================ {include file="page_header.tpl"}
{$tool_alert_message} {section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

{section name=shard loop=$tool_shard_list} {cycle assign="trclass" values="row1,row0"} {/section}
Shards
ID Name Shard ID Domain Language
{$tool_shard_list[shard].shard_id} {$tool_shard_list[shard].shard_name} {$tool_shard_list[shard].shard_as_id} {$tool_shard_list[shard].domain_name} {$tool_shard_list[shard].shard_lang}
{if $tool_shard_edit_data.shard_id} {/if}
Shard Details
Id :
Name :
Shard ID :
Domain :
Language :
  {if $tool_shard_edit_data.shard_id} {else} {/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_administration_users.tpl ================================================ {include file="page_header.tpl"}
{$tool_alert_message} {section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

{section name=user loop=$tool_user_list} {cycle assign="trclass" values="row1,row0"} {if $tool_user_list[user].user_logged_last > 0} {else} {/if} {/section}
Accounts
ID Login Group Created Last Logged Num Logs Active
{$tool_user_list[user].user_id} {$tool_user_list[user].user_name} {$tool_user_list[user].user_group_name} {$tool_user_list[user].user_created|date_format:"%Y/%m/%d %H:%M:%S"}{$tool_user_list[user].user_logged_last|date_format:"%Y/%m/%d %H:%M:%S"}never{$tool_user_list[user].user_logged_count} {if $tool_user_list[user].user_active == 1}Yes{else}No{/if}
{if $tool_user_edit_data.user_id} {/if}
Account Details
Id :
Name :
Password :
Group :
Active :
  {if $tool_user_edit_data.user_id} {else} {/if}
{if $tool_user_edit_data.user_id}
Application Access
Applications :
 

Domain Access
Domains :
 

Shard Access {if $tool_domain_list[domain].domain_disabled}(group){/if}
Shards :
  {* *}
{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_administration_users.tpl.backup ================================================ {include file="page_header.tpl"}
{$tool_alert_message} {section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

{section name=user loop=$tool_user_list} {if $tool_user_list[user].user_logged_last > 0} {else} {/if} {/section}
Accounts
ID Login Group Created Last Logged Num Logs Active
{$tool_user_list[user].user_id} {$tool_user_list[user].user_name} {$tool_user_list[user].user_group_name} {$tool_user_list[user].user_created|date_format:"%Y/%m/%d %H:%M:%S"}{$tool_user_list[user].user_logged_last|date_format:"%Y/%m/%d %H:%M:%S"}never{$tool_user_list[user].user_logged_count} {$tool_user_list[user].user_active}
{if $tool_user_edit_data.user_id} {/if}
Account Details
Id :
Name :
Password :
Group :
Active :
  {if $tool_user_edit_data.user_id} {else} {/if}
{if $tool_user_edit_data.user_id}
Domain Access
Domains :
 
{section name=domain loop=$tool_shard_list} {if $tool_shard_list[domain].domain_selected}
Domain '{$tool_shard_list[domain].domain_name}' {if $tool_domain_list[domain].domain_disabled}(group){/if}
Shards :
 
{/if} {/section} {/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_event_entities.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=shard loop=$tool_shard_list} {if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id} {/if} {/section}
Shards
{$tool_shard_list[shard].shard_name}
{/if}
  {if !$tool_domain_selected}
You need to select a domain.
{elseif $tool_domain_error}
{$tool_domain_error}
{else} {if $tool_as_error}
{$tool_as_error}

{/if}
{assign var="service_counter" value="0"} {section name=service loop=$tool_services_list} {assign var="service_shard_id" value=$tool_services_list[service].ShardName} {if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)} {cycle assign="trclass" values="row0,row1"} {assign var="tdclass1" value=""} {assign var="tdclass2" value=""} {if $tool_services_list[service]._flags_.rs_stopped}{assign var="tdclass1" value="class=\"cell_inactive1\""}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_stopped"}{/if} {if $tool_services_list[service]._flags_.rs_starting}{assign var="tdclass1" value="class=\"cell_inactive1\""}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_starting"}{/if} {if $tool_services_list[service]._flags_.alert_red}{assign var="trclass" value="row_red"}{/if} {if $tool_services_list[service]._flags_.alert_orange_dark}{assign var="trclass" value="row_orange_dark"}{/if} {if $tool_services_list[service]._flags_.alert_orange_light}{assign var="trclass" value="row_orange_light"}{/if} {assign var="check_name" value=$tool_services_list[service].AliasName} {assign var="service_counter" value="`$service_counter+1`"} {/if} {/section}
AliasName Shard ShortName Hostname Running State Running Tags State Report Counters User SL Tick SL Memory NbPlayers UpTime
{$tool_services_list[service].AliasName} {if $tool_services_list[service].ShardName != ""}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != ""}/{$tool_services_list[service].ShardId}{/if} {$tool_services_list[service].ShortName} {$tool_services_list[service].Hostname} {$tool_services_list[service].RunningState} {$tool_services_list[service].RunningTags} {$tool_services_list[service].State} {$tool_services_list[service].NoReportSince} {$tool_services_list[service].StartCounter} {$tool_services_list[service].UserSpeedLoop} {$tool_services_list[service].TickSpeedLoop} {$tool_services_list[service].ProcessUsedMemory} {$tool_services_list[service].NbPlayers} {$tool_services_list[service].UpTime}
{if $service_counter > 0}
Commands :    
{if $tool_entity_data} {assign var="entity_service" value="n/a"} {section name=entity loop=$tool_entity_data} {if $entity_service != $tool_entity_data[entity].service} {assign var="entity_service" value=$tool_entity_data[entity].service} {/if} {cycle assign="trclass" values="row0,row1"} {/section}
{$entity_service}
Service Entity Name State Param 1 Param 2
{$tool_entity_data[entity].service_id} {$tool_entity_data[entity].entity} {$tool_entity_data[entity].entity_name}
{/if} {if $tool_execute_command}
Command Results for '{$tool_execute_command}' :
{/if} {else}
No AIS to work with!
{/if} {/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_graphs.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

{if $tool_domain_selected && $tool_shard_selected} {if $tool_refresh_rate > 0} {/if}
Refresh

{/if} {section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=shard loop=$tool_shard_list} {if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id} {/if} {/section}
Shards
{$tool_shard_list[shard].shard_name}
{if $tool_frame_list} {/if} {if $tool_graph_list}
{section name=gvar loop=$tool_graph_variables} {assign var="var_name" value=$tool_graph_variables[gvar]} {section name=gdata loop=$tool_graph_datas.$var_name} {/section} {/section}
Graphs
{$tool_graph_variables[gvar]} High
{$tool_graph_datas.$var_name[gdata].service} {if $tool_graph_datas.$var_name[gdata].high_file != ''}Yes{else}No{/if}
{/if} {/if}
  {if $tool_domain_error}
{$tool_domain_error}
{elseif !$tool_domain_selected}
You need to select a domain.
{else} {if $tool_as_error}
{$tool_as_error}

{/if}
{if $tool_rrd_output} {section name=rrd loop=$tool_rrd_output} {$tool_rrd_output[rrd].desc}

{/section} {/if}
{if $tool_rrd_high_output} {section name=rrd loop=$tool_rrd_high_output} {$tool_rrd_high_output[rrd].desc}
{if $tool_rrd_high_output[rrd].img != ''}
{/if} {/section} {/if}
{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_graphs_ccu.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

{if $tool_domain_selected && $tool_frame_selected} {if $tool_refresh_rate > 0} {/if}
Refresh

{/if} {section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=frame loop=$tool_frame_list} {/section}
Time Frame
{$tool_frame_list[frame].title}
{/if}
  {if $tool_domain_error}
{$tool_domain_error}
{elseif !$tool_domain_selected}
You need to select a domain.
{elseif !$tool_frame_selected}
You need to select a time frame.
{else} {if $tool_as_error}
{$tool_as_error}

{/if}
{if $tool_rrd_output} {section name=rrd loop=$tool_rrd_output} {$tool_rrd_output[rrd].desc}

{/section} {/if}
{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_graphs_hires.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

{if $tool_domain_selected && $tool_shard_selected && $tool_frame_selected} {if $tool_refresh_rate > 0} {/if}
Refresh

{/if} {section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=shard loop=$tool_shard_list} {if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id} {/if} {/section}
Shards
{$tool_shard_list[shard].shard_name}

{section name=frame loop=$tool_frame_list} {/section}
Time Frame
{$tool_frame_list[frame].title}
{/if}
  {if $tool_domain_error}
{$tool_domain_error}
{elseif !$tool_domain_selected}
You need to select a domain.
{elseif !$tool_shard_selected}
You need to select a shard.
{elseif !$tool_frame_selected}
You need to select a time frame.
{else} {if $tool_as_error}
{$tool_as_error}

{/if}
{if $tool_rrd_high_output} {section name=rrd loop=$tool_rrd_high_output} {$tool_rrd_high_output[rrd].desc}
{if $tool_rrd_high_output[rrd].img != ''}
{/if} {/section} {/if}
{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_graphs_tech.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{section name=onemenu loop=$tool_menu} {/section}
{$tool_menu[onemenu].title}

{if $tool_domain_selected && $tool_shard_selected && $tool_frame_selected} {if $tool_refresh_rate > 0} {/if}
Refresh

{/if} {section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=shard loop=$tool_shard_list} {if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id} {/if} {/section}
Shards
{$tool_shard_list[shard].shard_name}

{section name=frame loop=$tool_frame_list} {/section}
Time Frame
{$tool_frame_list[frame].title}
{/if}
  {if $tool_domain_error}
{$tool_domain_error}
{elseif !$tool_domain_selected}
You need to select a domain.
{elseif !$tool_shard_selected}
You need to select a shard.
{elseif !$tool_frame_selected}
You need to select a time frame.
{else} {if $tool_as_error}
{$tool_as_error}

{/if}
{if $tool_rrd_output} {section name=rrd loop=$tool_rrd_output} {$tool_rrd_output[rrd].desc}

{/section} {/if}
{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_guild_locator.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{if $tool_domain_selected && $tool_shard_selected} {if $tool_refresh_rate > 0} {/if}
Refresh

{/if} {section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=shard loop=$tool_shard_list} {if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id} {/if} {/section}
Shards
{$tool_shard_list[shard].shard_name}
{/if}
  {if !$tool_domain_selected}
You need to select a domain.
{elseif $tool_domain_error}
{$tool_domain_error}
{else} {if $tool_as_error}
{$tool_as_error}

{/if}
{assign var="egs_counter" value="0"} {section name=service loop=$tool_services_list} {assign var="service_shard_id" value=$tool_services_list[service].ShardName} {if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)} {cycle assign="trclass" values="row0,row1"} {assign var="tdclass1" value=""} {assign var="tdclass2" value=""} {if $tool_services_list[service]._flags_.rs_stopped}{assign var="tdclass1" value="class=\"cell_inactive1\""}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_stopped"}{/if} {if $tool_services_list[service]._flags_.rs_starting}{assign var="tdclass1" value="class=\"cell_inactive1\""}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_starting"}{/if} {if $tool_services_list[service]._flags_.alert_red}{assign var="trclass" value="row_red"}{/if} {if $tool_services_list[service]._flags_.alert_orange_dark}{assign var="trclass" value="row_orange_dark"}{/if} {if $tool_services_list[service]._flags_.alert_orange_light}{assign var="trclass" value="row_orange_light"}{/if} {assign var="check_name" value=$tool_services_list[service].AliasName} {assign var="egs_counter" value="`$egs_counter+1`"} {/if} {/section}
AliasName Shard ShortName Hostname Running State Running Tags State Report Counters User SL Tick SL Memory NbPlayers UpTime
{$tool_services_list[service].AliasName} {if $tool_services_list[service].ShardName != ""}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != ""}/{$tool_services_list[service].ShardId}{/if} {$tool_services_list[service].ShortName} {$tool_services_list[service].Hostname} {$tool_services_list[service].RunningState} {$tool_services_list[service].RunningTags} {$tool_services_list[service].State} {$tool_services_list[service].NoReportSince} {$tool_services_list[service].StartCounter} {$tool_services_list[service].UserSpeedLoop} {$tool_services_list[service].TickSpeedLoop} {$tool_services_list[service].ProcessUsedMemory} {$tool_services_list[service].NbPlayers} {$tool_services_list[service].UpTime}
{if $egs_counter > 0}
Commands :    
{if $tool_guild_data} {assign var="service_name" value=""}
{section name=guild loop=$tool_guild_data} {if $service_name != $tool_guild_data[guild].service} {assign var="service_name" value=$tool_guild_data[guild].service} {/if} {cycle assign="trclass" values="row0,row1"} {/section}
{$service_name}
Guild Name Guild ID Guild Members Guild EID
{$tool_guild_data[guild].name} {$tool_guild_data[guild].shardid} - {$tool_guild_data[guild].guildid} {$tool_guild_data[guild].members} {$tool_guild_data[guild].guildeid}
{/if} {if $tool_guild_dump_data}
Guild Name ID (EID) Money Race Members
{$tool_guild_dump_data.guild_name} {$tool_guild_dump_data.shard_id}:{$tool_guild_dump_data.guild_id} {$tool_guild_dump_data.guild_eid} {$tool_guild_dump_data.guild_money} {$tool_guild_dump_data.guild_race} {$tool_guild_dump_data.members_count}
Description: {$tool_guild_dump_data.guild_description}

{if $restriction_tool_guild_locator_manage_guild}
Rename Guild   
Change Description   

{/if} {if $tool_guild_errors} {section name=err loop=$tool_guild_errors} {/section}
{$tool_guild_errors[err]}

{/if} {if $restriction_tool_guild_locator_manage_members} {/if} {section name=leader loop=$tool_guild_dump_data.Leader} {if $restriction_tool_guild_locator_manage_members} {/if} {sectionelse} {/section} {if $restriction_tool_guild_locator_manage_members} {/if} {section name=hofficer loop=$tool_guild_dump_data.HighOfficer} {if $restriction_tool_guild_locator_manage_members} {/if} {sectionelse} {/section} {if $restriction_tool_guild_locator_manage_members} {/if} {section name=officer loop=$tool_guild_dump_data.Officer} {if $restriction_tool_guild_locator_manage_members} {/if} {sectionelse} {/section} {if $restriction_tool_guild_locator_manage_members} {/if} {section name=member loop=$tool_guild_dump_data.Member} {if $restriction_tool_guild_locator_manage_members} {/if} {sectionelse} {/section}
Leader
Name Shard EntityID Index Enter Time 
{$tool_guild_dump_data.Leader[leader].name} {$tool_guild_dump_data.Leader[leader].shard} {$tool_guild_dump_data.Leader[leader].eid} {$tool_guild_dump_data.Leader[leader].index} {$tool_guild_dump_data.Leader[leader].entertime} 
none
HighOfficers
Name Shard EntityID Index Enter Time 
{$tool_guild_dump_data.HighOfficer[hofficer].name} {$tool_guild_dump_data.HighOfficer[hofficer].shard} {$tool_guild_dump_data.HighOfficer[hofficer].eid} {$tool_guild_dump_data.HighOfficer[hofficer].index} {$tool_guild_dump_data.HighOfficer[hofficer].entertime}[ Set :  Leader |  Officer |  Member ] 
none
Officers
Name Shard EntityID Index Enter Time 
{$tool_guild_dump_data.Officer[officer].name} {$tool_guild_dump_data.Officer[officer].shard} {$tool_guild_dump_data.Officer[officer].eid} {$tool_guild_dump_data.Officer[officer].index} {$tool_guild_dump_data.Officer[officer].entertime}[ Set :  Leader |  HighOfficer |  Member ] 
none
Members
Name Shard EntityID Index Enter Time 
{$tool_guild_dump_data.Member[member].name} {$tool_guild_dump_data.Member[member].shard} {$tool_guild_dump_data.Member[member].eid} {$tool_guild_dump_data.Member[member].index} {$tool_guild_dump_data.Member[member].entertime}[ Set :  Leader |  HighOfficer |  Officer ] 
none

{section name=outpost loop=$tool_guild_dump_data.outposts} {sectionelse} {/section}
Owned Outposts
Name Alias Sheet
{$tool_guild_dump_data.outposts[outpost].name} {$tool_guild_dump_data.outposts[outpost].alias} {$tool_guild_dump_data.outposts[outpost].sheet}
none

{section name=outpost loop=$tool_guild_dump_data.challenged_outposts} {sectionelse} {/section}
Challenged Outposts
Name Alias Sheet
{$tool_guild_dump_data.challenged_outposts[outpost].name} {$tool_guild_dump_data.challenged_outposts[outpost].alias} {$tool_guild_dump_data.challenged_outposts[outpost].sheet}
none

{if $restriction_tool_guild_locator_manage_forums} {if $tool_guild_forums_error} {elseif $tool_guild_forums} {section name=line loop=$tool_guild_forums} {/section} {/if}
Guild Forums
{$tool_guild_forums_error}
File Thread Action
{$tool_guild_forums[line].file} {$tool_guild_forums[line].thread} {if $tool_guild_forums[line].recover == 1}Recover{/if}

{if $tool_guild_thread}
{section name=msg loop=$tool_guild_thread.data} {/section}
Thread View
{$tool_guild_thread.topic.raw}
{$tool_guild_thread.data[msg].raw}
{/if} {/if} {/if} {if $tool_execute_command}
Command Results for '{$tool_execute_command}' :
{/if} {else}
No EGS to work with!
{/if} {/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_log_analyser.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=shard loop=$tool_shard_list} {if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id} {/if} {/section}
Shards
{$tool_shard_list[shard].shard_name}
{if $tool_file_list}
{section name=file loop=$tool_file_list} {/section}
Files
Size: {math equation="x / y" x=$tool_file_list[file].size y=1024 format="%d"} KB
', OFFSETX, 40, OFFSETY, 10);" onmouseout="return nd();">{$tool_file_list[file].name}
{/if} {/if}
  {if !$tool_domain_selected}
You need to select a domain.
{elseif $tool_domain_error}
{$tool_domain_error}
{else} {if $tool_as_error}
{$tool_as_error}

{/if}
{assign var="las_counter" value="0"} {section name=service loop=$tool_services_list} {assign var="service_shard_id" value=$tool_services_list[service].ShardName} {if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)} {cycle assign="trclass" values="row0,row1"} {assign var="tdclass1" value=""} {assign var="tdclass2" value=""} {if $tool_services_list[service]._flags_.rs_stopped}{assign var="tdclass1" value="class=\"cell_inactive1\""}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_stopped"}{/if} {if $tool_services_list[service]._flags_.rs_starting}{assign var="tdclass1" value="class=\"cell_inactive1\""}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_starting"}{/if} {if $tool_services_list[service]._flags_.alert_red}{assign var="trclass" value="row_red"}{/if} {if $tool_services_list[service]._flags_.alert_orange_dark}{assign var="trclass" value="row_orange_dark"}{/if} {if $tool_services_list[service]._flags_.alert_orange_light}{assign var="trclass" value="row_orange_light"}{/if} {assign var="check_name" value=$tool_services_list[service].AliasName} {assign var="las_counter" value="`$las_counter+1`"} {/if} {/section}
AliasName Shard ShortName Hostname Running State Running Tags State Report Counters User SL Tick SL Memory NbPlayers UpTime
{$tool_services_list[service].AliasName} {if $tool_services_list[service].ShardName != ""}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != ""}/{$tool_services_list[service].ShardId}{/if} {$tool_services_list[service].ShortName} {$tool_services_list[service].Hostname} {$tool_services_list[service].RunningState} {$tool_services_list[service].RunningTags} {$tool_services_list[service].State} {$tool_services_list[service].NoReportSince} {$tool_services_list[service].StartCounter} {$tool_services_list[service].UserSpeedLoop} {$tool_services_list[service].TickSpeedLoop} {$tool_services_list[service].ProcessUsedMemory} {$tool_services_list[service].NbPlayers} {$tool_services_list[service].UpTime}
{if $las_counter > 0}
Database :  
File Name : {$tool_file_name_error_msg}
Start Date : {$tool_start_date_error_msg}
End Date :  

EID Search :
Text Search :

Command :     
{if $tool_execute_command}
Command Results for '{$tool_execute_command}' :
{/if} {else}
No LAS to work with or select a shard on the left!
{/if}
{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_log_analyser_file_view.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=shard loop=$tool_shard_list} {if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id} {/if} {/section}
Shards
{$tool_shard_list[shard].shard_name}
{if $tool_file_list}
{section name=file loop=$tool_file_list} {/section}
Files
Size: {math equation="x / y" x=$tool_file_list[file].size y=1024 format="%d"} KB
', OFFSETX, 40, OFFSETY, 10);" onmouseout="return nd();">{$tool_file_list[file].name}
{/if} {/if}
  {if $tool_file_error}
{$tool_file_error}

{else} {section name=line loop=$tool_file_output} {cycle assign="trclass" values="row0,row1"} {/section}
Viewing File : {$tool_view_file_data.name} [ Downloads : RAW  -  PARSED ] {* [download] *} {* [delete] *}
{$tool_file_output[line]}
{if $tool_view_line_start_previous > -1} <Previous {else} Beginning {/if}  |  {if $tool_view_line_start_next > -1} Next> {else} End {/if}

{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_mfs.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=shard loop=$tool_shard_list} {if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id} {/if} {/section}
Shards
{$tool_shard_list[shard].shard_name}
{/if}
  {if !$tool_domain_selected}
You need to select a domain.
{else} {if !$tool_shard_selected}
You need to select a shard.
{/if} {/if}
{$tool_curl_output}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_notes.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{$tool_alert_message}

{if $restriction_tool_notes_global} {/if} {section name=note loop=$tool_note_list} {if $restriction_tool_notes_global} {/if} {/section}
Notes
ID Title Mode Last Update ActiveGlobal
{$tool_note_list[note].note_id} {$tool_note_list[note].note_title} {if $tool_note_list[note].note_mode == 0}Text{else}Popup{/if} {$tool_note_list[note].note_date|date_format:"%Y/%m/%d %H:%M:%S"} {if $tool_note_list[note].note_active == 1}Yes{else}No{/if}{if $tool_note_list[note].note_global == 1}Yes{else}No{/if}
  {if $tool_note_edit_data.note_id} {/if} {if $restriction_tool_notes_global} {/if}
Notes Details
Id :
Title :
Mode :
Text :
URI :
Restriction :
Active :
Global :
  {if $tool_note_edit_data.note_id} {else} {/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_player_locator.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{if $tool_domain_selected && $tool_shard_selected} {if $tool_refresh_rate > 0} {/if}
Refresh

{/if} {section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=shard loop=$tool_shard_list} {if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id} {/if} {/section}
Shards
{$tool_shard_list[shard].shard_name}
{/if}
  {if !$tool_domain_selected}
You need to select a domain.
{elseif $tool_domain_error}
{$tool_domain_error}
{else} {if $tool_as_error}
{$tool_as_error}

{/if}
{assign var="egs_counter" value="0"} {section name=service loop=$tool_services_list} {assign var="service_shard_id" value=$tool_services_list[service].ShardName} {if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)} {cycle assign="trclass" values="row0,row1"} {assign var="tdclass1" value=""} {assign var="tdclass2" value=""} {if $tool_services_list[service]._flags_.rs_stopped}{assign var="tdclass1" value="class=\"cell_inactive1\""}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_stopped"}{/if} {if $tool_services_list[service]._flags_.rs_starting}{assign var="tdclass1" value="class=\"cell_inactive1\""}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_starting"}{/if} {if $tool_services_list[service]._flags_.alert_red}{assign var="trclass" value="row_red"}{/if} {if $tool_services_list[service]._flags_.alert_orange_dark}{assign var="trclass" value="row_orange_dark"}{/if} {if $tool_services_list[service]._flags_.alert_orange_light}{assign var="trclass" value="row_orange_light"}{/if} {assign var="check_name" value=$tool_services_list[service].AliasName} {assign var="egs_counter" value="`$egs_counter+1`"} {/if} {/section}
AliasName Shard ShortName Hostname Running State Running Tags State Report Counters User SL Tick SL Memory NbPlayers UpTime
{$tool_services_list[service].AliasName} {if $tool_services_list[service].ShardName != ""}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != ""}/{$tool_services_list[service].ShardId}{/if} {$tool_services_list[service].ShortName} {$tool_services_list[service].Hostname} {$tool_services_list[service].RunningState} {$tool_services_list[service].RunningTags} {$tool_services_list[service].State} {$tool_services_list[service].NoReportSince} {$tool_services_list[service].StartCounter} {$tool_services_list[service].UserSpeedLoop} {$tool_services_list[service].TickSpeedLoop} {$tool_services_list[service].ProcessUsedMemory} {$tool_services_list[service].NbPlayers} {$tool_services_list[service].UpTime}
{if $egs_counter > 0} {if $restriction_tool_player_locator_display_players}
Player Name :    {if $restriction_tool_player_locator_display_players} {/if}
{/if} {if $restriction_tool_player_locator_locate}
Locate :     
{/if} {if $tool_locate_data} {if $tool_relocate_data && $restriction_tool_player_locator_csr_relocate}
{if $tool_relocate_data.success == 1} {else} {/if}
Successfully relocated character {$tool_relocate_data.charid} from account {$tool_relocate_data.uid}!Failed relocating character {$tool_relocate_data.charid} from account {$tool_relocate_data.uid}! Account is online!
{/if} {assign var="service_name" value=""}
{section name=entity loop=$tool_locate_data} {if $service_name != $tool_locate_data[entity].service} {assign var="service_name" value=$tool_locate_data[entity].service} {/if} {cycle assign="trclass" values="row0,row1"} {if $tool_locate_data[entity].status == "Online"}{assign var="trclass" value="row_starting"}{/if} {if $tool_locate_data[entity].status == "Online"} {elseif $restriction_tool_player_locator_csr_relocate} {else} {/if} {/section}
{$service_name}
UId UserName EId EntityName EntitySlot SaveFile Status Session X Y Z
{$tool_locate_data[entity].uid} {$tool_locate_data[entity].user_name} {if $tool_locate_data[entity].status == "Online"}{$tool_locate_data[entity].eid}{else}{$tool_locate_data[entity].eid}{/if} {$tool_locate_data[entity].entity_name} {$tool_locate_data[entity].entity_slot} {$tool_locate_data[entity].save_file} {$tool_locate_data[entity].status}{$tool_locate_data[entity].session} {$tool_locate_data[entity].posx} {$tool_locate_data[entity].posy} {$tool_locate_data[entity].posz}relocate: {$tool_locate_data[entity].session} {$tool_locate_data[entity].posx} {$tool_locate_data[entity].posy} {$tool_locate_data[entity].posz}
{elseif $tool_player_data} {assign var="service_name" value=""}
{section name=entity loop=$tool_player_data} {if $service_name != $tool_player_data[entity].service} {assign var="service_name" value=$tool_player_data[entity].service} {/if} {cycle assign="trclass" values="row0,row1"} {/section}
{$service_name}
Player Name ID FE Sheet Priv Session X Y Z
{$tool_player_data[entity].player} {$tool_player_data[entity].name} {$tool_player_data[entity].id} {$tool_player_data[entity].fe} {$tool_player_data[entity].sheet} {$tool_player_data[entity].priv} {$tool_player_data[entity].session} {$tool_player_data[entity].posx} {$tool_player_data[entity].posy} {$tool_player_data[entity].posz}
{/if} {if $restriction_tool_player_locator_userid_check}
{if $user_check_list} {section name=char loop=$user_check_list} {cycle assign="trclass" values="row0,row1"} {/section} {else} {/if}
Character List (user_id = 0)
Character Name Character ID Best Combat Level Ring Access
{$user_check_list[char].char_name} {$user_check_list[char].char_id} {$user_check_list[char].best_combat_level} {$user_check_list[char].ring_access}
{* *}  
No characters with user_id=0 were found!
{/if} {if $tool_execute_command}
Command Results for '{$tool_execute_command}' :
{/if} {else}
No EGS to work with!
{/if}
{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_preferences.tpl ================================================ {include file="page_header.tpl"}
{if $tool_error != null} {/if}
My Preferences
Login: {$tool_v_login}
Old Password:
New Password:
Menu Style:
 
{$tool_error}

Default Application
Application :
 
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default/tool_shop.tpl ================================================ {include file="page_header.tpl"} {literal} {/literal}
{if $tool_domain_selected && $tool_shard_selected} {if $tool_refresh_rate > 0} {/if}
Refresh

{/if} {section name=domain loop=$tool_domain_list} {/section}
Domains
{$tool_domain_list[domain].domain_name}
{if $tool_domain_selected}
{section name=shard loop=$tool_shard_list} {if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id} {/if} {/section}
Shards
{$tool_shard_list[shard].shard_name}
{/if}
  {if !$tool_domain_selected}
You need to select a domain.
{elseif $tool_domain_error}
{$tool_domain_error}
{else} {if $tool_as_error}
{$tool_as_error}

{/if}
{assign var="egs_counter" value="0"} {section name=service loop=$tool_services_list} {assign var="service_shard_id" value=$tool_services_list[service].ShardName} {if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)} {cycle assign="trclass" values="row0,row1"} {assign var="tdclass1" value=""} {assign var="tdclass2" value=""} {if $tool_services_list[service]._flags_.rs_stopped}{assign var="tdclass1" value="class=\"cell_inactive1\""}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_stopped"}{/if} {if $tool_services_list[service]._flags_.rs_starting}{assign var="tdclass1" value="class=\"cell_inactive1\""}{assign var="tdclass2" value="class=\"cell_inactive2\""}{assign var="trclass" value="row_starting"}{/if} {if $tool_services_list[service]._flags_.alert_red}{assign var="trclass" value="row_red"}{/if} {if $tool_services_list[service]._flags_.alert_orange_dark}{assign var="trclass" value="row_orange_dark"}{/if} {if $tool_services_list[service]._flags_.alert_orange_light}{assign var="trclass" value="row_orange_light"}{/if} {assign var="check_name" value=$tool_services_list[service].AliasName} {assign var="egs_counter" value="`$egs_counter+1`"} {/if} {/section}
AliasName Shard ShortName Hostname Running State Running Tags State Report Counters User SL Tick SL Memory NbPlayers UpTime
{$tool_services_list[service].AliasName} {if $tool_services_list[service].ShardName != ""}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != ""}/{$tool_services_list[service].ShardId}{/if} {$tool_services_list[service].ShortName} {$tool_services_list[service].Hostname} {$tool_services_list[service].RunningState} {$tool_services_list[service].RunningTags} {$tool_services_list[service].State} {$tool_services_list[service].NoReportSince} {$tool_services_list[service].StartCounter} {$tool_services_list[service].UserSpeedLoop} {$tool_services_list[service].TickSpeedLoop} {$tool_services_list[service].ProcessUsedMemory} {$tool_services_list[service].NbPlayers} {$tool_services_list[service].UpTime}
{if $egs_counter > 0} {if $restriction_tool_shop}
Command :      物品ID:  数量:  价格:             
{/if} {if $tool_shop_list_data} {assign var="service_name" value=""}
{section name=entity loop=$tool_shop_list_data} {if $service_name != $tool_shop_list_data[entity].service} {assign var="service_name" value=$tool_shop_list_data[entity].service} {/if} {cycle assign="trclass" values="row0,row1"} {/section}
ShardID IDX 模板ID 物品名称 数量 价格
{$tool_shop_list_data[entity].shardid} {$tool_shop_list_data[entity].idx} {$tool_shop_list_data[entity].tid} {$tool_shop_list_data[entity].name} {$tool_shop_list_data[entity].num} {$tool_shop_list_data[entity].price}
{/if} {if $tool_execute_command}
Command Results for '{$tool_execute_command}' :
{/if} {else}
No EGS to work with!
{/if}
{/if}
{include file="page_footer.tpl"} ================================================ FILE: tools/server/admin/templates/default_c/placeholder ================================================ ================================================ FILE: tools/server/admin/tool_actions.php ================================================ assign('tool_title', "Actions"); $tpl->display('tool_actions.tpl'); ?> ================================================ FILE: tools/server/admin/tool_administration.php ================================================ assign('tool_title', 'Administration / '. $tool_menu_item['title']); $tpl->assign('tool_menu', tool_admin_menu_get_list($IE_CHECK)); //$tool_admin_menu); // defined in 'functions_tool_administration.php' switch($NELTOOL['GET_VARS']['toolmode']) { case 'help': /* * ################################################################################################### * Help Admin * ################################################################################################### */ if ($IE_CHECK) $tpl->assign('ie_check', true); else $tpl->assign('ie_check', false); break; case 'logs': /* * ################################################################################################### * Logs Admin * ################################################################################################### */ if (!tool_admin_applications_check('tool_admin_logs')) nt_common_redirect('index.php'); $log_start = 0; $log_step = 30; $num_logs = tool_admin_logs_get_count(); if (isset($_GET['page'])) $log_start = $_GET['page']; $tool_log_list = tool_admin_logs_get_list($log_start * $log_step, $log_step); $log_page_first = 0; $log_page_last = ceil($num_logs / $log_step); $log_page_previous = $log_start - 1; $log_page_next = $log_start + 1; if ($log_page_previous < 0) $log_page_previous = 0; if ($log_page_next >= $log_page_last) $log_page_next = $log_page_last - 1; $tpl->assign('tool_log_page_first', $log_page_first); $tpl->assign('tool_log_page_last', $log_page_last - 1); $tpl->assign('tool_log_page_previous', $log_page_previous); $tpl->assign('tool_log_page_next', $log_page_next); $tpl->assign('tool_log_page_current', $log_start + 1); $tpl->assign('tool_log_page_total', $log_page_last); $tpl->assign('tool_log_list', $tool_log_list); break; case 'users': /* * ################################################################################################### * User Admin * ################################################################################################### */ if (!tool_admin_applications_check('tool_admin_user')) nt_common_redirect('index.php'); $tool_action = null; if (isset($_POST['toolaction'])) $tool_action = $_POST['toolaction']; elseif (isset($_GET['toolaction'])) $tool_action = $_GET['toolaction']; switch ($tool_action) { case 'update applications': if ($tool_action == 'update applications') { $tool_user_update_id = $_POST['tool_form_user_id']; $tool_user_update_appl_ids = $_POST['tool_form_application_ids']; tool_admin_users_applications_update($tool_user_update_id, $tool_user_update_appl_ids); $_GET['user_id'] = $tool_user_update_id; } // break; case 'update domains': if ($tool_action == 'update domains') { $tool_user_update_id = $_POST['tool_form_user_id']; $tool_user_update_domain_ids = $_POST['tool_form_domain_ids']; $tool_user_data = tool_admin_users_get_id($tool_user_update_id); $tool_user_group_id = $tool_user_data['user_group_id']; tool_admin_users_domains_update($tool_user_update_id, $tool_user_group_id, $tool_user_update_domain_ids); $_GET['user_id'] = $tool_user_update_id; } //break; case 'update shards': if ($tool_action == 'update shards') { $tool_user_update_id = $_POST['tool_form_user_id']; $tool_user_update_shard_ids = $_POST['tool_form_shard_ids']; $tool_user_data = tool_admin_users_get_id($tool_user_update_id); $tool_user_group_id = $tool_user_data['user_group_id']; tool_admin_users_shards_update($tool_user_update_id, $tool_user_group_id, $tool_user_update_shard_ids); $_GET['user_id'] = $tool_user_update_id; } //break; case 'update': /* * ------------------------------------------------------------------------------------------- * Update an existing User * ------------------------------------------------------------------------------------------- */ if ($tool_action == 'update') { $tool_user_update_id = $_POST['tool_form_user_id']; $tool_user_update_name = $_POST['tool_form_user_name']; $tool_user_update_password = $_POST['tool_form_user_password']; $tool_user_update_group = $_POST['tool_form_user_group']; $tool_user_update_active = $_POST['tool_form_user_active']; $tool_error = tool_admin_users_update($tool_user_update_id, $tool_user_update_name, $tool_user_update_password, $tool_user_update_group, $tool_user_update_active); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } $_GET['user_id'] = $tool_user_update_id; } //break; case 'edit': /* * ------------------------------------------------------------------------------------------- * Edit an existing User * ------------------------------------------------------------------------------------------- */ $tool_user_edit_id = $_GET['user_id']; $tool_user_edit_data = tool_admin_users_get_id($tool_user_edit_id); $tool_user_group_id = $tool_user_edit_data['user_group_id']; $tpl->assign('tool_user_edit_data', $tool_user_edit_data); $tool_domain_list = tool_admin_domains_get_list(); $tool_user_domain_list = tool_admin_users_domains_get_list($tool_user_edit_id, true); $tool_group_domain_list = tool_admin_groups_domains_get_list($tool_user_group_id, true); $tool_domain_list = tool_admin_users_domains_merge($tool_domain_list, $tool_user_domain_list, $tool_group_domain_list); $tpl->assign('tool_domain_list', $tool_domain_list); $tool_shard_list = tool_admin_shards_get_list(); $tool_user_shard_list = tool_admin_users_shards_get_list($tool_user_edit_id, true); $tool_group_shard_list = tool_admin_groups_shards_get_list($tool_user_group_id, true); $tool_shard_list = tool_admin_users_shards_merge($tool_domain_list, $tool_shard_list, $tool_user_shard_list, $tool_group_shard_list); $tpl->assign('tool_shard_list', $tool_shard_list); $tool_appl_list = tool_admin_applications_get_list(); $tool_user_appl_list = tool_admin_users_applications_get_list($tool_user_edit_id, true); $tool_group_appl_list = tool_admin_groups_applications_get_list($tool_user_group_id, true); $tool_appl_list = tool_admin_users_applications_merge($tool_appl_list, $tool_user_appl_list, $tool_group_appl_list); $tpl->assign('tool_application_list', $tool_appl_list); break; case 'delete': /* * ------------------------------------------------------------------------------------------- * Delete an existing User * ------------------------------------------------------------------------------------------- */ $tool_user_delete_id = $_POST['tool_form_user_id']; if (!($tool_user_delete_id > 0)) { $tpl->assign('tool_alert_message', "/!\ Error: invalid user!"); } elseif ($tool_user_delete_id == $nel_user['user_id']) { $tpl->assign('tool_alert_message', "/!\ Error: did you just try to delete yourself ?!"); } else { tool_admin_users_del($tool_user_delete_id); } break; case 'create': /* * ------------------------------------------------------------------------------------------- * Create a new User * ------------------------------------------------------------------------------------------- */ $tool_user_create_name = $_POST['tool_form_user_name']; $tool_user_create_password = $_POST['tool_form_user_password']; $tool_user_create_group = $_POST['tool_form_user_group']; $tool_user_create_active = $_POST['tool_form_user_active']; $tool_error = tool_admin_users_add($tool_user_create_name, $tool_user_create_password, $tool_user_create_group, $tool_user_create_active); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } break; } $tool_group_list = tool_admin_groups_get_list(); $tool_user_list = tool_admin_users_get_list($tool_group_list); $tpl->assign('tool_user_list', $tool_user_list); $tpl->assign('tool_group_list', $tool_group_list); break; case 'groups': /* * ################################################################################################### * Group Admin * ################################################################################################### */ if (!tool_admin_applications_check('tool_admin_group')) nt_common_redirect('index.php'); $tool_action = null; if (isset($_POST['toolaction'])) $tool_action = $_POST['toolaction']; elseif (isset($_GET['toolaction'])) $tool_action = $_GET['toolaction']; switch ($tool_action) { case 'update applications': if ($tool_action == 'update applications') { $tool_group_update_id = $_POST['tool_form_group_id']; $tool_group_update_appl_ids = $_POST['tool_form_application_ids']; tool_admin_groups_applications_update($tool_group_update_id, $tool_group_update_appl_ids); $_GET['group_id'] = $tool_group_update_id; } // break; case 'update domains': if ($tool_action == 'update domains') { $tool_group_update_id = $_POST['tool_form_group_id']; $tool_group_update_domain_ids = $_POST['tool_form_domain_ids']; tool_admin_groups_domains_update($tool_group_update_id, $tool_group_update_domain_ids); $_GET['group_id'] = $tool_group_update_id; } //break; case 'update shards': if ($tool_action == 'update shards') { $tool_group_update_id = $_POST['tool_form_group_id']; $tool_group_update_shard_ids = $_POST['tool_form_shard_ids']; tool_admin_groups_shards_update($tool_group_update_id, $tool_group_update_shard_ids); $_GET['group_id'] = $tool_group_update_id; } //break; case 'update': /* * ------------------------------------------------------------------------------------------- * Update an existing Group * ------------------------------------------------------------------------------------------- */ if ($tool_action == 'update') { $tool_group_update_id = $_POST['tool_form_group_id']; $tool_group_update_name = $_POST['tool_form_group_name']; $tool_group_update_level = $_POST['tool_form_group_level']; $tool_group_update_default = $_POST['tool_form_group_default']; $tool_group_update_active = $_POST['tool_form_group_active']; $tool_error = tool_admin_groups_update($tool_group_update_id, $tool_group_update_name, $tool_group_update_level, $tool_group_update_default, $tool_group_update_active); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } $_GET['group_id'] = $tool_group_update_id; } //break; case 'update default domain': /* * ------------------------------------------------------------------------------------------- * Update group default domain * ------------------------------------------------------------------------------------------- */ if ($tool_action == 'update default domain') { $tool_group_update_id = $_POST['tool_form_group_id']; $tool_group_default_domain = $_POST['tool_form_domain_default']; $tool_error = tool_admin_groups_update_default_domain($tool_group_update_id, $tool_group_default_domain); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } $_GET['group_id'] = $tool_group_update_id; } //break; case 'update default shard': /* * ------------------------------------------------------------------------------------------- * Update group default shard * ------------------------------------------------------------------------------------------- */ if ($tool_action == 'update default shard') { $tool_group_update_id = $_POST['tool_form_group_id']; $tool_group_default_shard = $_POST['tool_form_shard_default']; $tool_error = tool_admin_groups_update_default_shard($tool_group_update_id, $tool_group_default_shard); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } $_GET['group_id'] = $tool_group_update_id; } //break; case 'update default application': /* * ------------------------------------------------------------------------------------------- * Update group default application * ------------------------------------------------------------------------------------------- */ if ($tool_action == 'update default application') { $tool_group_update_id = $_POST['tool_form_group_id']; $tool_group_default_application = $_POST['tool_form_application_default']; $tool_error = tool_admin_groups_update_default_application($tool_group_update_id, $tool_group_default_application); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } $_GET['group_id'] = $tool_group_update_id; } //break; case 'edit': /* * ------------------------------------------------------------------------------------------- * Edit an existing Group * ------------------------------------------------------------------------------------------- */ $tool_group_edit_id = $_GET['group_id']; $tool_group_edit_data = tool_admin_groups_get_id($tool_group_edit_id); $tpl->assign('tool_group_edit_data', $tool_group_edit_data); $tool_domain_list = tool_admin_domains_get_list(); $tool_group_domain_list = tool_admin_groups_domains_get_list($tool_group_edit_id, true); $tool_domain_list = tool_admin_groups_domains_merge($tool_domain_list, $tool_group_domain_list); $tpl->assign('tool_domain_list', $tool_domain_list); $tool_shard_list = tool_admin_shards_get_list(); $tool_group_shard_list = tool_admin_groups_shards_get_list($tool_group_edit_id, true); $tool_shard_list = tool_admin_groups_shards_merge($tool_domain_list, $tool_shard_list, $tool_group_shard_list); $tpl->assign('tool_shard_list', $tool_shard_list); $tool_appl_list = tool_admin_applications_get_list(); $tool_group_appl_list = tool_admin_groups_applications_get_list($tool_group_edit_id, true); $tool_appl_list = tool_admin_groups_applications_merge($tool_appl_list, $tool_group_appl_list); $tpl->assign('tool_application_list', $tool_appl_list); $tool_group_user_list = tool_admin_groups_get_user_list($tool_group_edit_id); $tpl->assign('tool_group_user_list', $tool_group_user_list); break; case 'delete': /* * ------------------------------------------------------------------------------------------- * Delete an existing Group * ------------------------------------------------------------------------------------------- */ $tool_group_delete_id = $_POST['tool_form_group_id']; if (!($tool_group_delete_id > 0)) { $tpl->assign('tool_alert_message', "/!\ Error: invalid group!"); } elseif ($tool_group_delete_id == $nel_user['user_group_id']) { $tpl->assign('tool_alert_message', "/!\ Error: did you just try to delete your own group ?!"); } else { tool_admin_groups_del($tool_group_delete_id); } break; case 'create': /* * ------------------------------------------------------------------------------------------- * Create a new Group * ------------------------------------------------------------------------------------------- */ $tool_group_create_name = $_POST['tool_form_group_name']; $tool_group_create_level = $_POST['tool_form_group_level']; $tool_group_create_default = $_POST['tool_form_group_default']; $tool_group_create_active = $_POST['tool_form_group_active']; $tool_error = tool_admin_groups_add($tool_group_create_name, $tool_group_create_level, $tool_group_create_default, $tool_group_create_active); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } break; } $tool_group_list = tool_admin_groups_get_list(); $tpl->assign('tool_group_list', $tool_group_list); $tpl->assign('tool_group_level_list', $nel_user_group_levels); break; case 'applications': /* * ################################################################################################### * Application Admin * ################################################################################################### */ if (!tool_admin_applications_check('tool_admin_application')) nt_common_redirect('index.php'); $tool_action = null; if (isset($_POST['toolaction'])) $tool_action = $_POST['toolaction']; elseif (isset($_GET['toolaction'])) $tool_action = $_GET['toolaction']; switch ($tool_action) { case 'update': /* * ------------------------------------------------------------------------------------------- * Update an existing Group * ------------------------------------------------------------------------------------------- */ $tool_application_update_id = $_POST['tool_form_application_id']; $tool_application_update_name = $_POST['tool_form_application_name']; $tool_application_update_uri = $_POST['tool_form_application_uri']; $tool_application_update_restriction = $_POST['tool_form_application_restriction']; $tool_application_update_icon = $_POST['tool_form_application_icon']; $tool_application_update_order = $_POST['tool_form_application_order']; $tool_application_update_visible = $_POST['tool_form_application_visible']; $tool_error = tool_admin_applications_update($tool_application_update_id, $tool_application_update_name, $tool_application_update_uri, $tool_application_update_restriction, $tool_application_update_icon, $tool_application_update_order, $tool_application_update_visible); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } $_GET['application_id'] = $tool_application_update_id; //break; case 'edit': /* * ------------------------------------------------------------------------------------------- * Edit an existing Group * ------------------------------------------------------------------------------------------- */ $tool_application_edit_id = $_GET['application_id']; $tool_application_edit_data = tool_admin_applications_get_id($tool_application_edit_id); $tpl->assign('tool_application_edit_data', $tool_application_edit_data); break; case 'delete': /* * ------------------------------------------------------------------------------------------- * Delete an existing Group * ------------------------------------------------------------------------------------------- */ $tool_application_delete_id = $_POST['tool_form_application_id']; if (!($tool_application_delete_id > 0)) { $tpl->assign('tool_alert_message', "/!\ Error: invalid application!"); } else { tool_admin_applications_del($tool_application_delete_id); } break; case 'create': /* * ------------------------------------------------------------------------------------------- * Create a new Group * ------------------------------------------------------------------------------------------- */ $tool_application_create_name = $_POST['tool_form_application_name']; $tool_application_create_uri = $_POST['tool_form_application_uri']; $tool_application_create_restriction = $_POST['tool_form_application_restriction']; $tool_application_create_icon = $_POST['tool_form_application_icon']; $tool_application_create_order = $_POST['tool_form_application_order']; $tool_application_create_visible = $_POST['tool_form_application_visible']; $tool_error = tool_admin_applications_add($tool_application_create_name, $tool_application_create_uri, $tool_application_create_restriction, $tool_application_create_icon, $tool_application_create_order, $tool_application_create_visible); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } break; } $tool_application_list = tool_admin_applications_get_list(); $tpl->assign('tool_application_list', $tool_application_list); break; case 'domains': /* * ################################################################################################### * Domain Admin * ################################################################################################### */ if (!tool_admin_applications_check('tool_admin_domain')) nt_common_redirect('index.php'); $tool_action = null; if (isset($_POST['toolaction'])) $tool_action = $_POST['toolaction']; elseif (isset($_GET['toolaction'])) $tool_action = $_GET['toolaction']; switch ($tool_action) { case 'update': /* * ------------------------------------------------------------------------------------------- * Update an existing Domain * ------------------------------------------------------------------------------------------- */ $tool_domain_update_id = $_POST['tool_form_domain_id']; $tool_domain_update_name = $_POST['tool_form_domain_name']; $tool_domain_update_application = $_POST['tool_form_domain_application']; $tool_domain_update_as_host = $_POST['tool_form_domain_as_host']; $tool_domain_update_as_port = $_POST['tool_form_domain_as_port']; $tool_domain_update_mfs_web = $_POST['tool_form_domain_mfs_web']; $tool_domain_update_rrd_path = $_POST['tool_form_domain_rrd_path']; $tool_domain_update_las_admin_path = $_POST['tool_form_domain_las_admin_path']; $tool_domain_update_las_local_path = $_POST['tool_form_domain_las_local_path']; $tool_domain_update_sql_string = $_POST['tool_form_domain_sql_string']; $tool_domain_update_cs_sql_string = $_POST['tool_form_domain_cs_sql_string']; $tool_domain_update_hd_check = $_POST['tool_form_domain_hd_check']; $tool_error = tool_admin_domains_update($tool_domain_update_id, $tool_domain_update_name, $tool_domain_update_application, $tool_domain_update_as_host, $tool_domain_update_as_port, $tool_domain_update_rrd_path, $tool_domain_update_las_admin_path, $tool_domain_update_las_local_path, $tool_domain_update_sql_string, $tool_domain_update_cs_sql_string, $tool_domain_update_hd_check, $tool_domain_update_mfs_web); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } $_GET['domain_id'] = $tool_domain_update_id; //break; case 'update_nel': /* * ------------------------------------------------------------------------------------------- * Update an existing Domain (in the nel.domain table) * ------------------------------------------------------------------------------------------- */ if (isset($_POST['tool_form_domain_nel_id'])) { $tool_domain_nel_update_id = $_POST['tool_form_domain_nel_id']; $tool_domain_nel_update_name = $_POST['tool_form_domain_nel_name']; $tool_domain_nel_update_status = $_POST['tool_form_domain_nel_status']; //$tool_domain_nel_update_version = $_POST['tool_form_domain_nel_version']; //tool_admin_domains_update_nel($tool_domain_nel_update_id, $tool_domain_nel_update_name, $tool_domain_nel_update_version, $tool_domain_nel_update_status); tool_admin_domains_update_nel($tool_domain_nel_update_id, $tool_domain_nel_update_name, $tool_domain_nel_update_status); $_GET['domain_id'] = $_POST['tool_form_domain_id']; } // break; case 'edit': /* * ------------------------------------------------------------------------------------------- * Edit an existing Domain * ------------------------------------------------------------------------------------------- */ $tool_domain_edit_id = $_GET['domain_id']; $tool_domain_edit_data = tool_admin_domains_get_id($tool_domain_edit_id); $tpl->assign('tool_domain_edit_data', $tool_domain_edit_data); if ($tool_domain_edit_data['domain_application'] != '') { $domain_nel_status = array('ds_close','ds_dev','ds_restricted','ds_open'); $tpl->assign('tool_domain_nel_status', $domain_nel_status); $tool_domain_nel_data = tool_admin_domains_get_nel($tool_domain_edit_data['domain_application']); $tpl->assign('tool_domain_nel_data', $tool_domain_nel_data); } break; case 'delete': /* * ------------------------------------------------------------------------------------------- * Delete an existing Domain * ------------------------------------------------------------------------------------------- */ $tool_domain_delete_id = $_POST['tool_form_domain_id']; if (!($tool_domain_delete_id > 0)) { $tpl->assign('tool_alert_message', "/!\ Error: invalid domain!"); } else { tool_admin_domains_del($tool_domain_delete_id); } break; case 'create': /* * ------------------------------------------------------------------------------------------- * Create a new Domain * ------------------------------------------------------------------------------------------- */ $tool_domain_create_name = $_POST['tool_form_domain_name']; $tool_domain_create_application = $_POST['tool_form_domain_application']; $tool_domain_create_as_host = $_POST['tool_form_domain_as_host']; $tool_domain_create_as_port = $_POST['tool_form_domain_as_port']; $tool_domain_create_mfs_web = $_POST['tool_form_domain_mfs_web']; $tool_domain_create_rrd_path = $_POST['tool_form_domain_rrd_path']; $tool_domain_create_las_admin_path = $_POST['tool_form_domain_las_admin_path']; $tool_domain_create_las_local_path = $_POST['tool_form_domain_las_local_path']; $tool_domain_create_sql_string = $_POST['tool_form_domain_sql_string']; $tool_domain_create_cs_sql_string = $_POST['tool_form_domain_cs_sql_string']; $tool_domain_create_hd_check = $_POST['tool_form_domain_hd_check']; $tool_error = tool_admin_domains_add( $tool_domain_create_name, $tool_domain_create_application, $tool_domain_create_as_host, $tool_domain_create_as_port, $tool_domain_create_rrd_path, $tool_domain_create_las_admin_path, $tool_domain_create_las_local_path, $tool_domain_create_sql_string, $tool_domain_create_cs_sql_string, $tool_domain_create_hd_check, $tool_domain_create_mfs_web); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } break; } $tool_domain_list = tool_admin_domains_get_list(); $tpl->assign('tool_domain_list', $tool_domain_list); break; case 'shards': /* * ################################################################################################### * Shard Admin * ################################################################################################### */ if (!tool_admin_applications_check('tool_admin_shard')) nt_common_redirect('index.php'); $tool_action = null; if (isset($_POST['toolaction'])) $tool_action = $_POST['toolaction']; elseif (isset($_GET['toolaction'])) $tool_action = $_GET['toolaction']; switch ($tool_action) { case 'update': /* * ------------------------------------------------------------------------------------------- * Update an existing Shard * ------------------------------------------------------------------------------------------- */ $tool_shard_update_id = $_POST['tool_form_shard_id']; $tool_shard_update_name = $_POST['tool_form_shard_name']; $tool_shard_update_as_id = $_POST['tool_form_shard_as_id']; $tool_shard_update_domain_id = $_POST['tool_form_shard_domain_id']; $tool_shard_update_language = $_POST['tool_form_shard_language']; $tool_error = tool_admin_shards_update($tool_shard_update_id, $tool_shard_update_name, $tool_shard_update_as_id, $tool_shard_update_domain_id, $tool_shard_update_language); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } $_GET['shard_id'] = $tool_shard_update_id; //break; case 'edit': /* * ------------------------------------------------------------------------------------------- * Edit an existing Shard * ------------------------------------------------------------------------------------------- */ $tool_shard_edit_id = $_GET['shard_id']; $tool_shard_edit_data = tool_admin_shards_get_id($tool_shard_edit_id); $tpl->assign('tool_shard_edit_data', $tool_shard_edit_data); break; case 'delete': /* * ------------------------------------------------------------------------------------------- * Delete an existing Shard * ------------------------------------------------------------------------------------------- */ $tool_shard_delete_id = $_POST['tool_form_shard_id']; if (!($tool_shard_delete_id > 0)) { $tpl->assign('tool_alert_message', "/!\ Error: invalid shard!"); } else { tool_admin_shards_del($tool_shard_delete_id); } break; case 'create': /* * ------------------------------------------------------------------------------------------- * Create a new Shard * ------------------------------------------------------------------------------------------- */ $tool_shard_create_name = $_POST['tool_form_shard_name']; $tool_shard_create_as_id = $_POST['tool_form_shard_as_id']; $tool_shard_create_domain_id = $_POST['tool_form_shard_domain_id']; $tool_shard_create_language = $_POST['tool_form_shard_language']; $tool_error = tool_admin_shards_add($tool_shard_create_name, $tool_shard_create_as_id, $tool_shard_create_domain_id, $tool_shard_create_language); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } break; } $tool_shard_list = tool_admin_shards_get_list(); $tool_domain_list = tool_admin_domains_get_list(); $tpl->assign('tool_shard_list', $tool_shard_list); $tpl->assign('tool_domain_list', $tool_domain_list); $tpl->assign('tool_language_list', $tool_language_list); break; case 'restarts': /* * ################################################################################################### * Restart Admin * ################################################################################################### */ if (!tool_admin_applications_check('tool_admin_restart')) nt_common_redirect('index.php'); $tool_action = null; if (isset($_POST['toolaction'])) $tool_action = $_POST['toolaction']; elseif (isset($_GET['toolaction'])) $tool_action = $_GET['toolaction']; switch ($tool_action) { case 'update': /* * ------------------------------------------------------------------------------------------- * Update an existing Restart Group * ------------------------------------------------------------------------------------------- */ $tool_restart_update_id = $_POST['tool_form_restart_id']; $tool_restart_update_name = $_POST['tool_form_restart_name']; $tool_restart_update_services = $_POST['tool_form_restart_services']; $tool_restart_update_order = $_POST['tool_form_restart_order']; $tool_error = tool_admin_restarts_update($tool_restart_update_id, $tool_restart_update_name, $tool_restart_update_services, $tool_restart_update_order); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } $_GET['restart_id'] = $tool_restart_update_id; //break; case 'edit': /* * ------------------------------------------------------------------------------------------- * Edit an existing Restart Group * ------------------------------------------------------------------------------------------- */ $tool_restart_edit_id = $_GET['restart_id']; $tool_restart_edit_data = tool_admin_restarts_get_id($tool_restart_edit_id); $tpl->assign('tool_restart_edit_data', $tool_restart_edit_data); break; case 'delete': /* * ------------------------------------------------------------------------------------------- * Delete an existing Restart Group * ------------------------------------------------------------------------------------------- */ $tool_restart_delete_id = $_POST['tool_form_restart_id']; if (!($tool_restart_delete_id > 0)) { $tpl->assign('tool_alert_message', "/!\ Error: invalid restart group!"); } else { tool_admin_restarts_del($tool_restart_delete_id); } break; case 'create': /* * ------------------------------------------------------------------------------------------- * Create a new Restart Group * ------------------------------------------------------------------------------------------- */ $tool_restart_create_name = $_POST['tool_form_restart_name']; $tool_restart_create_services = $_POST['tool_form_restart_services']; $tool_restart_create_order = $_POST['tool_form_restart_order']; $tool_error = tool_admin_restarts_add($tool_restart_create_name, $tool_restart_create_services, $tool_restart_create_order); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } break; case 'update message': /* * ------------------------------------------------------------------------------------------- * Update an existing Restart Message * ------------------------------------------------------------------------------------------- */ $tool_message_update_id = $_POST['tool_form_message_id']; $tool_message_update_name = $_POST['tool_form_message_name']; $tool_message_update_value = $_POST['tool_form_message_value']; $tool_message_update_lang = $_POST['tool_form_message_lang']; $tool_error = tool_admin_restart_messages_update($tool_message_update_id, $tool_message_update_name, $tool_message_update_value, $tool_message_update_lang); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } $_GET['msg_id'] = $tool_message_update_id; //break; case 'editmsg': /* * ------------------------------------------------------------------------------------------- * Edit an existing Restart Message * ------------------------------------------------------------------------------------------- */ $tool_message_edit_id = $_GET['msg_id']; $tool_message_edit_data = tool_admin_restart_messages_get_id($tool_message_edit_id); $tpl->assign('tool_message_edit_data', $tool_message_edit_data); break; case 'delete message': /* * ------------------------------------------------------------------------------------------- * Delete an existing Restart Message * ------------------------------------------------------------------------------------------- */ $tool_message_delete_id = $_POST['tool_form_message_id']; if (!($tool_message_delete_id > 0)) { $tpl->assign('tool_alert_message', "/!\ Error: invalid restart message!"); } else { tool_admin_restart_messages_del($tool_message_delete_id); } break; case 'create message': /* * ------------------------------------------------------------------------------------------- * Create a new Restart Message * ------------------------------------------------------------------------------------------- */ $tool_message_create_name = $_POST['tool_form_message_name']; $tool_message_create_value = $_POST['tool_form_message_value']; $tool_message_create_lang = $_POST['tool_form_message_lang']; $tool_error = tool_admin_restart_messages_add($tool_message_create_name, $tool_message_create_value, $tool_message_create_lang); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } break; } $tpl->assign('tool_language_list', $tool_language_list); $tool_restart_list = tool_admin_restarts_get_list(); $tpl->assign('tool_restart_list', $tool_restart_list); $tool_message_list = tool_admin_restart_messages_get_list(); $tpl->assign('tool_message_list', $tool_message_list); break; } $tpl->display($tool_menu_item['tpl']); ?> ================================================ FILE: tools/server/admin/tool_event_entities.php ================================================ assign('tool_title', "Event Entities"); $view_domain_id = nt_auth_get_session_var('view_domain_id'); $view_shard_id = nt_auth_get_session_var('view_shard_id'); if (!$view_domain_id) { $view_domain_id = $nel_user['group_default_domain_id']; $view_shard_id = $nel_user['group_default_shard_id']; nt_auth_set_session_var('view_domain_id', $view_domain_id); nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (isset($NELTOOL['GET_VARS']['domain'])) { if ($view_domain_id != $NELTOOL['GET_VARS']['domain']) { $view_domain_id = $NELTOOL['GET_VARS']['domain']; nt_auth_set_session_var('view_domain_id', $view_domain_id); $view_shard_id = null; nt_auth_unset_session_var('view_shard_id'); } } if (isset($NELTOOL['GET_VARS']['shard'])) { $view_shard_id = $NELTOOL['GET_VARS']['shard']; nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (isset($NELTOOL['GET_VARS']['refdata'])) { $tmp_data = unserialize(base64_decode($NELTOOL['GET_VARS']['refdata'])); if (is_array($tmp_data)) { $NELTOOL['POST_VARS'] = $tmp_data; } } $tpl->assign('tool_domain_list', $nel_user['access']['domains']); $tpl->assign('tool_domain_selected', $view_domain_id); $tpl->assign('tool_shard_list', $nel_user['access']['shards']); $tpl->assign('tool_shard_selected', $view_shard_id); $tool_shard_filters = tool_main_get_shard_ids($view_shard_id); $tpl->assign('tool_shard_filters', $tool_shard_filters); //if (tool_admin_applications_check('tool_player_locator_display_players')) $tpl->assign('restriction_tool_player_locator_display_players', true); //if (tool_admin_applications_check('tool_player_locator_locate')) $tpl->assign('restriction_tool_player_locator_locate', true); if ($view_domain_id) { $tool_as_error = null; $AS_Name = tool_main_get_domain_name($view_domain_id); $AS_Host = tool_main_get_domain_host($view_domain_id); $AS_Port = tool_main_get_domain_port($view_domain_id); $AS_ShardName = tool_main_get_shard_name($view_shard_id); $tpl->assign('tool_page_title', 'Event Entities - '. $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : '')); $tool_as_error = null; if ($AS_Host && $AS_Port) { $adminService = new MyAdminService; if (@$adminService->connect($AS_Host, $AS_Port, $res) === false) { nt_common_add_debug($res); $tpl->assign('tool_domain_error', $res ); } else { $tool_services_ee = null; if (isset($NELTOOL['POST_VARS']['services_ee'])) $tool_services_ee = $NELTOOL['POST_VARS']['services_ee']; elseif (isset($NELTOOL['GET_VARS']['services_ee'])) $tool_services_ee = $NELTOOL['GET_VARS']['services_ee']; if ($tool_services_ee) { $tpl->assign('tool_post_data', base64_encode(serialize($NELTOOL['POST_VARS']))); switch ($tool_services_ee) { case 'update entities': $requested_service_list = $NELTOOL['POST_VARS']['requested_service_list']; $service_list = unserialize(base64_decode($requested_service_list)); //nt_common_add_debug($NELTOOL['POST_VARS']); $update_entities = tool_ee_get_entities($NELTOOL['POST_VARS']); nt_common_add_debug('update_entities'); nt_common_add_debug($update_entities); reset($update_entities); foreach($update_entities as $entity_data) { $service_command = ''; $_commands = array(); if ($entity_data['entity_state'] != $entity_data['source_entity_state']) $_commands[] = 'NamedEntityState='. $entity_data['entity_state']; if ($entity_data['entity_param1'] != $entity_data['source_entity_param1']) $_commands[] = 'NamedEntityParam1='. $entity_data['entity_param1']; if ($entity_data['entity_param2'] != $entity_data['source_entity_param2']) $_commands[] = 'NamedEntityParam2='. $entity_data['entity_param2']; if (sizeof($_commands) > 0) { nt_common_add_debug("something has been updated in entity : ". $entity_data['source_entity']); if (sizeof($_commands) == 1) { $service_command = 'getView '. $entity_data['source_entity'] .'.'. $_commands[0]; } else { $service_command = 'getView '. $entity_data['source_entity'] .'.['. implode(',', $_commands) .']'; } $service = strtolower($entity_data['source_service']); nt_log("Domain '$AS_Name' : '$service_command' on ". $service); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } } } //$requested_service = $NELTOOL['POST_VARS']['source_service']; //$requested_entity = $NELTOOL['POST_VARS']['source_entity']; //$requested_entity_name = $NELTOOL['POST_VARS']['source_entity_name']; // //$new_entity_state = $NELTOOL['POST_VARS']['entity_state']; //$new_entity_param1 = $NELTOOL['POST_VARS']['entity_param1']; //$new_entity_param2 = $NELTOOL['POST_VARS']['entity_param2']; // //$old_entity_state = $NELTOOL['POST_VARS']['source_entity_state']; //$old_entity_param1 = $NELTOOL['POST_VARS']['source_entity_param1']; //$old_entity_param2 = $NELTOOL['POST_VARS']['source_entity_param2']; // //$service_command = ''; // //$_commands = array(); // //if ($new_entity_state != $old_entity_state) $_commands[] = 'NamedEntityState='. $new_entity_state; //if ($new_entity_param1 != $old_entity_param1) $_commands[] = 'NamedEntityParam1='. $new_entity_param1; //if ($new_entity_param2 != $old_entity_param2) $_commands[] = 'NamedEntityParam2='. $new_entity_param2; // //if (sizeof($_commands) > 0) //{ // nt_common_add_debug("something has been updated in entity : ". $requested_entity); // if (sizeof($_commands) == 1) // { // $service_command = 'getView '. $requested_entity .'.'. $_commands[0]; // } // else // { // $service_command = 'getView '. $requested_entity .'.['. implode(',', $_commands) .']'; // } // // $service = strtolower($requested_service); // // nt_log("Domain '$AS_Name' : '$service_command' on ". $service); // // $adminService->serviceCmd($service, $service_command); // if (!$adminService->waitCallback()) // { // nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); // } // //} //break; case 'display entities': if (!isset($service_list)) $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { $service_command = 'getView *.[NamedEntityName,NamedEntityState,NamedEntityParam1,NamedEntityParam2]'; nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $tpl->assign('tool_execute_result', ''); $command_return_data = array(); reset($service_list); foreach($service_list as $service) { //nt_common_add_debug("about to run 'displayPlayers' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { // the locator displays a nice output, no need for the raw one //$tpl->assign('tool_execute_command', $service_command); } } if (sizeof($command_return_data)) { $entity_data = tool_ee_parse_getview($command_return_data); nt_common_add_debug($entity_data); $tpl->assign('tool_entity_data', $entity_data); $tpl->assign('requested_service_list', base64_encode(serialize($service_list))); } } break; } } $status = $adminService->getStates(); nt_common_add_debug($status); $domainServices = tool_main_parse_status($status); $filteredServices = array(); reset($domainServices); foreach($domainServices as $aKey => $aService) { // we are only interested in EGS if ($aService['ShortName'] == 'AIS') { $filteredServices[] = $aService; } } $tpl->assign('tool_services_list', $filteredServices); } } } $tpl->display('tool_event_entities.tpl'); ?> ================================================ FILE: tools/server/admin/tool_graphs.php ================================================ assign('toolmode', $NELTOOL['GET_VARS']['toolmode']); $tpl->assign('tool_title', 'Graphs / '. $tool_menu_item['title']); $tpl->assign('tool_menu', tool_graphs_menu_get_list()); $view_domain_id = nt_auth_get_session_var('view_domain_id'); $view_shard_id = nt_auth_get_session_var('view_shard_id'); $view_time_highframe = nt_auth_get_session_var('view_time_highframe'); $view_time_lowframe = nt_auth_get_session_var('view_time_lowframe'); if (!$view_domain_id) { $view_domain_id = $nel_user['group_default_domain_id']; $view_shard_id = $nel_user['group_default_shard_id']; nt_auth_set_session_var('view_domain_id', $view_domain_id); nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (isset($NELTOOL['GET_VARS']['domain'])) { if ($view_domain_id != $NELTOOL['GET_VARS']['domain']) { $view_domain_id = $NELTOOL['GET_VARS']['domain']; nt_auth_set_session_var('view_domain_id', $view_domain_id); $view_shard_id = null; nt_auth_unset_session_var('view_shard_id'); } } if (isset($NELTOOL['GET_VARS']['shard'])) { $view_shard_id = $NELTOOL['GET_VARS']['shard']; nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (isset($NELTOOL['GET_VARS']['highframe'])) { $view_time_highframe = $NELTOOL['GET_VARS']['highframe']; nt_auth_set_session_var('view_time_highframe', $view_time_highframe); } if (isset($NELTOOL['GET_VARS']['lowframe'])) { $view_time_lowframe = $NELTOOL['GET_VARS']['lowframe']; nt_auth_set_session_var('view_time_lowframe', $view_time_lowframe); } if ($view_time_highframe == null) { $view_time_highframe = tool_graphs_time_frame_get_default($tool_hires_frames); } if ($view_time_lowframe == null) { $view_time_lowframe = tool_graphs_time_frame_get_default($tool_lowres_frames); } $current_refresh_rate = nt_auth_get_session_var('current_refresh_rate'); if (isset($_POST['services_refresh'])) { if ($current_refresh_rate != $_POST['services_refresh']) { $current_refresh_rate = $_POST['services_refresh']; nt_auth_set_session_var('current_refresh_rate',$current_refresh_rate); } } if ($current_refresh_rate == null) { $current_refresh_rate = 0; } elseif ($current_refresh_rate > 0) { $tpl->assign('nel_tool_refresh', ''); } $tpl->assign('tool_refresh_list', $refresh_rates); $tpl->assign('tool_refresh_rate', $current_refresh_rate); $tpl->assign('tool_domain_list', $nel_user['access']['domains']); $tpl->assign('tool_domain_selected', $view_domain_id); $tpl->assign('tool_shard_list', $nel_user['access']['shards']); $tpl->assign('tool_shard_selected', $view_shard_id); $tool_shard_filters = tool_main_get_shard_ids($view_shard_id); $tpl->assign('tool_shard_filters', $tool_shard_filters); if ($view_domain_id) { $tool_as_error = null; $AS_Name = tool_main_get_domain_name($view_domain_id); $AS_Host = tool_main_get_domain_host($view_domain_id); $AS_Port = tool_main_get_domain_port($view_domain_id); $AS_ShardName = tool_main_get_shard_name($view_shard_id); $AS_InternalName = tool_main_get_shard_as_id($view_shard_id); $AS_RRDPath = tool_main_get_domain_rrd_path($view_domain_id); if ($AS_RRDPath != "") { // lets make sure there is a trailing / if (substr($AS_RRDPath, -1) != '/') $AS_RRDPath .= '/'; $tpl->assign('tool_page_title', 'Graphs - '. $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : '')); switch($NELTOOL['GET_VARS']['toolmode']) { case 'ccu': /* * ################################################################################################### * CCU Pages * ################################################################################################### */ $tpl->assign('tool_frame_list', $tool_lowres_frames); $tpl->assign('tool_frame_selected', $view_time_lowframe); if ($view_time_lowframe) { $graph_data_tmp = tool_graphs_get_list_v2($AS_RRDPath, strtolower($AS_InternalName), false, true); $tool_tech_graph_list = array( array('service' => 'fes', 'variable' => 'FPSProcessMsg'), ); $graph_list = tool_graphs_find($tool_tech_graph_list, $graph_data_tmp['datas']); nt_common_add_debug($graph_list); $rrd_webs = array(); reset($graph_list); foreach($graph_list as $graph_item) { $rrd_path = $AS_RRDPath . $graph_item['rd_file']; $rrd_def = "DEF:val=". $rrd_path .":var:AVERAGE"; $rrd_draw = "LINE2:val#0000FF --no-legend"; $rrd_output = NELTOOL_RRDSYSBASE . $graph_item['rd_file'] ."-". $view_time_lowframe .".gif"; $rrd_web = NELTOOL_RRDWEBBASE . $graph_item['rd_file'] ."-". $view_time_lowframe .".gif"; $rrd_exec = NELTOOL_RRDTOOL ." graph ". $rrd_output ." --width 916 --height 110 --start -". $view_time_lowframe ." ". $rrd_def ." ". $rrd_draw; nt_common_add_debug($rrd_exec); exec($rrd_exec, $rrd_result, $rrd_code); $file_description = str_replace(array('.rrd','.hrd','.'), array('', '', ' - '), $graph_item['rd_file']); $time_string = ''; tool_main_get_elapsed_time_string($view_time_lowframe, $time_string); $rrd_webs[] = array('desc' => $file_description .' over '. $time_string, 'img' => $rrd_web); } } $tpl->assign('tool_rrd_output', $rrd_webs); break; case 'tech': /* * ################################################################################################### * Tech Shard Pages (Low Res) // ts_mainland01.TotalSpeedLoop.rrd // egs_mainland01.NbPlayers.rrd // egs_mainland01.ProcessUsedMemory.rrd // egs_mainland01.TickSpeedLoop.rrd * ################################################################################################### */ $tpl->assign('tool_frame_list', $tool_lowres_frames); $tpl->assign('tool_frame_selected', $view_time_lowframe); if ($view_shard_id && $view_time_lowframe) { $graph_data_tmp = tool_graphs_get_list_v2($AS_RRDPath, strtolower($AS_InternalName), false); //print_r($graph_data_tmp);print_r('
'); $tool_tech_graph_list = array( array('service' => 'pds', 'variable' => 'ProcessUsedMemory'), array('service' => 'egs', 'variable' => 'ProcessUsedMemory'), array('service' => 'fes', 'variable' => 'ProcessUsedMemory'), array('service' => 'fes', 'variable' => 'FPSProcessMsg'), ); $graph_list = tool_graphs_find($tool_tech_graph_list, $graph_data_tmp['datas']); nt_common_add_debug($graph_list); $rrd_webs = array(); reset($graph_list); foreach($graph_list as $graph_item) { $rrd_path = $AS_RRDPath . $graph_item['rd_file']; $rrd_path = str_replace("\\","\\\\",$rrd_path); $rrd_def = "DEF:val=". $rrd_path .":var:AVERAGE"; $rrd_draw = "LINE2:val#0000FF --no-legend"; $rrd_output = NELTOOL_RRDSYSBASE . $graph_item['rd_file'] ."-". $view_time_lowframe .".gif"; $rrd_web = NELTOOL_RRDWEBBASE . $graph_item['rd_file'] ."-". $view_time_lowframe .".gif"; $rrd_exec = NELTOOL_RRDTOOL ." graph ". $rrd_output ." --width 916 --height 110 --start -". $view_time_lowframe ." ". $rrd_def ." ". $rrd_draw; nt_common_add_debug($rrd_exec); exec($rrd_exec, $rrd_result, $rrd_code); nt_common_add_debug($rrd_result); nt_common_add_debug($rrd_code); $file_description = str_replace(array('.rrd','.hrd','.'), array('', '', ' - '), $graph_item['rd_file']); $time_string = ''; tool_main_get_elapsed_time_string($view_time_lowframe, $time_string); $rrd_webs[] = array('desc' => $file_description .' over '. $time_string, 'img' => $rrd_web); } $tpl->assign('tool_rrd_output', $rrd_webs); } break; case 'hires': /* * ################################################################################################### * Hi-Res Shard Pages // ts_mainland01.TotalSpeedLoop.hrd // egs_mainland01.TickSpeedLoop.hrd // ais_fyros_mainland01.ProcessUsedMemory.hrd // ais_matis_mainland01.ProcessUsedMemory.hrd // ais_zorai_mainland01.ProcessUsedMemory.hrd // ais_tryker_mainland01.ProcessUsedMemory.hrd // ais_pr_mainland01.ProcessUsedMemory.hrd // ais_newbyland_mainland01.ProcessUsedMemory.hrd // gpms_mainland01.ProcessUsedMemory.hrd // fes_mainland01.ProcessUsedMemory.hrd * ################################################################################################### */ $tpl->assign('tool_frame_list', $tool_hires_frames); $tpl->assign('tool_frame_selected', $view_time_highframe); if ($view_shard_id && $view_time_highframe) { $graph_data_tmp = tool_graphs_get_list_v2($AS_RRDPath, strtolower($AS_InternalName), true); $tool_tech_graph_list = array( array('service' => 'ts', 'variable' => 'TotalSpeedLoop'), array('service' => 'egs', 'variable' => 'TickSpeedLoop'), array('service' => 'ais', 'variable' => 'TickSpeedLoop'), array('service' => 'gpms', 'variable' => 'TickSpeedLoop'), array('service' => 'fes', 'variable' => 'TickSpeedLoop'), ); $graph_list = tool_graphs_find($tool_tech_graph_list, $graph_data_tmp['datas']); nt_common_add_debug($graph_list); $adminService = new MyAdminService; if (@$adminService->connect($AS_Host, $AS_Port, $res) === false) { nt_common_add_debug($res); $tpl->assign('tool_domain_error', $res ); } else { $now = time(); $rrd_webs = array(); reset($graph_list); foreach($graph_list as $graph_item) { nt_common_add_debug(" getHighRezGraph : ". $graph_item['service'] .".". $graph_item['variable'] ." , ". ($now - ($view_time_highframe / 1000)) ." , ". $now ." , 0"); $tmp = $adminService->getHighRezGraph($graph_item['service'] .'.'. $graph_item['variable'], $now - ($view_time_highframe / 1000), $now, 0); //nt_common_add_debug($tmp); $mean_values = tool_graphs_extract_mean_values($tmp); //nt_common_add_debug($mean_values); if (sizeof($mean_values['val'])) { $graph = new Graph(1000,150); $graph->SetMargin(35,10,5,25); // left - right - top - bottom $graph->SetScale("intlin"); $graph->xgrid->Show(true,true); $graph->ygrid->Show(true,true); $graph->xaxis->SetLabelFormatCallback('tool_graphs_xaxis_callback'); $line = new LinePlot($mean_values['val'], $mean_values['ref']); $line->SetColor('blue'); $line->SetFillColor('lightblue'); $graph->Add($line); $high_sys_name = NELTOOL_RRDSYSBASE . $graph_item['rd_file'] ."-". $view_time_highframe .'_0.png'; $high_web_name = NELTOOL_RRDWEBBASE . $graph_item['rd_file'] ."-". $view_time_highframe .'_0.png'; $graph->Stroke($high_sys_name); $file_description = str_replace(array('.rrd','.hrd','.'), array('', '', ' - '), $graph_item['rd_file']); $time_string = ''; tool_main_get_elapsed_time_string($view_time_highframe / 1000, $time_string); $rrd_webs[] = array('desc' => $file_description .' over '. $time_string .' - ('. sizeof($mean_values['val']) .' values)', 'img' => $high_web_name); } else { $rrd_webs[] = array('desc' => 'Not enough values to render plot for '. $graph_item['rd_file'] .' over '. ($view_time_highframe / 1000) .'s.', 'img' => ''); } } } } $tpl->assign('tool_rrd_high_output', $rrd_webs); break; case 'old': /* * ################################################################################################### * Old Page * ################################################################################################### */ $tool_as_error = null; if ($AS_Host && $AS_Port) { $graph_data_tmp = tool_graphs_get_list($AS_RRDPath, strtolower($AS_InternalName)); $graph_variables = $graph_data_tmp['variables']; $graph_datas = $graph_data_tmp['datas']; if (sizeof($graph_datas)) { $tpl->assign('tool_graph_list', true); $tpl->assign('tool_graph_variables', $graph_variables); $tpl->assign('tool_graph_datas', $graph_datas); $tool_variable_selected = $_GET['variable']; $tool_service_selected = $_GET['service']; $tpl->assign('tool_graph_variable_selected', $tool_variable_selected); $tpl->assign('tool_graph_service_selected', $tool_service_selected); $tool_selected_variable_data = tool_graphs_get_data($graph_datas, $tool_variable_selected, $tool_service_selected); if ($tool_selected_variable_data['low_file'] != '') { $rrd_values = array(1200, 10800, 86400, 604800, 2592000, 7776000); // 20mins, 3h, 24h, 7days, 30 days, 90 days (unit is 1 second) $rrd_path = $AS_RRDPath . $tool_selected_variable_data['low_file']; $rrd_def = "DEF:val=". $rrd_path .":var:AVERAGE"; $rrd_draw = "LINE2:val#0000FF"; $rrd_webs = array(); reset($rrd_values); foreach($rrd_values as $rrd_value) { $rrd_output = NELTOOL_RRDSYSBASE . $tool_selected_variable_data['low_file'] ."-". $rrd_value .".gif"; $rrd_web = NELTOOL_RRDWEBBASE . $tool_selected_variable_data['low_file'] ."-". $rrd_value .".gif"; $rrd_exec = NELTOOL_RRDTOOL ." graph ". $rrd_output ." --start -". $rrd_value ." ". $rrd_def ." ". $rrd_draw; nt_common_add_debug($rrd_exec); exec($rrd_exec, $rrd_result, $rrd_code); $rrd_webs[] = array('desc' => $tool_selected_variable_data['low_file'] .' over '. $rrd_value .'s.', 'img' => $rrd_web); } $tpl->assign('tool_rrd_output', $rrd_webs); } if ($tool_selected_variable_data['high_file'] != '') { $rrd_webs = array(); $rrd_values = array(array(10000,10), array(30000,10), array(90000,10)); // 10s, 30s, 90s (unit is 1 ms) $adminService = new MyAdminService; if (@$adminService->connect($AS_Host, $AS_Port, $res) === false) { nt_common_add_debug($res); $tpl->assign('tool_domain_error', $res ); } else { $now = time(); $rrd_webs = array(); reset($rrd_values); foreach($rrd_values as $rrd_value) { nt_common_add_debug(" getHighRezGraph : ". $tool_selected_variable_data['service'] .".". $tool_selected_variable_data['variable'] ." , ". ($now - ($rrd_value[0] / 1000)) ." , ". $now ." , ". $rrd_value[1]); $tmp = $adminService->getHighRezGraph($tool_selected_variable_data['service'] .'.'. $tool_selected_variable_data['variable'], $now - ($rrd_value[0] / 1000), $now, $rrd_value[1]); //nt_common_add_debug(" getHighRezGraph : ". $tool_selected_variable_data['service'] .".". $tool_selected_variable_data['variable'] ." , ". ($rrd_value[0] / 1000) ." , 0 , 0"); //$tmp = $adminService->getHighRezGraph($tool_selected_variable_data['service'] .'.'. $tool_selected_variable_data['variable'], ($rrd_value[0] / 1000), 0, 0); nt_common_add_debug($tmp); $mean_values = tool_graphs_extract_mean_values($tmp); nt_common_add_debug($mean_values); if (sizeof($mean_values['val'])) { $graph = new Graph(480,160); $graph->SetMargin(35,10,5,25); // left - right - top - bottom // Now specify the X-scale explicit but let the Y-scale be auto-scaled //$graph->SetScale("intlin",0,0,$adjstart,$adjend); $graph->SetScale("intlin"); // display grids $graph->xgrid->Show(true,true); $graph->ygrid->Show(true,true); //$graph->SetGridDepth(DEPTH_FRONT); // Setup the callback and adjust the angle of the labels $graph->xaxis->SetLabelFormatCallback('tool_graphs_xaxis_callback'); //$graph->xaxis->title->Set("ms."); //$graph->xaxis->SetLabelAngle(90); // Set the labels every 5min (i.e. 300seconds) and minor ticks every minute //$graph->xaxis->scale->ticks->Set(1000); //$graph->yscale->SetAutoTicks(); $line = new LinePlot($mean_values['val'], $mean_values['ref']); $line->SetColor('blue'); $line->SetFillColor('lightblue'); $graph->Add($line); $high_sys_name = NELTOOL_RRDSYSBASE . $tool_selected_variable_data['high_file'] ."-". $rrd_value[0] .'_'. $rrd_value[1] .".png"; $high_web_name = NELTOOL_RRDWEBBASE . $tool_selected_variable_data['high_file'] ."-". $rrd_value[0] .'_'. $rrd_value[1] .".png"; $graph->Stroke($high_sys_name); $rrd_webs[] = array('desc' => $tool_selected_variable_data['high_file'] .' over '. ($rrd_value[0] / 1000) .'s. ('. sizeof($mean_values['val']) .' values)', 'img' => $high_web_name); } else { $rrd_webs[] = array('desc' => 'Not enough values to render plot for '. $tool_selected_variable_data['high_file'] .' over '. ($rrd_value[0] / 1000) .'s.', 'img' => ''); } } $tpl->assign('tool_rrd_high_output', $rrd_webs); } } } } break; } } else { $tpl->assign('tool_domain_error', "This domain has not been configured to handle graphs!"); } } else { } $tpl->display($tool_menu_item['tpl']); ?> ================================================ FILE: tools/server/admin/tool_guild_locator.php ================================================ assign('tool_title', "Guild Locator"); $view_domain_id = nt_auth_get_session_var('view_domain_id'); $view_shard_id = nt_auth_get_session_var('view_shard_id'); if (!$view_domain_id) { $view_domain_id = $nel_user['group_default_domain_id']; $view_shard_id = $nel_user['group_default_shard_id']; nt_auth_set_session_var('view_domain_id', $view_domain_id); nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (isset($NELTOOL['GET_VARS']['domain'])) { if ($view_domain_id != $NELTOOL['GET_VARS']['domain']) { $view_domain_id = $NELTOOL['GET_VARS']['domain']; nt_auth_set_session_var('view_domain_id', $view_domain_id); $view_shard_id = null; nt_auth_unset_session_var('view_shard_id'); } } if (isset($NELTOOL['GET_VARS']['shard'])) { $view_shard_id = $NELTOOL['GET_VARS']['shard']; nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (isset($NELTOOL['GET_VARS']['refdata'])) { $tmp_data = unserialize(base64_decode($NELTOOL['GET_VARS']['refdata'])); if (is_array($tmp_data)) { $NELTOOL['POST_VARS'] = $tmp_data; } } $current_refresh_rate = nt_auth_get_session_var('current_refresh_rate'); if (isset($_POST['services_refresh'])) { if ($current_refresh_rate != $_POST['services_refresh']) { $current_refresh_rate = $_POST['services_refresh']; nt_auth_set_session_var('current_refresh_rate',$current_refresh_rate); } } if ($current_refresh_rate == null) { $current_refresh_rate = 0; } elseif ($current_refresh_rate > 0) { $tpl->assign('nel_tool_refresh', ''); } $tpl->assign('tool_refresh_list', $refresh_rates); $tpl->assign('tool_refresh_rate', $current_refresh_rate); $tpl->assign('tool_domain_list', $nel_user['access']['domains']); $tpl->assign('tool_domain_selected', $view_domain_id); $tpl->assign('tool_shard_list', $nel_user['access']['shards']); $tpl->assign('tool_shard_selected', $view_shard_id); $tool_shard_filters = tool_main_get_shard_ids($view_shard_id); $tpl->assign('tool_shard_filters', $tool_shard_filters); if (tool_admin_applications_check('tool_guild_locator_manage_guild')) $tpl->assign('restriction_tool_guild_locator_manage_guild',true); if (tool_admin_applications_check('tool_guild_locator_manage_members')) $tpl->assign('restriction_tool_guild_locator_manage_members',true); if (tool_admin_applications_check('tool_guild_locator_manage_forums')) $tpl->assign('restriction_tool_guild_locator_manage_forums',true); if ($view_domain_id) { $tool_as_error = null; $AS_Name = tool_main_get_domain_name($view_domain_id); $AS_Host = tool_main_get_domain_host($view_domain_id); $AS_Port = tool_main_get_domain_port($view_domain_id); $AS_ShardName = tool_main_get_shard_name($view_shard_id); $MFS_Web = tool_main_get_domain_data($view_domain_id, 'domain_mfs_web'); $tpl->assign('tool_page_title', 'Guild Locator - '. $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : '')); $tool_as_error = null; if ($AS_Host && $AS_Port) { $adminService = new MyAdminService; if (@$adminService->connect($AS_Host, $AS_Port, $res) === false) { nt_common_add_debug($res); $tpl->assign('tool_domain_error', $res ); } else { $tool_services_gl = null; if (isset($NELTOOL['POST_VARS']['services_gl'])) $tool_services_gl = $NELTOOL['POST_VARS']['services_gl']; elseif (isset($NELTOOL['GET_VARS']['services_gl'])) $tool_services_gl = $NELTOOL['GET_VARS']['services_gl']; if ($tool_services_gl) { $tpl->assign('tool_post_data', base64_encode(serialize($NELTOOL['POST_VARS']))); switch ($tool_services_gl) { case 'display guilds': $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { $service_command = 'dumpGuildList local'; nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $tpl->assign('tool_execute_result', ''); $command_return_data = array(); reset($service_list); foreach($service_list as $service) { //nt_common_add_debug("about to run 'displayPlayers' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { // the locator displays a nice output, no need for the raw one //$tpl->assign('tool_execute_command', $service_command); } } if (sizeof($command_return_data)) { $guild_data = tool_gl_parse_dump_guild_list($command_return_data); $tpl->assign('tool_guild_data', $guild_data); } } break; case 'update name': if (($tool_services_gl == 'update name') && tool_admin_applications_check('tool_guild_locator_manage_guild')) { $service = $NELTOOL['POST_VARS']['servicealias']; $guild_shard_id = $NELTOOL['POST_VARS']['guildshardid']; $guild_id = $NELTOOL['POST_VARS']['guildid']; $new_guild_name = $NELTOOL['POST_VARS']['new_guild_name']; $new_guild_name = trim($new_guild_name); if (ereg("^[a-zA-Z0-9\ ]+$", $new_guild_name)) { // this is a small hack that was done by daniel so i could use the renameGuild command without an EID $service_command = 'renameGuild admin_tool '. $guild_shard_id .':'. $guild_id .' "'. $new_guild_name .'"'; nt_log("Domain '$AS_Name' : '$service_command' on ". $service); $tpl->assign('tool_execute_result', ''); $command_return_data = array(); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { // tool_guild_errors } } else { $tpl->assign('tool_guild_errors', array('New name contains illegal characters.')); } $NELTOOL['GET_VARS']['servicealias'] = $service; $NELTOOL['GET_VARS']['guildshardid'] = $guild_shard_id; $NELTOOL['GET_VARS']['guildid'] = $guild_id; } case 'update description': if (($tool_services_gl == 'update description') && tool_admin_applications_check('tool_guild_locator_manage_guild')) { $service = $NELTOOL['POST_VARS']['servicealias']; $guild_shard_id = $NELTOOL['POST_VARS']['guildshardid']; $guild_id = $NELTOOL['POST_VARS']['guildid']; $new_guild_desc = $NELTOOL['POST_VARS']['new_guild_description']; $new_guild_desc = trim($new_guild_desc); if (ereg("^[a-zA-Z0-9\ ]+$", $new_guild_desc)) { $service_command = 'setGuildDescription '. $guild_shard_id .':'. $guild_id .' "'. $new_guild_desc .'"'; nt_log("Domain '$AS_Name' : '$service_command' on ". $service); $tpl->assign('tool_execute_result', ''); $command_return_data = array(); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { // tool_guild_errors } } else { $tpl->assign('tool_guild_errors', array('New description contains illegal characters.')); } $NELTOOL['GET_VARS']['servicealias'] = $service; $NELTOOL['GET_VARS']['guildshardid'] = $guild_shard_id; $NELTOOL['GET_VARS']['guildid'] = $guild_id; } case 'setleader': if (($tool_services_gl == 'setleader') && tool_admin_applications_check('tool_guild_locator_manage_members')) { $service = $NELTOOL['GET_VARS']['servicealias']; $guild_shard_id = $NELTOOL['GET_VARS']['guildshardid']; $guild_id = $NELTOOL['GET_VARS']['guildid']; $member_eid = $NELTOOL['GET_VARS']['eid']; // guildSetLeader : $service_command = 'guildSetLeader '. $guild_shard_id .':'. $guild_id .' '. $member_eid; nt_log("Domain '$AS_Name' : '$service_command' on ". $service); $tpl->assign('tool_execute_result', ''); $command_return_data = array(); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { // the locator displays a nice output, no need for the raw one //$tpl->assign('tool_execute_command', $service_command); $tpl->assign('tool_guild_errors', tool_gl_parse_grade_change($command_return_data)); } } case 'promote': if (($tool_services_gl == 'promote') && tool_admin_applications_check('tool_guild_locator_manage_members')) { $service = $NELTOOL['GET_VARS']['servicealias']; $guild_shard_id = $NELTOOL['GET_VARS']['guildshardid']; $guild_id = $NELTOOL['GET_VARS']['guildid']; $member_eid = $NELTOOL['GET_VARS']['eid']; $member_grade = $NELTOOL['GET_VARS']['grade']; $new_grade = 'Member'; if ($member_grade == 'Officer') $new_grade = 'Officer'; elseif ($member_grade == 'HighOfficer') $new_grade = 'HighOfficer'; // guildSetGrade : $service_command = 'guildSetGrade '. $guild_shard_id .':'. $guild_id .' '. $member_eid .' '. $new_grade; nt_log("Domain '$AS_Name' : '$service_command' on ". $service); $tpl->assign('tool_execute_result', ''); $command_return_data = array(); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { // the locator displays a nice output, no need for the raw one //$tpl->assign('tool_execute_command', $service_command); $tpl->assign('tool_guild_errors', tool_gl_parse_grade_change($command_return_data)); } } case 'demote': if (($tool_services_gl == 'demote') && tool_admin_applications_check('tool_guild_locator_manage_members')) { $service = $NELTOOL['GET_VARS']['servicealias']; $guild_shard_id = $NELTOOL['GET_VARS']['guildshardid']; $guild_id = $NELTOOL['GET_VARS']['guildid']; $member_eid = $NELTOOL['GET_VARS']['eid']; $member_grade = $NELTOOL['GET_VARS']['grade']; $new_grade = 'Member'; if ($member_grade == 'Officer') $new_grade = 'Officer'; elseif ($member_grade == 'Member') $new_grade = 'Member'; // guildSetGrade : $service_command = 'guildSetGrade '. $guild_shard_id .':'. $guild_id .' '. $member_eid .' '. $new_grade; nt_log("Domain '$AS_Name' : '$service_command' on ". $service); $tpl->assign('tool_execute_result', ''); $command_return_data = array(); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { // the locator displays a nice output, no need for the raw one //$tpl->assign('tool_execute_command', $service_command); $tpl->assign('tool_guild_errors', tool_gl_parse_grade_change($command_return_data)); } } case 'dumpguild': $service = $NELTOOL['GET_VARS']['servicealias']; $guild_shard_id = $NELTOOL['GET_VARS']['guildshardid']; $guild_id = $NELTOOL['GET_VARS']['guildid']; if (($guild_shard_id > 0) && ($guild_id > 0) && ($service != '')) { $service_command = 'dumpGuild '. $guild_shard_id .':'. $guild_id; nt_log("Domain '$AS_Name' : '$service_command' on ". $service); $tpl->assign('tool_execute_result', ''); $command_return_data = array(); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { // the locator displays a nice output, no need for the raw one //$tpl->assign('tool_execute_command', $service_command); } if (sizeof($command_return_data)) { $tool_sub_services_gl = null; if (isset($NELTOOL['POST_VARS']['subservices_gl'])) $tool_sub_services_gl = $NELTOOL['POST_VARS']['subservices_gl']; elseif (isset($NELTOOL['GET_VARS']['subservices_gl'])) $tool_sub_services_gl = $NELTOOL['GET_VARS']['subservices_gl']; $guild_dump_data = tool_gl_parse_dump_guild($command_return_data); $tpl->assign('tool_guild_dump_data', $guild_dump_data); $tpl->assign('tool_service', $service); // view ingame guild forums if (tool_admin_applications_check('tool_guild_locator_manage_forums')) { if ($tool_sub_services_gl) { switch ($tool_sub_services_gl) { case 'viewthread': $view_forum_threadid = $NELTOOL['GET_VARS']['threadid']; $view_forum_recoverable = $NELTOOL['GET_VARS']['recoverable']; $thread_name = ($view_forum_recoverable == 1 ? '_':'') .'thread_'. $view_forum_threadid .'.index'; $view_thread_data_raw = tool_gl_view_forum($MFS_Web, $guild_shard_id, $guild_dump_data['guild_name'], $thread_name); $view_thread_data = tool_gl_parse_thread_view($view_thread_data_raw); $tpl->assign('tool_guild_thread', $view_thread_data); break; case 'recoverthread': $recover_forum_threadid = $NELTOOL['GET_VARS']['threadid']; $thread_name = '_thread_'. $recover_forum_threadid .'.index'; tool_gl_view_forum($MFS_Web, $guild_shard_id, $guild_dump_data['guild_name'], $recover_forum_threadid, true); break; } } $view_forum_data_raw = tool_gl_view_forum($MFS_Web, $guild_shard_id, $guild_dump_data['guild_name']); $view_forum_data = tool_gl_parse_forum_view($view_forum_data_raw); if (is_array($view_forum_data)) $tpl->assign('tool_guild_forums', $view_forum_data); else $tpl->assign('tool_guild_forums_error', $view_forum_data); } } } break; } } if (isset($NELTOOL['GET_VARS']['eid'])) { $locate_eid = $NELTOOL['GET_VARS']['eid']; } $status = $adminService->getStates(); nt_common_add_debug($status); $domainServices = tool_main_parse_status($status); $filteredServices = array(); reset($domainServices); foreach($domainServices as $aKey => $aService) { // we are only interested in EGS if ($aService['ShortName'] == 'EGS') { $filteredServices[] = $aService; } } $tpl->assign('tool_services_list', $filteredServices); } } } $tpl->display('tool_guild_locator.tpl'); ?> ================================================ FILE: tools/server/admin/tool_log_analyser.php ================================================ assign('tool_title', "Log Analyser"); $view_domain_id = nt_auth_get_session_var('view_domain_id'); $view_shard_id = nt_auth_get_session_var('view_shard_id'); if (!$view_domain_id) { $view_domain_id = $nel_user['group_default_domain_id']; $view_shard_id = $nel_user['group_default_shard_id']; nt_auth_set_session_var('view_domain_id', $view_domain_id); nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (isset($NELTOOL['GET_VARS']['domain'])) { if ($view_domain_id != $NELTOOL['GET_VARS']['domain']) { $view_domain_id = $NELTOOL['GET_VARS']['domain']; nt_auth_set_session_var('view_domain_id', $view_domain_id); $view_shard_id = null; nt_auth_unset_session_var('view_shard_id'); } } if (isset($NELTOOL['GET_VARS']['shard'])) { $view_shard_id = $NELTOOL['GET_VARS']['shard']; nt_auth_set_session_var('view_shard_id', $view_shard_id); } $tpl->assign('tool_domain_list', $nel_user['access']['domains']); $tpl->assign('tool_domain_selected', $view_domain_id); $tpl->assign('tool_shard_list', $nel_user['access']['shards']); $tpl->assign('tool_shard_selected', $view_shard_id); $tool_shard_filters = tool_main_get_shard_ids($view_shard_id); $tpl->assign('tool_shard_filters', $tool_shard_filters); //$nel_tool_notes_meta = "\n"; //$nel_tool_notes_meta .= "\n"; //$nel_tool_notes_meta .= "\n"; //$tpl->assign('nel_tool_notes_meta', $nel_tool_notes_meta); $template_file = 'tool_log_analyser.tpl'; if ($view_domain_id) { $tool_as_error = null; $AS_Name = tool_main_get_domain_name($view_domain_id); $AS_Host = tool_main_get_domain_host($view_domain_id); $AS_Port = tool_main_get_domain_port($view_domain_id); $AS_ShardName = tool_main_get_shard_name($view_shard_id); $tpl->assign('tool_page_title', 'Log Analyser - '. $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : '')); $tool_as_error = null; $AS_LAS_AdminPath = tool_main_get_domain_data($view_domain_id, 'domain_las_admin_path'); $AS_LAS_LocalPath = tool_main_get_domain_data($view_domain_id, 'domain_las_local_path'); $tool_las_file_list = tool_las_get_file_list($AS_LAS_AdminPath); if (isset($NELTOOL['GET_VARS']['fileview'])) { // FILE VIEWER $template_file = 'tool_log_analyser_file_view.tpl'; $view_file_name = base64_decode($NELTOOL['GET_VARS']['fileview']); $tpl->assign('tool_file_list', $tool_las_file_list); $view_file_data = tool_las_check_for_file($tool_las_file_list, $view_file_name); if (isset($NELTOOL['GET_VARS']['downloadraw'])) { if ($fp = fopen($view_file_data['path'] . $view_file_data['name'], 'r')) { header("Content-type: text/plain"); header("Content-Disposition: attachment; filename=las_raw_". $view_file_data['name']); header("Pragma: no-cache"); header("Expires: 0"); fpassthru($fp); fclose($fp); exit(); } } elseif (isset($NELTOOL['GET_VARS']['downloadparsed'])) { $char_eid_data = tool_las_parse_file($view_file_data['path'] . $view_file_data['name']); // NOTE: 'ring_live' needs to be replace with the ringdb field from the domain table $db_char_data = tool_las_get_character_names('ring_live', $char_eid_data); if (sizeof($db_char_data)) { $search_eid_ary = array(); $search_char_ary = array(); reset($char_eid_data); foreach($char_eid_data as $char_id => $char_eid) { if (isset($db_char_data[$char_id])) { $search_eid_ary[] = $char_eid; $search_char_ary[] = $db_char_data[$char_id]; } } tool_las_fpassthru_replace($view_file_data['path'],$view_file_data['name'], $search_eid_ary, $search_char_ary); exit(); } } //elseif (isset($NELTOOL['GET_VARS']['delete'])) //{ // nt_common_add_debug('unlinking file : '. $view_file_data['path'] . $view_file_data['name']); // @unlink($view_file_data['path'] . $view_file_data['name']); // nt_common_redirect('tool_log_analyser.php'); // exit(); //} elseif (is_array($view_file_data)) { $tpl->assign('tool_view_file_data', $view_file_data); $file_line_start = 0; if (isset($NELTOOL['GET_VARS']['viewstart'])) { $file_line_start = $NELTOOL['GET_VARS']['viewstart']; } $file_line_read_max = 200; $view_file_output_data = tool_las_read_file($view_file_data['path'] . $view_file_data['name'], $file_line_read_max, $file_line_start, $file_line_start_previous, $file_line_start_next); $tpl->assign('tool_file_output', $view_file_output_data); $tpl->assign('tool_view_line_start_previous', $file_line_start_previous); $tpl->assign('tool_view_line_start_next', $file_line_start_next); } else { $tpl->assign('tool_file_error', 'File not found !'); } } elseif (($AS_LAS_AdminPath != '') && ($AS_LAS_LocalPath != '')) { // REGULAR SERVICE VIEW WITH COMMANDS $tpl->assign('tool_file_list', $tool_las_file_list); if (substr($AS_LAS_AdminPath,-1) != '/') $AS_LAS_AdminPath .= '/'; if (substr($AS_LAS_LocalPath,-1) != '/') $AS_LAS_LocalPath .= '/'; if ($AS_Host && $AS_Port) { $adminService = new MyAdminService; if (@$adminService->connect($AS_Host, $AS_Port, $res) === false) { nt_common_add_debug($res); $tpl->assign('tool_domain_error', $res ); } else { if (isset($NELTOOL['POST_VARS']['services_las'])) { $tool_services_las = $NELTOOL['POST_VARS']['services_las']; $tpl->assign('tool_post_data', base64_encode(serialize($NELTOOL['POST_VARS']))); $service_search_database = $NELTOOL['POST_VARS']['service_search_database']; $service_search_file_name = $NELTOOL['POST_VARS']['service_search_file_name']; $service_search_start_date = $NELTOOL['POST_VARS']['service_search_start_date']; $service_search_end_date = $NELTOOL['POST_VARS']['service_search_end_date']; $tpl->assign('tool_form_service_search_database', $service_search_database); $tpl->assign('tool_form_service_search_file_name', $service_search_file_name); $tpl->assign('tool_form_service_search_start_date', $service_search_start_date); $tpl->assign('tool_form_service_search_end_date', $service_search_end_date); $file_name_error_msg = null; $start_date_error_msg = null; switch ($tool_services_las) { case 'search eids': if ($service_search_file_name == '') $file_name_error_msg = "Need to specify a filename !"; if ($service_search_start_date == '') $start_date_error_msg = "Need to specify a start date !"; $tpl->assign('tool_file_name_error_msg', $file_name_error_msg); $tpl->assign('tool_start_date_error_msg', $start_date_error_msg); if (isset($NELTOOL['POST_VARS']['service_eids']) && !$file_name_error_msg && !$start_date_error_msg) { $service_eids = trim(stripslashes($NELTOOL['POST_VARS']['service_eids'])); $tpl->assign('tool_form_service_eids', $service_eids); $service_eids_ary = tool_las_parse_eids_to_array($service_eids); nt_common_add_debug($service_eids_ary); if (sizeof($service_eids_ary) > 0) { $service_command = 'executeToFile '. $AS_LAS_LocalPath . $service_search_file_name ; if (sizeof($service_eids_ary) == 1) $service_command .= ' searchEId '; else $service_command .= ' searchEIds '; $service_command .= $service_search_database .' '; $service_command .= implode(' ', $service_eids_ary) .' '; if (sizeof($service_eids_ary) > 1) $service_command .= '- '; $service_command .= $service_search_start_date; if ($service_search_end_date != '') $service_command .= ' '. $service_search_end_date; nt_common_add_debug($service_command); $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); nt_common_add_debug(array_combine($service_list, $service_list)); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $tpl->assign('tool_execute_result', ''); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run command '$service_command' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } } } } } break; case 'search text': if ($service_search_file_name == '') $file_name_error_msg = "Need to specify a filename !"; if ($service_search_start_date == '') $start_date_error_msg = "Need to specify a start date !"; $tpl->assign('tool_file_name_error_msg', $file_name_error_msg); $tpl->assign('tool_start_date_error_msg', $start_date_error_msg); if (isset($NELTOOL['POST_VARS']['service_text']) && !$file_name_error_msg && !$start_date_error_msg) { $service_text = trim(stripslashes(html_entity_decode($NELTOOL['POST_VARS']['service_text'], ENT_QUOTES))); $tpl->assign('tool_form_service_text', htmlentities($service_text,ENT_QUOTES)); if ($service_text != '') { $service_command = 'executeToFile '. $AS_LAS_LocalPath . $service_search_file_name ; $service_command .= ' searchString '. $service_search_database .' "'. addslashes($service_text) .'" '; $service_command .= $service_search_start_date; if ($service_search_end_date != '') $service_command .= ' '. $service_search_end_date; nt_common_add_debug($service_command); $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); nt_common_add_debug(array_combine($service_list, $service_list)); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $tpl->assign('tool_execute_result', ''); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run command '$service_command' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } } } } } break; case 'execute': if (isset($NELTOOL['POST_VARS']['service_command'])) { $service_command = trim(stripslashes(html_entity_decode($NELTOOL['POST_VARS']['service_command'], ENT_QUOTES))); $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); nt_common_add_debug(array_combine($service_list, $service_list)); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $tpl->assign('tool_execute_result', ''); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run command '$service_command' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { $tpl->assign('tool_execute_command', htmlentities($service_command, ENT_QUOTES)); } } } } break; } } $status = $adminService->getStates(); nt_common_add_debug($status); $domainServices = tool_main_parse_status($status); $filteredServices = array(); reset($domainServices); foreach($domainServices as $aKey => $aService) { // we are only interested in EGS if ($aService['ShortName'] == 'LAS') { $filteredServices[] = $aService; } } $tpl->assign('tool_services_list', $filteredServices); } } } } $tpl->display($template_file); ?> ================================================ FILE: tools/server/admin/tool_mfs.php ================================================ assign('tool_title', "Mails & Forums"); $view_domain_id = nt_auth_get_session_var('view_domain_id'); $view_shard_id = nt_auth_get_session_var('view_shard_id'); if (isset($NELTOOL['GET_VARS']['domain'])) { if ($view_domain_id != $NELTOOL['GET_VARS']['domain']) { $view_domain_id = $NELTOOL['GET_VARS']['domain']; nt_auth_set_session_var('view_domain_id', $view_domain_id); $view_shard_id = null; nt_auth_unset_session_var('view_shard_id'); } } if (isset($NELTOOL['GET_VARS']['shard'])) { $view_shard_id = $NELTOOL['GET_VARS']['shard']; nt_auth_set_session_var('view_shard_id', $view_shard_id); } $tpl->assign('tool_domain_list', $nel_user['access']['domains']); $tpl->assign('tool_domain_selected', $view_domain_id); $tpl->assign('tool_shard_list', $nel_user['access']['shards']); $tpl->assign('tool_shard_selected', $view_shard_id); $tool_shard_filters = tool_main_get_shard_ids($view_shard_id); $tpl->assign('tool_shard_filters', $tool_shard_filters); $template_file = 'tool_mfs.tpl'; if ($view_domain_id && $view_shard_id) { $tpl->assign('tool_page_title', 'Mails & Forums'); $tpl->assign('tool_curl_output',tool_mfs_HTTPOpen("http://")); } $tpl->display($template_file); ?> ================================================ FILE: tools/server/admin/tool_notes.php ================================================ assign('tool_title', "Notes"); if (tool_admin_applications_check('tool_notes_global')) $tpl->assign('restriction_tool_notes_global', true); if (isset($NELTOOL['GET_VARS']['note_id'])) { $note_id = $NELTOOL['GET_VARS']['note_id']; $tool_note_data = tool_notes_get_id($nel_user['user_id'], $note_id); $tpl->assign('tool_note_edit_data', $tool_note_data); } if (isset($NELTOOL['POST_VARS']['toolaction'])) { $tool_action = $NELTOOL['POST_VARS']['toolaction']; switch($tool_action) { case 'create': $note_title = $NELTOOL['POST_VARS']['tool_form_note_title']; $note_data = $NELTOOL['POST_VARS']['tool_form_note_data']; $note_active = $NELTOOL['POST_VARS']['tool_form_note_active']; $note_global = (isset($NELTOOL['POST_VARS']['tool_form_note_global']) ? $NELTOOL['POST_VARS']['tool_form_note_global'] : 0); $note_mode = $NELTOOL['POST_VARS']['tool_form_note_mode']; $note_uri = $NELTOOL['POST_VARS']['tool_form_note_popup_uri']; $note_restriction = $NELTOOL['POST_VARS']['tool_form_note_popup_restriction']; $tool_error = tool_notes_add($nel_user['user_id'], $note_title, $note_data, $note_active, $note_global, $note_mode, $note_uri, $note_restriction); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } break; case 'update': $note_id = $NELTOOL['POST_VARS']['tool_form_note_id']; $note_title = $NELTOOL['POST_VARS']['tool_form_note_title']; $note_data = $NELTOOL['POST_VARS']['tool_form_note_data']; $note_active = $NELTOOL['POST_VARS']['tool_form_note_active']; $note_global = (isset($NELTOOL['POST_VARS']['tool_form_note_global']) ? $NELTOOL['POST_VARS']['tool_form_note_global'] : 0); $note_mode = $NELTOOL['POST_VARS']['tool_form_note_mode']; $note_uri = $NELTOOL['POST_VARS']['tool_form_note_popup_uri']; $note_restriction = $NELTOOL['POST_VARS']['tool_form_note_popup_restriction']; $tool_error = tool_notes_update($nel_user['user_id'], $note_id, $note_title, $note_data, $note_active, $note_global, $note_mode, $note_uri, $note_restriction); if ($tool_error != "") { $tpl->assign('tool_alert_message', $tool_error); } break; case 'delete': $note_id = $NELTOOL['POST_VARS']['tool_form_note_id']; tool_notes_del($nel_user['user_id'], $note_id); break; } } $tool_note_list = tool_notes_get_list($nel_user['user_id']); $tpl->assign('tool_note_list', $tool_note_list); $tpl->display('tool_notes.tpl'); ?> ================================================ FILE: tools/server/admin/tool_player_locator.php ================================================ assign('tool_title', "Player Locator"); $view_domain_id = nt_auth_get_session_var('view_domain_id'); $view_shard_id = nt_auth_get_session_var('view_shard_id'); if (!$view_domain_id) { $view_domain_id = $nel_user['group_default_domain_id']; $view_shard_id = $nel_user['group_default_shard_id']; nt_auth_set_session_var('view_domain_id', $view_domain_id); nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (isset($NELTOOL['GET_VARS']['domain'])) { if ($view_domain_id != $NELTOOL['GET_VARS']['domain']) { $view_domain_id = $NELTOOL['GET_VARS']['domain']; nt_auth_set_session_var('view_domain_id', $view_domain_id); $view_shard_id = null; nt_auth_unset_session_var('view_shard_id'); } } if (isset($NELTOOL['GET_VARS']['shard'])) { $view_shard_id = $NELTOOL['GET_VARS']['shard']; nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (isset($NELTOOL['GET_VARS']['refdata'])) { $tmp_data = unserialize(base64_decode($NELTOOL['GET_VARS']['refdata'])); if (is_array($tmp_data)) { $NELTOOL['POST_VARS'] = $tmp_data; } } $current_refresh_rate = nt_auth_get_session_var('current_refresh_rate'); if (isset($_POST['services_refresh'])) { if ($current_refresh_rate != $_POST['services_refresh']) { $current_refresh_rate = $_POST['services_refresh']; nt_auth_set_session_var('current_refresh_rate',$current_refresh_rate); } } if ($current_refresh_rate == null) { $current_refresh_rate = 0; } elseif ($current_refresh_rate > 0) { $tpl->assign('nel_tool_refresh', ''); } $tpl->assign('tool_refresh_list', $refresh_rates); $tpl->assign('tool_refresh_rate', $current_refresh_rate); $tpl->assign('tool_domain_list', $nel_user['access']['domains']); $tpl->assign('tool_domain_selected', $view_domain_id); $tpl->assign('tool_shard_list', $nel_user['access']['shards']); $tpl->assign('tool_shard_selected', $view_shard_id); $tool_shard_filters = tool_main_get_shard_ids($view_shard_id); $tpl->assign('tool_shard_filters', $tool_shard_filters); if (tool_admin_applications_check('tool_player_locator_display_players')) $tpl->assign('restriction_tool_player_locator_display_players', true); if (tool_admin_applications_check('tool_player_locator_locate')) $tpl->assign('restriction_tool_player_locator_locate', true); if (tool_admin_applications_check('tool_player_locator_userid_check')) $tpl->assign('restriction_tool_player_locator_userid_check', true); if (tool_admin_applications_check('tool_player_locator_csr_relocate')) $tpl->assign('restriction_tool_player_locator_csr_relocate', true); if ($view_domain_id) { $tool_as_error = null; $AS_Name = tool_main_get_domain_name($view_domain_id); $AS_Host = tool_main_get_domain_host($view_domain_id); $AS_Port = tool_main_get_domain_port($view_domain_id); $AS_ShardName = tool_main_get_shard_name($view_shard_id); $AS_Application = tool_main_get_domain_data($view_domain_id, 'domain_application'); $AS_RingSQL = tool_main_get_domain_data($view_domain_id, 'domain_sql_string'); $tpl->assign('tool_page_title', 'Player Locator - '. $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : '')); $tool_as_error = null; if ($AS_Host && $AS_Port) { $adminService = new MyAdminService; if (@$adminService->connect($AS_Host, $AS_Port, $res) === false) { nt_common_add_debug($res); $tpl->assign('tool_domain_error', $res ); } else { if (isset($NELTOOL['POST_VARS']['services_pl'])) { $tool_services_pl = $NELTOOL['POST_VARS']['services_pl']; $tpl->assign('tool_post_data', base64_encode(serialize($NELTOOL['POST_VARS']))); switch ($tool_services_pl) { case 'display players': if (tool_admin_applications_check('tool_player_locator_display_players')) { $tool_locate_plname = trim($NELTOOL['POST_VARS']['services_plname_locate']); $tpl->assign('tool_locate_name_value', $tool_locate_plname); $service_list = tool_main_get_checked_services(); if (sizeof($service_list) && ($tool_locate_plname != '')) { $service_command = 'displayPlayers '. $tool_locate_plname; nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $tpl->assign('tool_execute_result', ''); $command_return_data = array(); reset($service_list); foreach($service_list as $service) { //nt_common_add_debug("about to run 'displayPlayers' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { // the locator displays a nice output, no need for the raw one //$tpl->assign('tool_execute_command', $service_command); } } if (sizeof($command_return_data)) { $player_data = tool_pl_parse_display_players($command_return_data); $tpl->assign('tool_player_data', $player_data); } } } break; // case 'csr relocate': case 'ani': case 'ari': case 'lea': if (tool_admin_applications_check('tool_player_locator_csr_relocate')) { $relocate_su = $NELTOOL['POST_VARS']['pl_su']; $relocate_shardid = $NELTOOL['POST_VARS']['relocate_shardid']; $relocate_eid = $NELTOOL['POST_VARS']['relocate_eid']; if ($relocate_eid != 'na' && $relocate_shardid != 'na') { $service = $relocate_su; $service_command = 'cs.relocChar ' . $relocate_eid . ' ' . $relocate_shardid; nt_common_add_debug("about to run command '$service_command' on '$service' ..."); $tpl->assign('tool_execute_result', ''); $command_return_data = array(); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { //$tpl->assign('tool_execute_command', $service_command); } if (sizeof($command_return_data)) { $relocate_data = tool_pl_parse_relocate($command_return_data); $tpl->assign('tool_relocate_data', $relocate_data); } } } //break; case 'locate': if (tool_admin_applications_check('tool_player_locator_locate')) { $tool_locate_name = trim($NELTOOL['POST_VARS']['services_pl_locate']); $tpl->assign('tool_locate_value', $tool_locate_name); $service_list = tool_main_get_checked_services(); if (sizeof($service_list) && ($tool_locate_name != '')) { $service_command = 'playerinfo '. $tool_locate_name; nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); //$tpl->assign('tool_execute_result', ''); $command_return_data = array(); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'playerinfo' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { // the locator displays a nice output, no need for the raw one //$tpl->assign('tool_execute_command', $service_command); $tpl->assign('tool_execute_command', htmlentities($service_command, ENT_QUOTES)); } } // 不拆出来显示了,直接在上面显示了原结果 //if (sizeof($command_return_data)) //{ // $locate_data = tool_pl_parse_locate($command_return_data); // $tpl->assign('tool_locate_data', $locate_data); //} } } break; case 'Compute User IDs and Clear SQL Cache': if (tool_admin_applications_check('tool_player_locator_userid_check')) { $check_su = $NELTOOL['POST_VARS']['pl_su']; tool_pl_fix_character_check_list($AS_Application); $service = $check_su; $service_command = 'sqlObjectCache.clearCache'; nt_common_add_debug("about to run command '$service_command' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } } break; } } if (isset($NELTOOL['GET_VARS']['eid'])) { $locate_eid = $NELTOOL['GET_VARS']['eid']; // someday i'll do something here :) } $status = $adminService->getStates(); nt_common_add_debug($status); $domainServices = tool_main_parse_status($status); $filteredServices = array(); reset($domainServices); foreach($domainServices as $aKey => $aService) { // we are only interested in EGS if ($aService['ShortName'] == 'EGS') { $filteredServices[] = $aService; } } $tpl->assign('tool_services_list', $filteredServices); $tpl->assign('shard_su_name', tool_main_get_su_from_status($domainServices)); // user_id == 0 check system if (tool_admin_applications_check('tool_player_locator_userid_check')) { $user_check_list = tool_pl_get_character_check_list($AS_Application, $AS_RingSQL); $tpl->assign('user_check_list', $user_check_list); } } } } $tpl->display('tool_player_locator.tpl'); ?> ================================================ FILE: tools/server/admin/tool_preferences.php ================================================ assign("tool_title", "My Preferences"); $tpl->assign("tool_v_login", $nel_user['user_name']); $tpl->assign("tool_v_user_id", $nel_user['user_id']); $tpl->assign("tool_v_menu", $nel_user['user_menu_style']); $tpl->assign("tool_v_application", isset($nel_user['user_default_application_id']) ? $nel_user['user_default_application_id']:'') ; if (isset($NELTOOL['POST_VARS']['tool_form_user_id'])) { $post_user_id = $NELTOOL['POST_VARS']['tool_form_user_id']; $tool_action = $NELTOOL['POST_VARS']['toolaction']; switch ($tool_action) { /* * update main preferences */ case 'update': $post_old_pwd = $NELTOOL['POST_VARS']['tool_form_password_old']; $post_new_pwd = $NELTOOL['POST_VARS']['tool_form_password_new']; $post_menu = $NELTOOL['POST_VARS']['tool_form_menu_style']; // update menu style if ($nel_user['user_menu_style'] != $post_menu) { tool_pref_update_menu_style($nel_user, $post_menu); $tpl->assign("tool_v_menu", $post_menu); } // update password if (($post_old_pwd != '') && ($post_new_pwd != '')) { if (tool_pref_check_old_password($nel_user, $post_old_pwd)) { if (tool_pref_update_user_password($nel_user, $post_new_pwd)) { $tpl->assign("tool_error", "Password has been updated!"); } else { $tpl->assign("tool_error", "Invalid new password!"); } } else { $tpl->assign("tool_error", "Old password does not match!"); } } elseif (($post_old_pwd != '') || ($post_new_pwd != '')) { $tpl->assign("tool_error", "You need to type your current and new passwords!"); } break; /* * update default application */ case 'update default application': $post_new_application = $NELTOOL['POST_VARS']['tool_form_application_default']; if ($nel_user['user_default_application_id'] != $post_new_application) { tool_pref_update_default_application($nel_user, $post_new_application); $tpl->assign("tool_v_application", $post_new_application); } break; } } $tpl->display('tool_preferences.tpl'); ?> ================================================ FILE: tools/server/admin/tool_shop.php ================================================ assign('tool_title', "商城管理"); $view_domain_id = nt_auth_get_session_var('view_domain_id'); $view_shard_id = nt_auth_get_session_var('view_shard_id'); if (!$view_domain_id) { $view_domain_id = $nel_user['group_default_domain_id']; $view_shard_id = $nel_user['group_default_shard_id']; nt_auth_set_session_var('view_domain_id', $view_domain_id); nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (isset($NELTOOL['GET_VARS']['domain'])) { if ($view_domain_id != $NELTOOL['GET_VARS']['domain']) { $view_domain_id = $NELTOOL['GET_VARS']['domain']; nt_auth_set_session_var('view_domain_id', $view_domain_id); $view_shard_id = null; nt_auth_unset_session_var('view_shard_id'); } } if (isset($NELTOOL['GET_VARS']['shard'])) { $view_shard_id = $NELTOOL['GET_VARS']['shard']; nt_auth_set_session_var('view_shard_id', $view_shard_id); } if (isset($NELTOOL['GET_VARS']['refdata'])) { $tmp_data = unserialize(base64_decode($NELTOOL['GET_VARS']['refdata'])); if (is_array($tmp_data)) { $NELTOOL['POST_VARS'] = $tmp_data; } } $current_refresh_rate = nt_auth_get_session_var('current_refresh_rate'); if (isset($_POST['services_refresh'])) { if ($current_refresh_rate != $_POST['services_refresh']) { $current_refresh_rate = $_POST['services_refresh']; nt_auth_set_session_var('current_refresh_rate',$current_refresh_rate); } } if ($current_refresh_rate == null) { $current_refresh_rate = 0; } elseif ($current_refresh_rate > 0) { $tpl->assign('nel_tool_refresh', ''); } $tpl->assign('tool_refresh_list', $refresh_rates); $tpl->assign('tool_refresh_rate', $current_refresh_rate); $tpl->assign('tool_domain_list', $nel_user['access']['domains']); $tpl->assign('tool_domain_selected', $view_domain_id); $tpl->assign('tool_shard_list', $nel_user['access']['shards']); $tpl->assign('tool_shard_selected', $view_shard_id); $tool_shard_filters = tool_main_get_shard_ids($view_shard_id); $tpl->assign('tool_shard_filters', $tool_shard_filters); if (tool_admin_applications_check('tool_shop')) $tpl->assign('restriction_tool_shop', true); if ($view_domain_id) { $tool_as_error = null; $AS_Name = tool_main_get_domain_name($view_domain_id); $AS_Host = tool_main_get_domain_host($view_domain_id); $AS_Port = tool_main_get_domain_port($view_domain_id); $AS_ShardName = tool_main_get_shard_name($view_shard_id); $AS_Application = tool_main_get_domain_data($view_domain_id, 'domain_application'); $AS_RingSQL = tool_main_get_domain_data($view_domain_id, 'domain_sql_string'); $tpl->assign('tool_page_title', 'Player Locator - '. $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : '')); $tool_as_error = null; if ($AS_Host && $AS_Port) { $adminService = new MyAdminService; if (@$adminService->connect($AS_Host, $AS_Port, $res) === false) { nt_common_add_debug($res); $tpl->assign('tool_domain_error', $res ); } else { if (isset($NELTOOL['POST_VARS']['services_pl'])) { $tool_services_pl = $NELTOOL['POST_VARS']['services_pl']; $tpl->assign('tool_post_data', base64_encode(serialize($NELTOOL['POST_VARS']))); switch ($tool_services_pl) { case '刷新物品列表': if (tool_admin_applications_check('tool_shop')) { $service_list = tool_main_get_checked_services(); if (sizeof($service_list)) { $service_command = 'shoplist'; nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $tpl->assign('tool_execute_result', ''); $command_return_data = array(); reset($service_list); foreach($service_list as $service) { //nt_common_add_debug("about to run 'displayPlayers' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } else { // the locator displays a nice output, no need for the raw one //$tpl->assign('tool_execute_command', $service_command); } } if (sizeof($command_return_data)) { $shop_list_data = tool_sp_parse_shop_list($command_return_data); $tpl->assign('tool_shop_list_data', $shop_list_data); } } } break; case '添加物品': if (tool_admin_applications_check('tool_shop')) { $tool_template_id = trim($NELTOOL['POST_VARS']['tpl_item_template_id']); $tpl->assign('tool_template_id_value', $tool_template_id); $tool_item_num = trim($NELTOOL['POST_VARS']['tpl_item_num']); $tpl->assign('tool_item_num_value', $tool_item_num); $tool_item_price = trim($NELTOOL['POST_VARS']['tpl_item_price']); $tpl->assign('tool_item_price_value', $tool_item_price); nt_common_add_debug('----- \''. $tool_template_id .'\' for command : '. $tool_item_num); $service_list = tool_main_get_checked_services(); if (sizeof($service_list) && ($tool_template_id != '') && ($tool_item_num != '') && ($tool_item_price != '')) { $service_command = 'addshopitem '. $tool_template_id. ' '. $tool_item_num. ' '. $tool_item_price; nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $command_return_data = array(); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'addshopitem' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } } if (sizeof($command_return_data)) { $shop_list_data = tool_sp_parse_shop_list($command_return_data); $tpl->assign('tool_shop_list_data', $shop_list_data); } } } break; case '删除物品': if (tool_admin_applications_check('tool_shop')) { $check_item_list = tool_shop_get_check_items(); $service_list = tool_main_get_checked_services(); if (sizeof($service_list) && sizeof($check_item_list)) { $service_command = 'removeshopitem '. $check_item_list; nt_log("Domain '$AS_Name' : '$service_command' on ". implode(', ',array_values($service_list))); $tpl->assign('tool_service_select_list', array_combine($service_list, $service_list)); $command_return_data = array(); reset($service_list); foreach($service_list as $service) { nt_common_add_debug("about to run 'removeshopitem' on '$service' ..."); $adminService->serviceCmd($service, $service_command); if (!$adminService->waitCallback()) { nt_common_add_debug('Error while waiting for callback on service \''. $service .'\' for command : '. $service_command); } } if (sizeof($command_return_data)) { $shop_list_data = tool_sp_parse_shop_list($command_return_data); $tpl->assign('tool_shop_list_data', $shop_list_data); } } } break; } } if (isset($NELTOOL['GET_VARS']['eid'])) { $locate_eid = $NELTOOL['GET_VARS']['eid']; // someday i'll do something here :) } $status = $adminService->getStates(); nt_common_add_debug($status); $domainServices = tool_main_parse_status($status); $filteredServices = array(); reset($domainServices); foreach($domainServices as $aKey => $aService) { // we are only interested in EGS if ($aService['ShortName'] == 'EGS') { $filteredServices[] = $aService; } } $tpl->assign('tool_services_list', $filteredServices); $tpl->assign('shard_su_name', tool_main_get_su_from_status($domainServices)); } } } $tpl->display('tool_shop.tpl'); ?> ================================================ FILE: tools/server/sql/d_mt_account.sql ================================================ /* Navicat MySQL Data Transfer Source Server : localhost_3306 Source Server Version : 50611 Source Host : localhost:3306 Source Database : d_mt_account Target Server Type : MYSQL Target Server Version : 50611 File Encoding : 65001 Date: 2013-05-05 14:05:10 */ drop database if exists d_mt_account ; create database d_mt_account default character set utf8mb4; use d_mt_account ; -- ---------------------------- -- Table structure for `t_account_id` -- ---------------------------- CREATE TABLE `t_account_id` ( `f_account_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '帐号id' UNIQUE, `f_appname` varchar(16) NOT NULL DEFAULT '' COMMENT '游戏类型', `f_name` varchar(128) NOT NULL DEFAULT '' COMMENT '帐号名称', `f_chal` varchar(16) NOT NULL DEFAULT 0 COMMENT '渠道', `f_mobile` varchar(32) NOT NULL DEFAULT '' COMMENT '手机号', `f_freeze_to` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '冻结到什么时间', `f_inserttime` timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '记录生成时间', PRIMARY KEY (`f_appname`, `f_name`, `f_chal`) ) ENGINE=MyISAM AUTO_INCREMENT=1002 DEFAULT CHARSET=utf8mb4; -- ---------------------------- -- Table structure for `t_account_mobile` -- ---------------------------- CREATE TABLE `t_account_mobile` ( `f_mobile` varchar(32) NOT NULL DEFAULT '' COMMENT '手机号', `f_pwd` varchar(32) NOT NULL DEFAULT '' COMMENT '密码', `f_slat` varchar(8) NOT NULL DEFAULT '' COMMENT 'salt', `f_inserttime` timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '记录生成时间', PRIMARY KEY (`f_mobile`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4; -- ---------------------------- -- Table structure for `t_account_info` -- ---------------------------- CREATE TABLE `t_account_info` ( `f_account_id` int(10) unsigned NOT NULL COMMENT '帐号id', `f_nickname` varchar(128) NOT NULL DEFAULT '' COMMENT '普通用户昵称', `f_sex` smallint(4) NOT NULL DEFAULT 0 COMMENT '普通用户性别,1为男性,2为女性', `f_province` varchar(64) NOT NULL DEFAULT '' COMMENT '普通用户个人资料填写的省份', `f_city` varchar(32) NOT NULL DEFAULT '' COMMENT '普通用户个人资料填写的城市', `f_country` varchar(32) NOT NULL DEFAULT '' COMMENT '国家,如中国为CN', `f_headimgurl` varchar(512) NOT NULL DEFAULT '' COMMENT '头像', `f_inserttime` timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '记录生成时间', PRIMARY KEY(`f_account_id`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4; ================================================ FILE: tools/server/sql/d_mt_player_procedure.sql ================================================ use d_mt_player ; drop procedure if exists _t_mt_add_player; /* t_playerinfo */ drop procedure if exists _t_mt_select_playerinfo; drop procedure if exists _t_mt_insert_playerinfo; drop procedure if exists _t_mt_update_playerinfo_low; drop procedure if exists _t_mt_update_playerinfo; DELIMITER ;; create procedure _t_mt_select_playerinfo( in af_uid bigint(20) unsigned ) begin select f_uid, f_nickname, f_portrait, f_money, f_rmb, f_main, f_flag_bit from t_playerinfo where f_uid=af_uid; end;; create procedure _t_mt_insert_playerinfo( in af_uid bigint(20) unsigned ) begin insert into t_playerinfo( f_uid ) values( af_uid ); end;; create procedure _t_mt_update_playerinfo_low( in af_uid bigint(20) unsigned, in af_nickname varchar(64), in af_portrait int(10) unsigned ) begin update t_playerinfo set f_nickname = af_nickname, f_portrait = af_portrait where f_uid = af_uid; end;; create procedure _t_mt_update_playerinfo( in af_uid bigint(20) unsigned, in af_money bigint(20) unsigned, in af_rmb bigint(20) unsigned, in af_main int(10) unsigned, in af_flag_bit bigint(20) unsigned ) begin update t_playerinfo set f_money = af_money, f_rmb = af_rmb, f_main = af_main, f_flag_bit = af_flag_bit where f_uid = af_uid; end;; create procedure _t_mt_add_player() begin declare v int default 1; declare f_uid int default 1; while v < 10000 do call _t_mt_insert_playerinfo( f_uid+1 ); set v = v + 1; set f_uid = f_uid + 1; end while; end ;; DELIMITER ; ================================================ FILE: tools/server/sql/d_mt_player_table.sql ================================================ /* Navicat MySQL Data Transfer Source Server : localhost_3306 Source Server Version : 50611 Source Host : localhost:3306 Source Database : d_mt_player Target Server Type : MYSQL Target Server Version : 50611 File Encoding : 65001 Date: 2013-05-05 14:05:24 */ drop database if exists d_mt_player ; create database d_mt_player default character set utf8mb4 ; use d_mt_player ; /*==============================================================*/ /* Table: t_playerinfo */ /*==============================================================*/ drop table if exists t_playerinfo; create table t_playerinfo ( f_uid bigint(20) unsigned NOT NULL DEFAULT 0 comment '' , f_nickname varchar(64) NOT NULL DEFAULT " " comment '昵称', f_portrait int(10) unsigned NOT NULL DEFAULT 0 comment '头像', f_money bigint(20) unsigned NOT NULL DEFAULT 0 comment '', f_rmb bigint(20) unsigned NOT NULL DEFAULT 0 comment '', f_main int(10) unsigned NOT NULL DEFAULT 0 comment '', f_flag_bit bigint(20) unsigned NOT NULL DEFAULT 0 comment '各种占一位的标识', f_insert_time timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '记录生成时间', primary key (f_uid) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; alter table t_playerinfo comment '角色基础信息'; ================================================ FILE: tools/server/sql/nel_tool.sql ================================================ /* Navicat MySQL Data Transfer Source Server : localhost Source Server Version : 50611 Source Host : localhost:3306 Source Database : nel_tool Target Server Type : MYSQL Target Server Version : 50611 File Encoding : 65001 Date: 2014-09-10 20:48:57 */ drop database if exists nel_tool ; create database nel_tool default character set utf8 ; use nel_tool ; SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for `neltool_annotations` -- ---------------------------- DROP TABLE IF EXISTS `neltool_annotations`; CREATE TABLE `neltool_annotations` ( `annotation_id` int(11) NOT NULL AUTO_INCREMENT, `annotation_domain_id` int(11) DEFAULT NULL, `annotation_shard_id` int(11) DEFAULT NULL, `annotation_data` varchar(255) NOT NULL DEFAULT '', `annotation_user_name` varchar(32) NOT NULL DEFAULT '', `annotation_date` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`annotation_id`), UNIQUE KEY `annotation_shard_id` (`annotation_shard_id`), UNIQUE KEY `annotation_domain_id` (`annotation_domain_id`) ) ENGINE=MyISAM AUTO_INCREMENT=14 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_annotations -- ---------------------------- INSERT INTO `neltool_annotations` VALUES ('12', null, '106', 'Welcome to the Shard Admin Website!', 'admin', '1409802992'); INSERT INTO `neltool_annotations` VALUES ('13', null, '302', '宽字节注入测试(縗) -- 这里是这组服务器的注释。', 'admin', '1409909065'); -- ---------------------------- -- Table structure for `neltool_applications` -- ---------------------------- DROP TABLE IF EXISTS `neltool_applications`; CREATE TABLE `neltool_applications` ( `application_id` int(11) NOT NULL AUTO_INCREMENT, `application_name` varchar(64) NOT NULL DEFAULT '', `application_uri` varchar(255) NOT NULL DEFAULT '', `application_restriction` varchar(64) NOT NULL DEFAULT '', `application_order` int(11) NOT NULL DEFAULT '0', `application_visible` int(11) NOT NULL DEFAULT '0', `application_icon` varchar(128) NOT NULL DEFAULT '', PRIMARY KEY (`application_id`) ) ENGINE=MyISAM AUTO_INCREMENT=41 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_applications -- ---------------------------- INSERT INTO `neltool_applications` VALUES ('1', 'Main', 'index.php', '', '100', '1', 'imgs/icon_main.gif'); INSERT INTO `neltool_applications` VALUES ('2', 'Logout', 'index.php?mode=logout', '', '999999', '1', 'imgs/icon_logout.gif'); INSERT INTO `neltool_applications` VALUES ('3', 'Admin', 'tool_administration.php', 'tool_admin', '1500', '1', 'imgs/icon_admin.gif'); INSERT INTO `neltool_applications` VALUES ('4', 'Prefs', 'tool_preferences.php', 'tool_preferences', '1000', '1', 'imgs/icon_preferences.gif'); INSERT INTO `neltool_applications` VALUES ('5', 'Admin/Users', '', 'tool_admin_user', '1502', '0', ''); INSERT INTO `neltool_applications` VALUES ('6', 'Admin/Applications', '', 'tool_admin_application', '1501', '0', ''); INSERT INTO `neltool_applications` VALUES ('7', 'Admin/Domains', '', 'tool_admin_domain', '1504', '0', ''); INSERT INTO `neltool_applications` VALUES ('8', 'Admin/Shards', '', 'tool_admin_shard', '1505', '0', ''); INSERT INTO `neltool_applications` VALUES ('9', 'Admin/Groups', '', 'tool_admin_group', '1503', '0', ''); INSERT INTO `neltool_applications` VALUES ('10', 'Admin/Logs', '', 'tool_admin_logs', '1506', '0', ''); INSERT INTO `neltool_applications` VALUES ('11', 'Main/Start', '', 'tool_main_start', '101', '0', ''); INSERT INTO `neltool_applications` VALUES ('12', 'Main/Stop', '', 'tool_main_stop', '102', '0', ''); INSERT INTO `neltool_applications` VALUES ('13', 'Main/Restart', '', 'tool_main_restart', '103', '0', ''); INSERT INTO `neltool_applications` VALUES ('14', 'Main/Kill', '', 'tool_main_kill', '104', '0', ''); INSERT INTO `neltool_applications` VALUES ('15', 'Main/Abort', '', 'tool_main_abort', '105', '0', ''); INSERT INTO `neltool_applications` VALUES ('16', 'Main/Execute', '', 'tool_main_execute', '108', '0', ''); INSERT INTO `neltool_applications` VALUES ('18', 'Notes', 'tool_notes.php', 'tool_notes', '900', '1', 'imgs/icon_notes.gif'); INSERT INTO `neltool_applications` VALUES ('19', 'Player Locator', 'tool_player_locator.php', 'tool_player_locator', '200', '1', 'imgs/icon_player_locator.gif'); INSERT INTO `neltool_applications` VALUES ('20', 'Player Locator/Display Players', '', 'tool_player_locator_display_players', '201', '0', ''); INSERT INTO `neltool_applications` VALUES ('21', 'Player Locator/Locate', '', 'tool_player_locator_locate', '202', '0', ''); INSERT INTO `neltool_applications` VALUES ('22', 'Main/LockDomain', '', 'tool_main_lock_domain', '110', '0', ''); INSERT INTO `neltool_applications` VALUES ('23', 'Main/LockShard', '', 'tool_main_lock_shard', '111', '0', ''); INSERT INTO `neltool_applications` VALUES ('24', 'Main/WS', '', 'tool_main_ws', '112', '0', ''); INSERT INTO `neltool_applications` VALUES ('25', 'Main/ResetCounters', '', 'tool_main_reset_counters', '113', '0', ''); INSERT INTO `neltool_applications` VALUES ('26', 'Main/ServiceAutoStart', '', 'tool_main_service_autostart', '114', '0', ''); INSERT INTO `neltool_applications` VALUES ('27', 'Main/ShardAutoStart', '', 'tool_main_shard_autostart', '115', '0', ''); INSERT INTO `neltool_applications` VALUES ('28', 'Main/WS/Old', '', 'tool_main_ws_old', '112', '0', ''); INSERT INTO `neltool_applications` VALUES ('29', 'Graphs', 'tool_graphs.php', 'tool_graph', '500', '1', 'imgs/icon_graphs.gif'); INSERT INTO `neltool_applications` VALUES ('30', 'Notes/Global', '', 'tool_notes_global', '901', '0', ''); INSERT INTO `neltool_applications` VALUES ('31', 'Log Analyser', 'tool_log_analyser.php', 'tool_las', '400', '1', 'imgs/icon_log_analyser.gif'); INSERT INTO `neltool_applications` VALUES ('32', 'Guild Locator', 'tool_guild_locator.php', 'tool_guild_locator', '300', '1', 'imgs/icon_guild_locator.gif'); INSERT INTO `neltool_applications` VALUES ('33', 'Player Locator/UserID Check', '', 'tool_player_locator_userid_check', '203', '0', ''); INSERT INTO `neltool_applications` VALUES ('34', 'Player Locator/CSR Relocate', '', 'tool_player_locator_csr_relocate', '204', '0', ''); INSERT INTO `neltool_applications` VALUES ('35', 'Guild Locator/Guilds Update', '', 'tool_guild_locator_manage_guild', '301', '0', ''); INSERT INTO `neltool_applications` VALUES ('36', 'Guild Locator/Members Update', '', 'tool_guild_locator_manage_members', '302', '0', ''); INSERT INTO `neltool_applications` VALUES ('37', 'Entities', 'tool_event_entities.php', 'tool_event_entities', '350', '1', 'imgs/icon_entity.gif'); INSERT INTO `neltool_applications` VALUES ('38', 'Admin/Restarts', '', 'tool_admin_restart', '1507', '0', ''); INSERT INTO `neltool_applications` VALUES ('39', 'Main/EasyRestart', '', 'tool_main_easy_restart', '116', '0', ''); INSERT INTO `neltool_applications` VALUES ('40', '商城管理', 'tool_shop.php', 'tool_shop', '340', '1', 'imgs/shop.png'); -- ---------------------------- -- Table structure for `neltool_domains` -- ---------------------------- DROP TABLE IF EXISTS `neltool_domains`; CREATE TABLE `neltool_domains` ( `domain_id` int(11) NOT NULL AUTO_INCREMENT, `domain_name` varchar(128) NOT NULL DEFAULT '', `domain_as_host` varchar(128) NOT NULL DEFAULT '', `domain_as_port` int(11) NOT NULL DEFAULT '0', `domain_rrd_path` varchar(255) NOT NULL DEFAULT '', `domain_las_admin_path` varchar(255) NOT NULL DEFAULT '', `domain_las_local_path` varchar(255) NOT NULL DEFAULT '', `domain_application` varchar(128) NOT NULL DEFAULT '', `domain_sql_string` varchar(128) NOT NULL DEFAULT '', `domain_hd_check` int(11) NOT NULL DEFAULT '0', `domain_mfs_web` text, `domain_cs_sql_string` varchar(255) DEFAULT NULL, PRIMARY KEY (`domain_id`) ) ENGINE=MyISAM AUTO_INCREMENT=13 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_domains -- ---------------------------- INSERT INTO `neltool_domains` VALUES ('12', '测试一区', '127.0.0.1', '46700', 'D:/MT/trunk/code/EVA/server/save_shard/rrd_graphs', '', '', 'ryzom_open', 'mysql://shard@localhost/ring_open', '0', '', 'mysql://shard@localhost/atrium_forums'); -- ---------------------------- -- Table structure for `neltool_groups` -- ---------------------------- DROP TABLE IF EXISTS `neltool_groups`; CREATE TABLE `neltool_groups` ( `group_id` int(11) NOT NULL AUTO_INCREMENT, `group_name` varchar(32) NOT NULL DEFAULT 'NewGroup', `group_level` int(11) NOT NULL DEFAULT '0', `group_default` int(11) NOT NULL DEFAULT '0', `group_active` int(11) NOT NULL DEFAULT '0', `group_default_domain_id` tinyint(3) unsigned DEFAULT NULL, `group_default_shard_id` tinyint(3) unsigned DEFAULT NULL, PRIMARY KEY (`group_id`) ) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_groups -- ---------------------------- INSERT INTO `neltool_groups` VALUES ('1', 'AdminGroup', '0', '0', '1', '12', '255'); INSERT INTO `neltool_groups` VALUES ('2', 'NevraxGroup', '0', '1', '1', null, null); INSERT INTO `neltool_groups` VALUES ('3', 'AdminDebugGroup', '10', '0', '1', '12', '255'); INSERT INTO `neltool_groups` VALUES ('4', 'SupportSGMGroup', '0', '0', '1', null, null); INSERT INTO `neltool_groups` VALUES ('5', 'NevraxATSGroup', '0', '0', '1', null, null); INSERT INTO `neltool_groups` VALUES ('6', 'SupportGMGroup', '0', '0', '1', null, null); INSERT INTO `neltool_groups` VALUES ('7', 'SupportReadOnlyGroup', '0', '0', '1', null, null); INSERT INTO `neltool_groups` VALUES ('8', 'NevraxLevelDesigners', '0', '0', '1', null, null); INSERT INTO `neltool_groups` VALUES ('9', 'NevraxReadOnlyGroup', '0', '0', '1', '9', '56'); INSERT INTO `neltool_groups` VALUES ('10', 'YubDevGroup', '0', '0', '1', '12', '106'); INSERT INTO `neltool_groups` VALUES ('11', 'GuestGroup', '0', '0', '1', '12', '106'); -- ---------------------------- -- Table structure for `neltool_group_applications` -- ---------------------------- DROP TABLE IF EXISTS `neltool_group_applications`; CREATE TABLE `neltool_group_applications` ( `group_application_id` int(11) NOT NULL AUTO_INCREMENT, `group_application_group_id` int(11) NOT NULL DEFAULT '0', `group_application_application_id` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`group_application_id`), KEY `group_application_group_id` (`group_application_group_id`), KEY `group_application_application_id` (`group_application_application_id`) ) ENGINE=MyISAM AUTO_INCREMENT=1003 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_group_applications -- ---------------------------- INSERT INTO `neltool_group_applications` VALUES ('879', '1', '10'); INSERT INTO `neltool_group_applications` VALUES ('878', '1', '8'); INSERT INTO `neltool_group_applications` VALUES ('877', '1', '7'); INSERT INTO `neltool_group_applications` VALUES ('876', '1', '9'); INSERT INTO `neltool_group_applications` VALUES ('875', '1', '5'); INSERT INTO `neltool_group_applications` VALUES ('874', '1', '6'); INSERT INTO `neltool_group_applications` VALUES ('873', '1', '3'); INSERT INTO `neltool_group_applications` VALUES ('872', '1', '4'); INSERT INTO `neltool_group_applications` VALUES ('871', '1', '30'); INSERT INTO `neltool_group_applications` VALUES ('870', '1', '18'); INSERT INTO `neltool_group_applications` VALUES ('869', '1', '29'); INSERT INTO `neltool_group_applications` VALUES ('868', '1', '31'); INSERT INTO `neltool_group_applications` VALUES ('867', '1', '37'); INSERT INTO `neltool_group_applications` VALUES ('866', '1', '36'); INSERT INTO `neltool_group_applications` VALUES ('865', '1', '35'); INSERT INTO `neltool_group_applications` VALUES ('864', '1', '32'); INSERT INTO `neltool_group_applications` VALUES ('863', '1', '34'); INSERT INTO `neltool_group_applications` VALUES ('862', '1', '33'); INSERT INTO `neltool_group_applications` VALUES ('861', '1', '21'); INSERT INTO `neltool_group_applications` VALUES ('860', '1', '20'); INSERT INTO `neltool_group_applications` VALUES ('859', '1', '19'); INSERT INTO `neltool_group_applications` VALUES ('858', '1', '39'); INSERT INTO `neltool_group_applications` VALUES ('857', '1', '27'); INSERT INTO `neltool_group_applications` VALUES ('856', '1', '26'); INSERT INTO `neltool_group_applications` VALUES ('1001', '3', '10'); INSERT INTO `neltool_group_applications` VALUES ('1000', '3', '8'); INSERT INTO `neltool_group_applications` VALUES ('999', '3', '7'); INSERT INTO `neltool_group_applications` VALUES ('998', '3', '9'); INSERT INTO `neltool_group_applications` VALUES ('997', '3', '5'); INSERT INTO `neltool_group_applications` VALUES ('996', '3', '6'); INSERT INTO `neltool_group_applications` VALUES ('995', '3', '3'); INSERT INTO `neltool_group_applications` VALUES ('994', '3', '4'); INSERT INTO `neltool_group_applications` VALUES ('993', '3', '30'); INSERT INTO `neltool_group_applications` VALUES ('992', '3', '18'); INSERT INTO `neltool_group_applications` VALUES ('991', '3', '29'); INSERT INTO `neltool_group_applications` VALUES ('990', '3', '31'); INSERT INTO `neltool_group_applications` VALUES ('989', '3', '37'); INSERT INTO `neltool_group_applications` VALUES ('988', '3', '36'); INSERT INTO `neltool_group_applications` VALUES ('987', '3', '35'); INSERT INTO `neltool_group_applications` VALUES ('986', '3', '32'); INSERT INTO `neltool_group_applications` VALUES ('985', '3', '40'); INSERT INTO `neltool_group_applications` VALUES ('984', '3', '34'); INSERT INTO `neltool_group_applications` VALUES ('983', '3', '33'); INSERT INTO `neltool_group_applications` VALUES ('982', '3', '21'); INSERT INTO `neltool_group_applications` VALUES ('981', '3', '20'); INSERT INTO `neltool_group_applications` VALUES ('980', '3', '19'); INSERT INTO `neltool_group_applications` VALUES ('979', '3', '39'); INSERT INTO `neltool_group_applications` VALUES ('978', '3', '27'); INSERT INTO `neltool_group_applications` VALUES ('597', '4', '36'); INSERT INTO `neltool_group_applications` VALUES ('596', '4', '35'); INSERT INTO `neltool_group_applications` VALUES ('595', '4', '32'); INSERT INTO `neltool_group_applications` VALUES ('594', '4', '21'); INSERT INTO `neltool_group_applications` VALUES ('593', '4', '20'); INSERT INTO `neltool_group_applications` VALUES ('592', '4', '19'); INSERT INTO `neltool_group_applications` VALUES ('591', '4', '24'); INSERT INTO `neltool_group_applications` VALUES ('590', '4', '23'); INSERT INTO `neltool_group_applications` VALUES ('589', '4', '14'); INSERT INTO `neltool_group_applications` VALUES ('588', '4', '12'); INSERT INTO `neltool_group_applications` VALUES ('632', '2', '18'); INSERT INTO `neltool_group_applications` VALUES ('631', '2', '37'); INSERT INTO `neltool_group_applications` VALUES ('630', '2', '32'); INSERT INTO `neltool_group_applications` VALUES ('629', '2', '21'); INSERT INTO `neltool_group_applications` VALUES ('628', '2', '20'); INSERT INTO `neltool_group_applications` VALUES ('627', '2', '19'); INSERT INTO `neltool_group_applications` VALUES ('626', '2', '24'); INSERT INTO `neltool_group_applications` VALUES ('625', '2', '23'); INSERT INTO `neltool_group_applications` VALUES ('624', '2', '22'); INSERT INTO `neltool_group_applications` VALUES ('623', '2', '16'); INSERT INTO `neltool_group_applications` VALUES ('622', '2', '15'); INSERT INTO `neltool_group_applications` VALUES ('621', '2', '14'); INSERT INTO `neltool_group_applications` VALUES ('620', '2', '13'); INSERT INTO `neltool_group_applications` VALUES ('977', '3', '26'); INSERT INTO `neltool_group_applications` VALUES ('855', '1', '25'); INSERT INTO `neltool_group_applications` VALUES ('619', '2', '12'); INSERT INTO `neltool_group_applications` VALUES ('976', '3', '25'); INSERT INTO `neltool_group_applications` VALUES ('854', '1', '28'); INSERT INTO `neltool_group_applications` VALUES ('975', '3', '28'); INSERT INTO `neltool_group_applications` VALUES ('718', '5', '18'); INSERT INTO `neltool_group_applications` VALUES ('717', '5', '37'); INSERT INTO `neltool_group_applications` VALUES ('716', '5', '32'); INSERT INTO `neltool_group_applications` VALUES ('715', '5', '21'); INSERT INTO `neltool_group_applications` VALUES ('714', '5', '20'); INSERT INTO `neltool_group_applications` VALUES ('713', '5', '19'); INSERT INTO `neltool_group_applications` VALUES ('712', '5', '27'); INSERT INTO `neltool_group_applications` VALUES ('711', '5', '26'); INSERT INTO `neltool_group_applications` VALUES ('710', '5', '24'); INSERT INTO `neltool_group_applications` VALUES ('709', '5', '23'); INSERT INTO `neltool_group_applications` VALUES ('708', '5', '22'); INSERT INTO `neltool_group_applications` VALUES ('707', '5', '16'); INSERT INTO `neltool_group_applications` VALUES ('706', '5', '15'); INSERT INTO `neltool_group_applications` VALUES ('705', '5', '14'); INSERT INTO `neltool_group_applications` VALUES ('974', '3', '24'); INSERT INTO `neltool_group_applications` VALUES ('609', '6', '35'); INSERT INTO `neltool_group_applications` VALUES ('608', '6', '32'); INSERT INTO `neltool_group_applications` VALUES ('607', '6', '21'); INSERT INTO `neltool_group_applications` VALUES ('606', '6', '20'); INSERT INTO `neltool_group_applications` VALUES ('605', '6', '19'); INSERT INTO `neltool_group_applications` VALUES ('604', '6', '24'); INSERT INTO `neltool_group_applications` VALUES ('603', '6', '23'); INSERT INTO `neltool_group_applications` VALUES ('602', '6', '14'); INSERT INTO `neltool_group_applications` VALUES ('601', '6', '12'); INSERT INTO `neltool_group_applications` VALUES ('600', '6', '11'); INSERT INTO `neltool_group_applications` VALUES ('973', '3', '23'); INSERT INTO `neltool_group_applications` VALUES ('972', '3', '22'); INSERT INTO `neltool_group_applications` VALUES ('853', '1', '24'); INSERT INTO `neltool_group_applications` VALUES ('704', '5', '13'); INSERT INTO `neltool_group_applications` VALUES ('703', '5', '12'); INSERT INTO `neltool_group_applications` VALUES ('852', '1', '23'); INSERT INTO `neltool_group_applications` VALUES ('587', '4', '11'); INSERT INTO `neltool_group_applications` VALUES ('618', '2', '11'); INSERT INTO `neltool_group_applications` VALUES ('702', '5', '11'); INSERT INTO `neltool_group_applications` VALUES ('612', '7', '19'); INSERT INTO `neltool_group_applications` VALUES ('851', '1', '22'); INSERT INTO `neltool_group_applications` VALUES ('971', '3', '16'); INSERT INTO `neltool_group_applications` VALUES ('970', '3', '15'); INSERT INTO `neltool_group_applications` VALUES ('598', '4', '18'); INSERT INTO `neltool_group_applications` VALUES ('599', '4', '4'); INSERT INTO `neltool_group_applications` VALUES ('610', '6', '18'); INSERT INTO `neltool_group_applications` VALUES ('611', '6', '4'); INSERT INTO `neltool_group_applications` VALUES ('613', '7', '20'); INSERT INTO `neltool_group_applications` VALUES ('614', '7', '21'); INSERT INTO `neltool_group_applications` VALUES ('615', '7', '32'); INSERT INTO `neltool_group_applications` VALUES ('616', '7', '35'); INSERT INTO `neltool_group_applications` VALUES ('617', '7', '4'); INSERT INTO `neltool_group_applications` VALUES ('633', '2', '4'); INSERT INTO `neltool_group_applications` VALUES ('969', '3', '14'); INSERT INTO `neltool_group_applications` VALUES ('968', '3', '13'); INSERT INTO `neltool_group_applications` VALUES ('850', '1', '16'); INSERT INTO `neltool_group_applications` VALUES ('849', '1', '15'); INSERT INTO `neltool_group_applications` VALUES ('848', '1', '14'); INSERT INTO `neltool_group_applications` VALUES ('847', '1', '13'); INSERT INTO `neltool_group_applications` VALUES ('846', '1', '12'); INSERT INTO `neltool_group_applications` VALUES ('719', '5', '4'); INSERT INTO `neltool_group_applications` VALUES ('720', '8', '11'); INSERT INTO `neltool_group_applications` VALUES ('721', '8', '12'); INSERT INTO `neltool_group_applications` VALUES ('722', '8', '13'); INSERT INTO `neltool_group_applications` VALUES ('723', '8', '14'); INSERT INTO `neltool_group_applications` VALUES ('724', '8', '15'); INSERT INTO `neltool_group_applications` VALUES ('725', '8', '16'); INSERT INTO `neltool_group_applications` VALUES ('726', '8', '22'); INSERT INTO `neltool_group_applications` VALUES ('727', '8', '23'); INSERT INTO `neltool_group_applications` VALUES ('728', '8', '24'); INSERT INTO `neltool_group_applications` VALUES ('729', '8', '25'); INSERT INTO `neltool_group_applications` VALUES ('730', '8', '26'); INSERT INTO `neltool_group_applications` VALUES ('731', '8', '27'); INSERT INTO `neltool_group_applications` VALUES ('732', '8', '19'); INSERT INTO `neltool_group_applications` VALUES ('733', '8', '20'); INSERT INTO `neltool_group_applications` VALUES ('734', '8', '21'); INSERT INTO `neltool_group_applications` VALUES ('735', '8', '37'); INSERT INTO `neltool_group_applications` VALUES ('736', '8', '4'); INSERT INTO `neltool_group_applications` VALUES ('737', '9', '29'); INSERT INTO `neltool_group_applications` VALUES ('738', '9', '4'); INSERT INTO `neltool_group_applications` VALUES ('967', '3', '12'); INSERT INTO `neltool_group_applications` VALUES ('845', '1', '11'); INSERT INTO `neltool_group_applications` VALUES ('966', '3', '11'); INSERT INTO `neltool_group_applications` VALUES ('880', '1', '38'); INSERT INTO `neltool_group_applications` VALUES ('909', '10', '18'); INSERT INTO `neltool_group_applications` VALUES ('908', '10', '29'); INSERT INTO `neltool_group_applications` VALUES ('907', '10', '37'); INSERT INTO `neltool_group_applications` VALUES ('906', '10', '36'); INSERT INTO `neltool_group_applications` VALUES ('905', '10', '35'); INSERT INTO `neltool_group_applications` VALUES ('904', '10', '32'); INSERT INTO `neltool_group_applications` VALUES ('903', '10', '34'); INSERT INTO `neltool_group_applications` VALUES ('902', '10', '33'); INSERT INTO `neltool_group_applications` VALUES ('901', '10', '21'); INSERT INTO `neltool_group_applications` VALUES ('900', '10', '20'); INSERT INTO `neltool_group_applications` VALUES ('899', '10', '19'); INSERT INTO `neltool_group_applications` VALUES ('898', '10', '23'); INSERT INTO `neltool_group_applications` VALUES ('897', '10', '13'); INSERT INTO `neltool_group_applications` VALUES ('910', '10', '30'); INSERT INTO `neltool_group_applications` VALUES ('965', '11', '29'); INSERT INTO `neltool_group_applications` VALUES ('964', '11', '37'); INSERT INTO `neltool_group_applications` VALUES ('963', '11', '32'); INSERT INTO `neltool_group_applications` VALUES ('962', '11', '34'); INSERT INTO `neltool_group_applications` VALUES ('961', '11', '33'); INSERT INTO `neltool_group_applications` VALUES ('960', '11', '21'); INSERT INTO `neltool_group_applications` VALUES ('959', '11', '20'); INSERT INTO `neltool_group_applications` VALUES ('958', '11', '19'); INSERT INTO `neltool_group_applications` VALUES ('1002', '3', '38'); -- ---------------------------- -- Table structure for `neltool_group_domains` -- ---------------------------- DROP TABLE IF EXISTS `neltool_group_domains`; CREATE TABLE `neltool_group_domains` ( `group_domain_id` int(11) NOT NULL AUTO_INCREMENT, `group_domain_group_id` int(11) NOT NULL DEFAULT '0', `group_domain_domain_id` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`group_domain_id`), KEY `group_domain_group_id` (`group_domain_group_id`) ) ENGINE=MyISAM AUTO_INCREMENT=91 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_group_domains -- ---------------------------- INSERT INTO `neltool_group_domains` VALUES ('76', '1', '12'); INSERT INTO `neltool_group_domains` VALUES ('90', '3', '12'); INSERT INTO `neltool_group_domains` VALUES ('89', '11', '12'); -- ---------------------------- -- Table structure for `neltool_group_shards` -- ---------------------------- DROP TABLE IF EXISTS `neltool_group_shards`; CREATE TABLE `neltool_group_shards` ( `group_shard_id` int(11) NOT NULL AUTO_INCREMENT, `group_shard_group_id` int(11) NOT NULL DEFAULT '0', `group_shard_shard_id` int(11) NOT NULL DEFAULT '0', `group_shard_domain_id` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`group_shard_id`), KEY `group_shard_group_id` (`group_shard_group_id`), KEY `group_shard_domain_id` (`group_shard_domain_id`) ) ENGINE=MyISAM AUTO_INCREMENT=1523 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_group_shards -- ---------------------------- INSERT INTO `neltool_group_shards` VALUES ('1490', '1', '302', '12'); INSERT INTO `neltool_group_shards` VALUES ('1522', '3', '302', '12'); INSERT INTO `neltool_group_shards` VALUES ('1521', '11', '302', '12'); -- ---------------------------- -- Table structure for `neltool_locks` -- ---------------------------- DROP TABLE IF EXISTS `neltool_locks`; CREATE TABLE `neltool_locks` ( `lock_id` int(11) NOT NULL AUTO_INCREMENT, `lock_domain_id` int(11) DEFAULT NULL, `lock_shard_id` int(11) DEFAULT NULL, `lock_user_name` varchar(32) NOT NULL DEFAULT '', `lock_date` int(11) NOT NULL DEFAULT '0', `lock_update` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`lock_id`), UNIQUE KEY `lock_shard_id` (`lock_shard_id`), UNIQUE KEY `lock_domain_id` (`lock_domain_id`) ) ENGINE=MyISAM AUTO_INCREMENT=19 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_locks -- ---------------------------- INSERT INTO `neltool_locks` VALUES ('18', null, '302', 'admin', '1410346920', '1410346920'); -- ---------------------------- -- Table structure for `neltool_logs` -- ---------------------------- DROP TABLE IF EXISTS `neltool_logs`; CREATE TABLE `neltool_logs` ( `logs_id` int(11) NOT NULL AUTO_INCREMENT, `logs_user_name` varchar(32) NOT NULL DEFAULT '0', `logs_date` int(11) NOT NULL DEFAULT '0', `logs_data` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`logs_id`) ) ENGINE=MyISAM AUTO_INCREMENT=258 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_logs -- ---------------------------- -- ---------------------------- -- Table structure for `neltool_notes` -- ---------------------------- DROP TABLE IF EXISTS `neltool_notes`; CREATE TABLE `neltool_notes` ( `note_id` int(11) NOT NULL AUTO_INCREMENT, `note_user_id` int(11) NOT NULL DEFAULT '0', `note_title` varchar(128) NOT NULL DEFAULT '', `note_data` text NOT NULL, `note_date` int(11) NOT NULL DEFAULT '0', `note_active` int(11) NOT NULL DEFAULT '0', `note_global` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`note_id`) ) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_notes -- ---------------------------- INSERT INTO `neltool_notes` VALUES ('2', '27', 'Welcome', 'Welcome to the shard administration website!\r\n\r\nThis website is used to monitor and restart shards.\r\n\r\nIt also gives some player characters information.', '1272378065', '1', '1'); INSERT INTO `neltool_notes` VALUES ('3', '27', 'Shard Start', '# At the same time : NS and TS\r\n[1 min] : all MS, you can boot them all at the same time\r\n[1 min] : IOS\r\n[3 mins] : GMPS\r\n[3 mins] : EGS\r\n[5 mins] : AI Fyros\r\n[1 min 30] : AI Zorai\r\n[1 min 30] : AI Matis\r\n[1 min 30] : AI TNP\r\n[1 min 30] : AI NPE\r\n[1 min 30] : AI Tryker\r\n[1 min 30] : All FS and SBS at the same time\r\n[30 secs] : WS (atm the WS starts in OPEN mode by default, so be fast before CSR checkage, fix for that inc soon)\r\n\r\nNOTE: you can check the uptime for those timers in the right column of the admin tool: UpTime\r\n', '1158751126', '1', '0'); INSERT INTO `neltool_notes` VALUES ('5', '27', 'shutting supplementary', 'the writing wont change when lock the ws\r\n\r\nuntick previous boxes as you shut down\r\n\r\nwait 5 between the ws and the egs ie egs is 5 past rest is 10 past', '1153395380', '1', '0'); INSERT INTO `neltool_notes` VALUES ('4', '27', 'Shard Stop', '1. Broadcast to warn players\r\n\r\n2. 10 mins before shutdown, lock the WS\r\n\r\n3. At the right time shut down WS\r\n\r\n4. Shut down EGS\r\nOnly the EGS. Wait 5 reals minutes. Goal is to give enough time to egs, in order to save all the info he has to, and letting him sending those message to all services who need it.\r\n\r\n5. Shut down the rest, et voilà, you're done.', '1153314198', '1', '0'); INSERT INTO `neltool_notes` VALUES ('6', '27', 'Start (EGS to high?)', 'If [EGS] is to high on startup:\r\n\r\n[shut down egs]\r\n[5 mins]\r\n\r\n[IOS] & [GPMS] (shut down at same time)\r\n\r\nAfter the services are down follow "UP" process with timers again.\r\n\r\nIOS\r\n[3 mins]\r\nGPMS\r\n[3 mins]\r\nEGS\r\n[5 mins]\r\nbla bla...', '1153395097', '1', '0'); INSERT INTO `neltool_notes` VALUES ('7', '27', 'opening if the egs is too high on reboot', '<kadael> here my note on admin about egs to high on startup\r\n<kadael> ---\r\n<kadael> If [EGS] is to high on startup:\r\n<kadael> [shut down egs]\r\n<kadael> [5 mins]\r\n<kadael> [IOS] & [GPMS] (at same time shut down )\r\n<kadael> after the services are down follow "UP" process with timers again.\r\n<kadael> IOS\r\n<kadael> [3 mins]\r\n<kadael> GPMS\r\n<kadael> [3 mins]\r\n<kadael> EGS\r\n<kadael> [5 mins]\r\n<kadael> bla bla...\r\n<kadael> ---', '1153395362', '1', '0'); INSERT INTO `neltool_notes` VALUES ('10', '27', 'Ring points', 'Commande pour donner tout les points ring à tout le monde :\r\n\r\nDans le DSS d'un Shard Ring entrer : DefaultCharRingAccess f7:j7:l6:d7:p13:g9:a9', '1155722296', '1', '0'); INSERT INTO `neltool_notes` VALUES ('9', '27', 'Start (EGS to high?)', 'If [EGS] is to high on startup: \r\n \r\n [shut down egs] \r\n [5 mins] \r\n \r\n [IOS] & [GPMS] (shut down at same time) \r\n \r\n After the services are down follow "UP" process with timers again. \r\n \r\n IOS \r\n [3 mins] \r\n GPMS \r\n [3 mins] \r\n EGS \r\n [5 mins] \r\n bla bla...', '1153929658', '1', '0'); -- ---------------------------- -- Table structure for `neltool_restart_groups` -- ---------------------------- DROP TABLE IF EXISTS `neltool_restart_groups`; CREATE TABLE `neltool_restart_groups` ( `restart_group_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `restart_group_name` varchar(50) DEFAULT NULL, `restart_group_list` varchar(50) DEFAULT NULL, `restart_group_order` varchar(50) DEFAULT NULL, PRIMARY KEY (`restart_group_id`), UNIQUE KEY `restart_group_id` (`restart_group_id`), KEY `restart_group_id_2` (`restart_group_id`) ) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_restart_groups -- ---------------------------- INSERT INTO `neltool_restart_groups` VALUES ('1', 'Low Level', 'rns,ts,ms', '1'); INSERT INTO `neltool_restart_groups` VALUES ('3', 'Mid Level', 'ios,gpms,egs', '2'); INSERT INTO `neltool_restart_groups` VALUES ('4', 'High Level', 'ais', '3'); INSERT INTO `neltool_restart_groups` VALUES ('5', 'Front Level', 'fes,sbs,dss,rws', '4'); -- ---------------------------- -- Table structure for `neltool_restart_messages` -- ---------------------------- DROP TABLE IF EXISTS `neltool_restart_messages`; CREATE TABLE `neltool_restart_messages` ( `restart_message_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `restart_message_name` varchar(20) DEFAULT NULL, `restart_message_value` varchar(128) DEFAULT NULL, `restart_message_lang` varchar(5) DEFAULT NULL, PRIMARY KEY (`restart_message_id`), UNIQUE KEY `restart_message_id` (`restart_message_id`), KEY `restart_message_id_2` (`restart_message_id`) ) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_restart_messages -- ---------------------------- INSERT INTO `neltool_restart_messages` VALUES ('5', 'reboot', 'The shard is about to go down. Please find a safe location and log out.', 'en'); INSERT INTO `neltool_restart_messages` VALUES ('4', 'reboot', 'Le serveur va redemarrer dans $minutes$ minutes. Merci de vous deconnecter en lieu sur.', 'fr'); INSERT INTO `neltool_restart_messages` VALUES ('6', 'reboot', 'Der Server wird heruntergefahren. Findet eine sichere Stelle und logt aus.', 'de'); INSERT INTO `neltool_restart_messages` VALUES ('10', 'reboot', 'Arret du serveur dans $minutes+1$ minutes', 'fr'); -- ---------------------------- -- Table structure for `neltool_restart_sequences` -- ---------------------------- DROP TABLE IF EXISTS `neltool_restart_sequences`; CREATE TABLE `neltool_restart_sequences` ( `restart_sequence_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `restart_sequence_domain_id` int(10) unsigned NOT NULL DEFAULT '0', `restart_sequence_shard_id` int(10) unsigned NOT NULL DEFAULT '0', `restart_sequence_user_name` varchar(50) DEFAULT NULL, `restart_sequence_step` int(10) unsigned NOT NULL DEFAULT '0', `restart_sequence_date_start` int(11) DEFAULT NULL, `restart_sequence_date_end` int(11) DEFAULT NULL, `restart_sequence_timer` int(11) unsigned DEFAULT '0', PRIMARY KEY (`restart_sequence_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_restart_sequences -- ---------------------------- -- ---------------------------- -- Table structure for `neltool_shards` -- ---------------------------- DROP TABLE IF EXISTS `neltool_shards`; CREATE TABLE `neltool_shards` ( `shard_id` int(11) NOT NULL AUTO_INCREMENT, `shard_name` varchar(128) NOT NULL DEFAULT '', `shard_as_id` varchar(255) NOT NULL DEFAULT '0', `shard_domain_id` int(11) NOT NULL DEFAULT '0', `shard_lang` char(2) NOT NULL DEFAULT 'en', `shard_restart` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`shard_id`), KEY `shard_domain_id` (`shard_domain_id`) ) ENGINE=MyISAM AUTO_INCREMENT=303 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_shards -- ---------------------------- INSERT INTO `neltool_shards` VALUES ('302', '测试一区', '测试一区', '12', 'en', '0'); -- ---------------------------- -- Table structure for `neltool_stats_hd_datas` -- ---------------------------- DROP TABLE IF EXISTS `neltool_stats_hd_datas`; CREATE TABLE `neltool_stats_hd_datas` ( `hd_id` int(11) NOT NULL AUTO_INCREMENT, `hd_domain_id` int(11) NOT NULL DEFAULT '0', `hd_server` varchar(32) NOT NULL DEFAULT '', `hd_device` varchar(64) NOT NULL DEFAULT '', `hd_size` varchar(16) NOT NULL DEFAULT '', `hd_used` varchar(16) NOT NULL DEFAULT '', `hd_free` varchar(16) NOT NULL DEFAULT '', `hd_percent` int(11) NOT NULL DEFAULT '0', `hd_mount` varchar(128) NOT NULL DEFAULT '', PRIMARY KEY (`hd_id`), KEY `hd_domain_id` (`hd_domain_id`), KEY `hd_server` (`hd_server`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_stats_hd_datas -- ---------------------------- -- ---------------------------- -- Table structure for `neltool_stats_hd_times` -- ---------------------------- DROP TABLE IF EXISTS `neltool_stats_hd_times`; CREATE TABLE `neltool_stats_hd_times` ( `hd_domain_id` int(11) NOT NULL DEFAULT '0', `hd_last_time` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`hd_domain_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_stats_hd_times -- ---------------------------- -- ---------------------------- -- Table structure for `neltool_users` -- ---------------------------- DROP TABLE IF EXISTS `neltool_users`; CREATE TABLE `neltool_users` ( `user_id` int(11) NOT NULL AUTO_INCREMENT, `user_name` varchar(32) NOT NULL DEFAULT '', `user_password` varchar(64) NOT NULL DEFAULT '', `user_group_id` int(11) NOT NULL DEFAULT '0', `user_created` int(11) NOT NULL DEFAULT '0', `user_active` int(11) NOT NULL DEFAULT '0', `user_logged_last` int(11) NOT NULL DEFAULT '0', `user_logged_count` int(11) NOT NULL DEFAULT '0', `user_menu_style` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`user_id`), UNIQUE KEY `user_login` (`user_name`), KEY `user_group_id` (`user_group_id`), KEY `user_active` (`user_active`) ) ENGINE=MyISAM AUTO_INCREMENT=33 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_users -- ---------------------------- INSERT INTO `neltool_users` VALUES ('27', 'admin', '084e0343a0486ff05530df6c705c8bb4', '3', '1213886454', '1', '1409731772', '383', '2'); INSERT INTO `neltool_users` VALUES ('32', 'guest', '084e0343a0486ff05530df6c705c8bb4', '11', '1272379014', '1', '1273335407', '273', '2'); -- ---------------------------- -- Table structure for `neltool_user_applications` -- ---------------------------- DROP TABLE IF EXISTS `neltool_user_applications`; CREATE TABLE `neltool_user_applications` ( `user_application_id` int(11) NOT NULL AUTO_INCREMENT, `user_application_user_id` int(11) NOT NULL DEFAULT '0', `user_application_application_id` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`user_application_id`), KEY `user_application_user_id` (`user_application_user_id`), KEY `user_application_application_id` (`user_application_application_id`) ) ENGINE=MyISAM AUTO_INCREMENT=22 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_user_applications -- ---------------------------- INSERT INTO `neltool_user_applications` VALUES ('8', '12', '33'); INSERT INTO `neltool_user_applications` VALUES ('20', '6', '31'); INSERT INTO `neltool_user_applications` VALUES ('19', '6', '34'); INSERT INTO `neltool_user_applications` VALUES ('9', '12', '31'); INSERT INTO `neltool_user_applications` VALUES ('21', '10', '34'); -- ---------------------------- -- Table structure for `neltool_user_domains` -- ---------------------------- DROP TABLE IF EXISTS `neltool_user_domains`; CREATE TABLE `neltool_user_domains` ( `user_domain_id` int(11) NOT NULL AUTO_INCREMENT, `user_domain_user_id` int(11) NOT NULL DEFAULT '0', `user_domain_domain_id` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`user_domain_id`), KEY `user_domain_user_id` (`user_domain_user_id`) ) ENGINE=MyISAM AUTO_INCREMENT=20 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_user_domains -- ---------------------------- INSERT INTO `neltool_user_domains` VALUES ('5', '6', '2'); INSERT INTO `neltool_user_domains` VALUES ('9', '22', '1'); INSERT INTO `neltool_user_domains` VALUES ('10', '23', '4'); INSERT INTO `neltool_user_domains` VALUES ('4', '12', '3'); INSERT INTO `neltool_user_domains` VALUES ('6', '6', '3'); INSERT INTO `neltool_user_domains` VALUES ('11', '23', '2'); INSERT INTO `neltool_user_domains` VALUES ('12', '23', '1'); INSERT INTO `neltool_user_domains` VALUES ('13', '23', '8'); INSERT INTO `neltool_user_domains` VALUES ('18', '15', '1'); INSERT INTO `neltool_user_domains` VALUES ('17', '15', '2'); INSERT INTO `neltool_user_domains` VALUES ('19', '31', '9'); -- ---------------------------- -- Table structure for `neltool_user_shards` -- ---------------------------- DROP TABLE IF EXISTS `neltool_user_shards`; CREATE TABLE `neltool_user_shards` ( `user_shard_id` int(11) NOT NULL AUTO_INCREMENT, `user_shard_user_id` int(11) NOT NULL DEFAULT '0', `user_shard_shard_id` int(11) NOT NULL DEFAULT '0', `user_shard_domain_id` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`user_shard_id`), KEY `user_shard_user_id` (`user_shard_user_id`), KEY `user_shard_domain_id` (`user_shard_domain_id`) ) ENGINE=MyISAM AUTO_INCREMENT=166 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of neltool_user_shards -- ---------------------------- INSERT INTO `neltool_user_shards` VALUES ('1', '8', '1', '1'); INSERT INTO `neltool_user_shards` VALUES ('2', '9', '2', '1'); INSERT INTO `neltool_user_shards` VALUES ('68', '7', '3', '1'); INSERT INTO `neltool_user_shards` VALUES ('143', '6', '4', '1'); INSERT INTO `neltool_user_shards` VALUES ('142', '6', '2', '1'); INSERT INTO `neltool_user_shards` VALUES ('141', '6', '45', '1'); INSERT INTO `neltool_user_shards` VALUES ('140', '6', '3', '1'); INSERT INTO `neltool_user_shards` VALUES ('90', '23', '26', '4'); INSERT INTO `neltool_user_shards` VALUES ('89', '23', '20', '4'); INSERT INTO `neltool_user_shards` VALUES ('13', '14', '1', '1'); INSERT INTO `neltool_user_shards` VALUES ('14', '14', '3', '1'); INSERT INTO `neltool_user_shards` VALUES ('15', '14', '2', '1'); INSERT INTO `neltool_user_shards` VALUES ('139', '6', '1', '1'); INSERT INTO `neltool_user_shards` VALUES ('74', '17', '2', '1'); INSERT INTO `neltool_user_shards` VALUES ('73', '17', '45', '1'); INSERT INTO `neltool_user_shards` VALUES ('72', '17', '3', '1'); INSERT INTO `neltool_user_shards` VALUES ('71', '17', '1', '1'); INSERT INTO `neltool_user_shards` VALUES ('70', '17', '18', '4'); INSERT INTO `neltool_user_shards` VALUES ('88', '23', '19', '4'); INSERT INTO `neltool_user_shards` VALUES ('87', '23', '24', '4'); INSERT INTO `neltool_user_shards` VALUES ('83', '23', '23', '4'); INSERT INTO `neltool_user_shards` VALUES ('82', '23', '22', '4'); INSERT INTO `neltool_user_shards` VALUES ('81', '23', '21', '4'); INSERT INTO `neltool_user_shards` VALUES ('34', '12', '15', '3'); INSERT INTO `neltool_user_shards` VALUES ('36', '18', '2', '1'); INSERT INTO `neltool_user_shards` VALUES ('138', '6', '7', '2'); INSERT INTO `neltool_user_shards` VALUES ('80', '23', '17', '4'); INSERT INTO `neltool_user_shards` VALUES ('79', '22', '45', '1'); INSERT INTO `neltool_user_shards` VALUES ('78', '22', '3', '1'); INSERT INTO `neltool_user_shards` VALUES ('77', '21', '45', '1'); INSERT INTO `neltool_user_shards` VALUES ('76', '21', '3', '1'); INSERT INTO `neltool_user_shards` VALUES ('75', '17', '4', '1'); INSERT INTO `neltool_user_shards` VALUES ('69', '7', '45', '1'); INSERT INTO `neltool_user_shards` VALUES ('146', '6', '54', '3'); INSERT INTO `neltool_user_shards` VALUES ('91', '23', '18', '4'); INSERT INTO `neltool_user_shards` VALUES ('92', '23', '7', '2'); INSERT INTO `neltool_user_shards` VALUES ('93', '23', '13', '2'); INSERT INTO `neltool_user_shards` VALUES ('94', '23', '8', '2'); INSERT INTO `neltool_user_shards` VALUES ('95', '23', '14', '2'); INSERT INTO `neltool_user_shards` VALUES ('145', '6', '53', '3'); INSERT INTO `neltool_user_shards` VALUES ('97', '23', '10', '2'); INSERT INTO `neltool_user_shards` VALUES ('144', '6', '15', '3'); INSERT INTO `neltool_user_shards` VALUES ('99', '23', '5', '1'); INSERT INTO `neltool_user_shards` VALUES ('100', '23', '6', '1'); INSERT INTO `neltool_user_shards` VALUES ('101', '23', '1', '1'); INSERT INTO `neltool_user_shards` VALUES ('102', '23', '3', '1'); INSERT INTO `neltool_user_shards` VALUES ('103', '23', '45', '1'); INSERT INTO `neltool_user_shards` VALUES ('104', '23', '46', '1'); INSERT INTO `neltool_user_shards` VALUES ('105', '23', '2', '1'); INSERT INTO `neltool_user_shards` VALUES ('106', '23', '42', '1'); INSERT INTO `neltool_user_shards` VALUES ('107', '23', '43', '1'); INSERT INTO `neltool_user_shards` VALUES ('108', '23', '44', '1'); INSERT INTO `neltool_user_shards` VALUES ('109', '23', '4', '1'); INSERT INTO `neltool_user_shards` VALUES ('110', '23', '41', '8'); INSERT INTO `neltool_user_shards` VALUES ('111', '23', '39', '8'); INSERT INTO `neltool_user_shards` VALUES ('112', '23', '30', '8'); INSERT INTO `neltool_user_shards` VALUES ('113', '23', '32', '8'); INSERT INTO `neltool_user_shards` VALUES ('114', '23', '47', '8'); INSERT INTO `neltool_user_shards` VALUES ('115', '23', '31', '8'); INSERT INTO `neltool_user_shards` VALUES ('116', '23', '36', '8'); INSERT INTO `neltool_user_shards` VALUES ('117', '23', '37', '8'); INSERT INTO `neltool_user_shards` VALUES ('118', '23', '40', '8'); INSERT INTO `neltool_user_shards` VALUES ('156', '15', '45', '1'); INSERT INTO `neltool_user_shards` VALUES ('155', '15', '3', '1'); INSERT INTO `neltool_user_shards` VALUES ('154', '15', '1', '1'); INSERT INTO `neltool_user_shards` VALUES ('153', '15', '6', '1'); INSERT INTO `neltool_user_shards` VALUES ('152', '15', '5', '1'); INSERT INTO `neltool_user_shards` VALUES ('151', '15', '10', '2'); INSERT INTO `neltool_user_shards` VALUES ('150', '15', '14', '2'); INSERT INTO `neltool_user_shards` VALUES ('149', '15', '8', '2'); INSERT INTO `neltool_user_shards` VALUES ('148', '15', '13', '2'); INSERT INTO `neltool_user_shards` VALUES ('147', '15', '7', '2'); INSERT INTO `neltool_user_shards` VALUES ('157', '15', '46', '1'); INSERT INTO `neltool_user_shards` VALUES ('158', '15', '2', '1'); INSERT INTO `neltool_user_shards` VALUES ('159', '15', '42', '1'); INSERT INTO `neltool_user_shards` VALUES ('160', '15', '43', '1'); INSERT INTO `neltool_user_shards` VALUES ('161', '15', '44', '1'); INSERT INTO `neltool_user_shards` VALUES ('162', '15', '4', '1'); INSERT INTO `neltool_user_shards` VALUES ('163', '31', '57', '9'); INSERT INTO `neltool_user_shards` VALUES ('164', '31', '104', '9'); INSERT INTO `neltool_user_shards` VALUES ('165', '31', '103', '9'); ================================================ FILE: tools/server/www/login/code2accesstoken.php ================================================ = $freeze_to ) { $UserID = $row["f_account_id"]; $SessionKey = $wx_dejson['session_key']; $NonceStr = RandomStr(20); $Timestamp = time(); $login_sign_data = $UserID . $Channel . $GameType . $AppName . $UserName . $NonceStr . $Timestamp . $SIG_KEY[$AppName]; $Token = strtoupper(md5($login_sign_data)); $redata = array(); $redata['Token'] = $Token; $redata['User'] = $UserName; $redata['NonceStr'] = $NonceStr; $redata['Timestamp'] = $Timestamp; $redata['SessionKey'] = $SessionKey; $redata['UID'] = $UserID; $redata['FES'] = "127.0.0.1:9999"; echo json_encode($redata); } } } else { echo $wx_dejson['errMsg']; } // no more to do (other global statement are old garbage) die(); // ---------------------------------------------------------------------------------------- // Functions // ---------------------------------------------------------------------------------------- ?> ================================================ FILE: tools/server/www/login/config.php ================================================ ================================================ FILE: tools/server/www/login/login_test.php ================================================ = $freeze_to ) { $UserID = $row["f_account_id"]; $NonceStr = RandomStr(20); $Timestamp = time(); $login_sign_data = $UserID . $Channel . $GameType . $AppName . $UserName . $NonceStr . $Timestamp . $SIG_KEY[$AppName]; $Token = strtoupper(md5($login_sign_data)); $redata = array(); $redata['Token'] = $Token; $redata['User'] = $UserName; $redata['NonceStr'] = $NonceStr; $redata['Timestamp'] = $Timestamp; $redata['UID'] = $UserID; $redata['FES'] = "ws://127.0.0.1:9999"; echo json_encode($redata); } else { $redata = array(); $redata['errcode'] = 1005; $redata['errmsg'] = "freezeto:" . $freeze_to; echo json_encode($redata); } die(); } } // no more to do (other global statement are old garbage) die(); // ---------------------------------------------------------------------------------------- // Functions // ---------------------------------------------------------------------------------------- ?> ================================================ FILE: tools/server/www/login/logs/placeholder ================================================ ================================================ FILE: tools/server/www/login/pay_service_itf.php ================================================ setName("CBUP"); $msg->serialUint32($userId); $msg->serialUint32($oid); echo $userId; echo $oid; return parent::sendMessage($msg); } function waitCallback() { $message = parent::waitMessage(); if ($message == false) return false; switch($message->MsgName) { case "CBUP": $userId = 0; $oid = 0; $message->serialUint32($userId); $message->serialUint32($oid); echo $userId; echo $oid; break; default: return false; } return true; } } ?> ================================================ FILE: tools/server/www/login/public_func.php ================================================ array( 'timeout' => 7 ) ) ); $html = file_get_contents($RequestURL, 0, $ctx); return json_decode($html, TRUE); } class CWwwLog { //function CWwwLog() {} /* * Return the log directory. Create it if it does not exist, or return false if creation failed. */ function getSafeLogDir() { // Examples: // __FILE__ = r:\code\ryzom\www\login\config.php // $_SERVER['PATH_TRANSLATED'] = 'r:/code/ryzom/www/login//r2_login.php' // $_SERVER['SCRIPT_FILENAME'] = 'r:/code/ryzom/www/login//r2_login.php' global $LogRelativePath; $pathInfo = pathinfo(__FILE__); $logPath = $pathInfo['dirname'].'/'.$LogRelativePath; if (!is_dir($logPath)) { $res = mkdir($LogPath, 0700); return $res ? $logPath : false; } return $logPath; } function logStr($str) { $logPath = $this->getSafeLogDir(); if ($logPath !== false) { $fp = fopen($logPath.'/r2_login_'.date('Y-m-d').'.log', 'a'); fwrite($fp, date('Y-m-d H:i:s').' ('.$_SERVER['REMOTE_ADDR'].':'.$_SERVER['REQUEST_URI']."): $str\n"); fclose($fp); } } } function getIP() { static $realip; if (isset($_SERVER)){ if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])){ $realip = $_SERVER["HTTP_X_FORWARDED_FOR"]; } else if (isset($_SERVER["HTTP_CLIENT_IP"])) { $realip = $_SERVER["HTTP_CLIENT_IP"]; } else { $realip = $_SERVER["REMOTE_ADDR"]; } } else { if (getenv("HTTP_X_FORWARDED_FOR")){ $realip = getenv("HTTP_X_FORWARDED_FOR"); } else if (getenv("HTTP_CLIENT_IP")) { $realip = getenv("HTTP_CLIENT_IP"); } else { $realip = getenv("REMOTE_ADDR"); } } return $realip; } // Callback called on end of output buffering function ob_callback_r2login($buffer) { // Log only in case of error or malformed result string $blockHd = substr($buffer, 0, 2); if ($blockHd != '1:') { $logFile = new CWwwLog(); $logFile->logStr(str_replace("\n",'\n',$buffer)); } return $buffer; // sent to output } // Callback called on error function err_callback($errno, $errmsg, $filename, $linenum, $vars) { $logFile = new CWwwLog(); $logFile->logStr("PHP ERROR/$errno $errmsg ($filename:$linenum)"); // Never die after an error } ?> ================================================ FILE: tools/server/www/tools/nel_message.php ================================================ InputStream = false; $this->Pos = 0; $this->Buffer = ""; debug("A : ".gettype($this->Buffer)."
"); } function setBuffer ($Buffer) { $this->InputStream = true; $this->Buffer = $Buffer; $this->Pos = 0; } function isReading () { return $this->InputStream; } function serialUInt8 (&$val) { if ($this->isReading()) { $val = ord($this->Buffer{$this->Pos++}); debug(sprintf ("read uint8 '%d'
\n", $val)); } else { debug("B".gettype($this->Buffer)."
"); debug(sprintf ("write uint8 Buffer size before = %u
\n", strlen($this->Buffer))); $this->Buffer = $this->Buffer . chr($val & 0xFF); $this->Pos++; debug("C".gettype($this->Buffer)."
"); debug(sprintf ("write uint8 '%d' %d
\n", $val, $this->Pos)); debug(sprintf ("write uint8 Buffer size after = %u
\n", strlen($this->Buffer))); } } function serialUInt32 (&$val) { if ($this->isReading()) { $val = ord($this->Buffer{$this->Pos++}); $val += ord($this->Buffer{$this->Pos++})*256; $val += ord($this->Buffer{$this->Pos++})*(double)256*256; $val += ord($this->Buffer{$this->Pos++})*(double)256*256*256; debug(sprintf ("read uint32 '%d'
\n", $val)); // var_dump($val); } else { debug("D".gettype($this->Buffer)."
"); $this->Buffer .= chr($val & 0xFF); $this->Buffer .= chr(($val>>8) & 0xFF); $this->Buffer .= chr(($val>>16) & 0xFF); $this->Buffer .= chr(($val>>24) & 0xFF); $this->Pos += 4; debug("E".gettype($this->Buffer)."
"); debug(sprintf ("write uint32 '%d' %d
\n", $val, $this->Pos)); } } function serialString (&$val) { if ($this->isReading()) { $this->serialUInt32($size); debug(sprintf ("read string : size = %u
\n", $size)); $val = substr ($this->Buffer, $this->Pos, $size); debug(sprintf ("read string '%s'
\n", $val)); $this->Pos += strlen($val); } else { $val_len = strlen($val); $this->serialUInt32($val_len); $this->Buffer .= $val; $this->Pos += strlen($val); debug(sprintf ("write string '%s' %d
\n", $val, $this->Pos)); } } function serialEnum (&$val) { if ($this->isReading()) { $intValue = 0; $this->serialUInt32($intValue); $val->fromInt((int)$intValue); debug(sprintf ("read enum '%s'
\n", $val->toString())); } else { $this->serialUInt32($val->toInt()); debug(sprintf ("write enum '%s' %d
\n", $val->toString(), $this->Pos)); } } } class CMessage extends CMemStream { var $MsgName; function CMessage() { $this->CMemStream(); } function setName($name) { $this->MsgName = $name; } } class CCallbackClient { var $ConSock = false; var $MsgNum = 0; function connect($addr, $port, &$res) { global $SockTimeOut; debug(sprintf("Connect
")); $this->MsgNum = 0; $this->ConSock = fsockopen ($addr, $port, $errno, $errstr, $SockTimeOut); debug("H".gettype($this->ConSock)."
"); if (!$this->ConSock) { $res = "Can't connect to the callback server '$addr:$port' ($errno: $errstr)"; return false; } else { // set time out on the socket to 2 secondes stream_set_timeout($this->ConSock, $SockTimeOut); $res = ""; return true; } } function close() { if ($this->ConSock) { fclose($this->ConSock); debug(sprintf("Close
")); } else debug(sprintf("Already Closed !
")); } function sendMessage(&$message) { if (!$this->ConSock) { debug(sprintf ("Socket is not valid\n")); return false; } debug(sprintf ("sendMessage : message Buffer is '%d'
\n", $message->Pos)); debug(sprintf ("sendMessage : message Buffer is '%d'
\n", strlen($message->Buffer))); $hd = new CMemStream; debug(sprintf("SendMessage number %u
", $this->MsgNum)); $hd->serialUInt32 ($this->MsgNum); // number the packet $this->MsgNum += 1; debug(sprintf("After SendMessage, number %u
", $this->MsgNum)); $messageType = 0; $hd->serialUInt8 ($messageType); $hd->serialString ($message->MsgName); debug(sprintf ("sendMessage : header size is '%d'
\n", $hd->Pos)); // $sb .= $message->Buffer; $size = $hd->Pos + $message->Pos; $Buffer = (string) chr(($size>>24)&0xFF); $Buffer .= chr(($size>>16)&0xFF); $Buffer .= chr(($size>>8)&0xFF); $Buffer .= chr($size&0xFF); debug( "E".gettype($hd->Buffer)."
"); debug("F".gettype($message->Buffer)."
"); $Buffer .= (string) $hd->Buffer; $Buffer .= (string) $message->Buffer; debug("G".gettype($this->ConSock)."
"); if (!fwrite ($this->ConSock, $Buffer)) { debug(sprintf ("Error writing to socket\n")); return false; } debug(sprintf ("sent packet size '%d' (written size = %d)
\n", strlen($Buffer), $size)); fflush ($this->ConSock); return true; } function waitMessage() { if (!$this->ConSock) { debug(sprintf ("Socket is not valid\n")); return false; } $size = 0; $val = fread ($this->ConSock, 1); $info = stream_get_meta_data($this->ConSock); if ($info['timed_out']) { debug('Connection timed out!'); return false; } $size = ord($val) << 24; $val = fread ($this->ConSock, 1); $info = stream_get_meta_data($this->ConSock); if ($info['timed_out']) { debug('Connection timed out!'); return false; } $size = ord($val) << 16; $val = fread ($this->ConSock, 1); $info = stream_get_meta_data($this->ConSock); if ($info['timed_out']) { debug('Connection timed out!'); return false; } $size += ord($val) << 8; $val = fread ($this->ConSock, 1); $info = stream_get_meta_data($this->ConSock); if ($info['timed_out']) { debug('Connection timed out!'); return false; } $size += ord($val); debug(sprintf ("receive packet size '%d'
\n", $size)); $fake = fread ($this->ConSock, 5); $info = stream_get_meta_data($this->ConSock); if ($info['timed_out']) { debug('Connection timed out!'); return false; } $size -= 5; // remove the fake $Buffer = ""; while ($size > 0 && strlen($Buffer) != $size) { $Buffer .= fread ($this->ConSock, $size - strlen($Buffer)); $info = stream_get_meta_data($this->ConSock); if ($info['timed_out']) { debug('Connection timed out!'); return false; } } $msgin = new CMemStream; $msgin->setBuffer ($Buffer); // decode msg name $msgin->serialString($name); debug(sprintf("Message name = '%s'
", $name)); $message = new CMessage; $message->setBuffer(substr($msgin->Buffer, $msgin->Pos)); $message->setName($name); debug(sprintf("In message name = '%s'
", $message->MsgName)); return $message; } } // class CSessionManagerProxy // { // function createSession($userId, $sessionType, $callbackClient) // { // debug(sprintf("Creating session for user %u, type %s
", $userId, $sessionType)); // $msg = new CMessage; // $msg->setName("CSS"); // $msg->serialUInt32($userId); // $msg->serialString($sessionType); // // $callbackClient->sendMessage($msg); // } // } // class CSessionManagerClientSkel // { // function waitCallback($callbackClient) // { // $message = $callbackClient->waitMessage(); // // debug(sprintf("Received message '%s'
", $message->MsgName)); // // switch($message->MsgName) // { // case "CSSR": // debug(sprintf("Create session result
")); // $this->createSessionResult_skel($message); // break; // // case "CSNR": // debug(sprintf("Create scenario result
")); // $this->createScenarioResult_skel($message); // break; // }; // } // // function createSessionResult_skel($message) // { // $userId = 0; // $sessionId = 0; // $result = false; // // $message->serialUInt32($userId); // $message->serialUInt32($sessionId); // $message->serialUInt8($result); // // createSessionResult($userId, $sessionId, $result); // } // } // printf("creating callback client...
"); // // $cb = new CCallbackClient; // $ret = ""; // $cb->connect("192.168.0.1", "8060", $ret); // // $smp = new CSessionManagerProxy; // // printf("creating a new sessions...
"); // $smp->createSession(10, "st_edit", $cb); // // $smcs = new CSessionManagerClientSkel; // $smcs->waitCallback($cb); // // // function createSessionResult($userId, $sessionId, $result) // { // echo "The session result for user $userId is the session $sessionId with a result of $result\n"; // } // // This function connect to the AS. // If true, $res contains the url to connect. // If false, $res contains the reason why it s not okay. // function connectToAS(&$fp, &$res) // { // global $ASHost, $ASPort; ///* // $sid = session_id(); // $result = sqlquery("SELECT socket_id FROM resident_socket"); // if (!$result || sqlnumrows($result) == 0) // { // $fp = pfsockopen ($ASHost, $ASPort, $errno, $errstr, 30); // echo "opened resident socket '$fp'\n"; // // $result = sqlquery("SELECT socket_id FROM resident_socket WHERE socket_id='$fp'"); // if ($result && sqlnumrows($result)>0) // sqlquery("DELETE FROM resident_socket WHERE socket_id='$fp'"); // // sqlquery("INSERT INTO resident_socket SET socket_id='$fp', session_id='$sid', last_access=NOW()"); // } // else // { // $result = sqlfetch($result); // $fp = $result["socket_id"]; // } // // // remove too old sockets // sqlquery("SELECT socket_id FROM resident_socket WHERE NOW()-last_access > 1800"); // while ($result && ($arr=sqlfetch($result))) // { // fclose((int)($arr["socket_id"])); // sqlquery("DELETE FROM resident_socket WHERE socket_id='".$arr["socket_id"]."'"); // } // // // update current socket last access // sqlquery("UPDATE resident_socket SET last_access=NOW() WHERE socket_id='$fp' AND session_id='$sid'"); //*/ // // // connect to the login service that must be $ASHost:$ASPort // $fp = fsockopen ($ASHost, $ASPort, $errno, $errstr, 30); // if (!$fp) // { // $res = "Can't connect to the admin service '$ASHost:$ASPort' ($errno: $errstr)"; // } // else // { // $res = ""; // } // // } // // function disconnectFromAS(&$fp) // { ///* // $result = sqlquery("SELECT socket_id FROM resident_socket WHERE socket_id='$fp'"); // if (!$result || sqlnumrows($socket)==0) // fclose($fp); //*/ // fclose($fp); // } // // function sendMessage ($fp, $msgout) // { // $size = $msgout->Pos; // $Buffer = chr(($size>>24)&0xFF); // $Buffer .= chr(($size>>16)&0xFF); // $Buffer .= chr(($size>>8)&0xFF); // $Buffer .= chr($size&0xFF); // $Buffer .= $msgout->Buffer; // // fwrite ($fp, $Buffer); // // //printf ("sent packet size '%d'
", strlen($Buffer)); // // fflush ($fp); // } // // function waitMessage ($fp, &$msgin) // { // //echo "waiting a message"; // $size = 0; // $val = fread ($fp, 1); // $size = ord($val) << 24; // $val = fread ($fp, 1); // $size = ord($val) << 16; // $val = fread ($fp, 1); // $size += ord($val) << 8; // $val = fread ($fp, 1); // $size += ord($val); // //printf ("receive packet size '%d'
", $size); // $fake = fread ($fp, 4); // $size -= 4; // remove the fake // // $Buffer = fread ($fp, $size); // $msgin = new CMemStream; // $msgin->setBuffer ($Buffer); // } // // function logNelQuery($query) // { // global $uid; ///* // $f = fopen("./nel_queries.log", "a"); // fwrite($f, date("Y/m/d H:i:s")." ".sprintf("%-16s", $admlogin)." $query\n"); // fclose($f); //*/ // // logUser($uid, "QUERY=".$query); // } // // function nel_query($rawvarpath, &$result) // { // global $nel_queries; // // $nel_queries[] = $rawvarpath; // $ok = false; // //echo "rawvarpath=$rawvarpath
\n"; // // //logNelQuery($rawvarpath); // // connectToAS($fp, $result); // if(strlen($result) != 0) // return $ok; // // // send the message that say that we want to add a user // $msgout = new CMemStream; // $fake = 0; // $msgout->serialuint32 ($fake); // fake used to number the packet // $messageType = 0; // $msgout->serialuint8 ($messageType); // $msgout->serialstring ($rawvarpath); // // sendMessage ($fp, $msgout); // // waitMessage ($fp, $msgin); // // $msgin->serialstring($result); // // if(strlen($result) == 0) // { // // it failed // } // else // { // // it's ok // $ok = true; // } // // //printf("receive response '$result'
\n"); // // disconnectFromAS(&$fp); // //echo "sent OK.

\n"; // // return $ok; // } ?> ================================================ FILE: tools/xlsx2json/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 yulijun Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: tools/xlsx2json/README.md ================================================ ### xlsx2json ([English Document](./docs/doc_en.md)) > 让excel支持表达复杂的json格式,将xlsx文件转成json。 ### 日志 * 2017-10-31 v0.3.1 * 修复: 对象类型列,对象值里面有冒号值解析错误。 * 功能: 增加#id类型,主键索引(json格式以map形式输出,无id的表以数组格式输出)。 * 功能: 输出的json是否压缩可以在config.json里面配置。 * 2017-10-26 v0.3.0 * 修复中文自动追加拼音问题。 * 修复日期解析错误。 * 去掉主外键功能(以后再追加)。 * 增加代码静态检查,核心代码重写并改成ES6语法。 * 更新依赖插件的版本。 ### npm相关 * 如需当做npm模块引用请切换到`npm`分支。 ### 使用说明 * 目前只支持.xlsx格式,不支持.xls格式。 * 本项目是基于nodejs的,所以需要先安装nodejs环境。 * 执行命令 ```bash # Clone this repository git clone https://github.com/koalaylj/xlsx2json.git # Go into the repository cd xlsx2json # Install dependencies npm install ``` * 配置config.json ```javascript { "xlsx": { /** * 表头所在的行,第一行可以是注释,第二行是表头 */ "head": 2, /** * xlsx文件所在的目录 * glob配置风格 */ "src": "./excel/**/[^~$]*.xlsx", /** * 导出的json存放的位置 */ "dest": "./json", /** * 数组的分隔符 * 有时候特殊需要,在excel单元格中里面逗号被当做他用。 * 已过时,将在v0.5.x移除。参考列类型是数组类型时候表头设置。 */ "arraySeparator":"," }, "json": { /** * 导出的json是否需要压缩 * true:压缩,false:不压缩(便于阅读的格式) */ "uglify": false } } ``` * 执行`export.sh|export.bat`即可将`./excel/*.xlsx` 文件导成json并存放到 `./json` 下。json名字以excel的sheet名字命名。 * 补充(一般用不上): * 执行`node index.js -h` 查看使用帮助。 * 命令行传参方式使用:执行 node `index.js --help` 查看。 #### 示例1 test.xlsx | id | desc | flag | nums#[] | words#[] | map#[]/ | data#{} | hero#[{}] | | ---- | -------------| ------ | ------- | ----------- | ---------- | ------------ | -------------------------- | | 123 | description | true | 1,2 | 哈哈,呵呵 | true/true | a:123;b:45 | id:2;level:30,id:3;level:80 | | 456 | 描述 | false | 3,5,8 | shit,my god | false/true | a:11;b:22 | id:9;level:38,id:17;level:100 | 输出如下: ```json [{ "id": 123, "desc": "description", "flag": true, "nums": [1, 2], "words": ["哈哈", "呵呵"], "map": [true, true], "data": { "a": 123, "b": 45 }, "hero": [ {"id": 2,"level": 30}, {"id": 3,"level": 80} ] }, { "id": 456, "desc": "描述", "flag": false, "nums": [3, 5, 8], "words": ["shit", "my god"], "map": [false, true], "data": { "a": 11, "b": 22 }, "hero": [ {"id": 9, "level": 38 }, {"id": 17,"level": 100} ] }] ``` ### 支持以下数据类型 * number 数字类型。 * boolean 布尔。 * string 字符串。 * date 日期类型。 * object 简单对象,暂时不支持对象里面有对象或数组这种。 * number-array 数字数组。 * boolean-array 布尔数组。 * string-array 字符串数组。 * object-array 对象数组。 * id 主键类型(当表中有这个类型的时候,json会以map格式输出,否则以数组格式输出)。 ### 表头规则 * 基本数据类型(string,number,bool)时候,一般不需要设置会自动判断,但是也可以明确声明数据类型。 * 字符串类型:命名形式 `列名#string` 。 * 数字类型:命名形式 `列名#number` 。 * 日期类型:`列名#date` 。日期格式要符合标准日期格式。比如`YYYY/M/D H:m:s` or `YYYY/M/D` 等等。 * 布尔类型:命名形式 `列名#bool` 。 * 基本类型数组:命名形式 `列名#[]`,数组元素默认用逗号分隔(a,b,c),自定义数组元素分隔符`列名#[]/`(a/b/c)。 * 对象:命名形式 `列名#{}` 。 * 对象数组:命名形式`列名#[{}]` 。 * 主键:命名形式`列名#id` 。 ### 数据规则 * 关键符号都是半角符号。 * 对象属性使用分号`;`分割。 ### TODO - [ ] 列为数组类型时候,嵌套复杂类型。 - [ ] 列为对象类型时候,嵌套复杂类型。 - [ ] 外键支持。 - [ ] 将主分支的代码合并到npm分支。 - [x] 数组分隔符的设置放到表头,默认用逗号。 ### 感谢 某些想法也是借鉴了一个clojure的excel转json的开源项目 [excel-to-json](https://github.com/mhaemmerle/excel-to-json)。 ### 补充 * windows/mac/linux都支持。 * 项目地址 [xlsx2json master](https://github.com/koalaylj/xlsx2json) * 如有问题可以到QQ群内讨论:223460081 * 招募协作开发者,有时间帮助一起维护下这个项目,可以发issue或者到qq群里把你github邮箱告诉我。 ================================================ FILE: tools/xlsx2json/config.json ================================================ { "xlsx": { "head": 2, "src": "./excel/**/[^~$]*.xlsx", "dest": "./json", "arraySeparator": "," }, "json": { "uglify": false } } ================================================ FILE: tools/xlsx2json/export.bat ================================================ @echo off title [convert excel to json] rem echo press any button to start. rem @pause > nul echo start converting .... node index.js --export copy json\*.json ..\..\code\EVA\server\script\DataTable\ /y echo convert over! @pause ================================================ FILE: tools/xlsx2json/export.sh ================================================ #!/bin/sh chmod u+x ./export.sh node index.js --export ================================================ FILE: tools/xlsx2json/index.js ================================================ const xlsx = require('./lib/xlsx-to-json.js'); const path = require('path'); const glob = require('glob'); const config = require('./config.json'); /** * all commands */ let commands = { "--help": { "alias": ["-h"], "desc": "show this help manual.", "action": showHelp }, "--export": { "alias": ["-e"], "desc": "export excel to json. --export [files]", "action": exportJson, "default": true } }; let alias_map = {}; // mapping of alias_name -> name let parsed_cmds = []; //cmds of parsed out. // process.on('uncaughtException', function(err) { // console.log('error: ' + err); // }); //cache of command's key ("--help"...) let keys = Object.keys(commands); for (let key in commands) { let alias_array = commands[key].alias; alias_array.forEach((e) => { alias_map[e] = key; }); } parsed_cmds = parseCommandLine(process.argv); // console.log("%j", parsed_cmds); parsed_cmds.forEach(function(e) { exec(e); }); /** * export json * args: --export [cmd_line_args] [.xlsx files list]. */ function exportJson(args) { if (typeof args === 'undefined' || args.length === 0) { glob(config.xlsx.src, function(err, files) { if (err) { console.error("exportJson error:", err); throw err; } files.forEach(function(element, index, array) { xlsx.toJson(path.join(__dirname, element), path.join(__dirname, config.xlsx.dest),config); }); }); } else { if (args instanceof Array) { args.forEach(function(element, index, array) { xlsx.toJson(path.join(__dirname, element), path.join(__dirname, config.xlsx.dest),config); }); } } } /** * show help */ function showHelp() { let usage = "usage: \n"; for (let p in commands) { if (typeof commands[p] !== "function") { usage += "\t " + p + "\t " + commands[p].alias + "\t " + commands[p].desc + "\n "; } } usage += "\nexamples: "; usage += "\n\n $node index.js --export\n\tthis will export all files configed to json."; usage += "\n\n $node index.js --export ./excel/foo.xlsx ./excel/bar.xlsx\n\tthis will export foo and bar xlsx files."; console.log(usage); } /**************************** parse command line *********************************/ /** * execute a command */ function exec(cmd) { if (typeof cmd.action === "function") { cmd.action(cmd.args); } } /** * parse command line args */ function parseCommandLine(args) { let parsed_cmds = []; if (args.length <= 2) { parsed_cmds.push(defaultCommand()); } else { let cli = args.slice(2); let pos = 0; let cmd; cli.forEach(function(element, index, array) { //replace alias name with real name. if (element.indexOf('--') === -1 && element.indexOf('-') === 0) { cli[index] = alias_map[element]; } //parse command and args if (cli[index].indexOf('--') === -1) { cmd.args.push(cli[index]); } else { if (keys[cli[index]] === "undefined") { throw new Error("not support command:" + cli[index]); } pos = index; cmd = commands[cli[index]]; if (typeof cmd.args === 'undefined') { cmd.args = []; } parsed_cmds.push(cmd); } }); } return parsed_cmds; } /** * default command when no command line argas provided. */ function defaultCommand() { if (keys.length <= 0) { throw new Error("Error: there is no command at all!"); } for (let p in commands) { if (commands[p]["default"]) { return commands[p]; } } if (keys["--help"]) { return commands["--help"]; } else { return commands[keys[0]]; } } /*************************************************************************/ ================================================ FILE: tools/xlsx2json/lib/xlsx-to-json.js ================================================ const xlsx = require('node-xlsx'); const fs = require('fs'); const path = require('path'); // const moment = require('moment'); let arraySeparator; /** * sheet(table) 的类型 * 影响输出json的类型 * 当有#id类型的时候 表输出json的是map形式(id:{xx:1}) * 当没有#id类型的时候 表输出json的是数组类型 没有id索引 */ const SheetType = { /** * 普通表 */ NORMAL: 0, /** * 有主外键关系的主表 * primary key */ PRIMARY: 1, /** * 有主外键关系的附表 * foreign key */ FOREIGN: 2 }; /** * 支持的数据类型 */ const DataType = { NUMBER: 'number', STRING: 'string', BOOL: 'bool', DATE: 'date', ID: 'id', ARRAY: '[]', OBJECT: '{}', OBJECT_ARRAY: '[{}]', UNKOWN: 'unkown' }; module.exports = { /** * convert xlsx file to json and save it to file system. * @param {String} src path of .xlsx files. * @param {String} dest directory for exported json files. * @param {Number} headIndex index of head line. * @param {String} separator array separator. * * excel structure * workbook > worksheet > table(row column) */ toJson: function(src, dest, config) { let headIndex = config.xlsx.head - 1; arraySeparator = config.xlsx.arraySeparator; let uglifyJson = config.json.uglify; if (!fs.existsSync(dest)) { fs.mkdirSync(dest); } console.log("parsing excel:", src); let workbook = xlsx.parse(src); parseWorkbook(workbook, dest, headIndex, uglifyJson); } }; /** * convert worksheet in workbook and save to file for each. * @param {[Object]} workbook json object of excel's workbook. * @param {[String]} dest directory for exported json files. * @param {[Number]} headIndex index of head line. */ function parseWorkbook(workbook, dest, headIndex, uglifyJson) { workbook.forEach(sheet => { // ignore sheet with external keys only, or start with a '#' if (sheet.name.indexOf('@') === -1 && sheet.name[0] !== "#") { let parsedSheet = parseSheet(sheet, headIndex); let dest_file = path.resolve(dest, sheet.name + ".json"); let formatedJson = JSON.stringify(parsedSheet, null, uglifyJson ? 0 : 2); //, null, 2 fs.writeFile(dest_file, formatedJson, err => { if (err) { console.error("error:", err); throw err; } console.log('exported successfully --> ', path.basename(dest_file)); }); } }); } /** * parse one sheet and return the result as a json object or array * * @param sheet * @param headIndex * @private */ function parseSheet(sheet, headIndex) { console.log('\t parsing sheet', sheet.name); if (sheet && sheet.data) { let head = parseHead(sheet, headIndex); let result; if (head.sheetType === SheetType.NORMAL) { result = []; } else if (head.sheetType === SheetType.PRIMARY) { result = {}; } for (let i_row = headIndex + 1; i_row < sheet.data.length; i_row++) { let row = sheet.data[i_row]; let parsedRow = parseRow(row, i_row, head); if (head.sheetType === SheetType.NORMAL) { ////json以数组的格式输出 result.push(parsedRow); } else if (head.sheetType === SheetType.PRIMARY) { //json以map的格式输出 let id = parsedRow[head.getIdKey()]; result[id] = parsedRow; } else { throw '无法识别表格类型!'; } } return result; } } function parseHead(sheet, headIndex) { let headRow = sheet.data[headIndex]; // console.log("\t\t parsing head", headIndex, headRow); let head = { //所有名字 json的key names: [], //所有列的数据类型 types: [], //表头所在的行索引 index: headIndex, //表类型 普通表 主表 引用表 sheetType: SheetType.NORMAL, getIdKey: function() { let id_col_index = this.types.indexOf(DataType.ID); if (id_col_index < 0) { throw '获取不到id列的名字'; } return this.names[id_col_index]; } }; headRow.forEach(cell => { let type = DataType.UNKOWN; let name = cell; if ((cell + '').indexOf('#') !== -1) { let pair = cell.split('#'); name = pair[0].trim(); type = pair[1].toLowerCase().trim(); if (type === DataType.ID) { head.sheetType = SheetType.PRIMARY; } } head.types.push(type); head.names.push(name); }); return head; } function parseRow(row, rowIndex, head) { let result = {}; let id; console.log('parsing row', row); row.forEach((cell, index) => { // if (cell) { let name = head.names[index]; let type = head.types[index]; switch (type) { case DataType.ID: // number string boolean if (isNumber(cell)) { id = Number(cell); } else { id = cell; } result[name] = id; break; case DataType.UNKOWN: // number string boolean if (isNumber(cell)) { result[name] = Number(cell); } else if (isBoolean(cell)) { result[name] = toBoolean(cell); } else { if (cell) { result[name] = cell; } } break; case DataType.DATE: if (isNumber(cell)) { //xlsx's bug!!! result[name] = numdate(cell); } else { if (cell) { result[name] = cell.toString(); } } break; case DataType.STRING: result[name] = cell.toString(); break; case DataType.NUMBER: //+xxx.toString() '+' means convert it to number if (isNumber(cell)) { result[name] = Number(cell); } else { console.warn("type error at [" + rowIndex + "," + index + "]," + cell + " is not a number"); } break; case DataType.BOOL: result[name] = toBoolean(cell); break; case DataType.OBJECT: //support {number boolean string date} property type if (cell) { result[name] = array2object(cell.split(';')); } break; case DataType.ARRAY: //[number] [boolean] [string] todo:support [date] type result[name] = parseBasicArrayField(cell, arraySeparator); break; case DataType.OBJECT_ARRAY: result[name] = parseObjectArrayField(cell); break; default: // foo#[]| 处理自定义数组分隔符 if (type.indexOf(DataType.ARRAY) !== -1) { // if (!type.endsWith(DataType.ARRAY)) { let separator = type.substr(-1, 1); //get the last character result[name] = parseBasicArrayField(cell, separator); // } } else { console.log('unrecognized type', '[' + rowIndex + ',' + index + ']', cell, typeof(cell)); } break; } // } }); return result; // switch (head.sheetType) { // case SheetType.NORMAL: //json以数组的格式输出 // return result; // case SheetType.PRIMARY: //json以map的格式输出 // let map = {}; // map[id] = result; // return map; // default: // throw '无法识别表格类型!'; // } // return result; } /** * parse object array. */ function parseObjectArrayField(value) { let obj_array = []; if (value) { if (value.indexOf(',') !== -1) { obj_array = value.split(','); } else { obj_array.push(value.toString()); } } // if (typeof(value) === 'string' && value.indexOf(',') !== -1) { // obj_array = value.split(','); // } else { // obj_array.push(value.toString()); // }; let result = []; obj_array.forEach(function(e) { if (e) { result.push(array2object(e.split(';'))); } }); // row[key] = result; return result; } /** * parse object from array. * for example : [a:123,b:45] => {'a':123,'b':45} */ function array2object(array) { let result = {}; array.forEach(function(e) { if (e) { let colonIndex = e.indexOf(':'); let key = e.substring(0, colonIndex); let value = e.substring(colonIndex + 1); if (isNumber(value)) { value = Number(value); } else if (isBoolean(value)) { value = toBoolean(value); } result[key] = value; } }); return result; } /** * parse simple array. */ function parseBasicArrayField(array, arraySeparator) { let basic_array; if (typeof array === "string") { basic_array = array.split(arraySeparator); } else { basic_array = []; basic_array.push(array); } let result = []; if (isNumberArray(basic_array)) { basic_array.forEach(function(element) { result.push(Number(element)); }); } else if (isBooleanArray(basic_array)) { basic_array.forEach(function(element) { result.push(toBoolean(element)); }); } else { //string array result = basic_array; } // console.log("basic_array", result + "|||" + cell.value); // field[key] = result; return result; } /** * convert value to boolean. */ function toBoolean(value) { return value.toString().toLowerCase() === 'true'; } /** * is a boolean array. */ function isBooleanArray(arr) { return arr.every(function(element, index, array) { return isBoolean(element); }); } /** * is a number array. */ function isNumberArray(arr) { return arr.every(function(element, index, array) { return isNumber(element); }); } /** * is a number. */ function isNumber(value) { if (typeof value === 'number') { return true; } if (value) { return !isNaN(+value.toString()); } return false; } /** * boolean type check. */ function isBoolean(value) { if (typeof(value) === "undefined") { return false; } if (typeof value === 'boolean') { return true; } let b = value.toString().trim().toLowerCase(); return b === 'true' || b === 'false'; } /** * date type check. */ // function isDateType(value) { // if (isNumber(value)) { // return false; // } // if (value) { // return moment(new Date(value), "YYYY-M-D", true).isValid() || moment(value, "YYYY-M-D H:m:s", true).isValid() || moment(value, "YYYY/M/D H:m:s", true).isValid() || moment(value, "YYYY/M/D", true).isValid(); // } // return false; // } //fuck xlsx's bug var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000 // var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000; var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000; // function datenum(v, date1904) { // var epoch = v.getTime(); // if(date1904) epoch -= 1462*24*60*60*1000; // return (epoch - dnthresh) / (24 * 60 * 60 * 1000); // } function numdate(v) { var out = new Date(); out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh); return out; } //fuck over ================================================ FILE: tools/xlsx2json/package.json ================================================ { "name": "xlsx2json", "main": "index.js", "version": "0.3.0", "description": "convert complex xlsx to json", "homepage": "https://github.com/koalaylj/xlsx2json", "author": "于小懒", "licenses": "MIT", "repository": { "type": "git", "url": "https://github.com/koalaylj/xlsx2json.git" }, "keywords": [ "xlsx", "excel", "json", "convert", "game developer", "mongo" ], "scripts": { "test": "mocha ./test/test.js" }, "dependencies": { "glob": "3.2.9", "minimatch": "~3.0.4", "moment": "^2.19.1", "node-xlsx": "^0.11.0", "xlsx": "^0.11.6" } }