diff --git a/engine/shared/library/sharedFoundation/CMakeLists.txt b/engine/shared/library/sharedFoundation/CMakeLists.txt new file mode 100644 index 00000000..0ceac90f --- /dev/null +++ b/engine/shared/library/sharedFoundation/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.8) + +project(sharedFoundation) + +if(WIN32) + add_definitions(/D_CRT_SECURE_NO_WARNINGS) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public) + +add_subdirectory(src) diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ApplicationVersion.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ApplicationVersion.h new file mode 100644 index 00000000..be446638 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ApplicationVersion.h @@ -0,0 +1 @@ +#include "../../src/shared/ApplicationVersion.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ArrayList.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ArrayList.h new file mode 100644 index 00000000..524cefc9 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ArrayList.h @@ -0,0 +1 @@ +#include "../../src/shared/ArrayList.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/AutoDeltaNetworkIdPackedMap.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/AutoDeltaNetworkIdPackedMap.h new file mode 100644 index 00000000..c2d55422 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/AutoDeltaNetworkIdPackedMap.h @@ -0,0 +1 @@ +#include "../../src/shared/AutoDeltaNetworkIdPackedMap.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Binary.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Binary.h new file mode 100644 index 00000000..00dfd984 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Binary.h @@ -0,0 +1 @@ +#include "../../src/shared/Binary.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/BitArray.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/BitArray.h new file mode 100644 index 00000000..5edacc68 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/BitArray.h @@ -0,0 +1 @@ +#include "../../src/shared/BitArray.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Branch.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Branch.h new file mode 100644 index 00000000..4f7a0c30 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Branch.h @@ -0,0 +1 @@ +#include "../../src/shared/Branch.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ByteOrder.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ByteOrder.h new file mode 100644 index 00000000..5dec355e --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ByteOrder.h @@ -0,0 +1,7 @@ +#if defined(PLATFORM_WIN32) +#include "../../src/win32/ByteOrder.h" +#elif defined(PLATFORM_LINUX) +#include "../../src/linux/ByteOrder.h" +#else +#error unsupported platform +#endif diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CalendarTime.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CalendarTime.h new file mode 100644 index 00000000..35a07e33 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CalendarTime.h @@ -0,0 +1 @@ +#include "../../src/shared/CalendarTime.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CallbackEntryBase.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CallbackEntryBase.h new file mode 100644 index 00000000..7b430379 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CallbackEntryBase.h @@ -0,0 +1 @@ +#include "../../src/shared/CallbackEntryBase.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Clock.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Clock.h new file mode 100644 index 00000000..c2ea66e5 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Clock.h @@ -0,0 +1 @@ +#include "../../src/shared/Clock.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CommandLine.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CommandLine.h new file mode 100644 index 00000000..e7b2f48f --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CommandLine.h @@ -0,0 +1 @@ +#include "../../src/shared/CommandLine.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ConfigFile.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ConfigFile.h new file mode 100644 index 00000000..a5200d27 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ConfigFile.h @@ -0,0 +1 @@ +#include "../../src/shared/ConfigFile.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ConfigSharedFoundation.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ConfigSharedFoundation.h new file mode 100644 index 00000000..6c1c3863 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ConfigSharedFoundation.h @@ -0,0 +1,7 @@ +#if defined(PLATFORM_WIN32) +#include "../../src/win32/ConfigSharedFoundation.h" +#elif defined(PLATFORM_LINUX) +#include "../../src/linux/ConfigSharedFoundation.h" +#else +#error unsupported platform +#endif diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ConstCharCrcLowerString.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ConstCharCrcLowerString.h new file mode 100644 index 00000000..accfec10 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ConstCharCrcLowerString.h @@ -0,0 +1 @@ +#include "../../src/shared/ConstCharCrcLowerString.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ConstCharCrcString.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ConstCharCrcString.h new file mode 100644 index 00000000..2f52142d --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ConstCharCrcString.h @@ -0,0 +1 @@ +#include "../../src/shared/ConstCharCrcString.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CrashReportInformation.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CrashReportInformation.h new file mode 100644 index 00000000..aa8d4128 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CrashReportInformation.h @@ -0,0 +1 @@ +#include "../../src/shared/CrashReportInformation.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Crc.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Crc.h new file mode 100644 index 00000000..af5b1ea5 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Crc.h @@ -0,0 +1 @@ +#include "../../src/shared/Crc.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CrcLowerString.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CrcLowerString.h new file mode 100644 index 00000000..c531dc4f --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CrcLowerString.h @@ -0,0 +1 @@ +#include "../../src/shared/CrcLowerString.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CrcString.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CrcString.h new file mode 100644 index 00000000..6c7c9aa3 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CrcString.h @@ -0,0 +1 @@ +#include "../../src/shared/CrcString.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CrcStringTable.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CrcStringTable.h new file mode 100644 index 00000000..6f2bdce7 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/CrcStringTable.h @@ -0,0 +1 @@ +#include "../../src/shared/CrcStringTable.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DataResource.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DataResource.h new file mode 100644 index 00000000..9bb6fc7b --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DataResource.h @@ -0,0 +1 @@ +#include "../../src/shared/DataResource.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DataResourceList.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DataResourceList.h new file mode 100644 index 00000000..d6b56ebf --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DataResourceList.h @@ -0,0 +1 @@ +#include "../../src/shared/DataResourceList.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DebugInfoManager.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DebugInfoManager.h new file mode 100644 index 00000000..b2f3bf90 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DebugInfoManager.h @@ -0,0 +1 @@ +#include "../../src/shared/DebugInfoManager.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DynamicVariable.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DynamicVariable.h new file mode 100644 index 00000000..10d9c397 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DynamicVariable.h @@ -0,0 +1 @@ +#include "../../src/shared/dynamicVariable/DynamicVariable.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DynamicVariableList.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DynamicVariableList.h new file mode 100644 index 00000000..7c5519fc --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DynamicVariableList.h @@ -0,0 +1 @@ +#include "../../src/shared/dynamicVariable/DynamicVariableList.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DynamicVariableListNestedList.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DynamicVariableListNestedList.h new file mode 100644 index 00000000..68c925ea --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DynamicVariableListNestedList.h @@ -0,0 +1 @@ +#include "../../src/shared/dynamicVariable/DynamicVariableListNestedList.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DynamicVariableLocationData.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DynamicVariableLocationData.h new file mode 100644 index 00000000..59175634 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/DynamicVariableLocationData.h @@ -0,0 +1 @@ +#include "../../src/shared/dynamicVariable/DynamicVariableLocationData.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ExitChain.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ExitChain.h new file mode 100644 index 00000000..416a46fd --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ExitChain.h @@ -0,0 +1 @@ +#include "../../src/shared/ExitChain.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Fatal.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Fatal.h new file mode 100644 index 00000000..b1e25d33 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Fatal.h @@ -0,0 +1 @@ +#include "../../src/shared/Fatal.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FirstPlatform.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FirstPlatform.h new file mode 100644 index 00000000..5d30aa47 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FirstPlatform.h @@ -0,0 +1,7 @@ +#if defined(PLATFORM_WIN32) +#include "../../src/win32/FirstPlatform.h" +#elif defined(PLATFORM_LINUX) +#include "../../src/linux/FirstPlatform.h" +#else +#error unsupported platform +#endif diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FirstSharedFoundation.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FirstSharedFoundation.h new file mode 100644 index 00000000..9ba92c6b --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FirstSharedFoundation.h @@ -0,0 +1 @@ +#include "../../src/shared/FirstSharedFoundation.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FloatMath.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FloatMath.h new file mode 100644 index 00000000..adda22f2 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FloatMath.h @@ -0,0 +1 @@ +#include "../../src/shared/FloatMath.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FloatingPointUnit.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FloatingPointUnit.h new file mode 100644 index 00000000..4cdd53fc --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FloatingPointUnit.h @@ -0,0 +1,7 @@ +#if defined(PLATFORM_WIN32) +#include "../../src/win32/FloatingPointUnit.h" +#elif defined(PLATFORM_LINUX) +#include "../../src/linux/FloatingPointUnit.h" +#else +#error unsupported platform +#endif diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FormattedString.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FormattedString.h new file mode 100644 index 00000000..50788f1f --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/FormattedString.h @@ -0,0 +1 @@ +#include "../../src/shared/FormattedString.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/GameControllerMessage.def b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/GameControllerMessage.def new file mode 100644 index 00000000..b71122d1 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/GameControllerMessage.def @@ -0,0 +1 @@ +#include "../../src/shared/GameControllerMessage.def" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/GameControllerMessage.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/GameControllerMessage.h new file mode 100644 index 00000000..f7bfa200 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/GameControllerMessage.h @@ -0,0 +1 @@ +#include "../../src/shared/GameControllerMessage.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/LabelHash.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/LabelHash.h new file mode 100644 index 00000000..05ed2168 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/LabelHash.h @@ -0,0 +1 @@ +#include "../../src/shared/LabelHash.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/LessPointerComparator.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/LessPointerComparator.h new file mode 100644 index 00000000..81ea0331 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/LessPointerComparator.h @@ -0,0 +1 @@ +#include "../../src/shared/LessPointerComparator.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MacroFoundation.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MacroFoundation.h new file mode 100644 index 00000000..195575ca --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MacroFoundation.h @@ -0,0 +1 @@ +#include "../../src/shared/MacroFoundation.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Md5.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Md5.h new file mode 100644 index 00000000..55f5ee2c --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Md5.h @@ -0,0 +1 @@ +#include "../../src/shared/Md5.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MemoryBlockManager.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MemoryBlockManager.h new file mode 100644 index 00000000..a29473e4 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MemoryBlockManager.h @@ -0,0 +1 @@ +#include "../../src/shared/MemoryBlockManager.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MemoryBlockManagerMacros.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MemoryBlockManagerMacros.h new file mode 100644 index 00000000..932a8009 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MemoryBlockManagerMacros.h @@ -0,0 +1 @@ +#include "../../src/shared/MemoryBlockManagerMacros.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MessageQueue.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MessageQueue.h new file mode 100644 index 00000000..7103a7b0 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MessageQueue.h @@ -0,0 +1 @@ +#include "../../src/shared/MessageQueue.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MessageQueueDataTemplate.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MessageQueueDataTemplate.h new file mode 100644 index 00000000..8486adf0 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/MessageQueueDataTemplate.h @@ -0,0 +1 @@ +#include "../../src/shared/MessageQueueDataTemplate.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Misc.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Misc.h new file mode 100644 index 00000000..79383489 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Misc.h @@ -0,0 +1 @@ +#include "../../src/shared/Misc.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/NetworkId.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/NetworkId.h new file mode 100644 index 00000000..f33be2cc --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/NetworkId.h @@ -0,0 +1 @@ +#include "../../src/shared/NetworkId.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/NetworkIdArchive.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/NetworkIdArchive.h new file mode 100644 index 00000000..a4204148 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/NetworkIdArchive.h @@ -0,0 +1 @@ +#include "../../src/shared/NetworkIdArchive.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Os.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Os.h new file mode 100644 index 00000000..8578388e --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Os.h @@ -0,0 +1,7 @@ +#if defined(PLATFORM_WIN32) +#include "../../src/win32/Os.h" +#elif defined(PLATFORM_LINUX) +#include "../../src/linux/Os.h" +#else +#error unsupported platform +#endif diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/PerThreadData.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/PerThreadData.h new file mode 100644 index 00000000..31db1f7d --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/PerThreadData.h @@ -0,0 +1,7 @@ +#if defined(PLATFORM_WIN32) +#include "../../src/win32/PerThreadData.h" +#elif defined(PLATFORM_LINUX) +#include "../../src/linux/PerThreadData.h" +#else +#error unsupported platform +#endif diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/PersistentCrcString.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/PersistentCrcString.h new file mode 100644 index 00000000..ae0b6608 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/PersistentCrcString.h @@ -0,0 +1 @@ +#include "../../src/shared/PersistentCrcString.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/PlatformGlue.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/PlatformGlue.h new file mode 100644 index 00000000..394db13f --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/PlatformGlue.h @@ -0,0 +1,7 @@ +#if defined(PLATFORM_WIN32) +#include "../../src/win32/PlatformGlue.h" +#elif defined(PLATFORM_LINUX) +#include "../../src/linux/PlatformGlue.h" +#else +#error unsupported platform +#endif diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/PointerDeleter.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/PointerDeleter.h new file mode 100644 index 00000000..e1c3c5ad --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/PointerDeleter.h @@ -0,0 +1 @@ +#include "../../src/shared/PointerDeleter.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ProcessSpawner.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ProcessSpawner.h new file mode 100644 index 00000000..35e4a9da --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/ProcessSpawner.h @@ -0,0 +1 @@ +#include "../../src/win32/ProcessSpawner.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Production.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Production.h new file mode 100644 index 00000000..68a32388 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Production.h @@ -0,0 +1 @@ +#include "../../src/shared/Production.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/RegistryKey.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/RegistryKey.h new file mode 100644 index 00000000..ab5cf83c --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/RegistryKey.h @@ -0,0 +1,5 @@ +#if defined(PLATFORM_WIN32) +#include "../../src/win32/RegistryKey.h" +#else +#error unsupported platform +#endif diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/SafeCast.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/SafeCast.h new file mode 100644 index 00000000..525233d8 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/SafeCast.h @@ -0,0 +1 @@ +#include "../../src/shared/SafeCast.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Scheduler.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Scheduler.h new file mode 100644 index 00000000..5237d7b7 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Scheduler.h @@ -0,0 +1 @@ +#include "../../src/shared/Scheduler.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/SetupSharedFoundation.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/SetupSharedFoundation.h new file mode 100644 index 00000000..61b743bf --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/SetupSharedFoundation.h @@ -0,0 +1,7 @@ +#if defined(PLATFORM_WIN32) +#include "../../src/win32/SetupSharedFoundation.h" +#elif defined(PLATFORM_LINUX) +#include "../../src/linux/SetupSharedFoundation.h" +#else +#error unsupported platform +#endif diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/StaticCallbackEntry.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/StaticCallbackEntry.h new file mode 100644 index 00000000..a372b9d7 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/StaticCallbackEntry.h @@ -0,0 +1 @@ +#include "../../src/shared/StaticCallbackEntry.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/StationId.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/StationId.h new file mode 100644 index 00000000..472cc524 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/StationId.h @@ -0,0 +1 @@ +#include "../../src/shared/StationId.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/StlForwardDeclaration.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/StlForwardDeclaration.h new file mode 100644 index 00000000..020bdaeb --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/StlForwardDeclaration.h @@ -0,0 +1 @@ +#include "../../src/shared/StlForwardDeclaration.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/StringCompare.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/StringCompare.h new file mode 100644 index 00000000..414d943e --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/StringCompare.h @@ -0,0 +1 @@ +#include "../../src/shared/StringCompare.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Tag.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Tag.h new file mode 100644 index 00000000..8e791293 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Tag.h @@ -0,0 +1 @@ +#include "../../src/shared/Tag.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/TemporaryCrcString.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/TemporaryCrcString.h new file mode 100644 index 00000000..132e7a38 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/TemporaryCrcString.h @@ -0,0 +1 @@ +#include "../../src/shared/TemporaryCrcString.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Timer.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Timer.h new file mode 100644 index 00000000..293769fa --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Timer.h @@ -0,0 +1 @@ +#include "../../src/shared/Timer.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/VoidBindSecond.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/VoidBindSecond.h new file mode 100644 index 00000000..cd968358 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/VoidBindSecond.h @@ -0,0 +1 @@ +#include "../../src/shared/VoidBindSecond.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/VoidMemberFunction.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/VoidMemberFunction.h new file mode 100644 index 00000000..0f2be2a2 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/VoidMemberFunction.h @@ -0,0 +1 @@ +#include "../../src/shared/VoidMemberFunction.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Watcher.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Watcher.h new file mode 100644 index 00000000..bc4deeb8 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/Watcher.h @@ -0,0 +1 @@ +#include "../../src/shared/Watcher.h" diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/WindowsWrapper.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/WindowsWrapper.h new file mode 100644 index 00000000..f432a850 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/WindowsWrapper.h @@ -0,0 +1,5 @@ +#if defined(PLATFORM_WIN32) +#include "../../src/win32/WindowsWrapper.h" +#else +#error unsupported platform +#endif diff --git a/engine/shared/library/sharedFoundation/include/public/sharedFoundation/vsnprintf.h b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/vsnprintf.h new file mode 100644 index 00000000..a41562f6 --- /dev/null +++ b/engine/shared/library/sharedFoundation/include/public/sharedFoundation/vsnprintf.h @@ -0,0 +1,5 @@ +#if defined(PLATFORM_LINUX) +#include "../../src/linux/vsnprintf.h" +#else +#error unsupported platform +#endif diff --git a/engine/shared/library/sharedFoundation/src/CMakeLists.txt b/engine/shared/library/sharedFoundation/src/CMakeLists.txt new file mode 100644 index 00000000..4a2d4847 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/CMakeLists.txt @@ -0,0 +1,151 @@ + +set(SHARED_SOURCES + shared/ApplicationVersion.cpp + shared/ApplicationVersion.h + shared/ArrayList.h + shared/AutoDeltaNetworkIdPackedMap.cpp + shared/AutoDeltaNetworkIdPackedMap.h + shared/Binary.h + shared/BitArray.cpp + shared/BitArray.h + shared/Branch.cpp + shared/Branch.h + shared/CalendarTime.cpp + shared/CalendarTime.h + shared/CallbackEntryBase.h + shared/Clock.cpp + shared/Clock.h + shared/CommandLine.cpp + shared/CommandLine.h + shared/ConfigFile.cpp + shared/ConfigFile.h + shared/ConstCharCrcLowerString.cpp + shared/ConstCharCrcLowerString.h + shared/ConstCharCrcString.cpp + shared/ConstCharCrcString.h + shared/CrashReportInformation.cpp + shared/CrashReportInformation.h + shared/Crc.cpp + shared/Crc.h + shared/CrcLowerString.cpp + shared/CrcLowerString.h + shared/CrcString.cpp + shared/CrcString.h + shared/CrcStringTable.cpp + shared/CrcStringTable.h + shared/DataResource.cpp + shared/DataResource.h + shared/DataResourceList.h + shared/DebugInfoManager.cpp + shared/DebugInfoManager.h + shared/ExitChain.cpp + shared/ExitChain.h + shared/Fatal.cpp + shared/Fatal.h + shared/FirstSharedFoundation.h + shared/FloatMath.h + shared/FormattedString.h + shared/GameControllerMessage.h + shared/LabelHash.cpp + shared/LabelHash.h + shared/LessPointerComparator.h + shared/MacroFoundation.h + shared/Md5.cpp + shared/Md5.h + shared/MemoryBlockManager.cpp + shared/MemoryBlockManager.h + shared/MemoryBlockManagerMacros.h + shared/MessageQueue.cpp + shared/MessageQueueDataTemplate.cpp + shared/MessageQueueDataTemplate.h + shared/MessageQueue.h + shared/Misc.h + shared/NetworkIdArchive.cpp + shared/NetworkIdArchive.h + shared/NetworkId.cpp + shared/NetworkId.h + shared/PersistentCrcString.cpp + shared/PersistentCrcString.h + shared/PointerDeleter.h + shared/Production.h + shared/SafeCast.h + shared/Scheduler.cpp + shared/Scheduler.h + shared/StaticCallbackEntry.cpp + shared/StaticCallbackEntry.h + shared/StationId.h + shared/StlForwardDeclaration.h + shared/StringCompare.h + shared/Tag.h + shared/TemporaryCrcString.cpp + shared/TemporaryCrcString.h + shared/Timer.cpp + shared/Timer.h + shared/VoidBindSecond.h + shared/VoidMemberFunction.h + shared/Watcher.cpp + shared/Watcher.h + + shared/dynamicVariable/DynamicVariable.cpp + shared/dynamicVariable/DynamicVariable.h + shared/dynamicVariable/DynamicVariableList.cpp + shared/dynamicVariable/DynamicVariableList.h + shared/dynamicVariable/DynamicVariableListNestedList.cpp + shared/dynamicVariable/DynamicVariableListNestedList.h + shared/dynamicVariable/DynamicVariableLocationData.h +) + +if(WIN32) + set(PLATFORM_SOURCES + win32/ByteOrder.cpp + win32/ByteOrder.h + win32/ConfigSharedFoundation.cpp + win32/ConfigSharedFoundation.h + win32/FirstPlatform.h + win32/FloatingPointUnit.cpp + win32/FloatingPointUnit.h + win32/Os.cpp + win32/Os.h + win32/PerThreadData.cpp + win32/PerThreadData.h + win32/PlatformGlue.cpp + win32/PlatformGlue.h + win32/ProcessSpawner.cpp + win32/ProcessSpawner.h + win32/RegistryKey.cpp + win32/RegistryKey.h + win32/SetupSharedFoundation.cpp + win32/SetupSharedFoundation.h + win32/WindowsWrapper.h + ) + + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32) +else() + set(PLATFORM_SOURCES + linux/ByteOrder.h + linux/ConfigSharedFoundation.cpp + linux/ConfigSharedFoundation.h + linux/FirstPlatform.h + linux/FloatingPointUnit.cpp + linux/FloatingPointUnit.h + linux/Os.cpp + linux/Os.h + linux/PerThreadData.cpp + linux/PerThreadData.h + linux/PlatformGlue.cpp + linux/PlatformGlue.h + linux/SetupSharedFoundation.cpp + linux/SetupSharedFoundation.h + linux/vsnprintf.cpp + linux/vsnprintf.h + ) + + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/linux) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shared) + +add_library(sharedFoundation + ${SHARED_SOURCES} + ${PLATFORM_SOURCES} +) diff --git a/engine/shared/library/sharedFoundation/src/linux/ByteOrder.h b/engine/shared/library/sharedFoundation/src/linux/ByteOrder.h new file mode 100644 index 00000000..acb0e335 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/ByteOrder.h @@ -0,0 +1,20 @@ +// ====================================================================== +// +// ByteOrder.h +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#ifndef BYTE_ORDER_H +#define BYTE_ORDER_H + +// ====================================================================== + +#include "sharedFoundation/FirstPlatform.h" + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedFoundation/src/linux/ConfigSharedFoundation.cpp b/engine/shared/library/sharedFoundation/src/linux/ConfigSharedFoundation.cpp new file mode 100644 index 00000000..79aab435 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/ConfigSharedFoundation.cpp @@ -0,0 +1,289 @@ +// ====================================================================== +// +// ConfigSharedFoundation.cpp +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/ConfigSharedFoundation.h" + +#include "sharedFoundation/ConfigFile.h" + +// ====================================================================== + +const int c_defaultFatalCallStackDepth = 32; +const int c_defaultWarningCallStackDepth = 8; + +// ====================================================================== + +namespace ConfigSharedFoundationNamespace +{ + real ms_frameRateLimit; + real ms_minFrameRate; + bool ms_noExceptionHandling; + + bool ms_fpuExceptionPrecision; + bool ms_fpuExceptionUnderflow; + bool ms_fpuExceptionOverflow; + bool ms_fpuExceptionZeroDivide; + bool ms_fpuExceptionDenormal; + bool ms_fpuExceptionInvalid; + + bool ms_demoMode; + + bool ms_useRemoteDebug; + int ms_defaultRemoteDebugPort; + + bool ms_profilerExpandAllBranches = true; + + bool ms_memoryManagerReportAllocations; + bool ms_memoryManagerReportOnOutOfMemory; + + bool ms_useMemoryBlockManager; + bool ms_memoryBlockManagerDebugDumpOnRemove; + + int ms_fatalCallStackDepth; + int ms_warningCallStackDepth; + bool ms_lookUpCallStackNames; + + bool ms_alwaysCanSeeWorldCell; + + bool ms_verboseWarnings; + + float ms_debugReportLongFrameTime; +} + +using namespace ConfigSharedFoundationNamespace; + +// ====================================================================== + +#define KEY_INT(a,b) (ms_ ## a = ConfigFile::getKeyInt("SharedFoundation", #a, b)) +#define KEY_BOOL(a,b) (ms_ ## a = ConfigFile::getKeyBool("SharedFoundation", #a, b)) +#define KEY_FLOAT(a,b) (ms_ ## a = ConfigFile::getKeyFloat("SharedFoundation", #a, b)) +// #define KEY_STRING(a,b) (ms_ ## a = ConfigFile::getKeyString("SharedFoundation", #a, b)) + +// ====================================================================== +// Determine the Platform-specific configuration information +// +// Remarks: +// +// This routine inspects the ConfigFile class to set some variables for rapid access +// by the rest of the engine. + +void ConfigSharedFoundation::install (const Defaults &defaults) +{ + KEY_BOOL(noExceptionHandling, false); + + KEY_BOOL(fpuExceptionPrecision, false); + KEY_BOOL(fpuExceptionUnderflow, false); + KEY_BOOL(fpuExceptionOverflow, false); + KEY_BOOL(fpuExceptionZeroDivide, false); + KEY_BOOL(fpuExceptionDenormal, false); + KEY_BOOL(fpuExceptionInvalid, false); + + KEY_BOOL(demoMode, false); + + KEY_FLOAT(frameRateLimit, defaults.frameRateLimit); + KEY_FLOAT(minFrameRate, 0.0f); + + KEY_BOOL(useRemoteDebug, false); + KEY_INT(defaultRemoteDebugPort, 4445); + + KEY_BOOL(profilerExpandAllBranches, true); + KEY_BOOL(memoryManagerReportAllocations, true); + KEY_BOOL(memoryManagerReportOnOutOfMemory, true); + + KEY_BOOL(useMemoryBlockManager, true); + KEY_BOOL(memoryBlockManagerDebugDumpOnRemove, false); + + KEY_INT(fatalCallStackDepth, c_defaultFatalCallStackDepth); + KEY_INT(warningCallStackDepth, c_defaultWarningCallStackDepth); + KEY_BOOL(lookUpCallStackNames, true); + + KEY_BOOL(alwaysCanSeeWorldCell, false); + + KEY_BOOL(verboseWarnings, false); + + KEY_FLOAT(debugReportLongFrameTime, 0.25f); +} + +// ====================================================================== +/** + * Return the frame rate limit value for the game. + * + * @return The initial frame rate limiter value + */ + +real ConfigSharedFoundation::getFrameRateLimit(void) +{ + return ms_frameRateLimit; +} + +// ---------------------------------------------------------------------- +/** + * Return the minimum frame rate limit value for the game. Frame that take longer + * will be set to the minimum and a message will be logged. + * + * @return The minimum frame rate value + */ + +real ConfigSharedFoundation::getMinFrameRate(void) +{ + return ms_minFrameRate; +} + +// ---------------------------------------------------------------------- +/** + * Return whether to run with exception handling enabled. + * + * @return True to run without exception handling + */ + +bool ConfigSharedFoundation::getNoExceptionHandling(void) +{ + return ms_noExceptionHandling; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getFpuExceptionPrecision(void) +{ + return ms_fpuExceptionPrecision; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getFpuExceptionUnderflow(void) +{ + return ms_fpuExceptionUnderflow; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getFpuExceptionOverflow(void) +{ + return ms_fpuExceptionOverflow; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getFpuExceptionZeroDivide(void) +{ + return ms_fpuExceptionZeroDivide; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getFpuExceptionDenormal(void) +{ + return ms_fpuExceptionDenormal; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getFpuExceptionInvalid(void) +{ + return ms_fpuExceptionInvalid; +} + +// ---------------------------------------------------------------------- + +int ConfigSharedFoundation::getFatalCallStackDepth() +{ + return ms_fatalCallStackDepth; +} + +// ---------------------------------------------------------------------- + +int ConfigSharedFoundation::getWarningCallStackDepth() +{ + return ms_warningCallStackDepth; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getProfilerExpandAllBranches() +{ + return ms_profilerExpandAllBranches; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getUseRemoteDebug() +{ + return ms_useRemoteDebug; +} + +// ---------------------------------------------------------------------- + +int ConfigSharedFoundation::getDefaultRemoteDebugPort() +{ + return ms_defaultRemoteDebugPort; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getDemoMode() +{ + return ms_demoMode; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getAlwaysCanSeeWorldCell() +{ + return ms_alwaysCanSeeWorldCell; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getLookUpCallStackNames() +{ + return ms_lookUpCallStackNames; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getMemoryManagerReportAllocations() +{ + return ms_memoryManagerReportAllocations; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getMemoryManagerReportOnOutOfMemory() +{ + return ms_memoryManagerReportOnOutOfMemory; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getUseMemoryBlockManager() +{ + return ms_useMemoryBlockManager; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getMemoryBlockManagerDebugDumpOnRemove () +{ + return ms_memoryBlockManagerDebugDumpOnRemove; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getVerboseWarnings() +{ + return ms_verboseWarnings; +} + +// ---------------------------------------------------------------------- + +float ConfigSharedFoundation::getDebugReportLongFrameTime() +{ + return ms_debugReportLongFrameTime; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/linux/ConfigSharedFoundation.h b/engine/shared/library/sharedFoundation/src/linux/ConfigSharedFoundation.h new file mode 100644 index 00000000..ace08184 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/ConfigSharedFoundation.h @@ -0,0 +1,64 @@ +// ====================================================================== +// +// ConfigSharedFoundation.h +// copyright 1998 Bootprint Entertainment +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_ConfigSharedFoundation_H +#define INCLUDED_ConfigSharedFoundation_H + +// ====================================================================== + +class ConfigSharedFoundation +{ +public: + + struct Defaults + { + real frameRateLimit; + }; + +public: + + static void install (const Defaults &defaults); + + static real getFrameRateLimit(); + static real getMinFrameRate(); + static bool getNoExceptionHandling(); + + static bool getFpuExceptionPrecision(); + static bool getFpuExceptionUnderflow(); + static bool getFpuExceptionOverflow(); + static bool getFpuExceptionZeroDivide(); + static bool getFpuExceptionDenormal(); + static bool getFpuExceptionInvalid(); + + static bool getDemoMode(); + + static bool getUseRemoteDebug(); + static int getDefaultRemoteDebugPort(); + + static bool getProfilerExpandAllBranches(); + + static bool getMemoryManagerReportAllocations(); + static bool getMemoryManagerReportOnOutOfMemory(); + + static bool getUseMemoryBlockManager(); + static bool getMemoryBlockManagerDebugDumpOnRemove(); + + static int getFatalCallStackDepth(); + static int getWarningCallStackDepth(); + static bool getLookUpCallStackNames(); + + static bool getAlwaysCanSeeWorldCell(); + + static bool getVerboseWarnings(); + + static float getDebugReportLongFrameTime(); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/linux/FirstPlatform.h b/engine/shared/library/sharedFoundation/src/linux/FirstPlatform.h new file mode 100644 index 00000000..7d2ac3bc --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/FirstPlatform.h @@ -0,0 +1,54 @@ +// ====================================================================== +// +// FirstPlatform.h +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#ifndef FIRST_PLATFORM_H +#define FIRST_PLATFORM_H + +// ====================================================================== + +#include + +#define DLLEXPORT + +// ====================================================================== + +// C4514 unreferenced inline function has been removed +// C4710 inline function not expanded +// C4291 no matching operator delete found; memory will not be freed if initialization throws an exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sharedFoundation/PlatformGlue.h" +#include "sharedMemoryManager/MemoryManager.h" + + +// ====================================================================== + +template +inline int ComGetReferenceCount(T *t) +{ + t->AddRef(); + return t->Release(); +} + +// ====================================================================== + +#define FATAL_HR(a,b) FATAL(FAILED(b), (a, HRESULT_CODE(b))) +#define DEBUG_FATAL_HR(a,b) DEBUG_FATAL(FAILED(b), (a, HRESULT_CODE(b))) + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/linux/FloatingPointUnit.cpp b/engine/shared/library/sharedFoundation/src/linux/FloatingPointUnit.cpp new file mode 100644 index 00000000..3ad0c949 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/FloatingPointUnit.cpp @@ -0,0 +1,266 @@ +// ====================================================================== +// +// FloatingPointUnit.cpp +// jeff grills +// +// copyright 1999 Bootprint Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/FloatingPointUnit.h" + +#include "sharedFoundation/ConfigSharedFoundation.h" + +// ====================================================================== + +int FloatingPointUnit::updateNumber; +WORD FloatingPointUnit::status; +FloatingPointUnit::Precision FloatingPointUnit::precision; +FloatingPointUnit::Rounding FloatingPointUnit::rounding; +bool FloatingPointUnit::exceptionEnabled[E_max]; + +// ====================================================================== + +const WORD PRECISION_MASK = BINARY4(0000,0011,0000,0000); +const WORD PRECISION_24 = BINARY4(0000,0000,0000,0000); +const WORD PRECISION_53 = BINARY4(0000,0010,0000,0000); +const WORD PRECISION_64 = BINARY4(0000,0011,0000,0000); + +const WORD ROUND_MASK = BINARY4(0000,1100,0000,0000); +const WORD ROUND_NEAREST = BINARY4(0000,0000,0000,0000); +const WORD ROUND_CHOP = BINARY4(0000,1100,0000,0000); +const WORD ROUND_DOWN = BINARY4(0000,0100,0000,0000); +const WORD ROUND_UP = BINARY4(0000,1000,0000,0000); + +const WORD EXCEPTION_PRECISION = BINARY4(0000,0000,0010,0000); +const WORD EXCEPTION_UNDERFLOW = BINARY4(0000,0000,0001,0000); +const WORD EXCEPTION_OVERFLOW = BINARY4(0000,0000,0000,1000); +const WORD EXCEPTION_ZERO_DIVIDE = BINARY4(0000,0000,0000,0100); +const WORD EXCEPTION_DENORMAL = BINARY4(0000,0000,0000,0010); +const WORD EXCEPTION_INVALID = BINARY4(0000,0000,0000,0001); +const WORD EXCEPTION_ALL = BINARY4(0000,0000,0011,1111); + +// ====================================================================== + +void FloatingPointUnit::install(void) +{ + precision = P_24; + rounding = R_roundToNearestOrEven; + memset(exceptionEnabled, 0, sizeof(exceptionEnabled)); + + // preserve all other bits + status = getControlWord(); + status &= ~(PRECISION_MASK | ROUND_MASK | EXCEPTION_ALL); + + // set to single precision, rounding, and all exceptions masked + status |= PRECISION_24 | ROUND_NEAREST | EXCEPTION_ALL; + + // check the config platform flags to see if we should enable some exceptions + if (ConfigSharedFoundation::getFpuExceptionPrecision()) + { + exceptionEnabled[E_precision] = true; + status &= ~EXCEPTION_PRECISION; + } + + if (ConfigSharedFoundation::getFpuExceptionUnderflow()) + { + exceptionEnabled[E_underflow] = true; + status &= ~EXCEPTION_UNDERFLOW; + } + + if (ConfigSharedFoundation::getFpuExceptionOverflow()) + { + exceptionEnabled[E_overflow] = true; + status &= ~EXCEPTION_OVERFLOW; + } + + if (ConfigSharedFoundation::getFpuExceptionZeroDivide()) + { + exceptionEnabled[E_zeroDivide] = true; + status &= ~EXCEPTION_ZERO_DIVIDE; + } + + if (ConfigSharedFoundation::getFpuExceptionDenormal()) + { + exceptionEnabled[E_denormal] = true; + status &= ~EXCEPTION_DENORMAL; + } + + if (ConfigSharedFoundation::getFpuExceptionInvalid()) + { + exceptionEnabled[E_invalid] = true; + status &= ~EXCEPTION_INVALID; + } + + setControlWord(status); +} + +// ---------------------------------------------------------------------- + +void FloatingPointUnit::update(void) +{ + WORD currentStatus = getControlWord(); + + if (currentStatus != status) + { + DEBUG_REPORT_LOG_PRINT(true, ("FPU: update=%d, in mode=%04x, should be in mode=%04x", updateNumber, static_cast(currentStatus), static_cast(status))); + setControlWord(status); + } + + ++updateNumber; +} + +// ---------------------------------------------------------------------- + +WORD FloatingPointUnit::getControlWord(void) +{ + //TODO wtf is this asm statement? +#if 0 + WORD controlWord = 0; + __asm fnstcw controlWord; + return controlWord; +#else + return status; +#endif +} + +// ---------------------------------------------------------------------- + +void FloatingPointUnit::setControlWord(WORD controlWord) +{ + //TODO see above? + + UNREF(controlWord); +#if 0 + __asm fldcw controlWord; +#endif +} + +// ---------------------------------------------------------------------- + +void FloatingPointUnit::setPrecision(Precision newPrecision) +{ + WORD bits = 0; + + switch (precision) + { + case P_24: + bits = PRECISION_24; + break; + + case P_53: + bits = PRECISION_53; + break; + + case P_64: + bits = PRECISION_64; + break; + + case P_max: + default: + DEBUG_FATAL(true, ("bad case")); + } + + // record the current state + precision = newPrecision; + + // set the proper bit pattern + status &= ~PRECISION_MASK; + status |= bits; + + // slam it into the FPU + setControlWord(status); +} + +// ---------------------------------------------------------------------- + +void FloatingPointUnit::setRounding(Rounding newRounding) +{ + WORD bits = 0; + + switch (newRounding) + { + case R_roundToNearestOrEven: + bits = ROUND_NEAREST; + break; + + case R_chop: + bits = ROUND_CHOP; + break; + + case R_roundDown: + bits = ROUND_DOWN; + break; + + case R_roundUp: + bits = ROUND_UP; + break; + + case R_max: + default: + DEBUG_FATAL(true, ("bad case")); + } + + // record the current state + rounding = newRounding; + + // set the proper bit pattern + status &= ~ROUND_MASK; + status |= bits; + + // slam it into the FPU + setControlWord(status); +} + +// ---------------------------------------------------------------------- + +void FloatingPointUnit::setExceptionEnabled(Exception exception, bool enabled) +{ + WORD bits = 0; + + switch (exception) + { + case E_precision: + bits = EXCEPTION_PRECISION; + break; + + case E_underflow: + bits = EXCEPTION_UNDERFLOW; + break; + + case E_overflow: + bits = EXCEPTION_OVERFLOW; + break; + + case E_zeroDivide: + bits = EXCEPTION_ZERO_DIVIDE; + break; + + case E_denormal: + bits = EXCEPTION_DENORMAL; + break; + + case E_invalid: + bits = EXCEPTION_INVALID; + break; + + case E_max: + default: + DEBUG_FATAL(true, ("bad case")); + } + + // record the current state + exceptionEnabled[exception] = enabled; + + // twiddle the bit appropriately. these bits masks, so set the bit to disable the exception, clear the bit to enable it. + if (enabled) + status &= ~bits; + else + status |= bits; + + // slam it into the FPU + setControlWord(status); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/linux/FloatingPointUnit.h b/engine/shared/library/sharedFoundation/src/linux/FloatingPointUnit.h new file mode 100644 index 00000000..d435343a --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/FloatingPointUnit.h @@ -0,0 +1,102 @@ +// ====================================================================== +// +// FloatingPointUnit.h +// jeff grills +// +// copyright 1999 Bootprint Entertainment +// +// ====================================================================== + +#ifndef FLOATING_POINT_UNIT_H +#define FLOATING_POINT_UNIT_H + +// ====================================================================== + +class FloatingPointUnit +{ +public: + + enum Precision + { + P_24, + P_53, + P_64, + + P_max + }; + + enum Rounding + { + R_roundToNearestOrEven, + R_chop, + R_roundDown, + R_roundUp, + + R_max + }; + + enum Exception + { + E_precision, + E_underflow, + E_overflow, + E_zeroDivide, + E_denormal, + E_invalid, + + E_max + }; + +private: + + static int updateNumber; + static WORD status; + static Precision precision; + static Rounding rounding; + static bool exceptionEnabled[E_max]; + +public: + + static WORD getControlWord(void); + static void setControlWord(WORD controlWord); + +public: + + static void install(void); + + static void update(void); + + static void setPrecision(Precision newPrecision); + static void setRounding(Rounding newRounding); + static void setExceptionEnabled(Exception exception, bool enabled); + + static Precision getPrecision(void); + static Rounding getRounding(void); + static bool getExceptionEnabled(Exception exception); +}; + +// ====================================================================== + +inline FloatingPointUnit::Precision FloatingPointUnit::getPrecision(void) +{ + return precision; +} + +// ---------------------------------------------------------------------- + +inline FloatingPointUnit::Rounding FloatingPointUnit::getRounding(void) +{ + return rounding; +} + +// ---------------------------------------------------------------------- + +inline bool FloatingPointUnit::getExceptionEnabled(Exception exception) +{ + DEBUG_FATAL(static_cast(exception) < 0 || static_cast(exception) >= static_cast(E_max), ("exception out of range")); //lint !e568 // non-negative quantity is never less than 0 + return exceptionEnabled[exception]; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/linux/Os.cpp b/engine/shared/library/sharedFoundation/src/linux/Os.cpp new file mode 100644 index 00000000..e9f2b621 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/Os.cpp @@ -0,0 +1,468 @@ +// ====================================================================== +// +// Os.cpp +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/Os.h" + +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedDebug/DebugMonitor.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/FloatingPointUnit.h" +#include "sharedIoWin/IoWinManager.h" + +#include +#include + +// ====================================================================== + +bool Os::installed; +bool Os::runInBackground; +int Os::numberOfUpdates; +int Os::menuValue; +bool Os::paused; +bool Os::wasPaused; +bool Os::gameOver; +bool Os::shouldReturnFromAbort; +char Os::programName[PROGRAM_NAME_SIZE]; +char *Os::shortProgramName; +pthread_t Os::mainThreadId; +bool Os::threadDied; + +bool Os::isMp; +int Os::processorCount; + +// ---------------------------------------------------------------------- + +namespace OsNamespace +{ + class UncatchableException + { + }; +} + + +// ---------------------------------------------------------------------- +/** + * Install the Os subsystem for non-games. + * + * This routine is supported for all platforms, although different platforms may + * require different arguments to this routine. + * + * This routine will add Os::remove to the ExitChain. + * + * @see Os::remove() + */ + +void Os::install(void) +{ + installCommon(); +} + +// ---------------------------------------------------------------------- +/** + * This routine will remove the Os subsystem. + * + * This routine should not be called directly. It will be called from the ExitChain. + * + * @see Os::install() + */ + +void Os::remove(void) +{ + DEBUG_FATAL(!installed, ("not installed")); + installed = false; +} + +// ---------------------------------------------------------------------- + +void Os::installCommon(void) +{ + DEBUG_FATAL(installed, ("already installed")); + + ExitChain::add(Os::remove, "Os::remove", 0, true); + +#if 0 //TODO For now we won't screw with the priority of the process + HANDLE threadHandle = GetCurrentThread(); + DEBUG_FATAL(!SetThreadPriority(threadHandle, THREAD_PRIORITY_ABOVE_NORMAL), ("Failed to set game thread priority")); +#endif + + numberOfUpdates = 0; + mainThreadId = pthread_self(); + + // get the name of the executable +//Can't find UNIX call for this: DWORD result = GetModuleFileName(NULL, programName, sizeof(programName)); + strcpy(programName, "TempName"); + DWORD result = 1; + + + FATAL(result == 0, ("GetModuleFileName failed")); + + // get the file name without the path + shortProgramName = strrchr(programName, '\\'); + if (shortProgramName) + ++shortProgramName; + else + shortProgramName = programName; + + // determine the number of processors by parsing /proc/cpuinfo + processorCount = 1; + FILE * f = fopen("/proc/cpuinfo", "r"); + if (f) + { + char buffer[512]; + while (!feof(f)) + { + fgets(buffer, 512, f); + if (strncmp(buffer, "processor\t: ", 12)==0) + { + processorCount = atoi(buffer+12)+1; + } + } + fclose(f); + } + isMp = processorCount > 1; + + // switch into single-precision floating point mode + FloatingPointUnit::install(); + + installed = true; +} + +// ---------------------------------------------------------------------- + +bool Os::isMainThread(void) +{ + // if the Os class hasn't been installed, then assume we are the main thread. + // otherwise, check to see if our thread id is the main thread id + return !installed || (pthread_self() == mainThreadId); +} + +// ---------------------------------------------------------------------- +/** + * Terminate the application because of an error condition. + * + * This routine is supported for all platforms. + * + * This routine should not be called directly. The engine and game should use the + * FATAL macro to terminate the application because of an error. + * + * Calling Os::returnFromAbort() will cause the routine to do nothing but return + * immediately. + * + * @see Os::returnFromAbort(), FATAL() + */ +#include +void Os::abort(void) +{ + if (!isMainThread()) + { + threadDied = true; + pthread_exit(NULL); + } + + if (!shouldReturnFromAbort) + { + // let the C runtime deal with the abnormal termination + int * dummy = NULL; + int forceCrash = *dummy; + UNREF(forceCrash); + for (;;) + { + // One of these should work: + pthread_kill(pthread_self(), SIGSEGV); + ::kill(0,SIGSEGV); + ::abort(); + OsNamespace::UncatchableException ex; + throw ex; + sleep(10); + } + } +} +//----------------------------------------------------------------- +/** +* Create the specified directory and all of it's parents. +* @param directory the path to a directory +* @return always true currently +*/ + +bool Os::createDirectories (const char *directory) +{ + //-- construct list of subdirectories all the way down to root + std::stack directoryStack; + + std::string currentDirectory = directory; + + static const char path_seps [] = { '\\', '/', 0 }; + + // build the stack + while (!currentDirectory.empty()) + { + // remove trailing backslash + if (currentDirectory[currentDirectory.size()-1] == '\\' || currentDirectory[currentDirectory.size()-1] == '/') + IGNORE_RETURN(currentDirectory.erase(currentDirectory.size()-1)); + + if (currentDirectory[currentDirectory.size()-1] == ':') + { + // we've hit something like c: + break; + } + + if (!currentDirectory.empty()) + directoryStack.push(currentDirectory); + + // now strip off current directory + size_t previousDirIndex = currentDirectory.find_last_of (path_seps); + if (previousDirIndex == currentDirectory.npos) + break; + else + IGNORE_RETURN(currentDirectory.erase(previousDirIndex)); + } + + //-- build all directories specified by the initial directory + while (!directoryStack.empty()) + { + // get the directory + currentDirectory = directoryStack.top(); + directoryStack.pop(); + + // try to create it (don't pass any security attributes) + IGNORE_RETURN (mkdir (currentDirectory.c_str(), 0)); + } + + return true; +} +// ---------------------------------------------------------------------- +/** + * Write out a file. + * + * The file name and where the file is written is system-dependent. + * + * @param fileName Name of the file to write + * @param data Data buffer to write to the file + */ + +bool Os::writeFile(const char *fileName, const void *data, int length) // Length of the data bufferto write +{ + BOOL result; + HANDLE handle; + DWORD written; + + // open the file for writing + handle = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + // check if it was opened + if (handle == INVALID_HANDLE_VALUE) + return false; + + // attempt to write the data + result = WriteFile(handle, data, static_cast(length), &written, NULL); + + // make sure the data was written okay + if (!result || written != static_cast(length)) + { + static_cast(CloseHandle(handle)); + return false; + } + + // close the file + result = CloseHandle(handle); + + // make sure the close was sucessful + if (!result) + return false; + + return true; +} + +// ---------------------------------------------------------------------- +/** + * Update the Os subsystem. + * + * This routine is supported for all platforms. + * + * For the Win* platforms, this routine will process the windows message pump. + */ + +bool Os::update(void) +{ + static int ppid = getppid(); + + FloatingPointUnit::update(); + + ++numberOfUpdates; + +#if 0 +#ifdef _DEBUG + + if (DEBUG_FLAG_PLATFORM(validateHeap)) + { + PROFILER_START("validate heap"); + MemoryManager::validate(); + PROFILER_STOP("validate heap"); + } + +#endif +#endif + + Clock::update(); + + wasPaused = false; + + // if our parent's pid has changed, we tell our caller it should exit + if (getppid() != ppid) + { + WARNING(true, ("Parent process exited!")); + // reset the parent process id, so we don't keep spamming warnings for processes that don't exit because of this + ppid = getppid(); + return false; + } + + return true; +} + +// ---------------------------------------------------------------------- +/** + * Formats a message error using GetLastError() and FormatMessge(). + * + * The buffer returned from this function is dynamically allocated to prevent + * issues with this routine being called from multiple threads. The caller + * must delete the buffer when it is done. + * + * @return A dynamically allocated buffer containing the error message + */ + +char *Os::getLastError(void) +{ + return DuplicateString(strerror(errno)); +} + +// ---------------------------------------------------------------------- + +bool Os::getAbsolutePath(const char *relativePath, char *absolutePath, int absolutePathBufferSize) +{ + // realpath sucks and could cause a buffer overrun. however, it's better than writing it ourselves for now. + char *result = realpath(relativePath, absolutePath); + if (!result) + return false; + + FATAL(istrlen(absolutePath)+1 > absolutePathBufferSize, ("buffer overrun")); + return true; +} + +// ---------------------------------------------------------------------- +/** + * Get the actual system time, in seconds since the epoch. + * + * Do not use this for most game systems, since it does not take into account + * clock sku, game loop times, etc. + */ +time_t Os::getRealSystemTime(void) +{ + return time(0); +} + +// ---------------------------------------------------------------------- +/** + * Convert a time in seconds since the epoch to GMT. + * + */ + +void Os::convertTimeToGMT(const time_t &time, tm &zulu) +{ + zulu=*gmtime(&time); // gmtime uses a single static tm structure. Yuck! +} + +// ---------------------------------------------------------------------- +/** + * Convert a tm structure to the time in seconds since the epoch. + * + */ + +time_t Os::convertGMTToTime(const tm &zulu) +{ + return mktime(const_cast(&zulu)); +} + +// ---------------------------------------------------------------------- +/** + * Get a unique identifier for this thread. + * + * @return A unique identifier for this thread. + */ + +Os::ThreadId Os::getThreadId() +{ + return pthread_self(); +} + +// ---------------------------------------------------------------------- +/** + * Assign the given thread a reasonable name (only works for MSDev 6.0 debugger) + * Since this is Linux-specific, make sure this fuction does nothing + * + */ + +void Os::setThreadName(DWORD threadID, const char* threadName) +{ +} + +// ---------------------------------------------------------------------- +/** + * Cause the current thread to sleep for a period of time. If the period is + * zero, the current thread yields it's timeslice. + */ + +void Os::sleep(int ms) +{ + if (ms == 0) + { + sched_yield(); + } + else + { + usleep(ms * 1000); + } +} + +// ---------------------------------------------------------------------- +/** + * Copy text to the system clipboard. + * + * This routine can be used if the application wants to make some data easily available for pasting (like crash call stacks). + */ + +bool Os::copyTextToClipboard(const char *text) +{ + UNREF(text); + return false; +} + +// ---------------------------------------------------------------------- + +Os::OsPID_t Os::getProcessId() +{ + return getpid(); +} + +// ---------------------------------------------------------------------- + +void Os::setProgramName(const char * name) +{ + strncpy(programName, name, Os::PROGRAM_NAME_SIZE); +} + +// ---------------------------------------------------------------------- + +bool Os::isFocused() +{ + return true; +} + +// ---------------------------------------------------------------------- diff --git a/engine/shared/library/sharedFoundation/src/linux/Os.h b/engine/shared/library/sharedFoundation/src/linux/Os.h new file mode 100644 index 00000000..44778b4e --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/Os.h @@ -0,0 +1,264 @@ +// ====================================================================== +// +// Os.h +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#ifndef OS_H +#define OS_H + +#include + +// ====================================================================== + +struct DebugMenuEntry; + +// ====================================================================== + +class Os +{ +public: + + typedef pthread_t ThreadId; + typedef pid_t OsPID_t; + + enum + { + MAX_PATH_LENGTH = 512 + }; + + typedef void (*QueueCharacterHookFunction)(int keyboard, int character); + typedef void (*SetSystemMouseCursorPositionHookFunction)(int x, int y); + typedef void (*QueueKeyDownHookFunction)(int keyboard, int character); + + +private: + + Os(void); + Os(const Os &); + Os &operator =(const Os &); + + enum + { + PROGRAM_NAME_SIZE = 512 + }; + +private: + + static void remove(void); + + static void installCommon(void); + +private: + + static bool installed; + static bool runInBackground; + static int numberOfUpdates; + static int menuValue; + static DebugMenuEntry *debugMenuGame; + static bool paused; + static bool wasPaused; + static bool gameOver; + static bool shouldReturnFromAbort; + static bool wantPopupDebugMenu; + static char programName[PROGRAM_NAME_SIZE]; + static char *shortProgramName; + static pthread_t mainThreadId; + static bool threadDied; + static bool isMp; + static int processorCount; + + +public: + + static void install(void); + + static bool isGameOver(void); + static bool isMainThread(void); + static bool wasApplicationPaused(void); + + static bool update(void); + + static void returnFromAbort(void); + static void abort(void); + + static void requestPopupDebugMenu(); + + static bool createDirectories (const char *dirname); + + static bool writeFile(const char *fileName, const void *data, int length); + + static int getNumberOfUpdates(void); + + static char *getLastError(void); + + static void setThreadName(DWORD threadID, const char* name); + static ThreadId getThreadId(); + + static const char *getProgramName(void); + static const char *getShortProgramName(void); + static void setProgramName(const char * name); + + static bool getAbsolutePath(const char *relativePath, char *absolutePath, int absolutePathBufferSize); + + static void sleep(int ms); + + static time_t getRealSystemTime(void); + static void convertTimeToGMT(const time_t &time, tm &zulu); + static time_t convertGMTToTime(const tm &zulu); + + static bool isMultiprocessor(); + static int getProcessorCount(); + + static bool copyTextToClipboard(const char *text); + + static bool wasFocusLost(); + static void setQueueCharacterHookFunction(QueueCharacterHookFunction queueCharacterHookFunction); + static void setSetSystemMouseCursorPositionHookFunction(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction); + static OsPID_t getProcessId(); + static bool isFocused(); + + static void setQueueKeyDownHookFunction(QueueKeyDownHookFunction queueKeyDownHookFunction); +}; + +// ---------------------------------------------------------------------- +/** + * Return the full name of the running executable. + * + * The program name will include the path as well. + * + * @return The full name of the running executable + * @see Os::getShortProgramName() + */ + +inline const char *Os::getProgramName(void) +{ + return programName; +} + +// ---------------------------------------------------------------------- +/** + * Return the short name of the running executable. + * + * The program name will not include the path, but will just be the file name. + * + * @return The short name of the running executable + * @see Os::getProgramName() + */ + +inline const char *Os::getShortProgramName(void) +{ + return shortProgramName; +} + +// ---------------------------------------------------------------------- +/** + * Cause Os::abort() to return instead of abort the process. + * + * This routine should not be called directly by users. + * + * This routine is provided so that structured exception handling can catch + * an exception, call Fatal to run the ExitChain, and rethrow the exception + * so that the debugger will catch it. + */ + +inline void Os::returnFromAbort(void) +{ + shouldReturnFromAbort = true; +} + +// ---------------------------------------------------------------------- +/** + * Check if the Os knows the game needs to shut down. + * + * The Os can decide that the game need to end for a number of reasons, + * including closing the application or shutting the machine down. + * + * @return True if the game should quit, otherwise false + */ + +inline bool Os::isGameOver(void) +{ + return gameOver; +} + +// ---------------------------------------------------------------------- +/** + * Return the number of updates that the have occurred. + * + * @return This value is updated during the Os::update() routine. + */ + +inline int Os::getNumberOfUpdates(void) +{ + return numberOfUpdates; +} + +// ---------------------------------------------------------------------- +/** + * Indicate whether or not the application was paused. + * + * @return True if the application was in the background (paused), otherwise false + */ + +inline bool Os::wasApplicationPaused(void) +{ + return wasPaused; +} + +// ---------------------------------------------------------------------- +/** + * Return a flag indicating whether we are running a multiprocessor machine or not. + * + * @return True if the machine has more than one processor, false if not. + */ + +inline bool Os::isMultiprocessor(void) +{ + return isMp; +} + +// ---------------------------------------------------------------------- +/** + * Return the number of processors. + * + * @return The number of processors in the machine. + */ + +inline int Os::getProcessorCount(void) +{ + return processorCount; +} + +// ---------------------------------------------------------------------- + +inline bool Os::wasFocusLost() +{ + return false; +} + +// ---------------------------------------------------------------------- + +inline void Os::setQueueCharacterHookFunction(QueueCharacterHookFunction queueCharacterHookFunction) +{ +} + +// ---------------------------------------------------------------------- + +inline void Os::setSetSystemMouseCursorPositionHookFunction(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction) +{ +} + +// ---------------------------------------------------------------------- + +inline void Os::setQueueKeyDownHookFunction(QueueKeyDownHookFunction) +{ +} + + +// ---------------------------------------------------------------------- + +#endif diff --git a/engine/shared/library/sharedFoundation/src/linux/PerThreadData.cpp b/engine/shared/library/sharedFoundation/src/linux/PerThreadData.cpp new file mode 100644 index 00000000..3d7f8584 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/PerThreadData.cpp @@ -0,0 +1,161 @@ +// ====================================================================== +// +// PerThreadData.cpp +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/PerThreadData.h" + +#include "sharedSynchronization/Gate.h" + +// ====================================================================== + +pthread_key_t PerThreadData::slot; +bool PerThreadData::slotCreated=false; + +// ====================================================================== +// Install the per-thread-data subsystem +// +// Remarks: +// +// This routine will install the per-thread-data subsystem that is required for several +// other subsystems in the engine. It should be called from the primary thread before +// any other threads have been created. It will also call threadInstall() for the +// primary thread. +// +// See Also: +// +// PerThreadData::remove() + +void PerThreadData::install(void) +{ + if (pthread_key_create(&slot, 0)!=0) + { + FATAL(true, ("pthread_key_create failed")); + } + slotCreated=true; + + threadInstall(); +} + +// ---------------------------------------------------------------------- +/** + * Remove the per-thread-subsystem. + * + * This routine should be called by the primary thread after all other threads have + * terminated, and no other uses of per-thread-data will occur. + * + * @see PerThreadData::install() + */ + +void PerThreadData::remove(void) +{ + threadRemove(); + + if (pthread_key_delete(slot)!=0) + { + FATAL(true, ("pthread_key_delete failed")); + } + + slotCreated=false; +} + +// ---------------------------------------------------------------------- +/** + * Get access to the per-thread-data. + * + * This routine will verify the per-thread-data subsystem has been installed and the + * threadInstall() function has been called for the current thread. + * + * @return A pointer to the per-thread-data. + */ + +PerThreadData::Data *PerThreadData::getData(bool allowReturnNull) +{ + UNREF(allowReturnNull); + + if (!slotCreated) + { + DEBUG_FATAL(true && !allowReturnNull, ("not installed")); + return NULL; + } + + Data * const data = reinterpret_cast(pthread_getspecific(slot)); + DEBUG_FATAL(!data && !allowReturnNull, ("not installed for this thread")); + return data; +} + +// ---------------------------------------------------------------------- +/** + * Create the per-thread-data for a new thread. + * + * This routine should be called in a thread before the first usage of per-thread-data. + * + * If the client is calling this function on a thread that existed before the engine was + * installed, the client should set isNewThread to false. Setting isNewThread to false + * prevents the function from validating that the thread's TLS is NULL. For threads existing + * before the engine is installed, the TLS data for the thread is undefined. + * + * @param isNewThread [IN] true if the thread was created after the engine was installed, false otherwise + * @see PerThreadData::threadRemove() + */ + +void PerThreadData::threadInstall(bool isNewThread) +{ + UNREF(isNewThread); + + DEBUG_FATAL(!slotCreated, ("not installed")); + + // only check for already-set data if this is supposed to be a new thread + DEBUG_FATAL(isNewThread && pthread_getspecific(slot), ("already installed for this thread")); + + // create the data + Data * const data = new Data; + + // initialize the data + memset(data, 0, sizeof(*data)); + + //create the event for file streaming reads + data->readGate = new Gate(false); + + // set the data into the thread slot + const BOOL result = pthread_setspecific(slot, data); + UNREF(result); + DEBUG_FATAL(result, ("pthread_setspecific failed")); //NB: unlike Windows, returns 0 on success. +} //lint !e429 // Warning -- Custodial pointer 'data' has not been freed or returned) // stored int thread-local-storage + +// ---------------------------------------------------------------------- +/** + * Destroythe per-thread-data for a terminating thread. + * + * This routine should be called in a thread after the last usage of per-thread-data. + * + * @see PerThreadData::threadInstall() + */ + +void PerThreadData::threadRemove(void) +{ + DEBUG_FATAL(!slotCreated, ("not installed")); + DEBUG_FATAL(!pthread_getspecific(slot), ("thread not installed")); + + // get the data + Data *data = getData(); + + //close the event used for file streaming reads + delete data->readGate; + data->readGate = NULL; + + // wipe the data in the thread slot + const BOOL result2 = pthread_setspecific(slot, NULL); + UNREF(result2); + DEBUG_FATAL(result2, ("TlsSetValue failed")); //NB: unlike Windows, returns 0 on success. + + // free the memory + delete data; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/linux/PerThreadData.h b/engine/shared/library/sharedFoundation/src/linux/PerThreadData.h new file mode 100644 index 00000000..df4fd5f6 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/PerThreadData.h @@ -0,0 +1,232 @@ +// ====================================================================== +// +// PerThreadData.h +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#ifndef PER_THREAD_DATA_H +#define PER_THREAD_DATA_H + +// ====================================================================== + +#include "sharedFoundation/ExitChain.h" + +class Gate; + +// ====================================================================== +/** + * Provide thread local storage functionality. + * + * This class' purpose is to allow each thread to maintain some storage that is local and private to each thread. + * The system must be installed before use. Each thread that may use per-thread-data will also need to call the + * threadInstall() routine after creation and threadRemove() just before termination of the thread. + */ +class PerThreadData +{ +private: + + struct Data + { + bool exitChainRunning; + bool exitChainFataling; + ExitChain::Entry *exitChainFirstEntry; + + int debugPrintFlags; + + Gate *readGate; + }; + + static pthread_key_t slot; + static bool slotCreated; + +private: + + static Data *getData(bool allowReturnNull=false); + +private: + + PerThreadData(void); + PerThreadData(const PerThreadData &); + PerThreadData &operator =(const PerThreadData &); + +public: + + static void install(void); + static void remove(void); + + static void threadInstall(bool isNewThread = true); + static void threadRemove(void); + + static bool isThreadInstalled(void); + + static bool getExitChainRunning(void); + static void setExitChainRunning(bool newValue); + + static bool getExitChainFataling(void); + static void setExitChainFataling(bool newValue); + + static ExitChain::Entry *getExitChainFirstEntry(void); + static void setExitChainFirstEntry(ExitChain::Entry *newValue); + + static int getDebugPrintFlags(void); + static void setDebugPrintFlags(int newValue); + + static Gate *getFileStreamerReadGate(void); +}; + +// ====================================================================== +/** + * Determine if the per-thread-data is available for this thread + * + * Return value: + * + * True if the per-thread-data is installed correctly, false otherwise + * + * Remarks: + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * + * -TRF- looks like Win98 does not zero out a new TLS slot for + * threads existing at the time of slot creation. Thus, if you build a + * plugin that only initializes the engine the first time it is + * used, and other threads already exist in the app, those threads + * will contain bogus non-null data in the TLS slot. If the plugin really + * wants to do lazy initialization of the engine, it will need + * to handle calling PerThreadData::threadInstall() for all existing threads + * (except the thread that initialized the engine, which already + * has its PerThreadData::threadInstall() called). + */ + +inline bool PerThreadData::isThreadInstalled(void) +{ + return (getData(true) != NULL); +} + +// ---------------------------------------------------------------------- +/** + * Get the exit chain running flag value. + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * + * @return True if the exit chain is running, false otherwise. + * @see ExitChain::isRunning() + */ + +inline bool PerThreadData::getExitChainRunning(void) +{ + return getData()->exitChainRunning; +} + +// ---------------------------------------------------------------------- +/** + * Set the exit chain running flag value. + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * + * @param newValue New value for the exit chain running flag + */ + +inline void PerThreadData::setExitChainRunning(bool newValue) +{ + getData()->exitChainRunning = newValue; +} + +// ---------------------------------------------------------------------- +/** + * Get the exit chain fataling flag value. + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * + * @return True if the exit chain is fataling, false otherwise. + * @see ExitChain::isFataling() + */ + +inline bool PerThreadData::getExitChainFataling(void) +{ + return getData()->exitChainFataling; +} + +// ---------------------------------------------------------------------- +/** + * Set the exit chain fataling flag value. + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * + * @param newValue New value for the exit chain fataling flag + */ + +inline void PerThreadData::setExitChainFataling(bool newValue) +{ + getData()->exitChainFataling = newValue; +} + +// ---------------------------------------------------------------------- +/** + * Get the first entry for the exit chain. + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * This routine may return NULL. + * + * @return Pointer to the first entry on the exit chain + * @see ExitChain::isFataling() + */ + +inline ExitChain::Entry *PerThreadData::getExitChainFirstEntry(void) +{ + return getData()->exitChainFirstEntry; +} + +// ---------------------------------------------------------------------- +/** + * Set the exit chain fataling flag value. + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * The parameter to this routine may be NULL. + * + * @param newValue New value for the exit chain first entry + */ + +inline void PerThreadData::setExitChainFirstEntry(ExitChain::Entry *newValue) +{ + getData()->exitChainFirstEntry = newValue; +} + +// ---------------------------------------------------------------------- +/** + * Get the debug print flags. + * + * This routine is not intended for general use; it should only be used by the DebugPrint functions. + * + * @return Current value of the debug print flags + */ + +inline int PerThreadData::getDebugPrintFlags(void) +{ + return getData()->debugPrintFlags; +} + +// ---------------------------------------------------------------------- +/** + * Set the debug print flags value. + * + * This routine is not intended for general use; it should only be used by the DebugPrint functions. + */ + +inline void PerThreadData::setDebugPrintFlags(int newValue) +{ + getData()->debugPrintFlags = newValue; +} + +// ---------------------------------------------------------------------- + +inline Gate *PerThreadData::getFileStreamerReadGate(void) +{ + return getData()->readGate; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/linux/PlatformGlue.cpp b/engine/shared/library/sharedFoundation/src/linux/PlatformGlue.cpp new file mode 100644 index 00000000..e2d7da29 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/PlatformGlue.cpp @@ -0,0 +1,273 @@ +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/PlatformGlue.h" +#include + + +real abs(real x) +{ + return fabs(x); +} + +int _stricmp(const char* string1, const char* string2) +{ + int first, second; + + do + { + first = toupper(*string1); + second = toupper(*string2); + string1++; + string2++; + } while (first && first==second); + + return (first - second); +} + +char* _itoa(int value, char* stringOut, int radix) +{ + DEBUG_FATAL((radix != 10), ("itoa only supprts base 10")); + sprintf(stringOut, "%d", value); + return stringOut; +} + +bool QueryPerformanceCounter(__int64* time) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + *time = static_cast(tv.tv_sec); + *time = (*time * 1000000) + static_cast(tv.tv_usec); + + return TRUE; +} + +bool QueryPerformanceFrequency(__int64 *freq) +{ + *freq = CLOCKS_PER_SEC; + return TRUE; + +} + +void Sleep(DWORD msecs) +{ + //Sleep takes a time to sleep in milliseconds. + usleep(msecs*1000); //usleep works with microseconds +} + +int GetLastError() +{ + return errno; +} + +void OutputDebugString(const char* stringOut) +{ + fprintf(stderr,"%s",stringOut); +} + + +//File Support +BOOL WriteFile(FILE* hFile, const void* lpBuffer, DWORD numBytesToWrite, DWORD* numBytesWritten, void* unsup) +{ + int retval; + + if(unsup) + return FALSE; //Windows doesn't support this overrlap buffer + + retval = fwrite(lpBuffer, sizeof(char), numBytesToWrite, hFile); + *numBytesWritten = retval; + return (retval < 0) ? FALSE : TRUE; + +} + +BOOL ReadFile(FILE* hFile, void* lpBuffer, DWORD numBytesToRead, DWORD* numBytesRead, void* unsup) +{ + int retval; + + if(unsup) + return FALSE; //Windows doesn't support this overrlap buffer + + retval = fread(lpBuffer, sizeof(char), numBytesToRead, hFile); + *numBytesRead = retval; + return (retval <= 0) ? FALSE : TRUE; + +} + +DWORD SetFilePointer(FILE* hFile, long lDistanceToMove, long* lpDistanceToMoveHigh, DWORD dwMoveMethod) +{ + //Mimics the Win32 function to set the position of a file pointer. return -1 on failure else current position. + + int retval; + retval = fseek(hFile, lDistanceToMove, dwMoveMethod); + + return (retval == 0) ? ftell(hFile) : -1; +} + +//TODO Consider using a call to open() instead of fopen() to get a better mapping of parameters to Win32 +FILE* CreateFile(const char* fileName, DWORD access, DWORD shareMode, void* unsupA, DWORD creationDisposition, DWORD flagsAndAttributes, FILE* unsupB) +{ + FILE* retval = 0; + + DEBUG_FATAL(flagsAndAttributes != FILE_ATTRIBUTE_NORMAL, ("Unsupported File mode call to CreateFile()")); + DEBUG_FATAL(unsupB != NULL, ("Unsupported File mode call to CreateFile()")); + //DEBUG_FATAL(shareMode != 0, ("Unsupported File mode call to CreateFile()")); + DEBUG_FATAL(unsupA != 0, ("Unsupported File mode call to CreateFile()")); + + switch(creationDisposition) + { + case CREATE_NEW: + retval = fopen(fileName, "r"); + if (retval) + { + fclose(retval); + retval = NULL; + } + else + { + fclose(retval); + retval = fopen(fileName, "w"); + } + break; + + case CREATE_ALWAYS: + retval = fopen(fileName, "w"); + break; + + case OPEN_EXISTING: + retval = fopen(fileName, "r"); + if ((access & GENERIC_WRITE) && retval) + { + fclose(retval); + retval = fopen(fileName, "a"); + rewind(retval); + } + break; + + case OPEN_ALWAYS: + if (access & GENERIC_WRITE) + { + retval = fopen(fileName, "a"); + rewind(retval); + } + else + { + retval = fopen(fileName, "r"); + } + break; + + case TRUNCATE_EXISTING: + DEBUG_FATAL(!(access & GENERIC_WRITE),("Must open truncate file with write access")); + retval = fopen(fileName, "w"); + break; + } + + return retval; +} + + +BOOL CloseHandle(FILE* hFile) +{ + int retval = fclose(hFile); + return (retval == 0) ? TRUE : FALSE; +} + +//TODO There must be a more elegant UNIX command to get file size...fstat() needs filename +DWORD GetFileSize(FILE* hFile, DWORD* lpHighSize) +{ + long int curPos; + DWORD endPos; + curPos = ftell(hFile); + fseek(hFile, 0, SEEK_END); + endPos = ftell(hFile); + fseek(hFile, curPos, SEEK_SET); + return endPos; + +#if 0 +//This is what I want to do, but I have no file des number + struct stat buf; + fstat(hFile, &buf); + return buf->st_size; +#endif +} + +BOOL FileExists(const char* filename) +{ + BOOL retval = false; + + struct stat info; + if (stat(filename, &info) == 0) + { + if (S_ISREG(info.st_mode)) + retval = true; + } + + return retval; +} + + + +//Memory Functions + +void* VirtualAlloc(void* location, DWORD size, DWORD flAllocationType, DWORD flProtect) +{ + if (location) + return location; + + return malloc(size); +} + +BOOL VirtualFree(void* location, DWORD size, DWORD freeType) +{ + free(location); + return TRUE; +} + +BOOL VirtualProtect(void* location, DWORD size, DWORD newProtect, DWORD* oldProect) +{ + //Unused. Function stub for compatibility + return TRUE; +} + +BOOL IsBadReadPtr(const void* location, unsigned int size) +{ + //unused + return TRUE; +} + +void MessageBox (void* unused, const char* message, const char* unused2, int flags) +{ + OutputDebugString(message); +} + +char *ConvertCommandLine(int argc, char ** argv) +{ + static char buffer[2048]; + + int totalSize=0; + for (int i=0; i1023) + { + int argIndex = 0; + fprintf(stderr, "Exceeded command line args length of %d. Total size is %d\n", sizeof(buffer), totalSize); + for(argIndex = 0; argIndex < argc; ++argIndex) + { + fprintf(stderr, "argv[%d]=\"%s\"\n", argIndex, argv[argIndex]); + } + FATAL(true,("Command line exceeds maximum length.")); + } + + buffer[0]='\0'; + + for (int i=0; i +#include +#include + +#include +#include +#include + +typedef unsigned short int WORD; +typedef unsigned long int DWORD; +typedef bool BOOL; +typedef long long __int64; //lint !e13 !e19 // Error: 13 (Bad type), Error: 19 (Useless declaration) // -TRF- Lint preprocessor discrepency, @todo look into this. +typedef __int64 LARGE_INTEGER; + +const BOOL FALSE = 0; +const BOOL TRUE = 1; + + +float abs(float x); +int _stricmp(const char* string1, const char* string2); + +//String to numeric conversions +char* _itoa(int value, char* stringOut, int radix); + +//Format specifier for non-portable printf +#define UINT64_FORMAT_SPECIFIER "%llu" +#define INT64_FORMAT_SPECIFIER "%lli" + +//Constant definition macro for 64 bit values +#define UINT64_LITERAL(a) a ## ull +#define INT64_LITERAL(a) a ## ll + +bool QueryPerformanceCounter(__int64 *time); +bool QueryPerformanceFrequency(__int64 *freq); +void Sleep(DWORD msecs); +int GetLastError(); +void OutputDebugString(const char* stringOut); + +//File Support +#include +#include +#include + +typedef FILE* HANDLE; + +#define INVALID_HANDLE_VALUE NULL //Have to use a #define because this may be a FILE* + + +const int GENERIC_READ = 1 << 0; +const int GENERIC_WRITE = 1 << 1; + +const int CREATE_NEW = 1; +const int CREATE_ALWAYS = 2; +const int OPEN_EXISTING = 3; +const int OPEN_ALWAYS = 4; +const int TRUNCATE_EXISTING = 5; + +const DWORD FILE_ATTRIBUTE_NORMAL = 1; + +const int FILE_CURRENT = SEEK_CUR; +const int FILE_BEGIN = SEEK_SET; +const int FILE_END = SEEK_END; + +const int FILE_SHARE_READ = 1; + +BOOL WriteFile(FILE* hFile, const void* lpBuffer, DWORD numBytesToWrite, DWORD* numBytesWritten, void* unsup=NULL); +BOOL ReadFile(FILE* hFile, void* lpBuffer, DWORD numBytesToWrite, DWORD* numBytesRead, void* unsup=NULL); +DWORD SetFilePointer(FILE* hFile, long lDistanceToMove, long* lpDistanceToMoveHigh, DWORD dwMoveMethod); +FILE* CreateFile(const char* fileName, DWORD access, DWORD shareMode, void* unsupA, DWORD creationDisposition, DWORD flagsAndAttributes, FILE* unsup2); +BOOL CloseHandle(FILE* hFile); +DWORD GetFileSize(FILE* hFile, DWORD* lpHighSize); +BOOL FileExists(const char* fileName); + + +//Memory Support + +const int MEM_RESERVE = 0; +const int MEM_COMMIT = 1; +const int PAGE_READWRITE = 0; +const int MEM_RELEASE = 0; +const int PAGE_NOACCESS = 0; + +void* VirtualAlloc(void* location, DWORD size, DWORD flAllocationType, DWORD flProtect); +BOOL VirtualFree(void* location, DWORD size, DWORD freeType); +BOOL VirtualProtect(void* location, DWORD size, DWORD newProtect, DWORD* oldProect); +BOOL IsBadReadPtr(const void* location, unsigned int size); + +//Misc output stuff + +const int MB_OK = 0; +const int MB_ICONEXCLAMATION = 1; +void MessageBox (void* unused, const char* message, const char* unused2, int flags); +char *ConvertCommandLine(int argc, char ** argv); + +//String functions +#define _vsnprintf vsnprintf + +//----------------------------------------------------------------- + +inline int _strnicmp (const char * a, const char * b, size_t count) +{ + return ::strncasecmp (a, b, count); +} + +//----------------------------------------------------------------- + +inline int _open(const char *filename, int oflag) { return open(filename, oflag); } +inline int _open(const char *filename, int oflag, mode_t pmode) { return open(filename, oflag, pmode); } +inline int _creat(const char *filename, mode_t pmode) { return creat(filename, pmode); } +inline int _close(int fd) { return close(fd); } +inline int _write(int fd, const void *buffer, unsigned int count) { return write(fd, buffer, count); } +inline int _dup(int fd) { return dup(fd); } +inline int _dup2(int oldfd, int newfd) { return dup2(oldfd, newfd); } +inline long _lseek(int fd, long offset, int origin) { return lseek(fd, offset, origin); } +inline int _read(int fd, void *buffer, unsigned int count) { return read(fd, buffer, count); } +inline long _tell(int fd) { return _lseek(fd,0,SEEK_CUR); } +inline int _umask(int pmode) { return umask(pmode); } +inline int _unlink(const char *pathname) { return unlink(pathname); } + +//----------------------------------------------------------------- + +#endif //INCLUDED_MISC_H diff --git a/engine/shared/library/sharedFoundation/src/linux/SetupSharedFoundation.cpp b/engine/shared/library/sharedFoundation/src/linux/SetupSharedFoundation.cpp new file mode 100644 index 00000000..0a2fc1ec --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/SetupSharedFoundation.cpp @@ -0,0 +1,185 @@ +// ====================================================================== +// +// SetupSharedFoundation.cpp +// copyright 1998 Bootprint Entertainment +// copyright 2001 - 2002 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/SetupSharedFoundation.h" + +#include "sharedDebug/ConfigSharedDebugLinux.h" +#include "sharedDebug/DebugMonitor.h" +#include "sharedDebug/Profiler.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/CommandLine.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/Os.h" +#include "sharedFoundation/PerThreadData.h" +#include "sharedFoundation/StaticCallbackEntry.h" + +#include +#include + +// ====================================================================== +/** + * Install the engine. + * + * The settings in the Data structure will determine which subsystems + * get initialized. + */ + +void SetupSharedFoundation::install(const Data &data) +{ + // and get the command line stuff in quick so we can make decisions based on the command line settings + CommandLine::install(); + ConfigFile::install(); + + if (data.lpCmdLine) + CommandLine::absorbString(data.lpCmdLine); + if (data.argc) + CommandLine::absorbStrings(const_cast(data.argv+1), data.argc-1); + +#if 0 + //currently there's a problem that we cannot override the defaults here. + if (data.configFile) + IGNORE_RETURN(ConfigFile::loadFile(data.configFile)); +#endif + + // get the post command-line text for the ConfigFile (key-value pairs) + const char *configString = CommandLine::getPostCommandLineString(); + if (configString) + ConfigFile::loadFromCommandLine(configString); + + //@todo there is a lot of stuff in win32 setup not here...like exitchain + Profiler::registerDebugFlags(); +#if _DEBUG + MemoryManager::registerDebugFlags(); +#endif//_DEBUG + + // Setup Linux DebugMonitor support. + // @todo fix this dependency: DebugMonitor really should be moved into Foundation the way things currently are. TRF is following the existing win32 setup. +#ifdef _DEBUG + ConfigSharedDebugLinux::install(); + DebugMonitor::install(); +#endif + + // setup the engine configuration + ConfigSharedFoundation::Defaults defaults; + defaults.frameRateLimit = data.frameRateLimit; + ConfigSharedFoundation::install(defaults); + SetWarningStrictFatal(ConfigFile::getKeyBool("SharedDebug", "strict", false)); + Report::install(); + Clock::install(data.runInBackground, false); + + PersistentCrcString::install(); + CrcLowerString::install(); + StaticCallbackEntry::install(); +} + +// ---------------------------------------------------------------------- +// Call a function with appropriate exception handling (not) +// +// Remarks: +// +// this is stubbed and exception handling is ignored currently + +void SetupSharedFoundation::callbackWithExceptionHandling( + void (*callback)(void) // Routine to call with exception handling + ) +{ + if (ConfigSharedFoundation::getNoExceptionHandling()) + { + callback(); + } + else + { +#if 0 + try + { + callback(); + } + catch (__exception * mathException) + { + FATAL(true, ("Math Exception: %s\n", mathException->name)); + } + catch (const char* message) + { + FATAL(true, ("Character Exception: %s\n", message)); + } + catch(std::exception & m) + { + const char * c = m.what(); + FATAL(true, ("Std::exception: %s\n", c)); + } + catch(...) + { + FATAL(true, ("Unknown exception\n")); + } +#else + callback(); +#endif + } +} + +// ---------------------------------------------------------------------- +/** + * Uninstall the engine. + * + * This routine will properly uninstall the engine componenets that were + * installed by SetupSharedFoundation::install(). + */ + +void SetupSharedFoundation::remove(void) +{ + ExitChain::quit(); + + if (GetNumberOfWarnings()) + REPORT(true, Report::RF_print | Report::RF_log | Report::RF_dialog, ("%d warnings logged", GetNumberOfWarnings())); + + // this routine can't be on the exit chain because the exit chain depends upon the PerThreadData class being around + //PerThreadData::remove(); +} + +// ---------------------------------------------------------------------- + +SetupSharedFoundation::Data::Data(Defaults defaults) +{ + Zero(*this); + + switch (defaults) + { + case D_game: + runInBackground = true; + + lpCmdLine = NULL; + argc = 0; + argv = NULL; + + configFile = NULL; + + frameRateLimit = CONST_REAL(0); + break; + + case D_console: + runInBackground = true; + + lpCmdLine = NULL; + argc = 0; + argv = NULL; + + configFile = NULL; + + frameRateLimit = CONST_REAL(0); + break; + + default: + DEBUG_FATAL(true, ("unknown case")); + } +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/linux/SetupSharedFoundation.h b/engine/shared/library/sharedFoundation/src/linux/SetupSharedFoundation.h new file mode 100644 index 00000000..1d05421a --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/SetupSharedFoundation.h @@ -0,0 +1,58 @@ +// ====================================================================== +// +// SetupSharedFoundation.h +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_SetupSharedFoundation_H +#define INCLUDED_SetupSharedFoundation_H + +// ====================================================================== + +struct DebugMenuEntry; + +// ====================================================================== + +class SetupSharedFoundation +{ +public: + + struct Data + { + // allow running in background + bool runInBackground; + + // pointer to command line + char* lpCmdLine; + int argc; + char **argv; + + const char *configFile; + + real frameRateLimit; + + public: + + enum Defaults + { + D_game, + D_console + }; + + Data(Defaults defaults); + }; + +public: + + static void install(const Data &data); + static void remove(void); + + static void callbackWithExceptionHandling(void (*callback)(void)); + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/linux/vsnprintf.cpp b/engine/shared/library/sharedFoundation/src/linux/vsnprintf.cpp new file mode 100644 index 00000000..6b4c5647 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/vsnprintf.cpp @@ -0,0 +1,35 @@ +// ====================================================================== +// +// vsnprintf.cpp +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/vsnprintf.h" + +#include + +// ====================================================================== +// Format a printf-style string into a text buffer of fixed size +// +// Return value: +// +// The number of characters written into the buffer, or -1 if the buffer was too small +// +// Remarks: +// +// If the buffer would overflow, the null terminating character is not written and -1 +// will be returned. + +#ifdef _MSC_VER + +int vsnprintf(char *buffer, size_t count, const char *format, va_list va) +{ + return _vsnprintf(buffer, count, format, va); +} + +#endif +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/linux/vsnprintf.h b/engine/shared/library/sharedFoundation/src/linux/vsnprintf.h new file mode 100644 index 00000000..2dc53090 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/linux/vsnprintf.h @@ -0,0 +1,24 @@ +// ====================================================================== +// +// vsnprintf.h +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#ifndef VSNPRINTF_H +#define VSNPRINTF_H + +// ====================================================================== + +#ifdef _MSC_VER + +int vsnprintf(char *buffer, size_t count, const char *format, va_list va); + +#endif + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedFoundation/src/shared/ApplicationVersion.cpp b/engine/shared/library/sharedFoundation/src/shared/ApplicationVersion.cpp new file mode 100644 index 00000000..f17ba3db --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/ApplicationVersion.cpp @@ -0,0 +1,75 @@ +// ====================================================================== +// +// ApplicationVersion.cpp +// Copyright 2002-2004, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/ApplicationVersion.h" + +// ====================================================================== + +namespace ApplicationVersionNamespace +{ + // WARNING do not change this string without making sure that the hardcoded offsets below are correct + char ms_version[] = "ApplicationVersionMarker 000 123456789012345678901234567890"; + int const brandOffset = 25; + int const bootlegOffset = 26; + int const publishOffset = 27; + int const versionOffset = 29; + + bool isBranded(); +} +using namespace ApplicationVersionNamespace; + +// ====================================================================== + +bool ApplicationVersionNamespace::isBranded() +{ + return ms_version[brandOffset] == '1'; +} + +// ---------------------------------------------------------------------- + +bool ApplicationVersion::isBootlegBuild() +{ + return ms_version[bootlegOffset] == '1'; +} + +// ---------------------------------------------------------------------- + +bool ApplicationVersion::isPublishBuild() +{ + return ms_version[publishOffset] == '1'; +} + +// ---------------------------------------------------------------------- + +const char * ApplicationVersion::getPublicVersion() +{ + if (!isBranded()) + return "0"; + + char const * internal = ms_version + versionOffset; + while (*internal != '\0' && *internal != '.') + ++internal; + + if (*internal == '\0' || internal[1] == '\0') + return "0"; + + return internal + 1; +} + +// ---------------------------------------------------------------------- + +char const * ApplicationVersion::getInternalVersion() +{ + if (!isBranded()) + return "unknown.0"; + + return ms_version + versionOffset; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/ApplicationVersion.h b/engine/shared/library/sharedFoundation/src/shared/ApplicationVersion.h new file mode 100644 index 00000000..9cd0f8fc --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/ApplicationVersion.h @@ -0,0 +1,25 @@ +// ====================================================================== +// +// ApplicationVersion.h +// Copyright 2002-2004, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ApplicationVersion_H +#define INCLUDED_ApplicationVersion_H + +// ====================================================================== + +class ApplicationVersion +{ +public: + static bool isBootlegBuild(); + static bool isPublishBuild(); + static char const * getPublicVersion(); + static char const * getInternalVersion(); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/ArrayList.h b/engine/shared/library/sharedFoundation/src/shared/ArrayList.h new file mode 100644 index 00000000..ab3e2dd6 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/ArrayList.h @@ -0,0 +1,552 @@ +//=================================================================== +// +// ArrayList.h +// asommers 10-2-98 +// +// copyright 1998, bootprint entertainment +// copyright 2001, sony online entertainment +// +// generic list template +// +// @todo replace instances of ArrayList with std::vector +// +//=================================================================== + +#ifndef INCLUDED_ArrayList_H +#define INCLUDED_ArrayList_H + +//=================================================================== + +template +class ArrayList +{ +public: + + // construction/destruction + explicit ArrayList (int newSize=0); + ArrayList (const ArrayList& rhs); + ~ArrayList (void); + + // allow preallocation of list + void preallocate (int newSize, bool numberOfElementsToo=false); + void preallocateAndSet (int newSize, const T& newValue); + + // destroy the list if it was created statically + void destroy (void); + + // clear out the list + void clear (void); + + // add a new item to the list + void add (const T& newElement); + void addIfNotExist (const T& newElement); + void allocateNext (void); + int findOrAdd (const T& newElement); + + void insert (int index, const T& newElement); + + // remove an item from the list + void remove (const T& element, bool mustExist=false); + void removeIndexAndCompactList (int index); + + // delete the last item from the list + // NOTE: caller should know how to delete the element if necessary + void deleteLast (void); + + // returns true if element is already in the list + bool existsInList (const T& element) const; + bool existsInList (const T& element, int& index) const; + + // returns the number of elements in the list + int getNumberOfElements (void) const; + + // returns the index'th item in the list (DOES NOT check for out of bounds) + T& getElement (int index); + const T& getElement (int index) const; + T& getLastElement (void); + const T& getLastElement (void) const; + + // returns the index'th item in the list (DOES NOT check for out of bounds) + T& operator[] (int index); + const T& operator[] (int index) const; + + // + ArrayList& operator= (const ArrayList& rhs); + + // swapping + void swap (int index1, int index2); + + // stl interface to make transition easier + const T& back () const; + T& back (); + int size () const; + bool empty () const; + void push_back (const T& element); + void pop_back (); + +private: + + enum + { + DEFAULT_SIZE = 16 // initial list m_size + }; + +private: + + // resizes the list + void resizeUp (void); + + void copy (const ArrayList& rhs); + +private: + + int m_size; // list m_size + T* m_data; // list m_data + int m_numberOfElements; // number of items in the list +}; + +//=================================================================== + +template +inline ArrayList::ArrayList (int newSize) : + m_size (newSize), + m_data (0), + m_numberOfElements (0) +{ + if (newSize) + m_data = new T [m_size]; +} + +//------------------------------------------------------------------- + +template +inline ArrayList::ArrayList (const ArrayList& rhs) : + m_size (0), + m_data (0), + m_numberOfElements (0) +{ + copy (rhs); +} + +//------------------------------------------------------------------- + +template +inline ArrayList& ArrayList::operator= (const ArrayList& rhs) +{ + if (this != &rhs) + copy (rhs); + + return *this; +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::copy (const ArrayList& rhs) +{ + // only delete and re-new the list if we don't have enough elements to hold the contents of rhs + if (m_numberOfElements < rhs.m_numberOfElements) + { + if (m_data) + delete [] m_data; + + m_size = rhs.m_size; + m_data = new T [m_size]; + } + + // only copy the vital elements + memcpy (m_data, rhs.m_data, sizeof (T) * rhs.m_numberOfElements); + + m_numberOfElements = rhs.m_numberOfElements; +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::destroy (void) +{ + delete [] m_data; + m_data = 0; + + m_size = 0; + m_numberOfElements = 0; +} + +//------------------------------------------------------------------- + +template +inline ArrayList::~ArrayList (void) +{ + destroy (); +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::preallocate (int newSize, bool numberOfElementsToo) +{ + // if the m_size we want to preallocate is greater than our current m_size, grow to fit + if (newSize > m_size) + { + delete [] m_data; + m_data = new T [newSize]; + m_size = newSize; + } + + if (numberOfElementsToo) + m_numberOfElements = newSize; +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::preallocateAndSet (int newSize, const T& newValue) +{ + preallocate (newSize, true); + + int i; + for (i = 0; i < newSize; i++) + m_data [i] = newValue; +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::clear (void) +{ + m_numberOfElements = 0; +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::add (const T& newElement) +{ + // is the list full? if so, resize it + if (m_numberOfElements == m_size) + resizeUp (); + + // add the m_data to the list + NOT_NULL (m_data); + m_data [m_numberOfElements++] = newElement; +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::addIfNotExist (const T& newElement) +{ + if (existsInList (newElement)) + return; + + add (newElement); +} + +//------------------------------------------------------------------- + +template +inline int ArrayList::findOrAdd (const T& newElement) +{ + if (existsInList (newElement, index)) + return index; + + add (newElement); + + return getNumberOfElements () - 1; +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::insert (int index, const T& newElement) +{ + NOT_NULL (m_data); + + //-- if inserting at end, just add it + if (index == m_numberOfElements) + add (newElement); + else + { + //-- is the list full? if so, resize it + if (m_numberOfElements == m_size) + resizeUp (); + + //-- move everything from index to end of list down + int i; + for (i = m_numberOfElements - 1; i >= index; --i) + m_data [i + 1] = m_data [i]; + + //-- insert item into list + m_data [index] = newElement; + m_numberOfElements++; + } +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::allocateNext (void) +{ + // is the list full? if so, resize it + if (m_numberOfElements == m_size) + resizeUp (); + + m_numberOfElements++; +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::remove (const T& element, bool mustExist) +{ + NOT_NULL (m_data); + + // search the list for the element + int i; + for (i = 0; i < m_numberOfElements; i++) + { + // if we found it + if (m_data [i] == element) + { + // squish list + int j; + for (j = i; j < m_numberOfElements-1; j++) + m_data [j] = m_data [j+1]; + + m_numberOfElements--; + + return; + } + } + + UNREF (mustExist); + DEBUG_FATAL (mustExist, ("ArrayList::remove - not found in list")); +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::removeIndexAndCompactList (int index) +{ + NOT_NULL (m_data); + DEBUG_FATAL (index < 0 || index >= m_numberOfElements, ("index %d out of range", index)); + + // squish list + int j; + for (j = index; j < m_numberOfElements-1; j++) + m_data [j] = m_data [j+1]; + + m_numberOfElements--; +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::deleteLast (void) +{ + if (m_numberOfElements > 0) + m_numberOfElements--; +} + +//------------------------------------------------------------------- + +template +inline bool ArrayList::existsInList (const T& element) const +{ + if (m_numberOfElements > 0) + { + NOT_NULL (m_data); + + int i; + for (i = 0; i < m_numberOfElements; i++) + if (m_data [i] == element) + return true; + } + + return false; +} + +//------------------------------------------------------------------- + +template +inline bool ArrayList::existsInList (const T& element, int& index) const +{ + if (m_numberOfElements > 0) + { + NOT_NULL (m_data); + + int i; + for (i = 0; i < m_numberOfElements; i++) + if (m_data [i] == element) + { + index = i; + + return true; + } + } + + return false; +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::resizeUp (void) +{ + // allocate new memory for the list (just double it) + int newSize = m_size ? m_size * 2 : DEFAULT_SIZE; + + T* newData = new T [newSize]; + + // copy the contents of the old list into the new list + if (m_data) + memcpy (newData, m_data, sizeof (T) * m_size); + + // increase the m_size + m_size = newSize; + + // zap the old list + delete [] m_data; + + // point to the new list + m_data = newData; +} + +//------------------------------------------------------------------- + +template +inline int ArrayList::getNumberOfElements (void) const +{ + return m_numberOfElements; +} + +//------------------------------------------------------------------- + +template +inline const T& ArrayList::getElement (int index) const +{ + NOT_NULL (m_data); + DEBUG_FATAL (index < 0 || index >= m_numberOfElements, ("index %d out of range", index)); + + return m_data [index]; +} + +//------------------------------------------------------------------- + +template +inline const T& ArrayList::getLastElement (void) const +{ + NOT_NULL (m_data); + DEBUG_FATAL (m_numberOfElements == 0, ("ArrayList::getLastElement - list has no elements")); + + return m_data [m_numberOfElements - 1]; +} + +//------------------------------------------------------------------- + +template +inline const T& ArrayList::operator[] (int index) const +{ + NOT_NULL (m_data); + DEBUG_FATAL (index < 0 || index >= m_numberOfElements, ("index %d out of range", index)); + + return m_data [index]; +} + +//------------------------------------------------------------------- + +template +inline T& ArrayList::getElement (int index) +{ + NOT_NULL (m_data); + DEBUG_FATAL (index < 0 || index >= m_numberOfElements, ("index %d out of range", index)); + + return m_data [index]; +} + +//------------------------------------------------------------------- + +template +inline T& ArrayList::getLastElement (void) +{ + NOT_NULL (m_data); + DEBUG_FATAL (m_numberOfElements == 0, ("ArrayList::getLastElement - list has no elements")); + + return m_data [m_numberOfElements - 1]; +} + +//------------------------------------------------------------------- + +template +inline T& ArrayList::operator[] (int index) +{ + NOT_NULL (m_data); + DEBUG_FATAL (index < 0 || index >= m_numberOfElements, ("index %d out of range", index)); + + return m_data [index]; +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::swap (int index1, int index2) +{ + NOT_NULL (m_data); + DEBUG_FATAL (index1 < 0 || index1 >= m_numberOfElements || index2 < 0 || index2 >= m_numberOfElements, ("ArrayList::swap - index1 %d or index2 %d out of range", index1, index2)); + + T tmp = m_data [index1]; + m_data [index1] = m_data [index2]; + m_data [index2] = tmp; +} + +//------------------------------------------------------------------- + +template +inline const T& ArrayList::back () const +{ + return getLastElement (); +} + +//------------------------------------------------------------------- + +template +inline T& ArrayList::back () +{ + return getLastElement (); +} + +//------------------------------------------------------------------- + +template +inline int ArrayList::size () const +{ + return getNumberOfElements (); +} + +//------------------------------------------------------------------- + +template +inline bool ArrayList::empty () const +{ + return getNumberOfElements () == 0; +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::push_back (const T& element) +{ + add (element); +} + +//------------------------------------------------------------------- + +template +inline void ArrayList::pop_back () +{ + deleteLast (); +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/AutoDeltaNetworkIdPackedMap.cpp b/engine/shared/library/sharedFoundation/src/shared/AutoDeltaNetworkIdPackedMap.cpp new file mode 100644 index 00000000..4d0b6465 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/AutoDeltaNetworkIdPackedMap.cpp @@ -0,0 +1,33 @@ +// ====================================================================== +// +// AutoDeltaNetworkIdPackedMap.cpp +// copyright (c) 2004 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/AutoDeltaNetworkIdPackedMap.h" + +#include + +// ====================================================================== + +namespace Archive +{ + /* + int countCharacter(const std::string &str, char c) + { + int result=0; + for (std::string::const_iterator i=str.begin(); i!=str.end(); ++i) + { + if (*i==c) + ++result; + } + + return result; + } + + */ +} //namespace + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/AutoDeltaNetworkIdPackedMap.h b/engine/shared/library/sharedFoundation/src/shared/AutoDeltaNetworkIdPackedMap.h new file mode 100644 index 00000000..f79b79ec --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/AutoDeltaNetworkIdPackedMap.h @@ -0,0 +1,100 @@ +// ====================================================================== +// +// AutoDeltaNetworkIdPackedMap.h +// copyright (c) 2004 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_AutoDeltaNetworkIdPackedMap_H +#define INCLUDED_AutoDeltaNetworkIdPackedMap_H + +// ====================================================================== + +#include "Archive/AutoDeltaMap.h" +#include +#include "sharedFoundation/NetworkId.h" +#include "sharedFoundation/NetworkIdArchive.h" +#include "Archive/AutoDeltaPackedMap.h" + +// ====================================================================== + +namespace Archive +{ + /** + * An AutoDeltaNetworkIdPackedMap is an AutoDeltaMap that will be packed into + * a single value for storage. It functions as an AutoDeltaMap in + * all respects except that packDeltas() will send the entire map + * on the network. + */ + + void AutoDeltaPackedMap::pack(ByteStream & target, const std::string & buffer) + { + char temp[200]; + AutoDeltaMap::Command c; + + Archive::put(target, countCharacter(buffer,':')); + Archive::put(target, static_cast(0)); // baselineCommandCount + + int tempPos = 0; + for (std::string::const_iterator i=buffer.begin(); i!=buffer.end(); ++i) + { + if (*i==':') + { + temp[tempPos]='\0'; + sscanf(temp, "%d", &c.value); + Archive::put(target, static_cast(AutoDeltaMap::Command::ADD)); + Archive::put(target, c.key); + Archive::put(target, c.value); + tempPos=0; + } + else if (*i == ' ') + { + temp[tempPos] = '\0'; + c.key = NetworkId(temp); + tempPos = 0; + } + else + temp[tempPos++]=*i; + } + } + + void AutoDeltaPackedMap::unpack(ReadIterator & source, std::string & buffer) + { + char temp[200]; + + AutoDeltaMap::Command c; + size_t commandCount; + size_t baselineCommandCount; + + Archive::get(source, commandCount); + Archive::get(source, baselineCommandCount); + + if (commandCount==0) + { + buffer=' '; // An empty map is represented as a single space, because a completely empty string is used to mean "no change" + } + else + { + for (size_t i = 0; i < commandCount; ++i) + { + Archive::get(source, c.cmd); + Archive::get(source, c.key); + Archive::get(source, c.value); + +#ifdef WIN32 + _snprintf(temp, sizeof(temp)-1, "%s %d:", c.key.getValueString().c_str(), c.value); +#else + snprintf(temp, sizeof(temp)-1, "%s %d:", c.key.getValueString().c_str(), c.value); +#endif + + temp[sizeof(temp)-1]='\0'; + buffer+=temp; + } + } + } + +} //namespace + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/Binary.h b/engine/shared/library/sharedFoundation/src/shared/Binary.h new file mode 100644 index 00000000..f2a871b4 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Binary.h @@ -0,0 +1,72 @@ +// ====================================================================== +// +// Binary.h +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#ifndef BINARY_H +#define BINARY_H + +// ====================================================================== + +//lint -save -e1923 // could become const variable + +#define HEX_DIGIT_0000 0 +#define HEX_DIGIT_0001 1 +#define HEX_DIGIT_0010 2 +#define HEX_DIGIT_0011 3 +#define HEX_DIGIT_0100 4 +#define HEX_DIGIT_0101 5 +#define HEX_DIGIT_0110 6 +#define HEX_DIGIT_0111 7 +#define HEX_DIGIT_1000 8 +#define HEX_DIGIT_1001 9 +#define HEX_DIGIT_1010 a +#define HEX_DIGIT_1011 b +#define HEX_DIGIT_1100 c +#define HEX_DIGIT_1101 d +#define HEX_DIGIT_1110 e +#define HEX_DIGIT_1111 f + +//line -restore + +#define HEX_DIGIT(a) HEX_DIGIT_ ## a + +#define BINARY1H(a) (0x ## a) +#define BINARY1I(a) BINARY1H(a) +#define BINARY1(a) BINARY1I(HEX_DIGIT(a)) + +#define BINARY2H(a,b) (0x ## a ## b) +#define BINARY2I(a,b) BINARY2H(a,b) +#define BINARY2(a,b) BINARY2I(HEX_DIGIT(a), HEX_DIGIT(b)) + +#define BINARY3H(a,b,c) (0x ## a ## b ## c) +#define BINARY3I(a,b,c) BINARY3H(a,b,c) +#define BINARY3(a,b,c) BINARY3I(HEX_DIGIT(a), HEX_DIGIT(b), HEX_DIGIT(c)) + +#define BINARY4H(a,b,c,d) (0x ## a ## b ## c ## d) +#define BINARY4I(a,b,c,d) BINARY4H(a,b,c,d) +#define BINARY4(a,b,c,d) BINARY4I(HEX_DIGIT(a), HEX_DIGIT(b), HEX_DIGIT(c), HEX_DIGIT(d)) + +#define BINARY5H(a,b,c,d,e) (0x ## a ## b ## c ## d ## e) +#define BINARY5I(a,b,c,d,e) BINARY5H(a,b,c,d,e) +#define BINARY5(a,b,c,d,e) BINARY5I(HEX_DIGIT(a), HEX_DIGIT(b), HEX_DIGIT(c), HEX_DIGIT(d), HEX_DIGIT(e)) + +#define BINARY6H(a,b,c,d,e,f) (0x ## a ## b ## c ## d ## e ## f) +#define BINARY6I(a,b,c,d,e,f) BINARY6H(a,b,c,d,e,f) +#define BINARY6(a,b,c,d,e,f) BINARY6I(HEX_DIGIT(a), HEX_DIGIT(b), HEX_DIGIT(c), HEX_DIGIT(d), HEX_DIGIT(e), HEX_DIGIT(f)) + +#define BINARY7H(a,b,c,d,e,f,g) (0x ## a ## b ## c ## d ## e ## f ## g) +#define BINARY7I(a,b,c,d,e,f,g) BINARY7H(a,b,c,d,e,f,g) +#define BINARY7(a,b,c,d,e,f,g) BINARY7I(HEX_DIGIT(a), HEX_DIGIT(b), HEX_DIGIT(c), HEX_DIGIT(d), HEX_DIGIT(e), HEX_DIGIT(f), HEX_DIGIT(g)) + +#define BINARY8H(a,b,c,d,e,f,g,h) (0x ## a ## b ## c ## d ## e ## f ## g ## h) +#define BINARY8I(a,b,c,d,e,f,g,h) BINARY8H(a,b,c,d,e,f,g,h) +#define BINARY8(a,b,c,d,e,f,g,h) BINARY8I(HEX_DIGIT(a), HEX_DIGIT(b), HEX_DIGIT(c), HEX_DIGIT(d), HEX_DIGIT(e), HEX_DIGIT(f), HEX_DIGIT(g), HEX_DIGIT(h)) + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/BitArray.cpp b/engine/shared/library/sharedFoundation/src/shared/BitArray.cpp new file mode 100644 index 00000000..cb9fd7ad --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/BitArray.cpp @@ -0,0 +1,621 @@ +// ====================================================================== +// +// BitArray.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/BitArray.h" + +#include "Archive/Archive.h" +#include "sharedFoundation/FormattedString.h" + +// ====================================================================== + +BitArray::BitArray() : +m_arrayData(m_defaultData), +m_numAllocatedBytes(sizeof(m_defaultData)), +m_numInUseBytes(0), +m_numInUseBits(0) +{ + memset(m_arrayData, 0, m_numAllocatedBytes); +} + +// ----------------------------------------------------------------------- + +BitArray::BitArray(int numBits) : +m_arrayData(m_defaultData), +m_numAllocatedBytes(sizeof(m_defaultData)), +m_numInUseBytes(0), +m_numInUseBits(0) +{ + if (numBits > (m_numAllocatedBytes << 3)) + { + m_arrayData = NULL; + m_numAllocatedBytes = 0; + reserve(numBits); + m_numInUseBytes = 0; + m_numInUseBits = 0; + } + else + { + memset(m_arrayData, 0, m_numAllocatedBytes); + } +} + +// ----------------------------------------------------------------------- + +BitArray::BitArray(const BitArray &orig) : +m_arrayData(m_defaultData), +m_numAllocatedBytes(sizeof(m_defaultData)), +m_numInUseBytes(0), +m_numInUseBits(0) +{ + if (orig.m_numInUseBytes > m_numAllocatedBytes) + { + m_arrayData = new signed char[static_cast(orig.m_numInUseBytes)]; + m_numAllocatedBytes = orig.m_numInUseBytes; + } + + m_numInUseBytes = orig.m_numInUseBytes; + m_numInUseBits = orig.m_numInUseBits; + + if (m_numInUseBytes > 0) + { + memcpy(m_arrayData, orig.m_arrayData, m_numInUseBytes); + + if (m_numAllocatedBytes > m_numInUseBytes) + memset(&(m_arrayData[m_numInUseBytes]), 0, static_cast(m_numAllocatedBytes - m_numInUseBytes)); + } + else + { + memset(m_arrayData, 0, m_numAllocatedBytes); + } +} + +// ----------------------------------------------------------------------- + +BitArray::~BitArray() +{ + if (m_arrayData != m_defaultData) + delete []m_arrayData; +} + +// ----------------------------------------------------------------------- + +BitArray & BitArray::operator= (const BitArray &rhs) +{ + if (this != &rhs) + { + // trivial case, rhs is empty + if ((rhs.m_numInUseBits <= 0) || (rhs.m_numInUseBytes <= 0)) + { + clear(); + return *this; + } + + // char array is too small, reallocate new char array + if (m_numAllocatedBytes < rhs.m_numInUseBytes) + { + if (m_arrayData != m_defaultData) + delete []m_arrayData; + + m_arrayData = new signed char[static_cast(rhs.m_numInUseBytes)]; + m_numAllocatedBytes = rhs.m_numInUseBytes; + } + // char array is large enough, no reallocation required, + // but clear out char array, if necessary + else if (m_numInUseBytes > rhs.m_numInUseBytes) + { + memset(&(m_arrayData[rhs.m_numInUseBytes]), 0, static_cast(m_numInUseBytes - rhs.m_numInUseBytes)); + } + + m_numInUseBytes = rhs.m_numInUseBytes; + m_numInUseBits = rhs.m_numInUseBits; + memcpy(m_arrayData, rhs.m_arrayData, static_cast(m_numInUseBytes)); + } + + return *this; +} + +// ----------------------------------------------------------------------- +bool BitArray::operator== (const BitArray &rhs) const +{ + //-- Check for self equality + if (this == &rhs) + return true; + + // compare the individual chars in the 2 array up to the number + // of chars needed to hold the smaller of the 2 m_numInUseBits + int const smallerArraySize = std::min(m_numInUseBytes, rhs.m_numInUseBytes); + for (int i = 0; i < smallerArraySize; ++i) + if (m_arrayData[i] != rhs.m_arrayData[i]) + return false; + + // if there are any additional set bits (i.e. non-zero char) + // in the larger of the 2 arrays, then equality is false + if (m_numInUseBytes != rhs.m_numInUseBytes) + { + signed char const * largerArrayData; + int largerArraySize; + + if (m_numInUseBytes > rhs.m_numInUseBytes) + { + largerArraySize = m_numInUseBytes; + largerArrayData = m_arrayData; + } + else + { + largerArraySize = rhs.m_numInUseBytes; + largerArrayData = rhs.m_arrayData; + } + + for (int j = smallerArraySize; j < largerArraySize; ++j) + if (largerArrayData[j]) + return false; + } + + return true; +} + +// ----------------------------------------------------------------------- + +bool BitArray::operator!=(const BitArray &rhs) const +{ + return !operator==(rhs); +} + +// ----------------------------------------------------------------------- + +void BitArray::setBit(int const index) +{ + DEBUG_FATAL(index < 0, ("BitArray::setBit index [%d] out of range", index)); + + if (index >= 0) + { + if (index >= m_numInUseBits) + reserve(index+1); + + int const arrayPos = index >> 3; //lint !e702 shift right of signed quantity (DEBUG_FATALs if index < 0) + int const bitPos = index & 7; + m_arrayData[arrayPos] |= (1 << bitPos); + } +} + +// ----------------------------------------------------------------------- + +void BitArray::setValue(int const beginIndex, int const endIndex, unsigned long value) +{ + DEBUG_FATAL(beginIndex < 0, ("BitArray::setValue beginIndex [%d] out of range", beginIndex)); + DEBUG_FATAL(endIndex < 0, ("BitArray::setValue endIndex [%d] out of range", endIndex)); + DEBUG_FATAL(beginIndex > endIndex, ("BitArray::setValue beginIndex [%d] > endIndex [%d]", beginIndex, endIndex)); + + if ((beginIndex >= 0) && (endIndex >= 0) && (beginIndex <= endIndex)) + { + int currentIndex = beginIndex; + while (currentIndex <= endIndex) + { + if (value == 0) + break; + + if (value & 0x1) + setBit(currentIndex++); + else + clearBit(currentIndex++); + + value >>= 1; + } + + for (int i = currentIndex; i <= endIndex; ++i) + clearBit(i); + } +} + +// ----------------------------------------------------------------------- + +void BitArray::clearBit(int const index) +{ + DEBUG_FATAL(index < 0, ("BitArray::clearBit index [%d] out of range", index)); + + if ((index >= 0) && (index < m_numInUseBits)) + { + int const arrayPos = index >> 3; //lint !e702 shift right of signed quantity (DEBUG_FATALs if index < 0) + int const bitPos = index & 7; + m_arrayData[static_cast(arrayPos)] &= ~(1 << bitPos); + } +} + +// ----------------------------------------------------------------------- + +bool BitArray::testBit(int const index) const +{ + DEBUG_FATAL(index < 0, ("BitArray::testBit index [%d] out of range", index)); + + if ((index < 0) || (index >= m_numInUseBits)) + return false; + + int const arrayPos = index >> 3; //lint !e702 shift right of signed quantity (DEBUG_FATALs if index < 0) + int const bitPos = index & 7; + return ((m_arrayData[arrayPos] & (1 << bitPos)) != 0); +} + +// ----------------------------------------------------------------------- + +unsigned long BitArray::getValue(int const beginIndex, int const endIndex) const +{ + DEBUG_FATAL(beginIndex < 0, ("BitArray::setValue beginIndex [%d] out of range", beginIndex)); + DEBUG_FATAL(endIndex < 0, ("BitArray::setValue endIndex [%d] out of range", endIndex)); + DEBUG_FATAL(beginIndex > endIndex, ("BitArray::setValue beginIndex [%d] > endIndex [%d]", beginIndex, endIndex)); + + unsigned long value = 0; + if ((beginIndex >= 0) && (endIndex >= 0) && (beginIndex <= endIndex)) + { + for (int i = endIndex; i >= beginIndex; --i) + { + if (value) + value <<= 1; + + if (testBit(i)) + ++value; + } + } + + return value; +} + +// ----------------------------------------------------------------------- + +void BitArray::reserve(int const numBits) +{ + DEBUG_FATAL(numBits < 0, ("BitArray::reserve number of bits [%d] out of range", numBits)); + + if (numBits > 0) + { + // if shrinking, make sure to clear all the bits between + // the new size and the old size to to maintain requirement + // that every bit past 0-based index (m_numInUseBits - 1) is + // guaranteed to be unset + if (numBits < m_numInUseBits) + { + for (int i = numBits; i < m_numInUseBits; ++i) + clearBit(i); + } + + m_numInUseBits = numBits; + + int const oldNumInUseBytes = m_numInUseBytes; + m_numInUseBytes = (m_numInUseBits + 7) >> 3; + + if (m_numInUseBytes > m_numAllocatedBytes) + { + signed char * tmp = new signed char[static_cast(m_numInUseBytes)]; + memset(&(tmp[oldNumInUseBytes]), 0, static_cast(m_numInUseBytes - oldNumInUseBytes)); + if ((oldNumInUseBytes > 0) && (m_arrayData != NULL)) + memcpy(tmp, m_arrayData, static_cast(oldNumInUseBytes)); //lint !e671 !e670 logically, you can't enter this code block unless oldNumInUseBytes is smaller. + + m_numAllocatedBytes = m_numInUseBytes; + + if (m_arrayData != m_defaultData) + delete []m_arrayData; + + m_arrayData = tmp; + } + } + else if (numBits == 0) + { + if (m_arrayData != m_defaultData) + delete []m_arrayData; + + m_arrayData = m_defaultData; + m_numAllocatedBytes = sizeof(m_defaultData); + m_numInUseBytes = 0; + m_numInUseBits = 0; + + memset(m_arrayData, 0, m_numAllocatedBytes); + } +} + +// ----------------------------------------------------------------------- +bool BitArray::match(BitArray const & rhs) const +{ + return operator==(rhs); +} + +// ----------------------------------------------------------------------- + +bool BitArray::matchAnyBit(BitArray const & rhs) const +{ + // compare the individual chars in the 2 array up to the number + // of chars needed to hold the smaller of the 2 m_numInUseBits + int const smallerArraySize = std::min(m_numInUseBytes, rhs.m_numInUseBytes); + for (int i = 0; i < smallerArraySize; ++i) + if (m_arrayData[i] & rhs.m_arrayData[i]) + return true; + + return false; +} + +// ----------------------------------------------------------------------- + +namespace Archive +{ + void get(ReadIterator &source, BitArray &target) + { + int numInUseBytes; + int numInUseBits; + + get(source, numInUseBytes); + get(source, numInUseBits); + + // trivial case, rhs is empty + if ((numInUseBits <= 0) || (numInUseBytes <= 0)) + { + target.clear(); + return; + } + + // char array is too small, reallocate new char array + if (target.m_numAllocatedBytes < numInUseBytes) + { + if (target.m_arrayData != target.m_defaultData) + delete []target.m_arrayData; + + target.m_arrayData = new signed char[static_cast(numInUseBytes)]; + target.m_numAllocatedBytes = numInUseBytes; + } + // char array is large enough, no reallocation required, + // but clear out char array, if necessary + else if (target.m_numInUseBytes > numInUseBytes) + { + memset(&(target.m_arrayData[numInUseBytes]), 0, static_cast(target.m_numInUseBytes - numInUseBytes)); + } + + target.m_numInUseBytes = numInUseBytes; + target.m_numInUseBits = numInUseBits; + + for (int i = 0; i < target.m_numInUseBytes; ++i) + { + get(source, target.m_arrayData[i]); + } + } + + void put(ByteStream &target, const BitArray &source) + { + put(target, source.m_numInUseBytes); + put(target, source.m_numInUseBits); + if ((source.m_numInUseBits > 0) && (source.m_numInUseBytes > 0)) + { + put(target, source.m_arrayData, source.m_numInUseBytes); + } + } +} + +// ----------------------------------------------------------------------- + +void BitArray::clear() +{ + if (m_numInUseBytes > 0) + { + memset(m_arrayData, 0, static_cast(m_numInUseBytes)); + m_numInUseBytes = 0; + m_numInUseBits = 0; + } +} + +// ----------------------------------------------------------------------- + +void BitArray::setMultipleBits(int const count) +{ + if (count <= 0) + return; + + if (count > m_numInUseBits) + reserve(count); + + int const charCount = (count >> 3); + if (charCount) + memset(m_arrayData, static_cast(0xFFFFFFFF), static_cast(charCount)); + + for (int i = (charCount << 3); i < count; ++i) + setBit(i); +} + +// ----------------------------------------------------------------------- + +void BitArray::insertBit(int const index, bool const value) +{ + DEBUG_FATAL(index < 0, ("BitArray::insertBit index [%d] out of range", index)); + + // nothing to do if inserting a new bit past + // the end and the new bit will not be set + if (!value && (index >= m_numInUseBits)) + return; + + // if inserting a new bit in the middle, then shift all + // bits at and after the insertion point "backward" + if (index >= 0 && index < m_numInUseBits) + { + for(int i = (m_numInUseBits - 1); i >= index; --i) + { + if (testBit(i)) + setBit(i + 1); + else + clearBit(i + 1); + } + } + + // set/clear the inserted bit + if (value) + setBit(index); + else + clearBit(index); +} + +// ----------------------------------------------------------------------- + +void BitArray::removeBit(int const index) +{ + DEBUG_FATAL(index < 0, ("BitArray::removeBit index [%d] out of range", index)); + + // shift all bits after the removal point "forward" + if (index >= 0 && index < m_numInUseBits) + { + int const lastBitIndexToShift = m_numInUseBits - 1; + for(int i = index; i < lastBitIndexToShift; ++i) + { + if (testBit(i + 1)) + setBit(i); + else + clearBit(i); + } + + // shrink the array by 1 + reserve(m_numInUseBits - 1); + } +} + +// ----------------------------------------------------------------------- + +int BitArray::getNumberOfSetBits() const +{ + int count = 0; + for (int i = 0; i < m_numInUseBits; ++i) + if (testBit(i)) + ++count; + + return count; +} + +// ----------------------------------------------------------------------- + +bool BitArray::empty() const +{ + for (size_t i = 0; i < static_cast(m_numInUseBytes); ++i) + { + if (m_arrayData[i]) + return false; + } + + return true; +} + +// ----------------------------------------------------------------------- + +void BitArray::getAsDbTextString(std::string &result, int const maxNibbleCount /*= 32767*/) const +{ + result.clear(); + + static const char hexDigits[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + bool anyBitSet = false; + unsigned char nibbleIntValue; + int const nibbleCount = std::min(maxNibbleCount, (m_numInUseBytes << 1)); + for (int i = (nibbleCount - 1); i >= 0; --i) + { + nibbleIntValue = static_cast(m_arrayData[i >> 1]); + if (i % 2) + nibbleIntValue >>= 4; + else + nibbleIntValue &= static_cast(0xF); + + if (nibbleIntValue && !anyBitSet) + { + anyBitSet = true; + result.resize(i + 1); + } + + if (anyBitSet) + result[i] = hexDigits[nibbleIntValue]; + } +} + +// ----------------------------------------------------------------------- + +void BitArray::setFromDbTextString(const char * text) +{ + clear(); + + int const nibbleCount = (text ? strlen(text) : 0); + if (nibbleCount > 0) + { + bool anyBitSet = false; + unsigned char nibbleIntValue; + + // set the highest index bit first to avoid constant reallocation + for (int i = (nibbleCount - 1); i >= 0; --i) + { + if ((text[i] >= '0') && (text[i] <= '9')) + nibbleIntValue = static_cast(text[i] - '0'); + else if ((text[i] >= 'A') && (text[i] <= 'F')) + nibbleIntValue = static_cast(text[i] - 'A' + 10); + else if ((text[i] >= 'a') && (text[i] <= 'f')) + nibbleIntValue = static_cast(text[i] - 'a' + 10); + else + nibbleIntValue = static_cast(0); + + if (nibbleIntValue) + { + if (!anyBitSet) + { + anyBitSet = true; + reserve(((i >> 1) + 1) << 3); + } + + if (i % 2) + m_arrayData[i >> 1] |= static_cast(nibbleIntValue << 4); + else + m_arrayData[i >> 1] |= static_cast(nibbleIntValue); + } + } + } +} + +// ----------------------------------------------------------------------- + +std::string BitArray::getDebugString() const +{ + std::string s = FormattedString<512>().sprintf("%6d: ", m_numInUseBits); + int i; + for (i = 0; i < m_numInUseBits; ++i) + { + if ((i > 0) && ((i % 8) == 0)) + s += " "; + + if (testBit(i)) + s += "1"; + else + s += "0"; + } + + s += " ("; + + std::string baString; + getAsDbTextString(baString); + s += baString; + + s += ") ("; + + for (int i = 0; i < m_numAllocatedBytes; ++i) + { + if (i > 0) + s += " "; + + if (i == m_numInUseBytes) + s += " "; + + s += FormattedString<512>().sprintf("%02X", static_cast(m_arrayData[i])); + } + + s += ")"; + + if (m_arrayData == m_defaultData) + s += FormattedString<512>().sprintf(" (%d/%d default storage)", m_numInUseBytes, m_numAllocatedBytes); + else + s += FormattedString<512>().sprintf(" (%d/%d heap storage)", m_numInUseBytes, m_numAllocatedBytes); + + return s; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/BitArray.h b/engine/shared/library/sharedFoundation/src/shared/BitArray.h new file mode 100644 index 00000000..4960eea2 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/BitArray.h @@ -0,0 +1,111 @@ +// ====================================================================== +// +// BitArray.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_BitArray_H +#define INCLUDED_BitArray_H + +//---------------------------------------------------------------------- + +class BitArray; + +namespace Archive +{ + class ReadIterator; + class ByteStream; + + void get (ReadIterator &source, BitArray &target); + void put (ByteStream &target, const BitArray &source); +} + +//---------------------------------------------------------------------- + +class BitArray +{ +public: + BitArray (); + explicit BitArray (int numBits); + BitArray (const BitArray&); + virtual ~BitArray (); + + void setBit (int index); + void setValue (int beginIndex, int endIndex, unsigned long value); + void setMultipleBits(int count); + void clearBit (int index); + bool testBit (int index) const; + unsigned long getValue (int beginIndex, int endIndex) const; + void clear(); + int getNumberOfSetBits() const; + bool empty() const; + void insertBit(int const index, bool value); + void removeBit(int const index); + std::string getDebugString() const; + + // Equivalent to operator==() + bool match (const BitArray &rhs) const; + + // Returns true if array has any bits set which this array also has set. + bool matchAnyBit (const BitArray &rhs) const; + + //operators + BitArray & operator = (const BitArray &rhs); + bool operator == (const BitArray &rhs) const; + bool operator!= (const BitArray &rhs) const; + + // for DB persistence purpose, returns the BitArray as a + // std::string where each 4 bits are printed as a hex nibble; + // and the converse that takes the null-terminated string + // and converts it back into the BitArray + void getAsDbTextString(std::string &result, int maxNibbleCount = 32767) const; + void setFromDbTextString(const char * text); + + friend void Archive::get (ReadIterator &source, BitArray &target); + friend void Archive::put (ByteStream &target, const BitArray &source); + +private: + // *****WARNING***** *****WARNING***** *****WARNING***** *****WARNING***** + // do not expose the "size" (either m_numInUseBits, m_numInUseBytes, or + // m_numAllocatedBytes) to the outside world, since it is not guaranteed + // to be accurate in terms of what the outside world expects the "size" + // to be; for optimization, BitArray doesn't necessarily change the "size" + // value(s) if a particular bit index is not set; for example, if you do + // setBit(1000000), and then do clearBit(1000000), the "size" is not + // necessarily 1000000; the only guarantee we make here is that + // testBit(1000000) will return false; the bottom line is that BitArray + // does not maintain the "size" of the BitArray, so no function should + // ever be added to return the "size" of the BitArray + // *****WARNING***** *****WARNING***** *****WARNING***** *****WARNING***** + + // to avoid constant reallocation for small BitArray, small BitArray will + // use this as storage; only when the BitArray is larger than 128 (16*8) + // will we need to allocate off the heap + signed char m_defaultData[16]; + + // points to the storage for the BitArray, which will be either m_defaultData + // or heap allocated storage for BitArray larger than 128 (16*8) + signed char *m_arrayData; + + // how many chars allocated in m_arrayData + int m_numAllocatedBytes; + + // how many chars in m_arrayData that's actually used for the BitArray; + // this will always be <= m_numAllocatedBytes; + // this will always be 0 or (m_numInUseBits+7) >> 3, but we cache it here + // so we don't constantly have to calculate (m_numInUseBits+7) >> 3 + int m_numInUseBytes; + + // storage (i.e. m_arrayData) may be allocated to handle more than m_numInUseBits, + // because its expensive to be constantly expanding and shrinking m_arrayData; + // however, every bit past 0-based index (m_numInUseBits - 1) is guaranteed to be unset + int m_numInUseBits; + + void reserve (int numBits); +}; + +//---------------------------------------------------------------------- + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/Branch.cpp b/engine/shared/library/sharedFoundation/src/shared/Branch.cpp new file mode 100644 index 00000000..ebbc1b7d --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Branch.cpp @@ -0,0 +1,63 @@ +// ====================================================================== +// +// Branch.cpp +// +// copyright 2005 Sony Online Entertainment +// All Rights Reserved +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/Branch.h" + +//---------------------------------------------------------------------- + +namespace BranchNamespace +{ +#ifdef _WIN32 + const char * cs_win32PathSeperator = "\\"; +#endif + const char * cs_pathSeperator = "/"; + const char * cs_branchIdentifierString = "/src/engine/shared"; +} + +using namespace BranchNamespace; + +//---------------------------------------------------------------------- + +Branch::Branch() +{ + m_branchName = __FILE__; + + std::string::size_type slash = 0; + +#ifdef _WIN32 + while ( ( slash = m_branchName.find( cs_win32PathSeperator, slash ) ) != std::string::npos ) + { + m_branchName[ slash ] = *cs_pathSeperator; + } +#endif + + slash = m_branchName.find( cs_branchIdentifierString ); + + if ( slash != std::string::npos ) + { + m_branchName.resize( slash ); + + slash = m_branchName.rfind( cs_pathSeperator ); + + if ( slash != std::string::npos ) + { + m_branchName = m_branchName.substr( ++slash ); + } + } +} + +//---------------------------------------------------------------------- + +const std::string & Branch::getBranchName() const +{ + return m_branchName; +} + +//---------------------------------------------------------------------- diff --git a/engine/shared/library/sharedFoundation/src/shared/Branch.h b/engine/shared/library/sharedFoundation/src/shared/Branch.h new file mode 100644 index 00000000..273ff137 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Branch.h @@ -0,0 +1,26 @@ +// ====================================================================== +// +// Branch.h +// copyright 2005 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_Branch_H +#define INCLUDED_Branch_H + +#include + +class Branch +{ +public: + Branch(); + + const std::string & getBranchName() const; + +private: + std::string m_branchName; +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/CalendarTime.cpp b/engine/shared/library/sharedFoundation/src/shared/CalendarTime.cpp new file mode 100644 index 00000000..64595534 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CalendarTime.cpp @@ -0,0 +1,398 @@ +// ====================================================================== +// +// CalendarTime.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/CalendarTime.h" + +#include + +// ====================================================================== + +std::string CalendarTime::convertEpochToTimeStringGMT(time_t epoch) +{ + std::string result; + + struct tm * timeinfo = ::gmtime(&epoch); + if (timeinfo == NULL) + return result; + + char * asciiTime = ::asctime(timeinfo); + if (asciiTime == NULL) + return result; + + static char resultBuffer[512]; + char * buffer = resultBuffer; + if (strlen(asciiTime) >= sizeof(resultBuffer)) + buffer = new char[strlen(asciiTime) + 1]; + + strcpy(buffer, asciiTime); + buffer[strcspn(buffer, "\r\n")] = '\0'; + result = buffer; + + if (buffer != resultBuffer) + delete[] buffer; + + result += " GMT"; + + return result; +} + +// ====================================================================== + +std::string CalendarTime::convertEpochToTimeStringGMT_YYYYMMDDHHMMSS(time_t epoch) +{ + std::string result; + + struct tm * timeinfo = ::gmtime(&epoch); + if (timeinfo == NULL) + return result; + + static char resultBuffer[512]; + snprintf(resultBuffer, sizeof(resultBuffer), "%d-%02d-%02d %02d:%02d:%02d GMT", (timeinfo->tm_year + 1900), (timeinfo->tm_mon + 1), timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); + + return std::string(resultBuffer); +} + +//----------------------------------------------------------------- + +std::string CalendarTime::convertEpochToTimeStringLocal(time_t epoch) +{ + std::string result; + + struct tm * timeinfo = ::localtime(&epoch); + if (timeinfo == NULL) + return result; + + char * asciiTime = ::asctime(timeinfo); + if (asciiTime == NULL) + return result; + + static char resultBuffer[512]; + char * buffer = resultBuffer; + if (strlen(asciiTime) >= sizeof(resultBuffer)) + buffer = new char[strlen(asciiTime) + 1]; + + strcpy(buffer, asciiTime); + buffer[strcspn(buffer, "\r\n")] = '\0'; + result = buffer; + + if (buffer != resultBuffer) + delete[] buffer; + + // get local time zone string + static char buffer2[256]; + if (0 < ::strftime(buffer2, sizeof(buffer2)-1, "%Z", timeinfo)) + { + result += " "; + result += buffer2; + } + else + { + result += " local"; + } + + return result; +} + +//----------------------------------------------------------------- + +std::string CalendarTime::convertEpochToTimeStringLocal_YYYYMMDDHHMMSS(time_t epoch) +{ + std::string result; + + struct tm * timeinfo = ::localtime(&epoch); + if (timeinfo == NULL) + return result; + + static char resultBuffer[512]; + snprintf(resultBuffer, sizeof(resultBuffer), "%d-%02d-%02d %02d:%02d:%02d ", (timeinfo->tm_year + 1900), (timeinfo->tm_mon + 1), timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); + + result = resultBuffer; + + if (0 < ::strftime(resultBuffer, sizeof(resultBuffer)-1, "%Z", timeinfo)) + { + result += resultBuffer; + } + else + { + result += "local"; + } + + return result; +} + +//----------------------------------------------------------------- + +std::string CalendarTime::convertSecondsToDHMS(unsigned int numSeconds) +{ + char buffer[128]; + + snprintf(buffer, sizeof(buffer)-1, "%ud:%uh:%um:%us", + numSeconds / (60 * 60 * 24), + (numSeconds % (60 * 60 * 24)) / (60 * 60), + (numSeconds % (60 * 60)) / 60, + numSeconds % 60); + + buffer[sizeof(buffer)-1] = '\0'; + + return std::string(buffer); +} + +//----------------------------------------------------------------- + +std::string CalendarTime::convertSecondsToHMS(unsigned int numSeconds) +{ + char buffer[128]; + + snprintf(buffer, sizeof(buffer)-1, "%uh:%um:%us", + numSeconds / (60 * 60), + (numSeconds % (60 * 60)) / 60, + numSeconds % 60); + + buffer[sizeof(buffer)-1] = '\0'; + + return std::string(buffer); +} + +//----------------------------------------------------------------- + +std::string CalendarTime::convertSecondsToMS(unsigned int numSeconds) +{ + char buffer[128]; + + snprintf(buffer, sizeof(buffer)-1, "%um:%us", + numSeconds / 60, + numSeconds % 60); + + buffer[sizeof(buffer)-1] = '\0'; + + return std::string(buffer); +} + +//----------------------------------------------------------------- +// given a starting Epoch GMT time, returns the Epoch GMT time when the next specified +// GMT day of week, hour, minute, and second will occur; note that the day of week, hour, +// minute, and second specified will all be interpreted in terms of GMT time +// +// returns -1 if invalid parameters are specified or there are any system errors +// in making the calculation +// +// day of week is 0=Sunday, 1=Monday, 2=Tuesday, 3=Wednesday, 4=Thursday, 5=Friday, 6=Saturday +// if you just want to find out when the next hour, minute, second will occur, specify -1 for +// day of week +// +// hour must be between 0-23 +// if you just want to find out when the next minute, second will occur, specify -1 for day +// of week and -1 for hour +// +// minute must be between 0-59 +// +// second must be between 0-59 + +time_t CalendarTime::getNextGMTTimeOcurrence(time_t const startTime, int const dayOfWeek, int const hour, int const minute, int const second) +{ + // don't allow start time to be too far in the past + if (startTime < CalendarTimeNamespace::g_CalendarTimeEarliestTime) + return -1; + + if ((dayOfWeek < -1) || (dayOfWeek > 6)) + return -1; + + if ((hour < -1) || (hour > 23)) + return -1; + + if ((hour == -1) && (dayOfWeek != -1)) + return -1; + + if ((minute < 0) || (minute > 59)) + return -1; + + if ((second < 0) || (second > 59)) + return -1; + + // convert the start time into a broken down time containing + // the year, month, day, day of week, hour, minute, second + // in GMT time + struct tm * timeinfo = ::gmtime(&startTime); + if (timeinfo == NULL) + return -1; + + // get number of days until the specified day of week to search for + if (dayOfWeek >= 0) + { + int daysUntil = 0; + + // calculate the Epoch GMT time for the specified start time + // at the specified hour, minute, and second + time_t startTimeAtSpecifiedHourMinuteSecond = startTime + (((hour * 60 * 60) + (minute * 60) + second) - ((timeinfo->tm_hour * 60 * 60) + (timeinfo->tm_min * 60) + timeinfo->tm_sec)); + + if (timeinfo->tm_wday != dayOfWeek) + { + if (timeinfo->tm_wday < dayOfWeek) + daysUntil = dayOfWeek - timeinfo->tm_wday; + else + // wraparound + daysUntil = (6 - timeinfo->tm_wday) + dayOfWeek + 1; + } + else + { + // if the specified day of week matches the start day of week, but + // the specified time has already passed, then we want go forward + // to next week + if (startTimeAtSpecifiedHourMinuteSecond <= startTime) + daysUntil = 7; + } + + // the next time the that the day/time will match + startTimeAtSpecifiedHourMinuteSecond += (60 * 60 * 24 * daysUntil); + + return startTimeAtSpecifiedHourMinuteSecond; + } + + // dayOfWeek == -1 + if (hour >= 0) + { + // calculate the Epoch GMT time for the specified start time + // at the specified hour, minute, and second + time_t startTimeAtSpecifiedHourMinuteSecond = startTime + (((hour * 60 * 60) + (minute * 60) + second) - ((timeinfo->tm_hour * 60 * 60) + (timeinfo->tm_min * 60) + timeinfo->tm_sec)); + + // no day of week specified, we want when the time will + // match on the day of the start time, or if the time has + // already passed for the day of the start time, then we + // when the time will match for the day following the day + // of the start time + if (startTimeAtSpecifiedHourMinuteSecond <= startTime) + startTimeAtSpecifiedHourMinuteSecond += (60 * 60 * 24); + + return startTimeAtSpecifiedHourMinuteSecond; + } + + // dayOfWeek == -1 and hour == -1 + time_t startTimeAtSpecifiedHourMinuteSecond = startTime + (((minute * 60) + second) - ((timeinfo->tm_min * 60) + timeinfo->tm_sec)); + + // no day of week or hour specified, we want when the minute:second + // will match on the hour of the start time, or if the minute:second + // has already passed for the hour of the start time, then we want + // when the minute:second will match for the hour following the + // hour of the start time + if (startTimeAtSpecifiedHourMinuteSecond <= startTime) + startTimeAtSpecifiedHourMinuteSecond += (60 * 60); + + return startTimeAtSpecifiedHourMinuteSecond; +} + +//----------------------------------------------------------------- +// given a starting Epoch GMT time, returns the Epoch GMT time when the next specified +// GMT month, day of month, hour, minute, and second will occur; note that the month, +// day of month, hour, minute, and second specified will all be interpreted in terms +// of GMT time +// +// returns -1 if invalid parameters are specified or there are any system errors +// in making the calculation +// +// month must be between 1-12 +// if you just want to find out when the next day of month, hour, minute, and second will occur, +// specify -1 for month +// +// dayOfMonth must be between 1-31 +// +// hour must be between 0-23 +// +// minute must be between 0-59 +// +// second must be between 0-59 +time_t CalendarTime::getNextGMTTimeOcurrence(time_t const startTime, int const month, int const dayOfMonth, int const hour, int const minute, int const second) +{ + // don't allow start time to be too far in the past + if (startTime < CalendarTimeNamespace::g_CalendarTimeEarliestTime) + return -1; + + if (month == 0) + return -1; + + if ((month < -1) || (month > 12)) + return -1; + + if ((dayOfMonth < 1) || (dayOfMonth > 31)) + return -1; + + if ((hour < 0) || (hour > 23)) + return -1; + + if ((minute < 0) || (minute > 59)) + return -1; + + if ((second < 0) || (second > 59)) + return -1; + + // convert the start time into a broken down time containing + // the year, month, day, day of week, hour, minute, second + // in GMT time + struct tm * timeinfo = ::gmtime(&startTime); + if (timeinfo == NULL) + return -1; + + // calculate the Epoch GMT time for the specified start time + // at the specified hour, minute, and second + time_t startTimeAtSpecifiedHourMinuteSecond = startTime + (((hour * 60 * 60) + (minute * 60) + second) - ((timeinfo->tm_hour * 60 * 60) + (timeinfo->tm_min * 60) + timeinfo->tm_sec)); + + // timeinfo uses 0-based month + int const targetMonth = ((month == -1) ? -1 : (month - 1)); + + // to catch infinite loop caused by stuff like "April 31", but + // make sure we loop long enough to include the next leap day "February 29" + int const maxIterations = (((month == 2) && (dayOfMonth == 29)) ? (365*4+1) : (365+1)); + int sentinel = 0; + + while (true) + { + if (((targetMonth == -1) || (targetMonth == timeinfo->tm_mon)) && (dayOfMonth == timeinfo->tm_mday) && (startTimeAtSpecifiedHourMinuteSecond > startTime)) + break; + + // start adding 1 day at a time until the target month and day of month is reached + // TODO: find a better way of doing this rather than looping 1 day at a time + startTimeAtSpecifiedHourMinuteSecond += (60 * 60 * 24); + + timeinfo = ::gmtime(&startTimeAtSpecifiedHourMinuteSecond); + if (timeinfo == NULL) + return -1; + + if (++sentinel > maxIterations) + return -1; + } + + return startTimeAtSpecifiedHourMinuteSecond; +} + +//----------------------------------------------------------------- + +std::string CalendarTime::getCharacerBirthDateString(int characterBirthDate) +{ + // the birth date (for characters created on live and TC clusters) is the + // number of days since 00:00:00 Jan 1st, 2001 PST + // (see the server's PlayerObject::getCurrentBornDate()) + // 978336000 is the epoch value corresponding to 00:00:00 Jan 1st, 2001 PST + time_t const baseTime = 978336000 + static_cast(characterBirthDate * 60 * 60 * 24) - (60 * 60 * 12); + + struct tm const * const birthDateTimeData = ::localtime(&baseTime); + + // get local time zone string + std::string timeZone("local"); + + char buffer[256]; + if (0 < ::strftime(buffer, sizeof(buffer)-1, "%Z", birthDateTimeData)) + { + timeZone = buffer; + } + + snprintf(buffer, sizeof(buffer)-1, "%02d %02d %d %s", (birthDateTimeData->tm_mon + 1), birthDateTimeData->tm_mday, (birthDateTimeData->tm_year + 1900), timeZone.c_str()); + buffer[sizeof(buffer)-1] = '\0'; + + return std::string(buffer); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/CalendarTime.h b/engine/shared/library/sharedFoundation/src/shared/CalendarTime.h new file mode 100644 index 00000000..33044dfd --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CalendarTime.h @@ -0,0 +1,42 @@ +// ====================================================================== +// +// CalendarTime.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_CalendarTime_H +#define INCLUDED_CalendarTime_H + +// ====================================================================== + +// Sat Jan 01 00:00:00 1980 (just an arbitrary value) +namespace CalendarTimeNamespace +{ + const time_t g_CalendarTimeEarliestTime = 315550800; +}; + +class CalendarTime +{ +private: + + CalendarTime(void); + CalendarTime(const CalendarTime &); + CalendarTime &operator =(const CalendarTime &); + +public: + + static std::string convertEpochToTimeStringGMT(time_t epoch); + static std::string convertEpochToTimeStringGMT_YYYYMMDDHHMMSS(time_t epoch); + static std::string convertEpochToTimeStringLocal(time_t epoch); + static std::string convertEpochToTimeStringLocal_YYYYMMDDHHMMSS(time_t epoch); + static std::string convertSecondsToDHMS(unsigned int numSeconds); + static std::string convertSecondsToHMS(unsigned int numSeconds); + static std::string convertSecondsToMS(unsigned int numSeconds); + static time_t getNextGMTTimeOcurrence(time_t startTime, int dayOfWeek, int hour, int minute, int second); + static time_t getNextGMTTimeOcurrence(time_t startTime, int month, int dayOfMonth, int hour, int minute, int second); + + static std::string getCharacerBirthDateString(int characterBirthDate); +}; + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/CallbackEntryBase.h b/engine/shared/library/sharedFoundation/src/shared/CallbackEntryBase.h new file mode 100644 index 00000000..3223187b --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CallbackEntryBase.h @@ -0,0 +1,56 @@ +// CallbackEntryBase.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_CallbackEntryBase_H +#define _INCLUDED_CallbackEntryBase_H + +//----------------------------------------------------------------------- + +class Scheduler; + +//----------------------------------------------------------------------- +/** @brief Internally used class that identifies callbacks. + + @see CallbackEntry + @see StaticCallbackEntry + + @author Justin Randall +*/ +class CallbackEntryBase +{ +protected: + CallbackEntryBase(const unsigned long when); + virtual ~CallbackEntryBase() = 0; + +public: + virtual void expired() = 0; + const unsigned long getExpireCount() const; + + /** @brief Compare functor supplied for use with a priority queue. + */ + struct Compare + { + bool operator ()(const CallbackEntryBase * lhs, const CallbackEntryBase * rhs) const + { + return lhs->expireCount > rhs->expireCount; + } + }; + +protected: + friend struct Compare; + + unsigned long expireCount; +}; + +//----------------------------------------------------------------------- +/** @return the expiration count ("time", "frame", whatever) of the callback. +*/ +inline const unsigned long CallbackEntryBase::getExpireCount() const +{ + return expireCount; +} + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_CallbackEntryBase_H diff --git a/engine/shared/library/sharedFoundation/src/shared/Clock.cpp b/engine/shared/library/sharedFoundation/src/shared/Clock.cpp new file mode 100644 index 00000000..6851f8fb --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Clock.cpp @@ -0,0 +1,528 @@ +// ====================================================================== +// +// Clock.cpp +// +// Portions copyright 1998 Bootprint Entertainment +// Portsion copyright 2002 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/Clock.h" + +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedDebug/Profiler.h" +#include "sharedFile/TreeFile.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/Os.h" +#include "sharedFoundation/Production.h" +#include "sharedDebug/RemoteDebug.h" +#include "sharedSynchronization/Mutex.h" +#include "sharedSynchronization/Semaphore.h" +#include "sharedThread/RunThread.h" +#include "sharedThread/ThreadHandle.h" +#include + +#ifdef PLATFORM_WIN32 //@todo code reorg +#include "sharedFoundation/WindowsWrapper.h" +#endif + +// ====================================================================== + +real Clock::ms_lastFrameRate; + +// ====================================================================== + +namespace ClockNamespace +{ + __int64 ms_lastPoll; // the last time the clock was polled at the start of a frame + real ms_lastFrameTime; // the time (in seconds) that the last frame took + real ms_maxFrameTime; // the maximum time a frame is allowed to be. If exceeded, a warning is logged. + unsigned long ms_applicationStartTime; // the time the application was started + double ms_realTimeMilliseconds; + bool ms_useSleep; +#if PRODUCTION == 0 + bool ms_debugReportFlag; + bool ms_debugReportLogFlag; +#endif + bool ms_debugReportLongFrames; + int ms_previousNumberOfFilesOpenedTotal; + int ms_previousSizeOfFilesOpenedTotal; + int ms_timeZone; + ThreadHandle ms_threadHandle; + Mutex ms_mutex; + Semaphore ms_shutdownEvent; + bool ms_shutdown = false; + unsigned int const ms_recalibrationInterval = 1000; + unsigned int const ms_recalibrationMultiplier = 1000 / ms_recalibrationInterval; + real ms_realFrequency; // periodically calibrated clock frequency, updated from clock thread + real ms_frameFrequency; // clock frequency being used during the current frame, updated from realFrequency each frame + real ms_frameRateLimit; + + static const double cms_secondsPerMillisecond = 0.001; + +#if PRODUCTION == 0 + static void reportMinimumFrameTime(); + + bool ms_reportMinimumFrameTime; + bool ms_resetMinimumFrameTime; + float ms_minimumFrameTime; + bool ms_useRecalibrationThread; + bool ms_lastUseRecalibrationThread; +#endif + + bool ms_longFramesWarningAllowed = true; + + void threadRoutine(); +} +using namespace ClockNamespace; + +// ====================================================================== +// Install the Clock subsystem +// +// Remarks: +// +// The Clock currently requires the use of the high performance counter in Windows. +// If the high performance counter is unavailable, this routine will call Fatal. +// +// This routine will also add Clock::remove to the ExitChain. +// +// See Also: +// +// Clock::remove() + +void Clock::install(bool newUseSleep, bool useRecalibrationThread) +{ + BOOL result; + + ms_useSleep = newUseSleep; + +#if PRODUCTION == 0 + ms_useRecalibrationThread = useRecalibrationThread; + ms_lastUseRecalibrationThread = useRecalibrationThread; +#endif + + ExitChain::add(Clock::remove, "Clock::remove"); + + __int64 frequency; + result = QueryPerformanceFrequency(reinterpret_cast(&frequency)); + FATAL(!result, ("Clock::install QPF failed")); + + result = QueryPerformanceCounter(reinterpret_cast(&ms_lastPoll)); + FATAL(!result, ("Clock::install QPC failed")); + + ms_realFrequency = static_cast(frequency); + ms_frameFrequency = ms_realFrequency; + + if (ConfigSharedFoundation::getFrameRateLimit() != 0.0f) + setFrameRateLimit(ConfigSharedFoundation::getFrameRateLimit()); + setMinFrameRate(ConfigSharedFoundation::getMinFrameRate()); + +#if PRODUCTION == 0 + DebugFlags::registerFlag(ms_debugReportFlag, "SharedFoundation", "reportClock", debugReport, -1000); + DebugFlags::registerFlag(ms_reportMinimumFrameTime, "SharedFoundation", "reportMinimumFrameTime", reportMinimumFrameTime, -990); + DebugFlags::registerFlag(ms_resetMinimumFrameTime, "SharedFoundation", "resetMinimumFrameTime"); + DebugFlags::registerFlag(ms_debugReportLogFlag, "SharedFoundation", "logClock"); + DebugFlags::registerFlag(ms_debugReportLongFrames, "SharedFoundation", "debugReportLongFrames"); + DebugFlags::registerFlag(ms_useRecalibrationThread, "SharedFoundation", "useClockRecalibrationThread"); +#endif + + time_t t = 0; + localtime(&t); + ms_timeZone = timezone; + if(ms_timeZone < (12 * 60 * 60)) + { + ms_timeZone = -ms_timeZone; + } + ms_realTimeMilliseconds = static_cast(ms_lastPoll / ms_frameFrequency * 1000.f); + ms_applicationStartTime = timeSeconds(); + + if (useRecalibrationThread) + { + ms_shutdown = false; + ms_threadHandle = runNamedThread("Clock", threadRoutine); + ms_threadHandle->setPriority(Thread::kCritical); + } +} + +// ---------------------------------------------------------------------- +/** + * Remove the clock subsystem. + * + * This routine should not be called directly by users. Clock::install() will add + * this routine onto the ExitChain. + * + * @see Clock::install() + */ + +void Clock::remove(void) +{ +#if PRODUCTION == 0 + DebugFlags::unregisterFlag(ms_debugReportFlag); + DebugFlags::unregisterFlag(ms_debugReportLogFlag); + DebugFlags::unregisterFlag(ms_debugReportLongFrames); +#endif + + if (ms_threadHandle) + { + ms_mutex.enter(); + ms_shutdown = true; + ms_mutex.leave(); + ms_shutdownEvent.signal(); + ms_threadHandle->wait(); + } +} + +// ---------------------------------------------------------------------- +/** + * Update the clock. + * + * This routine will recompute the amount of time the last frame took to complete. + * If this routine is not called, the values returned by Clock::frameTime() and + * Clock::framesPerSecond() will not change. + * + * @see Clock::frameTime(), Clock::framesPerSecond() + */ + +void Clock::update(void) +{ + __int64 newPoll; + BOOL result; + +#if PRODUCTION == 0 + if (ms_lastUseRecalibrationThread != ms_useRecalibrationThread) + { + if (ms_useRecalibrationThread) + { + ms_shutdown = false; + ms_threadHandle = runNamedThread("Clock", threadRoutine); + ms_threadHandle->setPriority(Thread::kCritical); + } + else + { + ms_mutex.enter(); + ms_shutdown = true; + ms_mutex.leave(); + ms_shutdownEvent.signal(); + ms_threadHandle->wait(); + } + ms_lastUseRecalibrationThread = ms_useRecalibrationThread; + } +#endif + + result = QueryPerformanceCounter(reinterpret_cast(&newPoll)); + FATAL(!result, ("Clock::update QPC failed")); + + // We need to consider time before this frame as having passed with a + // potentially different frequency, and also need to consider portions + // of a millisecond. + + real const frameTime = static_cast(newPoll - ms_lastPoll) / ms_frameFrequency; + ms_realTimeMilliseconds += static_cast(frameTime*1000.f); + + ms_mutex.enter(); + ms_frameFrequency = ms_realFrequency; + ms_mutex.leave(); + + if (!Os::wasFocusLost()) + { + ms_lastFrameTime = frameTime; + +#if PRODUCTION == 0 + float const debugReportLongFrameTime = ConfigSharedFoundation::getDebugReportLongFrameTime(); + if (ms_debugReportLongFrames && ms_lastFrameTime > debugReportLongFrameTime) + { + REPORT_LOG(true, ("------------------------------------------------\n")); + REPORT_LOG(true, ("WARNING: Clock::update[%d] Last Frame took %f seconds\n", Os::getNumberOfUpdates(), ms_lastFrameTime)); + REPORT_LOG(true, ("Files: %4d opened, %4d KB\n", TreeFile::getNumberOfFilesOpenedTotal() - ms_previousNumberOfFilesOpenedTotal, (TreeFile::getSizeOfFilesOpenedTotal() - ms_previousSizeOfFilesOpenedTotal) / 1024)); + Profiler::setTemporaryExpandAll(true); + Profiler::printLastFrameData(); + REPORT_LOG(true, ("%s\n", Profiler::getLastFrameData())); + Profiler::setTemporaryExpandAll(false); + } +#endif + + if (ms_lastFrameTime > ms_maxFrameTime) + { + DEBUG_REPORT_LOG(ms_longFramesWarningAllowed, ("WARNING: Clock::update[%d] Last Frame took %f seconds\n", Os::getNumberOfUpdates(), ms_lastFrameTime)); + ms_lastFrameTime = ms_maxFrameTime; + } + + ms_lastFrameRate = RECIP(ms_lastFrameTime); + } + +#if 0 + // -qq- debugging W2K QueryPerformanceCounter + static DWORD lastTick; + DWORD newTick = GetTickCount(); + + DEBUG_REPORT_LOG_PRINT(true, ("Clock::update %I64d %I64d %6I64d %10d %10d %3d %6.2f=fps %6.4f=time\n", ms_lastPoll, newPoll, newPoll - ms_lastPoll, lastTick, newTick, newTick - lastTick, ms_lastFrameRate, ms_lastFrameTime)); + + static int bad = 0; + + if (bad && ++bad > 64) + __asm int 3; + + if (ms_lastFrameTime > 3.0) + bad = 1; + + lastTick = newTick; +#endif + + ms_lastPoll = newPoll; + + +#if PRODUCTION == 0 + ms_previousNumberOfFilesOpenedTotal = TreeFile::getNumberOfFilesOpenedTotal(); + ms_previousSizeOfFilesOpenedTotal = TreeFile::getSizeOfFilesOpenedTotal(); + + if (ms_resetMinimumFrameTime || ms_lastFrameTime < ms_minimumFrameTime) + { + ms_resetMinimumFrameTime = false; + ms_minimumFrameTime = ms_lastFrameTime; + } +#endif +} + +// ---------------------------------------------------------------------- +/** + * Display debugging information for the clock. + */ + +void Clock::debugReport(void) +{ +#if PRODUCTION == 0 + REPORT(true, Report::RF_print | (ms_debugReportLogFlag ? Report::RF_log : 0), ("Clock %6.2f=fps %8.6f=time\n", ms_lastFrameRate, ms_lastFrameTime)); + DEBUG_OUTPUT_STATIC_VIEW_BEGINFRAME("Foundation\\Clock"); + DEBUG_OUTPUT_STATIC_VIEW("Foundation\\Clock", ("Clock %6.2f=fps %6.4f=time\n", ms_lastFrameRate, ms_lastFrameTime)); + DEBUG_OUTPUT_STATIC_VIEW_ENDFRAME("Foundation\\Clock"); +#endif +} + +// ---------------------------------------------------------------------- + +#if PRODUCTION == 0 + +void ClockNamespace::reportMinimumFrameTime(void) +{ + REPORT(true, Report::RF_print, ("min frame time %8.6f\n", ms_minimumFrameTime)); +} + +#endif + +// ---------------------------------------------------------------------- +// Get the amount of time the last frame took +// +// Return Value: +// +// Time, in seconds, for the last frame +// +// Remarks: +// +// This routine currently does not take in to account if the game was +// task-switched out of. +// +// See Also: +// +// Clock::framesPerSecond() + +real Clock::frameTime(void) +{ + return ms_lastFrameTime; +} + +// ---------------------------------------------------------------------- +/** + * Disable the frame rate limiter. + * + * Calling this routine will make the Clock subsystem allow the game to run at + * the fastest rate possible. + * + * @see Clock::setFrameRateLimit() + */ + +void Clock::noFrameRateLimit(void) +{ + ms_frameRateLimit = 0.f; +} + +// ---------------------------------------------------------------------- +/** + * Enable the frame rate limiter to a specific frame rate value. + * + * This routine will set the maximum number of frame-per-second that the game + * will be allowed to run. If the game could run faster than that, the Clock + * subsystem will wait when Clock::limitFrameRate() is called. + * + * @param newFrameRateLimit Frames per second for the clock to limit the game to + * @see Clock::noFrameRateLimit(), Clock::limitFrameRate() + */ + +void Clock::setFrameRateLimit(real newFrameRateLimit) +{ + DEBUG_FATAL(newFrameRateLimit < 1.0f, ("Clock::setFrameRateLimit can not be under 1, %f", newFrameRateLimit)); + ms_frameRateLimit = newFrameRateLimit; +} + +// ---------------------------------------------------------------------- +/** + * Set a minimum frame rate for the game. + * + * This routine sets a minimum frame rate for the game. Any frames that take longer will + * log a warning then have the next frame time set to the given minimum value. + * + */ + +void Clock::setMinFrameRate(real newMinFrameRate) +{ + if (newMinFrameRate == 0) + ms_maxFrameTime = REAL_MAX; + else + ms_maxFrameTime = RECIP(newMinFrameRate); +} + + +// ---------------------------------------------------------------------- +/** + * Wait if the game is running too fast. + * + * If the frame rate limiter has been enabled by calling Clock::setFrameRateLimit(), this + * routine will make sure that the game never exceeds the framerate specified at + * that function call. + * + * If the frame rate limiter is not enabled, or has been disabled by calling + * Clock::noFrameRateLimit(), this routine will do nothing. + * + * @see Clock::noFrameRateLimit(), Clock::setFrameRateLimit() + */ + +void Clock::limitFrameRate(void) +{ + BOOL result; + + // check if the frame rate limiter is on + if (ms_frameRateLimit) + { + __int64 const frameRateLimitTicks = static_cast<__int64>(ms_frameFrequency / ms_frameRateLimit); + __int64 newPoll, delta; + + for (;;) + { + // get the current time + result = QueryPerformanceCounter(reinterpret_cast(&newPoll)); + FATAL(!result, ("Clock::limitFrameRate QPC failed")); + + // compute elapsed time + delta = newPoll - ms_lastPoll; + if (delta >= frameRateLimitTicks) + break; + + //@todo it looks like if delta is huge we will sleep a looong time. shouldn't we check delta and the frameRatelimit before sleeping? + if (ms_useSleep) + { + const DWORD sleepTicks = static_cast(static_cast((frameRateLimitTicks - delta) / ms_frameFrequency) * 1000.0f); + if (sleepTicks > 2) + Sleep(sleepTicks); + } + } + } +} + +//----------------------------------------------------------------------- + +const unsigned long Clock::timeMs() +{ + __int64 newPoll; + QueryPerformanceCounter(reinterpret_cast(&newPoll)); + double const frameTime = static_cast(newPoll - ms_lastPoll) / ms_frameFrequency; + return static_cast(ms_realTimeMilliseconds + frameTime*1000.f); +} + +//----------------------------------------------------------------------- + +const unsigned long Clock::timeSeconds() +{ + __int64 newPoll; + QueryPerformanceCounter(reinterpret_cast(&newPoll)); + double const frameTime = static_cast(newPoll - ms_lastPoll) / ms_frameFrequency; + return static_cast(ms_realTimeMilliseconds/1000.f + frameTime); +} + +// ---------------------------------------------------------------------- + +const unsigned long Clock::getFrameStartTimeMs() +{ + return static_cast(ms_realTimeMilliseconds); +} + +// ---------------------------------------------------------------------- + +double Clock::getCurrentTime() +{ + __int64 newPoll; + + QueryPerformanceCounter(reinterpret_cast(&newPoll)); + + double const frameTime = static_cast(newPoll - ms_lastPoll) / ms_frameFrequency; + + return getFrameStartTime() + frameTime; +} + +// ---------------------------------------------------------------------- + +double Clock::getFrameStartTime() +{ + return ms_realTimeMilliseconds * cms_secondsPerMillisecond; +} + +// ---------------------------------------------------------------------- + +const unsigned long Clock::getSecondsSinceStart() +{ + return timeSeconds() - ms_applicationStartTime; +} + +// ---------------------------------------------------------------------- + +const int Clock::getTimeZone() +{ + return ms_timeZone; +} + +// ---------------------------------------------------------------------- + +void ClockNamespace::threadRoutine() +{ + bool done = false; + + while (!done) + { + __int64 startCounter, endCounter; + + QueryPerformanceCounter(reinterpret_cast(&startCounter)); + ms_shutdownEvent.wait(ms_recalibrationInterval); + QueryPerformanceCounter(reinterpret_cast(&endCounter)); + + __int64 newFrequency = (endCounter-startCounter)*ms_recalibrationMultiplier; + + ms_mutex.enter(); + if (ms_shutdown) + done = true; + else if (newFrequency) + ms_realFrequency = static_cast(newFrequency); + ms_mutex.leave(); + } +} + +//---------------------------------------------------------------------- + +void Clock::setLongFramesWarningAllowed(bool allowed) +{ + ms_longFramesWarningAllowed = allowed; +} + +// ====================================================================== + diff --git a/engine/shared/library/sharedFoundation/src/shared/Clock.h b/engine/shared/library/sharedFoundation/src/shared/Clock.h new file mode 100644 index 00000000..dacb393c --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Clock.h @@ -0,0 +1,76 @@ +// ====================================================================== +// +// Clock.h +// +// Portions copyright 1998 Bootprint Entertainment +// Portions copyright 2002 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_Clock_H +#define INCLUDED_Clock_H + +// ====================================================================== + +class Clock +{ +private: + + Clock(void); + Clock(const Clock &); + Clock &operator =(const Clock &); + +private: + + // the instantaneous frame rate of the last frame (1 / lastFrameTime) + static real ms_lastFrameRate; + +public: + + static void install(bool newUseSleep, bool useRecalibrationThread); + static void remove(void); + + static void update(void); + + static void debugReport(); + + static DLLEXPORT real frameTime(void); + static real framesPerSecond(void); + + static void noFrameRateLimit(void); + static void setFrameRateLimit(real newFrameRateLimit); + static void limitFrameRate(void); + + static void setMinFrameRate(real newMinFrameRate); + static const unsigned long timeMs(); + static const unsigned long timeSeconds(); + static const unsigned long getFrameStartTimeMs(); + static double getCurrentTime(); + static double getFrameStartTime(); + + static const unsigned long getSecondsSinceStart(); + static const int getTimeZone(); + + static void setLongFramesWarningAllowed(bool allowed); +}; + +// ====================================================================== +/** + * Get the instantaneous frame rate. + * + * This number is really only useful for determining game performance + * + * @return The number of frames per second for the last frame + * @see Clock::frameTime() + */ + +inline real Clock::framesPerSecond(void) +{ + return ms_lastFrameRate; +} + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedFoundation/src/shared/CommandLine.cpp b/engine/shared/library/sharedFoundation/src/shared/CommandLine.cpp new file mode 100644 index 00000000..c4c1b0f4 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CommandLine.cpp @@ -0,0 +1,1801 @@ +// ====================================================================== +// +// CommandLine.h +// Todd Fiala +// +// copyright 1999, Bootprint Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/CommandLine.h" + +#include "sharedFoundation/ExitChain.h" + +#include + +// ====================================================================== + +bool CommandLine::installed; +bool CommandLine::wasParsed; +char CommandLine::buffer[STATIC_BUFFER_SIZE]; +int CommandLine::bufferSize; +CommandLine::Collection *CommandLine::treeRoot; +CommandLine::OptionTable *CommandLine::optionTable; +int CommandLine::absorbedStringCount; + +// ====================================================================== + +CommandLine::Option::Option( + char newShortName, + const char *newLongName, + ArgumentPolicy newArgumentPolicy + ) : + shortName(newShortName), + longName(0), + argumentPolicy(newArgumentPolicy) +{ + DEBUG_FATAL(shortName && !(isalnum(shortName) || (shortName == OP_SNAME_UNTAGGED)), ("specified shortname must satisfy isalnum() test or be special untagged character")); + + if (newLongName) + { + const size_t length = strlen(newLongName); + if (length) + { + longName = new char[length+1]; + memcpy(longName, newLongName, length+1); + } + } +} + +// ---------------------------------------------------------------------- + +CommandLine::Option::~Option(void) +{ + delete [] longName; + longName = 0; +} + +// ---------------------------------------------------------------------- + +bool CommandLine::Option::isOptionNext( + const OptionSpec *optionSpec, + int optionSpecCount + ) +{ + DEBUG_FATAL(!optionSpec, ("null optionSpec arg")); + if (!optionSpecCount) + return false; + else + return (optionSpec->optionType == OST_Option); +} + +// ---------------------------------------------------------------------- + +CommandLine::Option *CommandLine::Option::createOption( + const OptionSpec **optionSpec, + int *optionCount + ) +{ + DEBUG_FATAL(!optionSpec, ("null optionSpec arg")); + DEBUG_FATAL(!optionCount, ("null optionCount arg")); + DEBUG_FATAL(!isOptionNext(*optionSpec, *optionCount), ("attempted to create option with non-option data")); + + const char newShortName = (*optionSpec)->char1; + const char *newLongName = (*optionSpec)->charp1; + ArgumentPolicy newArgumentPolicy = AP_None; + + switch ((*optionSpec)->int1) + { + case OP_ARG_NONE: + newArgumentPolicy = AP_None; + break; + case OP_ARG_REQUIRED: + newArgumentPolicy = AP_Required; + break; + case OP_ARG_OPTIONAL: + newArgumentPolicy = AP_Optional; + break; + default: + DEBUG_FATAL(true, ("illegal argument policy(%d) specified in option spec", (*optionSpec)->int1)); + } + + // gobble up OST_Option + ++(*optionSpec); + --(*optionCount); + + // add the option to the option table + // first check if its already in the table + OptionTable::Record *record = 0; + if (newShortName) + record = optionTable->findOptionRecord(newShortName); + if (!record && newLongName) + record = optionTable->findOptionRecord(newLongName); + if (!record) + { + // option not already recorded as a valid option for the option table, add it now + static_cast(optionTable->createOptionRecord(newShortName, newLongName, newArgumentPolicy)); + } + + // create the new option for the search tree + return new Option(newShortName, newLongName, newArgumentPolicy); +} + +// ---------------------------------------------------------------------- + +CommandLine::MatchCode CommandLine::Option::match(void) +{ + // we match if we find an unmatched short or long command line option + // matching this short or long name. If the arg specs don't match, we've + // got an argument matching error. + + DEBUG_FATAL(!optionTable, ("internal error: null option table")); + + OptionTable::Record *record = 0; + + // get the option info record for this option + if (shortName) + { + record = optionTable->findOptionRecord(shortName); + DEBUG_FATAL(!record, ("failed to find option info record for option -%c", shortName)); + } + else if (longName) + { + record = optionTable->findOptionRecord(longName); + DEBUG_FATAL(!record, ("failed to find option info record for option --%s", longName)); + } + else + DEBUG_FATAL(true, ("corrupted option? both short and long name are null")); + + + // attempt to match against this option against commandline-specified options + const int occurrenceIndex = record->getMatchCount(); + if (occurrenceIndex >= record->getWriteCount()) + { + // this option has already been fully matched, so we don't match + return MC_NO_MATCH; + } + else + { + // we matched options + record->addMatch(); + + // ensure we match argument policy + const char *arg = record->getString(occurrenceIndex); + bool haveArgument = (arg && strlen(arg)); + + // fall out if wrong arg policy + switch(argumentPolicy) + { + case AP_None: + if (haveArgument) + return MC_ARG_NOT_EXPECTED; + break; + case AP_Required: + if (!haveArgument) + return MC_ARG_MISSING; + break; + case AP_Optional: + // always okay + break; + default: + DEBUG_FATAL(true, ("internal error: unknown argument policy(%d)", argumentPolicy)); + } + + // we're okay + return MC_MATCH; + } +} + +// ====================================================================== + +CommandLine::Collection::~Collection(void) +{ +} + +// ---------------------------------------------------------------------- + +bool CommandLine::Collection::isCollectionNext( + const OptionSpec *optionSpec, + int optionSpecCount + ) +{ + DEBUG_FATAL(!optionSpec, ("null optionSpec arg")); + if (!optionSpecCount) + return false; + else + return CommandLine::List::isListNext(optionSpec, optionSpecCount) || Switch::isSwitchNext(optionSpec, optionSpecCount); +} + +// ---------------------------------------------------------------------- + +CommandLine::Collection *CommandLine::Collection::createCollection( + const OptionSpec **optionSpec, + int *optionSpecCount + ) +{ + DEBUG_FATAL(!optionSpec, ("null optionSpec arg")); + DEBUG_FATAL(!optionSpecCount, ("null optionSpecCount arg")); + + DEBUG_FATAL(!isCollectionNext(*optionSpec, *optionSpecCount), ("tried to create collection from non-collection optionSpec")); + if ((*optionSpec)->optionType == OST_BeginList) + return List::createList(optionSpec, optionSpecCount); + else if ((*optionSpec)->optionType == OST_BeginSwitch) + return Switch::createSwitch(optionSpec, optionSpecCount); + else + { + DEBUG_FATAL(true, ("error: unknown collection type %d", (*optionSpec)->optionType)); + return 0; //lint !e527 // Unreachable + } +} + +// ====================================================================== + +CommandLine::List::Node::Node( + Option *newOption, + Collection *newCollection, + bool newMultipleIsAllowed, + bool newIsRequiredNode + ) : + option(newOption), + collection(newCollection), + multipleIsAllowed(newMultipleIsAllowed), + isRequiredNode(newIsRequiredNode), + next(0) +{ + DEBUG_FATAL(!newOption && !newCollection, ("neither option nor collection specified")); +} + +// ---------------------------------------------------------------------- + +CommandLine::List::Node::~Node(void) +{ + delete option; + option = 0; + + delete collection; + collection = 0; + + next = 0; +} + +// ---------------------------------------------------------------------- + +CommandLine::MatchCode CommandLine::List::Node::match(void) const +{ + MatchCode mc = MC_MATCH; + + // if we have an option, check if the option matches + if (option) + { + mc = option->match(); + + // only go forward if we match the option + if (mc != MC_MATCH) + return mc; + } + + // if we have a collection, check if the collection matches + if (collection) + mc = collection->match(); + + return mc; +} + +// ---------------------------------------------------------------------- + +bool CommandLine::List::Node::isNode( + const OptionSpec *optionSpec, + int optionCount + ) +{ + DEBUG_FATAL(!optionSpec, ("null optionSpec arg")); + if (!optionCount) + return false; + else + return (optionSpec->optionType == OST_BeginListNode); +} + +// ---------------------------------------------------------------------- + +CommandLine::List::Node *CommandLine::List::Node::createNode( + const OptionSpec **optionSpec, + int *optionCount + ) +{ + DEBUG_FATAL(!optionSpec, ("null optionSpec arg")); + DEBUG_FATAL(!optionCount, ("null optionCount arg")); + DEBUG_FATAL(!isNode(*optionSpec, *optionCount), ("attempted to create list node with non-list-node data")); + + Option *newOption = 0; + Collection *newCollection = 0; + bool newIsMultipleAllowed; + bool newIsRequiredNode; + + newIsMultipleAllowed = ( (*optionSpec)->int1 != 0 ); + newIsRequiredNode = ( (*optionSpec)->int2 != 0 ); + + // move past OST_BeginListNode + ++(*optionSpec); + --(*optionCount); + + // create optional option + if (Option::isOptionNext(*optionSpec, *optionCount)) + newOption = Option::createOption(optionSpec, optionCount); + + // create optional collection + if (Collection::isCollectionNext(*optionSpec, *optionCount)) + newCollection = Collection::createCollection(optionSpec, optionCount); + + DEBUG_FATAL(!newOption && !newCollection, ("neither option nor collection specified---client must specify at least one")); + + // ensure we're at the end of the list node spec + DEBUG_FATAL((*optionSpec)->optionType != OST_EndListNode, ("expecting end of list node, found %d instead", (*optionSpec)->optionType)); + + // move past OST_EndListNode + ++(*optionSpec); + --(*optionCount); + + return new Node(newOption, newCollection, newIsMultipleAllowed, newIsRequiredNode); +} + +// ====================================================================== + +CommandLine::List::List( + OP_ListType newListType, + Node *newFirstNode + ) : + Collection(), + firstNode(newFirstNode), + listType(newListType), + minimumNodeCount(0) +{ + DEBUG_FATAL(!newFirstNode, ("null newFirstNode arg")); + DEBUG_FATAL(newListType != OPLT_Normal, ("constructor only good for OPLT_Normal lists, caller passed %d", newListType)); +} + +// ---------------------------------------------------------------------- + +CommandLine::List::List( + OP_ListType newListType, + Node *newFirstNode, + int newMinimumNodeCount + ) : + Collection(), + firstNode(newFirstNode), + listType(newListType), + minimumNodeCount(newMinimumNodeCount) +{ + DEBUG_FATAL(!newFirstNode, ("null newFirstNode arg")); + DEBUG_FATAL(newListType != OPLT_MinimumMatch, ("constructor only good for OPLT_MinimumMatch lists, caller passed %d", newListType)); +} + +// ---------------------------------------------------------------------- + +CommandLine::List::~List(void) +{ + Node *killNode; + + while (firstNode) + { + killNode = firstNode; + firstNode = const_cast(firstNode->getNext()); + delete killNode; + } +} + +// ---------------------------------------------------------------------- + +bool CommandLine::List::isListNext( + const OptionSpec *optionSpec, + int optionCount + ) +{ + DEBUG_FATAL(!optionSpec, ("null optionSpec arg")); + if (!optionCount) + return false; + else + return (optionSpec->optionType == OST_BeginList); +} + +// ---------------------------------------------------------------------- + +CommandLine::List *CommandLine::List::createList( + const OptionSpec **optionSpec, + int *optionCount + ) +{ + DEBUG_FATAL(!optionSpec, ("null optionSpec arg")); + DEBUG_FATAL(!optionCount, ("null optionCount arg")); + DEBUG_FATAL(!isListNext(*optionSpec, *optionCount), ("tried to create list from non-list optionSpec")); + + Node *newFirstNode = 0; + Node *lastNode = 0; + + OP_ListType newListType = static_cast((*optionSpec)->int1); + int newMinimumNodeCount = (*optionSpec)->int2; + + // move past OST_BeginList + ++(*optionSpec); + --(*optionCount); + + while (*optionCount && ((*optionSpec)->optionType != OST_EndList)) + { + const int lastCount = *optionCount; + + DEBUG_FATAL(!Node::isNode(*optionSpec, *optionCount), ("expecting list node, found %d", (*optionSpec)->optionType)); + Node *newNode = Node::createNode(optionSpec, optionCount); + DEBUG_FATAL(!newNode, ("failed to create list node")); + + // append to node list + if (!lastNode) + newFirstNode = newNode; + else + lastNode->setNext(newNode); + lastNode = newNode; + + DEBUG_FATAL(lastCount == *optionCount, ("node creation failed to move forward through optionSpec array")); + UNREF(lastCount); + } + + DEBUG_FATAL(!*optionCount, ("failed to find end of option list")); + DEBUG_FATAL((*optionSpec)->optionType != OST_EndList, ("expecting OST_EndSwitch node")); + + // gobble up the end of list marker + --(*optionCount); + ++(*optionSpec); + + switch (newListType) + { + case OPLT_Normal: + return new List(newListType, newFirstNode); + case OPLT_MinimumMatch: + return new List(newListType, newFirstNode, newMinimumNodeCount); + default: + FATAL(true, ("tried to create unknown list type %d", newListType)); + } + return 0; //lint !e527 // Unreachable +} + +// ---------------------------------------------------------------------- + +CommandLine::MatchCode CommandLine::List::match(void) const +{ + // for lists, a match is successful if we match all required nodes and + // possibly match non-required nodes + + int childMatchCount = 0; + + for (const Node *node = firstNode; node; node = node->getNext()) + { + int thisNodeMatchCount = 0; + MatchCode mc; + + while ( (mc = node->match()) == MC_MATCH ) + ++thisNodeMatchCount; + + if (mc != MC_NO_MATCH) + { + // we fell out of other loop for a problem + return mc; + } + + if (thisNodeMatchCount) + { + ++childMatchCount; + if ((thisNodeMatchCount > 1) && !node->getMultipleIsAllowed()) + { + // matched this node too many times + return MC_TOO_MANY_NODE_MATCHES; + } + } + else if (node->getIsRequiredNode()) + { + if (!childMatchCount) + { + // we haven't matched any nodes in this list yet, + // so claim there isn't a match against this entire list + return MC_NO_MATCH; + } + else + { + // we've started to match against this list, but we didn't match against this required node. + // This is a legitimate problem. + return MC_REQUIRED_MATCH_MISSING; + } + } + + // we're okay, we've either matched one, which is always okay, + // we've matched 0 and it wasn't required, or we matched multiple + // and multiple is okay. continue on with next node in list. + } + + if (listType == OPLT_MinimumMatch) + { + // ensure we matched the minimum number of list nodes + + // if none matched, indicate a no match, otherwise ensure we matched at least the minimum or there's an error + if (!childMatchCount) + return MC_NO_MATCH; + else if (childMatchCount < minimumNodeCount) + return MC_TOO_FEW_CHILDREN_MATCHES; + } + + // we matched if we made it through all the nodes + return MC_MATCH; +} + +// ====================================================================== + +CommandLine::Switch::Node::Node( + Option *newOption, + Collection *newCollection, + bool newMultipleIsAllowed + ) : + option(newOption), + collection(newCollection), + multipleIsAllowed(newMultipleIsAllowed), + next(0) +{ + DEBUG_FATAL(!(newOption || newCollection), ("neither option nor collection specified for switch node --- must have at least one")); +} + +// ---------------------------------------------------------------------- + +CommandLine::Switch::Node::~Node(void) +{ + delete option; + option = 0; + + delete collection; + collection = 0; + + next = 0; +} + +// ---------------------------------------------------------------------- + +CommandLine::MatchCode CommandLine::Switch::Node::match(void) const +{ + MatchCode mc = MC_MATCH; + + // if we have an option, check if the option matches + if (option) + { + mc = option->match(); + + // only go forward if we match the option + if (mc != MC_MATCH) + return mc; + } + + // if we have a collection, check if the collection matches + if (collection) + mc = collection->match(); + + return mc; +} + +// ---------------------------------------------------------------------- + +bool CommandLine::Switch::Node::isNode( + const OptionSpec *optionSpec, + int optionCount) +{ + DEBUG_FATAL(!optionSpec, ("null optionSpec arg")); + if (!optionCount) + return false; + else + return (optionSpec->optionType == OST_BeginSwitchNode); +} + +// ---------------------------------------------------------------------- + +CommandLine::Switch::Node *CommandLine::Switch::Node::createNode( + const OptionSpec **optionSpec, + int *optionCount + ) +{ + DEBUG_FATAL(!optionSpec, ("null optionSpec arg")); + DEBUG_FATAL(!optionCount, ("null optionCount arg")); + DEBUG_FATAL(!isNode(*optionSpec, *optionCount), ("attempted to create list node with non-list-node data")); + + Option *newOption = 0; + Collection *newCollection = 0; + bool newIsMultipleAllowed; + + newIsMultipleAllowed = ( (*optionSpec)->int1 != 0 ); + + // move past OST_BeginSwitchNode + ++(*optionSpec); + --(*optionCount); + + // create optional option + if (Option::isOptionNext(*optionSpec, *optionCount)) + newOption = Option::createOption(optionSpec, optionCount); + + // create optional collection + if (Collection::isCollectionNext(*optionSpec, *optionCount)) + newCollection = Collection::createCollection(optionSpec, optionCount); + + DEBUG_FATAL(!newOption && !newCollection, ("neither option nor collection specified---client must specify at least one")); + + // ensure we're at the end of the list node spec + DEBUG_FATAL((*optionSpec)->optionType != OST_EndSwitchNode, ("expecting end of list node, found %d instead", (*optionSpec)->optionType)); + + // move past OST_EndSwitchNode + ++(*optionSpec); + --(*optionCount); + + return new Node(newOption, newCollection, newIsMultipleAllowed); +} + +// ====================================================================== + +CommandLine::Switch::Switch( + Node *newFirstNode, + bool newOneNodeIsRequired + ) : + Collection(), + firstNode(newFirstNode), + oneNodeIsRequired(newOneNodeIsRequired) +{ + DEBUG_FATAL(!newFirstNode, ("empty switch collection created")); +} + +// ---------------------------------------------------------------------- + +CommandLine::Switch::~Switch(void) +{ + Node *killNode; + + while (firstNode) + { + killNode = firstNode; + firstNode = const_cast(firstNode->getNext()); + delete killNode; + } +} + +// ---------------------------------------------------------------------- + +bool CommandLine::Switch::isSwitchNext( + const OptionSpec *optionSpec, + int optionCount + ) +{ + DEBUG_FATAL(!optionSpec, ("null optionSpec arg")); + if (!optionCount) + return false; + else + return (optionSpec->optionType == OST_BeginSwitch); +} + +// ---------------------------------------------------------------------- + +CommandLine::Switch *CommandLine::Switch::createSwitch( + const OptionSpec **optionSpec, + int *optionCount + ) +{ + DEBUG_FATAL(!optionSpec, ("null optionSpec arg")); + DEBUG_FATAL(!optionCount, ("null optionCount arg")); + DEBUG_FATAL(!isSwitchNext(*optionSpec, *optionCount), ("tried to create switch from non-switch option spec")); + + const bool newOneNodeIsRequired = ((*optionSpec)->int1 != 0); + Node *newFirstNode = 0; + Node *lastNode = 0; + + // move past OST_BeginSwitch + ++(*optionSpec); + --(*optionCount); + + while (*optionCount && ((*optionSpec)->optionType != OST_EndSwitch)) + { + const int lastCount = *optionCount; + + DEBUG_FATAL(!Node::isNode(*optionSpec, *optionCount), ("expecting list node, found %d", (*optionSpec)->optionType)); + Node *newNode = Node::createNode(optionSpec, optionCount); + DEBUG_FATAL(!newNode, ("failed to create switch node")); + + // append to node list + if (!lastNode) + newFirstNode = newNode; + else + lastNode->setNext(newNode); + lastNode = newNode; + + DEBUG_FATAL(lastCount == *optionCount, ("node creation failed to move forward through optionSpec array")); + UNREF(lastCount); + } + + DEBUG_FATAL(!*optionCount, ("failed to find end of option switch")); + DEBUG_FATAL((*optionSpec)->optionType != OST_EndSwitch, ("expecting OST_EndSwitch node")); + + // gobble up the end of switch marker + --(*optionCount); + ++(*optionSpec); + + return new Switch(newFirstNode, newOneNodeIsRequired); +} + +// ---------------------------------------------------------------------- + +CommandLine::MatchCode CommandLine::Switch::match(void) const +{ + // for switch, matching policy is based on value of + // oneNodeIsRequired: + // true: exactly one of the nodes must match. That node + // can optionally match multiple times. Error if + // no matches or more than one match are made. + // false: one node is a match, zero node is a no match. + // error if more than one match is made. + + int childMatchCount = 0; + + for (const Node *node = firstNode; node; node = node->getNext()) + { + int thisNodeMatchCount = 0; + MatchCode mc; + + // -TF- this can get into an infinite loop here if a list has one or more children, all optional, with nothing specified + // on the commandline. The command line will keep matching. + while ( (mc = node->match()) == MC_MATCH ) + ++thisNodeMatchCount; + + if (mc != MC_NO_MATCH) + { + // we fell out of other loop for a problem + return mc; + } + + if (thisNodeMatchCount) + { + ++childMatchCount; + if (childMatchCount > 1) + { + // ut oh, matched too many children nodes + return MC_TOO_MANY_CHILDREN_MATCHES; + } + + if ((thisNodeMatchCount > 1) && !node->getMultipleIsAllowed()) + { + // matched too many + return MC_TOO_MANY_NODE_MATCHES; + } + } + } + + if (!childMatchCount) + { + // didn't match any nodes + if (oneNodeIsRequired) + return MC_REQUIRED_MATCH_MISSING; + else + return MC_NO_MATCH; + } + else + { + // we must have matched exactly one + return MC_MATCH; + } +} + +// ====================================================================== + +CommandLine::OptionTable::Record::Record( + char newShortName, + const char *newLongName, + ArgumentPolicy newArgumentPolicy + ) : + shortName(newShortName), + longName(0), + writeCount(0), + matchCount(0), + argumentPolicy(newArgumentPolicy), + next(0) +{ + if (newLongName) + { + const size_t length = strlen(newLongName); + if (length) + { + longName = new char[length+1]; + memcpy(longName, newLongName, length+1); + } + } + memset(stringArray, 0, sizeof(stringArray)); +} + +// ---------------------------------------------------------------------- + +CommandLine::OptionTable::Record::~Record(void) +{ + for (int i = 0; i < writeCount; ++i) + delete [] stringArray[i]; + + delete [] longName; + longName = 0; + next = 0; +} + +// ---------------------------------------------------------------------- + +void CommandLine::OptionTable::Record::addOccurrence( + const char *newString + ) +{ + DEBUG_FATAL(writeCount + 1 > MAX_OCCURRENCE_COUNT, ("commandline option occurrence overflow, max per option=%d", MAX_OCCURRENCE_COUNT)); + + DEBUG_FATAL(stringArray[writeCount], ("internal error: stringArray already set")); + if (newString && *newString) + { + const size_t length = strlen(newString); + if (length) + { + stringArray[writeCount] = new char[length+1]; + memcpy(stringArray[writeCount], newString, length+1); + } + } + ++writeCount; +} + +// ====================================================================== + +CommandLine::OptionTable::OptionTable(void) +: + firstRecord(0) +{ +} + +// ---------------------------------------------------------------------- + +CommandLine::OptionTable::~OptionTable(void) +{ + Record *deadRecord; + + while (firstRecord) + { + deadRecord = firstRecord; + firstRecord = firstRecord->getNext(); + delete deadRecord; + } +} + +// ---------------------------------------------------------------------- + +CommandLine::OptionTable::Record *CommandLine::OptionTable::createOptionRecord( + char shortName, + const char *longName, + ArgumentPolicy newArgumentPolicy + ) +{ + DEBUG_FATAL(shortName && findOptionRecord(shortName), ("short name %c already exists in list", shortName)); + DEBUG_FATAL(longName && findOptionRecord(longName), ("long name \"%s\" already exists in list", longName)); + + Record *record = new Record(shortName, longName, newArgumentPolicy); + record->setNext(firstRecord); + firstRecord = record; + + return firstRecord; +} + +// ---------------------------------------------------------------------- + +CommandLine::OptionTable::Record *CommandLine::OptionTable::findOptionRecord( + char shortName + ) const +{ + DEBUG_FATAL(!shortName, ("null shortName arg")); + + // walk the list + for (Record *record = firstRecord; record; record = record->getNext()) + { + if (record->getShortName() == shortName) + return record; + } + + // didn't find it + return 0; +} + +// ---------------------------------------------------------------------- + +CommandLine::OptionTable::Record *CommandLine::OptionTable::findOptionRecord( + const char *longName + ) const +{ + DEBUG_FATAL(!longName || !*longName, ("invalid longName arg")); + + // walk the list + for (Record *record = firstRecord; record; record = record->getNext()) + { + const char *recordLongName = record->getLongName(); + if (!recordLongName) + continue; + if (!strcmp(recordLongName, longName)) + return record; + } + + // didn't find it + return 0; +} + +// ---------------------------------------------------------------------- +/** + * Return whether all written options in the option table were fully + * matched. + * + * @return true if each option written has an equal number of matches. + * false if any one of the option entries written has not been + * fully matched. + */ + +bool CommandLine::OptionTable::getAllOptionsMatched(void) const +{ + for (Record *record = firstRecord; record; record = record->getNext()) + { + if (record->getMatchCount() < record->getWriteCount()) + return false; + } + + // if we got this far, we're okay + return true; +} + +// ====================================================================== + +CommandLine::Lexer::Token::Token(void) +: + tokenType(TT_Error) +{ + name[0] = 0; + argument[0] = 0; +} + +// ====================================================================== + +CommandLine::Lexer::Lexer( + const char *newBuffer + ) : + nextCharacter(newBuffer) +{ + DEBUG_FATAL(!newBuffer, ("null newBuffer arg")); +} + +// ---------------------------------------------------------------------- + +CommandLine::Lexer::~Lexer(void) +{ + nextCharacter = 0; +} + +// ---------------------------------------------------------------------- +/** + * Gobble up a string from input. + * + * If isRequired is not set, the only way for the function to return false + * is for a lex error (e.g. "hello <- is missing trailing quote, or + * -agp <- unquoted strings cannot start with hyphen). If isRequired is + * set, the function only returns true if a non-zero-length string is + * found. + * + * @param isRequired [IN] if true, must find a valid string to gobble. if false, string is optional + * @param stringBuffer [OUT] buffer which will be filled with zero-terminated string upon exit + * @param stringSize [IN] size of the buffer in bytes + * @return if isRequired is true: + * true if string is found, stringBuffer filled appropriately. + * false if the string could not be found or if there was a lex error + * + * if isRequired is false: + * true if the string was found or if no string was found (stringBuffer filled appropriately) + * false if a lex error occurred + */ + +bool CommandLine::Lexer::gobbleString(bool isRequired, char *stringBuffer, int stringSize) +{ + DEBUG_FATAL(!stringBuffer, ("null stringStart arg")); + DEBUG_FATAL(!stringSize, ("stringSize is zero")); + + DEBUG_FATAL(!nextCharacter, ("null nextChar")); + + + int stringLength = 0; + bool inQuote = false; + + while ( *nextCharacter && (inQuote || ((*nextCharacter != '-') && !isspace(*nextCharacter) && (*nextCharacter != '='))) ) + { + if (stringLength >= (stringSize-1)) + { + DEBUG_REPORT_LOG_PRINT(true, ("string exceeded string buffer size of %d", stringSize)); + return false; + } + + if (*nextCharacter == '"') + { + ++nextCharacter; + inQuote = !inQuote; + } + else if (inQuote && (*nextCharacter == '\\')) + { + // handle escaped characters + ++nextCharacter; + switch (*nextCharacter) + { + case 'n': + // CR/LF pair + if (stringLength + 2 > (stringSize-1)) + { + DEBUG_REPORT_LOG_PRINT(true, ("string exceeded string buffer size of %d", stringSize)); + return false; + } + *(stringBuffer++) = 13; + *(stringBuffer++) = 10; + stringLength += 2; + break; + case 'r': + // CR + *(stringBuffer++) = '\r'; + ++stringLength; + break; + case 't': + // tab + *(stringBuffer++) = '\t'; + ++stringLength; + break; + default: + // assume all other escaped characters are the character themselves + *(stringBuffer++) = *nextCharacter; + ++stringLength; + } + // gobble up excaped character + ++nextCharacter; + } + else + { + // just copy the character + *(stringBuffer++) = *(nextCharacter++); + ++stringLength; + } + } + + if (inQuote) + { + // parse error, string ran out while still in quote + DEBUG_REPORT_LOG_PRINT(true, ("string parser ran out of characters while in quoted string")); + return false; + } + + if (isRequired && (stringLength == 0)) + return false; + + // null-terminate the string + *stringBuffer = 0; + return true; +} + +// ---------------------------------------------------------------------- + +bool CommandLine::Lexer::getNextToken(Token *token) +{ + DEBUG_FATAL(!token, ("null token arg")); + DEBUG_FATAL(!nextCharacter, ("null nextCharacter")); + + // clear out the token + memset(token, 0, sizeof(*token)); + + // gobble up whitespace + gobbleWhitespace(); + + if (!*nextCharacter) + { + token->tokenType = TT_End; + return true; + } + else if (*nextCharacter == '-') + { + // gobble it up + ++nextCharacter; + + if (!*nextCharacter) + { + token->tokenType = TT_Error; + return false; + } + else if (*nextCharacter == '-') + { + // we have a double dash + + // gobble up + ++nextCharacter; + + if (!*nextCharacter || isspace(*nextCharacter)) + { + // we've hit the double dash token + token->tokenType = TT_DoubleDash; + return true; + } + else + { + // retrieve the name + if (!gobbleString(true, token->name, MAX_LONG_NAME_SIZE)) + { + token->tokenType = TT_Error; + return false; + } + + token->tokenType = TT_LongOption; + return true; + } + } + else if (isalnum(*nextCharacter)) + { + token->name[0] = *nextCharacter; + token->name[1] = 0; + ++nextCharacter; + + token->tokenType = TT_ShortOption; + return true; + } + else + { + token->tokenType = TT_Error; + return false; + } + } + else if (*nextCharacter == '=') + { + ++nextCharacter; + token->tokenType = TT_Equal; + return true; + } + else + { + // either an argument or an error + + // retrieve the argument + if (!gobbleString(true, token->argument, MAX_ARGUMENT_SIZE)) + { + token->tokenType = TT_Error; + return false; + } + token->tokenType = TT_Argument; + return true; + } +} + +// ====================================================================== + +void CommandLine::install(void) +{ + DEBUG_FATAL(installed, ("CommandLine already installed")); + + installed = true; + ExitChain::add(remove, "CommandLine::remove"); +} + +// ---------------------------------------------------------------------- + +void CommandLine::remove(void) +{ + DEBUG_FATAL(!installed, ("CommandLine not installed")); + + installed = false; + + delete optionTable; + optionTable = 0; + + // reset state + bufferSize = 0; + wasParsed = false; +} + +// ---------------------------------------------------------------------- +/** + * Parse and build the option tree from the option spec list provided + * by the client. + * + * specList must contain entries following the grammar described in + * the engine SourceSafe file "$/new/doc/CommandLineGrammar.txt". + * + * @param specList [IN] spec list containing description of tree + * @param specCount [IN] number of entries in spec list + */ + +void CommandLine::buildOptionTree(const OptionSpec *specList, int specCount) +{ + DEBUG_FATAL(!specList, ("null specList arg")); + + if (!specCount) + { + // nothing to build + return; + } + + DEBUG_FATAL(!Collection::isCollectionNext(specList, specCount), ("expecting collection as first option spec")); + treeRoot = Collection::createCollection(&specList, &specCount); + DEBUG_FATAL(specCount, ("failed to consume entire specArray, %d entries remaining", specCount)); +} + +// ---------------------------------------------------------------------- + +CommandLine::MatchCode CommandLine::parseCommandLineBuffer(void) +{ + Lexer lexer(buffer); + Lexer::Token token; + + bool rc = lexer.getNextToken(&token); + + do + { + if (!rc) + { + DEBUG_REPORT_LOG_PRINT(true, ("error getting token")); + return MC_CL_PARSE_ERROR; + } + + switch (token.getTokenType()) + { + case Lexer::TT_DoubleDash: + // we're done, don't parse any more + + // return "okay" + // -TF- I don't like this, we're overloading the use of the match code. + // Maybe it should become a generic error code. + return MC_MATCH; + + case Lexer::TT_ShortOption: + // we've found a short option, make sure specified short option exists + { + DEBUG_FATAL(!optionTable, ("internal error: null optionTable")); + OptionTable::Record *record = optionTable->findOptionRecord(token.getShortName()); + if (!record) + { + // command line option is not a valid option + return MC_CL_OPTION_UNKNOWN; + } + + // consume token, check for argument + rc = lexer.getNextToken(&token); + if (!rc) + break; + if (record->getArgumentPolicy() == AP_None) + record->addOccurrence(0); + else // option can taken an argument + { + // if newly consumed token is an argument, post it as this option's argument + if (token.getTokenType() != Lexer::TT_Argument) + record->addOccurrence(0); + else + { + record->addOccurrence(token.getArgument()); + // gobble up argument token + rc = lexer.getNextToken(&token); + } + } + } + break; + + case Lexer::TT_LongOption: + // we've found a long option, make sure specified long option exists + { + DEBUG_FATAL(!optionTable, ("internal error: null optionTable")); + OptionTable::Record *record = optionTable->findOptionRecord(token.getLongName()); + if (!record) + { + // command line option is not a valid option + return MC_CL_OPTION_UNKNOWN; + } + + // consume token, check for option + rc = lexer.getNextToken(&token); + if (!rc) + break; + if (token.getTokenType() == Lexer::TT_Equal) + { + if (record->getArgumentPolicy() == AP_None) + // not expecting an argument here + return MC_CL_UNEXPECTED_ARG; + + // consume it, get argument + rc = lexer.getNextToken(&token); + if (!rc) + break; + + if (token.getTokenType() != Lexer::TT_Argument) + return MC_CL_EXPECTING_ARG; + + record->addOccurrence(token.getArgument()); + rc = lexer.getNextToken(&token); + } + else + { + if (record->getArgumentPolicy() == AP_Required) + { + // expecting an arg + return MC_CL_EXPECTING_ARG; + } + record->addOccurrence(0); + } + } + break; + + case Lexer::TT_Argument: + { + DEBUG_FATAL(!optionTable, ("internal error: null optionTable")); + OptionTable::Record *record = optionTable->findOptionRecord(OP_SNAME_UNTAGGED); + if (!record) + { + // user specified an untagged argument but not supported + return MC_CL_UNTAGGED_ARG_DENIED; + } + record->addOccurrence(token.getArgument()); + + // gobble up arg + rc = lexer.getNextToken(&token); + } + break; + + case Lexer::TT_Error: + return MC_CL_PARSE_ERROR; + + case Lexer::TT_End: + break; + + case Lexer::TT_Equal: + default: + DEBUG_FATAL(true, ("unexpected option code(%d)", token.getTokenType())); + } + + } while (token.getTokenType() != Lexer::TT_End); + + // made it through okay + return MC_MATCH; +} + +// ---------------------------------------------------------------------- +/** + * Absorb multiple strings into the current CommandLine parsing buffer. + * + * A space is inserted into the buffer after the new contents. This + * ensures separate buffer absorptions do not bleed together at the + * edges for parsing purposes. + * + * Under apps using the main(argc, argv) entry point, the user + * must quote arguments using escaped quotes when they need to + * include spaces in argument names. e.g.: + * viff \"c:\\my data\\tmp\\test.iff\" + * + * Under apps using WinMain(...), the user should not escape + * quoted strings. e.g.: + * viff "c:\\my data\\tmp\\test.iff" + * + * Once quoting, characters within the quotes will be interpreted + * using C-style backslash rules (well, a subset anyway). The + * following character escape code substitutions work within quoted strings: + * \t tab character + * \n CR/LF pair + * \r carriage return + * \\ single backslash (remember, this is required to get a single backslash in a quoted string) + */ + +void CommandLine::absorbString(const char *newString) +{ + DEBUG_FATAL(!installed, ("CommandLine not installed")); + DEBUG_FATAL(!newString, ("null newString arg")); + + const int stringLength = static_cast(strlen(newString)); + int requiredBufferSpace; + if (absorbedStringCount) + requiredBufferSpace = stringLength + 2; + else + requiredBufferSpace = stringLength + 1; + DEBUG_FATAL(bufferSize + requiredBufferSpace >= STATIC_BUFFER_SIZE, ("newString too large by %d bytes", bufferSize + requiredBufferSpace - STATIC_BUFFER_SIZE)); + + if (absorbedStringCount) + { + // prepend a space + buffer[bufferSize++] = ' '; + } + + // copy contents of buffer, including null + memcpy(buffer + bufferSize, newString, stringLength + 1); + bufferSize += stringLength; + + ++absorbedStringCount; +} + +// ---------------------------------------------------------------------- +/** + * Absorb multiple strings into the current CommandLine parsing buffer. + * + * A space is inserted into the buffer after each new string. This + * ensures separate buffer absorptions do not bleed together at the + * edges for parsing purposes. + * + * Under apps using the main(argc, argv) entry point, the user + * must quote arguments using escaped quotes when they need to + * include spaces in argument names. e.g.: + * viff \"c:\\my data\\tmp\\test.iff\" + * + * Under apps using WinMain(...), the user should not escape + * quoted strings. e.g.: + * viff "c:\\my data\\tmp\\test.iff" + * + * Once quoting, characters within the quotes will be interpreted + * using C-style backslash rules (well, a subset anyway). The + * following character escape code substitutions work within quoted strings: + * \t tab character + * \n CR/LF pair + * \r carriage return + * \\ single backslash (remember, this is required to get a single backslash in a quoted string) + * + * @param stringArray [IN] array of string pointers to absorb + * @param stringCount [IN] count of array + */ + +void CommandLine::absorbStrings(const char **stringArray, int stringCount) +{ + DEBUG_FATAL(!installed, ("CommandLine not installed")); + DEBUG_FATAL(!stringArray, ("null string array")); + + for (int i = 0; i < stringCount; ++i) + absorbString(stringArray[i]); +} + +// ---------------------------------------------------------------------- +/** + * Return the portion of the command line string not meant for the + * CommandLine class. + * + * Anything following the first double dash with trailing whitespace + * (i.e. "-- ") will be considered part of the post command line string. + * + * @return A read-only pointer to the portion of the command line not meant + * for CommandLine parsing. May be NULL if the entire command line + * was meant for CommandLine or if no command line was specified. + */ + +const char *CommandLine::getPostCommandLineString(void) +{ + Lexer lexer(buffer); + Lexer::Token token; + + // scan for the '--' or EOF ending CommandLine-owned strings + do + { + bool rc = lexer.getNextToken(&token); + if (!rc) + { + DEBUG_REPORT_LOG_PRINT(true, ("error getting token\n")); + return 0; + } + + switch (token.getTokenType()) + { + case Lexer::TT_DoubleDash: + { + // we're done, don't parse any more + const char *result = lexer.getNextCharacter(); + // skip leading whitespace + while (isspace(*result)) + ++result; + return result; + } + + case Lexer::TT_Error: + DEBUG_REPORT_LOG_PRINT(true, ("parse error while scanning for post command line string\n")); + return 0; + + case Lexer::TT_End: + case Lexer::TT_ShortOption: + case Lexer::TT_LongOption: + case Lexer::TT_Equal: + case Lexer::TT_Argument: + default: + // nothing to do + break; + } + + } while (token.getTokenType() != Lexer::TT_End); + + // if we made it here, there are no post command line options + return 0; +} + +// ---------------------------------------------------------------------- +/** + * Parse the command line according to the option parse tree specified. + * + * See $/new/doc/CommandLineGrammar.txt for a description of the option + * parse tree grammar. + * + * Options are tags that can be queried for their presence. In addition, + * options may have arguments associated with them (according to the + * rules specified within the option tree). + * + * Short options are formed by a hyphen followed immediately by an alphanumeric + * character (e.g. -c, -h, -i). If an argument is associated with the + * short option, it follows the short option with optional whitespace + * separating them. + * + * Long options are formed by two hyphens followed immediately by a text + * string (e.g. --inputfile, --pragmaTarget, --help). If an argument is + * associated with the long option, it is followed by an equal sign (=), + * then followed by the argument (with whitespace optionally interspersed), + * as in (--inputfile = \"c:\My Programs\something\"). + * + * @param optionTree [IN] option parse tree specification array + * @param optionSpecCount [IN] number of entries in the array + * @return A return code indicating the status of the operation. A value + * of MC_MATCH means the command line parsed successfully. Any other + * return value indicates some type of error. Errors can occur in + * different areas, including the option tree specification and the + * command line specification. + */ + +CommandLine::MatchCode CommandLine::parseOptions(const OptionSpec *optionTree, int optionSpecCount) +{ + DEBUG_FATAL(!installed, ("CommandLine not installed")); + + MatchCode mc; + + // create the option information table + if (optionTable) + delete optionTable; + optionTable = new OptionTable; + + // build the option tree corresponding to the option spec, + // filling the command line parse structures at the same time + buildOptionTree(optionTree, optionSpecCount); + + // parse the command line options into available options + mc = parseCommandLineBuffer(); + if (mc != MC_MATCH) + { + delete treeRoot; + treeRoot = 0; + return mc; + } + + // perform the match + if (treeRoot) + { + mc = treeRoot->match(); + delete treeRoot; + treeRoot = 0; + } + else + mc = MC_MATCH; + + if (mc == MC_MATCH) + { + // ensure all command line options specified were consumed + if (!optionTable->getAllOptionsMatched()) + mc = MC_UNMATCHED_OPTIONS; + else + wasParsed = true; + } + + // cleanup option tree + delete treeRoot; + treeRoot = 0; + + return mc; +} + +// ---------------------------------------------------------------------- +/** + * Retrieve whether an option was specified on the command line. + * + * To check if a second occurrence of the "-i" was specified, use + * CommandLine::getOptionExists('i', 1) + * + * The client may use either the short or long name version of this + * command. They will return the same value regardless of the form + * of the option specified by the user on the command line. + * + * @param shortName [IN] short name of the option + * @param occurrenceIndex [IN] zero-based occurrence number to check + * @return true if the option with the given was specified on the command line. + * false if the option was not specified on the command line. + */ + +bool CommandLine::getOptionExists(char shortName, int occurrenceIndex) +{ + DEBUG_FATAL(!installed, ("CommandLine not installed")); + DEBUG_FATAL(!wasParsed, ("commandline not parsed successfully")); + DEBUG_FATAL(!shortName, ("invalid shortName arg")); + + OptionTable::Record *record = optionTable->findOptionRecord(shortName); + if (!record) + return false; + else + return (occurrenceIndex < record->getWriteCount()); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve whether an option was specified on the command line. + * + * To check if an occurrence of the "-inputfile" was specified, use + * CommandLine::getOptionExists("inputfile", 0) + * + * The client may use either the short or long name version of this + * command. They will return the same value regardless of the form + * of the option specified by the user on the command line. + * + * @param longName [IN] the long name of the option to check + * @param occurrenceIndex [IN] the zero-based occurrence number to check + * @return true if the option with the given was specified on the command line. + * false if the option was not specified on the command line. + */ + +bool CommandLine::getOptionExists(const char *longName, int occurrenceIndex) +{ + DEBUG_FATAL(!installed, ("CommandLine not installed")); + DEBUG_FATAL(!wasParsed, ("commandline not parsed successfully")); + DEBUG_FATAL(!longName || !*longName, ("invalid longName arg")); + + OptionTable::Record *record = optionTable->findOptionRecord(longName); + if (!record) + return false; + else + return (occurrenceIndex < record->getWriteCount()); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve the number of times a given option occurred on the command line. + * + * The client may use either the short or long name version of this + * command. They will return the same value regardless of the form + * of the option specified by the user on the command line. + * + * @param shortName [IN] short name of the option to check + * @return The number of times the specified option appeared on the command line. + */ + +int CommandLine::getOccurrenceCount(char shortName) +{ + DEBUG_FATAL(!installed, ("CommandLine not installed")); + DEBUG_FATAL(!wasParsed, ("commandline not parsed successfully")); + DEBUG_FATAL(!shortName, ("invalid shortName arg")); + + OptionTable::Record *record = optionTable->findOptionRecord(shortName); + if (!record) + return 0; + else + return record->getWriteCount(); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve the number of times a given option occurred on the command line. + * + * The client may use either the short or long name version of this + * command. They will return the same value regardless of the form + * of the option specified by the user on the command line. + * + * @param longName [IN] long name of the option to check + * @return The number of times the specified option appeared on the command line. + */ + +int CommandLine::getOccurrenceCount(const char *longName) +{ + DEBUG_FATAL(!installed, ("CommandLine not installed")); + DEBUG_FATAL(!wasParsed, ("commandline not parsed successfully")); + DEBUG_FATAL(!longName || !*longName, ("invalid longName arg")); + + OptionTable::Record *record = optionTable->findOptionRecord(longName); + if (!record) + return 0; + else + return record->getWriteCount(); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve the argument associated with the given option occurrence. + * + * The client may use either the short or long name version of this + * command. They will return the same value regardless of the form + * of the option specified by the user on the command line. + * + * @param shortName [IN] short name of the option + * @param occurrenceIndex [IN] zero-based occurrence number + * @return The read-only argument string associated with the specified option occurrence. + * May be NULL if no argument was associated with the specified option. + */ + +const char *CommandLine::getOptionString(char shortName, int occurrenceIndex) +{ + DEBUG_FATAL(!installed, ("CommandLine not installed")); + DEBUG_FATAL(!wasParsed, ("commandline not parsed successfully")); + DEBUG_FATAL(!shortName, ("invalid shortName arg")); + + OptionTable::Record *record = optionTable->findOptionRecord(shortName); + DEBUG_FATAL(!record, ("requested option string for non-existant option '%c'", shortName)); + + return record->getString(occurrenceIndex); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve the argument associated with the given option occurrence. + * + * The client may use either the short or long name version of this + * command. They will return the same value regardless of the form + * of the option specified by the user on the command line. + * + * @param longName [IN] long name of the option + * @param occurrenceIndex [IN] zero-based occurrence number + * @return The read-only argument string associated with the specified option occurrence. + * May be NULL if no argument was associated with the specified option. + */ + +const char *CommandLine::getOptionString(const char *longName, int occurrenceIndex) +{ + DEBUG_FATAL(!installed, ("CommandLine not installed")); + DEBUG_FATAL(!wasParsed, ("commandline not parsed successfully")); + DEBUG_FATAL(!longName || !*longName, ("invalid longName arg")); + + OptionTable::Record *record = optionTable->findOptionRecord(longName); + DEBUG_FATAL(!record, ("requested option string for non-existant option \"%s\"", longName)); + + return record->getString(occurrenceIndex); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve the argument associated with the given option occurrence. + * + * The client may use either the short or long name version of this + * command. They will return the same value regardless of the form + * of the option specified by the user on the command line. + * + * @param shortName [IN] short name of the option + * @param occurrenceIndex [IN] zero-based occurrence number + * @return An integerized version of the option string associated with the specified option occurrence. + * Will return zero if the argument string could not be converted to an integer. + */ + +int CommandLine::getOptionInt(char shortName, int occurrenceIndex) +{ + DEBUG_FATAL(!installed, ("CommandLine not installed")); + DEBUG_FATAL(!wasParsed, ("commandline not parsed successfully")); + DEBUG_FATAL(!shortName, ("invalid shortName arg")); + + OptionTable::Record *record = optionTable->findOptionRecord(shortName); + DEBUG_FATAL(!record, ("requested option string for non-existant option '%c'", shortName)); + + return atoi(record->getString(occurrenceIndex)); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve the argument associated with the given option occurrence. + * + * The client may use either the short or long name version of this + * command. They will return the same value regardless of the form + * of the option specified by the user on the command line. + * + * @param longName [IN] long name of the option + * @param occurrenceIndex [IN] zero-based occurrence number + * @return An integerized version of the option string associated with the specified option occurrence. + * Will return zero if the argument string could not be converted to an integer. + */ + +int CommandLine::getOptionInt(const char *longName, int occurrenceIndex) +{ + DEBUG_FATAL(!installed, ("CommandLine not installed")); + DEBUG_FATAL(!wasParsed, ("commandline not parsed successfully")); + DEBUG_FATAL(!longName || !*longName, ("invalid longName arg")); + + OptionTable::Record *record = optionTable->findOptionRecord(longName); + DEBUG_FATAL(!record, ("requested option string for non-existant option \"%s\"", longName)); + + return atoi(record->getString(occurrenceIndex)); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/CommandLine.h b/engine/shared/library/sharedFoundation/src/shared/CommandLine.h new file mode 100644 index 00000000..358b2e40 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CommandLine.h @@ -0,0 +1,790 @@ +// ====================================================================== +// +// CommandLine.h +// Todd Fiala +// +// copyright 1999, Bootprint Entertainment +// +// ====================================================================== + +#ifndef COMMAND_LINE_H +#define COMMAND_LINE_H + +// ====================================================================== + +enum OP_ListType +{ + OPLT_Normal, + OPLT_MinimumMatch +}; + +#define OP_BEGIN_LIST() { CommandLine::OST_BeginList, static_cast(OPLT_Normal), 0, 0, 0 } +#define OP_END_LIST() { CommandLine::OST_EndList, 0, 0, 0, 0 } +#define OP_BEGIN_MINIMUM_MATCH_LIST(minimumNodeCount) { CommandLine::OST_BeginList, static_cast(OPLT_MinimumMatch), minimumNodeCount, 0, 0 } +#define OP_END_MINIMUM_MATCH_LIST() { CommandLine::OST_EndList, 0, 0, 0, 0 } +#define OP_BEGIN_SWITCH(oneIsRequired) { CommandLine::OST_BeginSwitch, oneIsRequired, 0, 0, 0 } +#define OP_END_SWITCH() { CommandLine::OST_EndSwitch, 0, 0, 0, 0 } +#define OP_BEGIN_LIST_NODE(multipleIsAllowed, isRequiredNode) { CommandLine::OST_BeginListNode, multipleIsAllowed, isRequiredNode, 0, 0 } +#define OP_END_LIST_NODE() { CommandLine::OST_EndListNode, 0, 0, 0, 0 } +#define OP_BEGIN_SWITCH_NODE(multipleIsAllowed) { CommandLine::OST_BeginSwitchNode, multipleIsAllowed, 0, 0, 0 } +#define OP_END_SWITCH_NODE() { CommandLine::OST_EndSwitchNode, 0, 0, 0, 0 } +#define OP_OPTION(shortName, longName, argumentPolicy) { CommandLine::OST_Option, argumentPolicy, 0, shortName, longName } + +#define OP_SINGLE_LIST_NODE(shortName, longName, argMode, multipleIsAllowed, isRequiredNode) OP_BEGIN_LIST_NODE(multipleIsAllowed, isRequiredNode), OP_OPTION(shortName, longName, argMode), OP_END_LIST_NODE() +#define OP_SINGLE_SWITCH_NODE(shortName, longName, argMode, multipleIsAllowed) OP_BEGIN_SWITCH_NODE(multipleIsAllowed), OP_OPTION(shortName, longName, argMode), OP_END_SWITCH_NODE() + +//lint -save -e1923 // #define could become const + +#define OP_ARG_NONE 0 +#define OP_ARG_REQUIRED 1 +#define OP_ARG_OPTIONAL 2 + +#define OP_NODE_REQUIRED 1 +#define OP_NODE_OPTIONAL 0 + +#define OP_MULTIPLE_ALLOWED 1 +#define OP_MULTIPLE_DENIED 0 + +#define OP_SNAME_UNTAGGED 1 +#define OP_LNAME_UNTAGGED static_cast(0) + +//lint -restore + +// ====================================================================== + +class CommandLine +{ + +private: + + enum + { + STATIC_BUFFER_SIZE = 4096 + }; + +public: + + enum MatchCode + { + MC_MATCH = 1, + MC_NO_MATCH = 0, + MC_REQUIRED_MATCH_MISSING = -1, + MC_TOO_MANY_CHILDREN_MATCHES = -2, + MC_TOO_MANY_NODE_MATCHES = -3, + MC_ARG_NOT_EXPECTED = -4, + MC_ARG_MISSING = -5, + MC_UNMATCHED_OPTIONS = -6, + MC_TOO_FEW_CHILDREN_MATCHES = -7, + + // parse errors from client's command line + MC_CL_OPTION_UNKNOWN = -101, + MC_CL_PARSE_ERROR = -102, + MC_CL_EXPECTING_ARG = -103, + MC_CL_UNEXPECTED_ARG = -104, + MC_CL_UNTAGGED_ARG_DENIED = -105 + }; + + enum OptionSpecType + { + OST_BeginList, + OST_EndList, + OST_BeginSwitch, + OST_EndSwitch, + OST_BeginListNode, + OST_EndListNode, + OST_BeginSwitchNode, + OST_EndSwitchNode, + OST_Option + }; + + enum + { + MAX_LONG_NAME_SIZE = 64, + MAX_ARGUMENT_SIZE = 1024 + }; + + struct OptionSpec + { + OptionSpecType optionType; + int int1; + int int2; + char char1; + const char *charp1; + +#if 0 + // if this node's parent is branch head, this variable is ignored. + // if this node's parent is list head, if node is required, at least one instance of this node must be present. + bool nodeRequired; + + // if this node is a list head, this variable is ignored. + // if this node is a branch head, false = 0 or 1 child may be present, true = one child must be present. + bool childrenRequired; +#endif + }; + + enum ArgumentPolicy + { + AP_None, + AP_Required, + AP_Optional + }; + + // ---------------------------------------------------------------------- + // -TF- clients, don't try to use this, it is here for compiler issues + + class Option + { + private: + + char shortName; + char *longName; + ArgumentPolicy argumentPolicy; + + protected: + + // disabled + Option(void); + Option(const Option&); + Option &operator =(const Option&); + + private: + + Option(char newShortName, const char *newLongName, ArgumentPolicy newArgumentPolicy); + + public: + + ~Option(void); + + static bool isOptionNext(const OptionSpec *optionSpec, int optionSpecCount); + static Option *createOption(const OptionSpec **optionSpec, int *optionSpecCount); + + char getShortName(void) const; + const char *getLongName(void) const; + ArgumentPolicy getArgumentPolicy(void) const; + + MatchCode match(void); + + }; + + // ---------------------------------------------------------------------- + + class Collection + { + + public: + + virtual ~Collection(void) = 0; + virtual MatchCode match(void) const = 0; + + static bool isCollectionNext(const OptionSpec *optionSpec, int optionSpecCount); + static Collection *createCollection(const OptionSpec **optionSpec, int *optionSpecCount); + }; + + // ---------------------------------------------------------------------- + +private: + + class List : public Collection + { + friend class Collection; + + private: + + class Node + { + private: + + Option *option; + Collection *collection; + bool multipleIsAllowed; + bool isRequiredNode; + + mutable Node *next; + + private: + + // disabled + Node(void); + Node(const Node&); + Node &operator =(const Node&); + + public: + + Node(Option *newOption, Collection *newCollection, bool newMultipleIsAllowed, bool newIsRequiredNode); + ~Node(void); + + const Option *getOption(void) const; + const Collection *getCollection(void) const; + bool getMultipleIsAllowed(void) const; + bool getIsRequiredNode(void) const; + + const Node *getNext(void) const; + void setNext(Node *newNext) const; + + MatchCode match(void) const; + + static bool isNode(const OptionSpec *optionSpec, int optionCount); + static Node *createNode(const OptionSpec **optionSpec, int *optionCount); + + }; + + private: + + Node *firstNode; + OP_ListType listType; + int minimumNodeCount; + + private: + + // disabled + List(void); + List(const List&); + List &operator =(const List&); + + private: + + List(OP_ListType newListType, Node *newFirstNode); + List(OP_ListType newListType, Node *newFirstNode, int newMinimumNodeCount); + + public: + + virtual ~List(void); + virtual MatchCode match(void) const; + + static bool isListNext(const OptionSpec *optionSpec, int optionCount); + static List *createList(const OptionSpec **optionSpec, int *optionCount); + + }; + + // ---------------------------------------------------------------------- + + class Switch : public Collection + { + friend class Collection; + + private: + + class Node + { + private: + + Option *option; + Collection *collection; + bool multipleIsAllowed; + + mutable Node *next; + + private: + + // disabled + Node(void); + Node(const Node&); + Node &operator =(const Node&); + + public: + + Node(Option *newOption, Collection *newCollection, bool newMultipleIsAllowed); + ~Node(void); + + const Option *getOption(void) const; + const Collection *getCollection(void) const; + bool getMultipleIsAllowed(void) const; + + const Node *getNext(void) const; + void setNext(Node *newNext) const; + + MatchCode match(void) const; + + static bool isNode(const OptionSpec *optionSpec, int optionCount); + static Node *createNode(const OptionSpec **optionSpec, int *optionCount); + + }; + + private: + + Node *firstNode; + bool oneNodeIsRequired; + + private: + + // disabled + Switch(void); + Switch(const Switch&); + Switch &operator =(const Switch&); + + private: + + Switch(Node *newFirstNode, bool newOneNodeIsRequired); + + public: + + virtual ~Switch(void); + virtual MatchCode match(void) const; + + static bool isSwitchNext(const OptionSpec *optionSpec, int optionCount); + static Switch *createSwitch(const OptionSpec **optionSpec, int *optionCount); + + + }; + + + // ---------------------------------------------------------------------- + + class OptionTable + { + + public: + + class Record + { + private: + + enum + { + MAX_OCCURRENCE_COUNT = 128 + }; + + private: + + char shortName; + char *longName; + int writeCount; + int matchCount; + char *stringArray[MAX_OCCURRENCE_COUNT]; + ArgumentPolicy argumentPolicy; + + mutable Record *next; + + private: + + // disabled + Record(void); + Record(const Record&); + Record &operator =(const Record&); + + public: + + Record(char newShortName, const char *newLongName, ArgumentPolicy newArgumentPolicy); + ~Record(void); + + char getShortName(void) const; + const char *getLongName(void) const; + + void addOccurrence(const char *newString); + void addMatch(void); + + const char *getString(int occurrenceIndex) const; + int getWriteCount(void) const; + int getMatchCount(void) const; + + const Record *getNext(void) const; + Record *getNext(void); + void setNext(Record *newNext) const; + + ArgumentPolicy getArgumentPolicy(void) const; + }; + + private: + + Record *firstRecord; + + private: + + // disabled + OptionTable(const OptionTable&); + OptionTable &operator =(const OptionTable&); + + public: + + OptionTable(void); + ~OptionTable(void); + + Record *createOptionRecord(char shortName, const char *longName, ArgumentPolicy newArgumentPolicy); + + Record *findOptionRecord(char shortName) const; + Record *findOptionRecord(const char *longName) const; + + bool getAllOptionsMatched(void) const; + + }; + + // ---------------------------------------------------------------------- + + class Lexer + { + public: + + enum TokenType + { + TT_Error, + TT_End, + TT_DoubleDash, + TT_ShortOption, + TT_LongOption, + TT_Equal, + TT_Argument + }; + + class Token + { + friend class Lexer; + + private: + + TokenType tokenType; + char name[MAX_LONG_NAME_SIZE]; + char argument[MAX_ARGUMENT_SIZE]; + + private: + + // disabled + Token(const Token&); + Token &operator =(const Token&); + + public: + + Token(void); + + TokenType getTokenType(void) const; + char getShortName(void) const; + const char *getLongName(void); + const char *getArgument(void); + + }; + + // -TF- so Token can see the TokenType enums --- this is making me puke... + friend class Token; + + private: + + const char *nextCharacter; + + private: + + // disabled + Lexer(void); + Lexer(const Lexer&); + Lexer &operator =(const Lexer&); + + private: + + void gobbleWhitespace(void); + bool gobbleString(bool isRequired, char *stringBuffer, int bufferSize); + + public: + + explicit Lexer(const char *newBuffer); + ~Lexer(void); + + bool getNextToken(Token *token); + const char *getNextCharacter(void); + + }; + + // ---------------------------------------------------------------------- + + // needed so that option can access variable optionTable + friend class Option; + +private: + + static bool installed; + static bool wasParsed; + static char buffer[STATIC_BUFFER_SIZE]; + static int bufferSize; + static Collection *treeRoot; + static OptionTable *optionTable; + static int absorbedStringCount; + +private: + + static bool findNextOccurence(char shortName, int *occurrenceIndex); + static bool findNextOccurence(const char *longName, int *occurrenceIndex); + + static bool getOptionArgExists(char shortName, int occurrenceIndex); + static bool getOptionArgExists(const char *longName, int occurrenceIndex); + + static void buildOptionTree(const OptionSpec *specList, int specCount); + static MatchCode parseCommandLineBuffer(void); + +public: + + static void install(void); + static void remove(void); + + static void absorbString(const char *newString); + static void absorbStrings(const char **stringArray, int stringCount); + + static const char *getPostCommandLineString(void); + + static MatchCode parseOptions(const OptionSpec *optionTree, int optionSpecCount); + + static bool getOptionExists(char shortName, int occurrenceIndex = 0); + static bool getOptionExists(const char *longName, int occurrenceIndex = 0); + + static int getOccurrenceCount(char shortName); + static int getOccurrenceCount(const char *longName); + + static const char *getOptionString(char shortName, int occurrenceIndex = 0); + static const char *getOptionString(const char *longName, int occurrenceIndex = 0); + + static int getOptionInt(char shortName, int occurrenceIndex = 0); + static int getOptionInt(const char *longName, int occurrenceIndex = 0); + + static int getUntaggedOccurrenceCount(void); + static const char *getUntaggedString(int occurrenceIndex = 0); + static int getUntaggedInt(int occurrenceIndex = 0); + +}; + +// ====================================================================== + +inline char CommandLine::Option::getShortName(void) const +{ + return shortName; +} + +// ---------------------------------------------------------------------- + +inline const char *CommandLine::Option::getLongName(void) const +{ + return longName; +} + +// ---------------------------------------------------------------------- + +inline CommandLine::ArgumentPolicy CommandLine::Option::getArgumentPolicy(void) const +{ + return argumentPolicy; +} + +// ====================================================================== + +inline const CommandLine::Option *CommandLine::List::Node::getOption(void) const +{ + return option; +} + +// ---------------------------------------------------------------------- + +inline const CommandLine::Collection *CommandLine::List::Node::getCollection(void) const +{ + return collection; +} + +// ---------------------------------------------------------------------- + +inline bool CommandLine::List::Node::getMultipleIsAllowed(void) const +{ + return multipleIsAllowed; +} + +// ---------------------------------------------------------------------- + +inline bool CommandLine::List::Node::getIsRequiredNode(void) const +{ + return isRequiredNode; +} + +// ---------------------------------------------------------------------- + +inline const CommandLine::List::Node *CommandLine::List::Node::getNext(void) const +{ + return next; +} + +// ---------------------------------------------------------------------- + +inline void CommandLine::List::Node::setNext(Node *newNext) const +{ + next = newNext; +} + +// ====================================================================== + +inline const CommandLine::Option *CommandLine::Switch::Node::getOption(void) const +{ + return option; +} + +// ---------------------------------------------------------------------- + +inline const CommandLine::Collection *CommandLine::Switch::Node::getCollection(void) const +{ + return collection; +} + +// ---------------------------------------------------------------------- + +inline bool CommandLine::Switch::Node::getMultipleIsAllowed(void) const +{ + return multipleIsAllowed; +} + +// ---------------------------------------------------------------------- + +inline const CommandLine::Switch::Node *CommandLine::Switch::Node::getNext(void) const +{ + return next; +} + +// ---------------------------------------------------------------------- + +inline void CommandLine::Switch::Node::setNext( + Node *newNext + ) const +{ + next = newNext; +} + +// ====================================================================== + +inline char CommandLine::OptionTable::Record::getShortName(void) const +{ + return shortName; +} + +// ---------------------------------------------------------------------- + +inline const char *CommandLine::OptionTable::Record::getLongName(void) const +{ + return longName; +} + +// ---------------------------------------------------------------------- + +inline void CommandLine::OptionTable::Record::addMatch(void) +{ + DEBUG_FATAL(matchCount >= writeCount, ("match overflow")); + ++matchCount; +} + +// ---------------------------------------------------------------------- + +inline const char *CommandLine::OptionTable::Record::getString( + int occurrenceIndex + ) const +{ + DEBUG_FATAL(occurrenceIndex >= writeCount, ("index out of range: val/max %d/%d", occurrenceIndex, writeCount-1)); + return stringArray[occurrenceIndex]; +} + +// ---------------------------------------------------------------------- + +inline int CommandLine::OptionTable::Record::getWriteCount(void) const +{ + return writeCount; +} + +// ---------------------------------------------------------------------- + +inline int CommandLine::OptionTable::Record::getMatchCount(void) const +{ + return matchCount; +} + +// ---------------------------------------------------------------------- + +inline const CommandLine::OptionTable::Record *CommandLine::OptionTable::Record::getNext(void) const +{ + return next; +} + +// ---------------------------------------------------------------------- + +inline CommandLine::OptionTable::Record *CommandLine::OptionTable::Record::getNext(void) +{ + return next; +} + +// ---------------------------------------------------------------------- + +inline void CommandLine::OptionTable::Record::setNext( + Record *newNext + ) const +{ + next = newNext; +} + +// ---------------------------------------------------------------------- + +inline CommandLine::ArgumentPolicy CommandLine::OptionTable::Record::getArgumentPolicy(void) const +{ + return argumentPolicy; +} + +// ====================================================================== + +inline CommandLine::Lexer::TokenType CommandLine::Lexer::Token::getTokenType(void) const +{ + return tokenType; +} + +// ---------------------------------------------------------------------- + +inline char CommandLine::Lexer::Token::getShortName(void) const +{ + DEBUG_FATAL(tokenType != TT_ShortOption, ("attempted to get short name for token type %d", tokenType)); + return name[0]; +} + +// ---------------------------------------------------------------------- + +inline const char *CommandLine::Lexer::Token::getLongName(void) +{ + DEBUG_FATAL(tokenType != TT_LongOption, ("attempted to get long name for token type %d", tokenType)); + return name; +} + +// ---------------------------------------------------------------------- + +inline const char *CommandLine::Lexer::Token::getArgument(void) +{ + DEBUG_FATAL(tokenType != TT_Argument, ("attempted to get argument for token type %d", tokenType)); + return argument; +} + +// ====================================================================== + +inline const char *CommandLine::Lexer::getNextCharacter(void) +{ + return nextCharacter; +} + +// ---------------------------------------------------------------------- + +inline void CommandLine::Lexer::gobbleWhitespace(void) +{ + DEBUG_FATAL(!nextCharacter, ("null nextCharacter")); + while (isspace(*nextCharacter)) + ++nextCharacter; +} + +// ---------------------------------------------------------------------- + +inline int CommandLine::getUntaggedOccurrenceCount(void) +{ + return getOccurrenceCount(OP_SNAME_UNTAGGED); +} + +// ---------------------------------------------------------------------- + +inline const char *CommandLine::getUntaggedString( + int occurrenceIndex + ) +{ + return getOptionString(OP_SNAME_UNTAGGED, occurrenceIndex); +} + +// ---------------------------------------------------------------------- + +inline int CommandLine::getUntaggedInt( + int occurrenceIndex + ) +{ + return getOptionInt(OP_SNAME_UNTAGGED, occurrenceIndex); +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/ConfigFile.cpp b/engine/shared/library/sharedFoundation/src/shared/ConfigFile.cpp new file mode 100644 index 00000000..341f83e3 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/ConfigFile.cpp @@ -0,0 +1,1408 @@ +// ====================================================================== +// +// ConfigFile.cpp +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/ConfigFile.h" + +#include "sharedDebug/DebugFlags.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/FormattedString.h" +#include "sharedFoundation/StringCompare.h" +#include "sharedFoundation/Os.h" + +#include + +#include +#include +#include +#include //for find + +#define DO_CONFIG_FILE_TEMPLATE_CREATE 0 + +#if DO_CONFIG_FILE_TEMPLATE_CREATE + +static char tagBuffer[6]; + +#define CONFIG_FILE_TEMPLATE_CREATE_INT(section, key, def) DEBUG_REPORT_LOG(true, ("cfg: [%s] %s=%d\n", section, key, def)) +#define CONFIG_FILE_TEMPLATE_CREATE_BOOL(section, key, def) DEBUG_REPORT_LOG(true, ("cfg: [%s] %s=%s\n", section, key, def ? "true" : "false")) +#define CONFIG_FILE_TEMPLATE_CREATE_FLOAT(section, key, def) DEBUG_REPORT_LOG(true, ("cfg: [%s] %s=%3.1f\n", section, key, def)) +#define CONFIG_FILE_TEMPLATE_CREATE_STRING(section, key, def) DEBUG_REPORT_LOG(true, ("cfg: [%s] %s=%s\n", section, key, def ? def : "NULL")) +#define CONFIG_FILE_TEMPLATE_CREATE_TAG(section, key, def) ConvertTagToString(def, tagBuffer), DEBUG_REPORT_LOG(true, ("cfg: [%s] %s=%d\n", section, key, tagBuffer)) + +#else + +#define CONFIG_FILE_TEMPLATE_CREATE_INT(section, key, def) NOP +#define CONFIG_FILE_TEMPLATE_CREATE_BOOL(section, key, def) NOP +#define CONFIG_FILE_TEMPLATE_CREATE_FLOAT(section, key, def) NOP +#define CONFIG_FILE_TEMPLATE_CREATE_STRING(section, key, def) NOP +#define CONFIG_FILE_TEMPLATE_CREATE_TAG(section, key, def) NOP + +#endif + +#define NO_SPACE_SECTION(a) DEBUG_FATAL(strchr(a, ' ') != NULL, ("No spaces are allowed in config file section names: %s", a)) +#define NO_SPACE_KEY(a) DEBUG_FATAL(strchr(a, ' ') != NULL, ("No spaces are allowed in config file key names: %s", a)) + +// ====================================================================== + +/// Pointer to the current section the parser is in +ConfigFile::Section *ConfigFile::ms_currentSection; + +/// Pointer to a std:: of Sections +ConfigFile::SectionMap *ConfigFile::ms_sections; + +/// Delimiter string used for include files +const char *ConfigFile::ms_IncludeDelimiter = ".include "; + +bool ConfigFile::ms_installed = false; + +bool ConfigFile::ms_logConfigSettings = false; + +// ====================================================================== +/** Install the command-line processor + * + * This routine adds ConfigFile::remove() to the ExitChain. + * + * @see remove() + */ +void ConfigFile::install(void) +{ +#if DO_CONFIG_FILE_TEMPLATE_CREATE + static bool warned = false; + DEBUG_WARNING(!warned, ("ConfigFile enabled DO_CONFIG_FILE_TEMPLATE_CREATE")); + warned = true; +#endif + +#ifdef _DEBUG + DebugFlags::registerFlag(ms_logConfigSettings, "SharedFoundation", "logConfigSettings", dump); +#endif + + ms_sections = new ConfigFile::SectionMap; + ms_currentSection = NULL; + ExitChain::add(ConfigFile::remove, "ConfigFile::remove"); + ms_installed = true; +} + +// ---------------------------------------------------------------------- +/** + * Check if the config file system is installed. + * + * @return true if it is installed, otherwise false. + */ + +bool ConfigFile::isInstalled() +{ + return ms_installed; +} + +// ---------------------------------------------------------------------- +/** Remove the command-line processor + * + * + * This routine should not be called by the game, but only by the ExitChain. + * @see install() + */ +void ConfigFile::remove(void) +{ + for (std::map::iterator it = ms_sections->begin(); it != ms_sections->end(); ++it) + delete it->second; + delete ms_sections; + ms_sections = NULL; + ms_installed = false; +} + +// ---------------------------------------------------------------------- +/** + * Check if the ConfigFile is completely empty. + */ + +bool ConfigFile::isEmpty() +{ + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + return ms_sections->empty(); +} + +// ---------------------------------------------------------------------- +/** Load and parse the given command line buffer into the config file system + * + * This function breaks up the buffer into files and keys and calls the appropriate + * functions on them + * @param buffer the buffer + * @return success or failure + */ +bool ConfigFile::loadFromCommandLine(const char *buffer) +{ + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + while (*buffer) + { + //trim off leading whitespace + while (isspace(*buffer)) + { + ++buffer; + // advancing buffer, check for null (trailing white space on command line) + if(! *buffer) + break; + } + + if(! *buffer) + break; + + //option 1: a file name, delimited by a "@" + if (*buffer == '@') + { + const char* fileBegin = buffer+1; + const char* fileEnd = fileBegin; + while (*fileEnd && !isspace(*fileEnd)) + { + ++fileEnd; + } + const int fileLen = fileEnd - fileBegin; + char *file = new char[static_cast(fileLen+1)]; + memcpy(file, fileBegin, static_cast(fileLen)); + file[fileLen] = '\0'; + IGNORE_RETURN(loadFile(file)); + delete[] file; + buffer = fileEnd; + } + + //option 2: a section name, delimited by a "-s " + else if (*buffer == '-' && *(buffer+1) == 's' && *(buffer+2) == ' ') + { + //find the section name in the buffer + const char* sectionBegin = buffer+3; + const char* sectionEnd = sectionBegin; + while (*sectionEnd &&!isspace(*sectionEnd)) + { + ++sectionEnd; + } + //make a string out of it + const int sectionLen = sectionEnd - sectionBegin; + char *sectionName = new char[static_cast(sectionLen+1)]; + memcpy(sectionName, sectionBegin, static_cast(sectionLen)); + sectionName[sectionLen] = '\0'; + + //try to get an existing section, otherwise add one + Section *section = getSection(sectionName); + if (section) + { + //put this back as the current section + ms_currentSection = section; + } + else + { + //allocate a new section and set it as the current one + Section *newSection = createSection(sectionName); + //note that newSection is memory owned by the created Section object + //while sectionName is memory allocated to create a null terminated string + ms_currentSection = newSection; + } + delete[] sectionName; + buffer = sectionEnd; + } + + //option 3: a key/value pair + else + { + //find the key name in the buffer + const char *keyBegin = buffer; + const char *keyEnd = strchr(keyBegin, '='); + NOT_NULL(keyEnd); + //make a string out of it + const int keyLen = keyEnd - keyBegin; + char *keyName = new char[static_cast(keyLen+1)]; + memcpy(keyName, keyBegin, static_cast(keyLen)); + keyName[keyLen] = '\0'; + + //find the value name in the buffer + const char *valueBegin = keyEnd + 1; //+1 to skip the equals sign + + const bool quoted = (*valueBegin == '"'); + if (quoted) + ++valueBegin; + + const char *valueEnd = valueBegin; + while (*valueEnd) + { + if (quoted && *valueEnd == '"') + break; + else if (!quoted && isspace(*valueEnd)) + break; + + ++valueEnd; + } + //make a string out of it + const int valueLen = valueEnd - valueBegin; + + //-- skip the trailing quote + if (quoted && *valueEnd == '"') + ++valueEnd; + + char *valueName = new char[static_cast(valueLen+1)]; + memcpy(valueName, valueBegin, static_cast(valueLen)); + valueName[valueLen] = '\0'; + + Key *key = ms_currentSection->findKey(keyName); + if (key) + { + key->addValue(valueName); + } + else + { + ms_currentSection->addKey(keyName, valueName); + } + + //add the key to the ConfigFile (you'd better be in a section) + //ms_currentSection->addKey(keyName, valueName); + + delete[] keyName; + delete[] valueName; + buffer = valueEnd; + } + } + return true; +} + +// ---------------------------------------------------------------------- + +bool ConfigFile::loadFromBuffer(char const * const buffer, int const length) +{ + //allocate here to prevent reallocation per loop + char const * bufferPosition = buffer; + char *currentLine; + char const *lineEnd; + int lineLength; + while(bufferPosition < buffer + length && *bufferPosition) + { + //trim leading whitespace + while (*bufferPosition && isspace(*bufferPosition)) + ++bufferPosition; + //build and process the next line + lineEnd = strchr(bufferPosition, '\n'); + + if (!lineEnd) + lineEnd = buffer + length - 1; + + lineLength = lineEnd - bufferPosition; + currentLine = new char[static_cast(lineLength+1)]; + strncpy(currentLine, bufferPosition, static_cast(lineLength)); + currentLine[lineLength] = '\0'; + processLine(currentLine); + delete[] currentLine; + bufferPosition += lineLength+1; + //trim ending whitespace. Remember that this string is not guaranteed to be NULL terminated. + while (*bufferPosition && (bufferPosition < buffer + length) && isspace(static_cast(*bufferPosition))) + ++bufferPosition; + } + + return true; +} + +// ---------------------------------------------------------------------- +/** Load and parse the given file into the config file system + * + * This function may be called recursively if includes are used + * @param file the filename string + * @return success or failure + */ +bool ConfigFile::loadFile(const char *file) +{ + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + NOT_NULL(file); + ms_currentSection = NULL; + HANDLE handle = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (handle != INVALID_HANDLE_VALUE) + { + // get the length of the config file + const DWORD length = GetFileSize(handle, NULL); + + if (length != 0xffffffff) + { + // create a buffer to load the config file into + char * const buffer = new char[length+2]; + + // make sure the buffer is null terminated + buffer[length] = '\n'; + buffer[length+1] = '\0'; + + // read the config file in + DWORD readResult; + const BOOL result = ReadFile(handle, buffer, length, &readResult, NULL); + + // make sure we read all the correct stuff + if (result && readResult == length) + IGNORE_RETURN(loadFromBuffer(buffer, length + 2)); + + delete [] buffer; + } + // close the file + static_cast(CloseHandle(handle)); + return true; + } + else + { + char *lastError = Os::getLastError(); + WARNING (true, ("ConfigFile::loadFile %s: %s", file, lastError)); + delete [] lastError; + return false; + } +} + +// ---------------------------------------------------------------------- +/** Load and parse the given line into the config file system + * + * @param line the line string + */ +void ConfigFile::processLine(const char *line) +{ + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + // validate argument + DEBUG_FATAL(!line, ("ConfigFile::processLine NULL")); + + // check for a full line comment + if (*line == '#' || *line == ';') + return; + + //check for .include statement (an optional trailing comment is ignored) + if (line == strstr(line, ms_IncludeDelimiter)) + { + //advance past the .include + const char *fileName = line + strlen(ms_IncludeDelimiter); + if (fileName[0] == '\"') + { + //find end of file name + const char* endQuote = strchr(++fileName, '\"'); + NOT_NULL(endQuote); + const int len = endQuote - fileName; + //allocate mem to hold filename + char *fileStr = new char[static_cast(len+1)]; + memcpy(fileStr, fileName, static_cast(len)); + fileStr[len] = '\0'; + //save off the current section, so that we return to it afterwards + Section *thisSection = ms_currentSection; + if (!loadFile(fileStr)) + WARNING (true, ("ConfigFile::processLine unable to load included file %s", fileStr)); + + //return to current section "scope" + ms_currentSection = thisSection; + delete[] fileStr; + } + return; + } + + //look for a section declaration + // check for a comment + if (*line == '[') + { + const char *beginSection = ++line; + //find end of section name + const char* endSection = strchr(line, ']'); + NOT_NULL(endSection); + const int len = endSection - line; + //allocate mem to hold section name + char *sectionName = new char[static_cast(len+1)]; + memcpy(sectionName, beginSection, static_cast(len)); + sectionName[len] = '\0'; + //see if we already have this section + Section *section = getSection(sectionName); + if (section) + { + //put this back as the current section + ms_currentSection = section; + } + else + { + //allocate a new section and set it as the current one + Section *newSection = createSection(sectionName); + //note that newSection is memory owned by the created Section object + //while sectionName is memory allocated to create a null terminated string + ms_currentSection = newSection; + } + delete[] sectionName; + return; + } + //if we get here, we should have a 1 or > key assignment(s) with an optional comment on the end + processKeys(line); +} + +// ---------------------------------------------------------------------- +/** Load and parse the given string into key/value pairs and enter them into the config file system + * + * @param line a string of one or more key/value pairs (i.e. a=6 & b = 7) + */ +void ConfigFile::processKeys(const char *line) +{ + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + + if (!*line) + return; + + DEBUG_FATAL(!ms_currentSection, ("ConfigFile::processKey key assigned outside a section")); + //build the key name + while (isspace(*line)) + ++line; + const char *beginKey = line; + //find end of key name + const char* endKey = strchr(line, '='); + WARNING_DEBUG_FATAL(!endKey, ("Invalid line in config file. Section = [%s]", ms_currentSection->getName())); + if (!endKey) + return; + + const char *beginValue = endKey +1; + //remove '=' from keyname + --endKey; + //trim trailing whitespace from before key name + while (isspace(*endKey)) + --endKey; + const int len = endKey - line + 1; + + //allocate mem to hold keyname + char *keyName = new char[static_cast(len+1)]; + memcpy(keyName, beginKey, static_cast(len)); + keyName[len] = '\0'; + + const char *endValue = beginValue; + while (*endValue) + { + //build the value + char *value = NULL; + while(isspace(*beginValue)) + ++beginValue; + if (*beginValue != '"') + { + //find the end of the key value + endValue = beginValue; + while(*endValue && + !isspace(*endValue) && + (*endValue) != '#' && + (*endValue) != '\n' && + (*endValue) != '&' && + (*endValue) != ';') + ++endValue; + int valueLength = endValue - beginValue; + value = new char[static_cast(valueLength+1)]; + memcpy(value, beginValue, static_cast(valueLength)); + value[valueLength] = '\0'; + } + else + { + // quoted string: go until we get a matching quote or eol + endValue = beginValue + 1; + while(*endValue && + *endValue != '"' && + *endValue != '\n') + ++endValue; + ++beginValue; + int valueLength = endValue - beginValue; + value = new char[static_cast(valueLength+1)]; + if (valueLength > 0) + memcpy(value, beginValue, static_cast(valueLength)); + value[valueLength] = '\0'; + if (*endValue == '"') + ++endValue; + } + + //see if we already have this key + Key *key = ms_currentSection->findKey(keyName); + if (key) + { + key->addValue(value); + } + else + { + ms_currentSection->addKey(keyName, value); + } + delete[] value; + + //advance and look for another key or value on this line + while ((*endValue) && isspace(*endValue)) + ++endValue; + if (*endValue == '&' || *endValue == '\0' || *endValue == ';' || *endValue == '#') + { + if (*endValue == '&') + processKeys(++endValue); + // move endValue to the end of the line + while (*endValue) + ++endValue; + delete[] keyName; + keyName = 0; + } + else + beginValue = endValue; + } + + delete[] keyName; + keyName = 0; +} + +// ---------------------------------------------------------------------- +/** Get a Section pointer from a string + * + * @param section the name of the section + * @return the pointer if valid, otherwise NULL +*/ +ConfigFile::Section *ConfigFile::getSection(const char *section) +{ + std::map::const_iterator it = ms_sections->find(section); + if (it != ms_sections->end()) + return it->second; + + return NULL; +} + +// ---------------------------------------------------------------------- +/** Create a new section + * + * @param section the name of the section + * @return a pointer to the newly created Section + */ +ConfigFile::Section *ConfigFile::createSection(const char *name) +{ + Section *newSection = new Section(name); + (*ms_sections)[newSection->getName()] = newSection; + return newSection; +} + +// ---------------------------------------------------------------------- +/** Removes a section + * + * @param section the name of the section + */ +void ConfigFile::removeSection(const char *name) +{ + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + NOT_NULL(name); + NOT_NULL(ms_sections); + + SectionMap::iterator iter = ms_sections->find(name); + if (iter != ms_sections->end()) + { + delete iter->second; + iter->second = NULL; + ms_sections->erase(iter); + } +} + +// ---------------------------------------------------------------------- +/** Print all the stored config data to stdout + * + */ +void ConfigFile::dump(void) +{ +#ifdef _DEBUG + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + for (std::map::iterator it = ms_sections->begin(); it != ms_sections->end(); ++it) + { + const char *name = it->first; + DEBUG_REPORT_LOG_PRINT(true, ("[%s]\n", name )); + it->second->dump(); + } + ms_logConfigSettings = false; +#endif +} + +// ---------------------------------------------------------------------- +/** Gets a value as an int + * + * Since access to this function is usually macroed, provide direct access + * + * @param section the section name string + * @param key the key name string + * @param index of the entry (since a key may hold > 1 value) + * @param defaultValue the value to return if the section, key, or index aren't valid + * @return the value + */ +int ConfigFile::getKeyInt(const char *section, const char *key, int index, int defaultValue) +{ + NO_SPACE_SECTION(section); + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_INT(section, key, defaultValue); + + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + //validate arguments + NOT_NULL(section); + NOT_NULL(key); + Section *s = getSection(section); + if (s) + return s->getKeyInt(key, index, defaultValue); + + return defaultValue; +} + +// ---------------------------------------------------------------------- +/** Gets a value as a bool + * + * Since access to this function is usually macroed, provide direct access + * + * @param section the section name string + * @param key the key name string + * @param index of the entry (since a key may hold > 1 value) + * @param defaultValue the value to return if the section, key, or index aren't valid + * @return the value + */ +bool ConfigFile::getKeyBool(const char *section, const char *key, int index, bool defaultValue) +{ + NO_SPACE_SECTION(section); + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_BOOL(section, key, defaultValue); + + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + //validate arguments + NOT_NULL(section); + NOT_NULL(key); + Section *s = getSection(section); + if (s) + return s->getKeyBool(key, index, defaultValue); + + return defaultValue; +} + +// ---------------------------------------------------------------------- +/** Gets a value as an float + * + * Since access to this function is usually macroed, provide direct access + * + * @param section the section name string + * @param key the key name string + * @param index of the entry (since a key may hold > 1 value) + * @param defaultValue the value to return if the section, key, or index aren't valid + * @return the value + */ +float ConfigFile::getKeyFloat(const char *section, const char *key, int index, float defaultValue) +{ + NO_SPACE_SECTION(section); + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_FLOAT(section, key, defaultValue); + + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + //validate arguments + NOT_NULL(section); + NOT_NULL(key); + Section *s = getSection(section); + if (s) + return s->getKeyFloat(key, index, defaultValue); + + return defaultValue; +} + +// ---------------------------------------------------------------------- +/** Gets a value as a string (const char *) + * + * Since access to this function is usually macroed, provide direct access + * + * @param section the section name string + * @param key the key name string + * @param index of the entry (since a key may hold > 1 value) + * @param defaultValue the value to return if the section, key, or index aren't valid + * @return the value + */ +const char *ConfigFile::getKeyString(const char *section, const char *key, int index, const char *defaultValue) +{ + NO_SPACE_SECTION(section); + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_STRING(section, key, defaultValue); + + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + //validate arguments + NOT_NULL(section); + NOT_NULL(key); + Section *s = getSection(section); + if (s) + return s->getKeyString(key, index, defaultValue); + + return defaultValue; +} + +// ---------------------------------------------------------------------- +/** Gets a value as a Tag + * + * Since access to this function is usually macroed, provide direct access + * + * @param section the section name string + * @param key the key name string + * @param index of the entry (since a key may hold > 1 value) + * @param defaultValue the value to return if the section, key, or index aren't valid + * @return the value + */ + +Tag ConfigFile::getKeyTag(const char *section, const char *key, int index, Tag defaultValue) +{ + NO_SPACE_SECTION(section); + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_TAG(section, key, defaultValue); + + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + //validate arguments + NOT_NULL(section); + NOT_NULL(key); + Section *s = getSection(section); + if (s) + return s->getKeyTag(key, index, defaultValue); + + return defaultValue; +} + +// ---------------------------------------------------------------------- +/** Gets a value as an int + * This function returns the *last* key in the list. This should be the item entered last + * into the system (after basic includes, etc.) + * + * Since access to this function is usually macroed, provide direct access + * + * @param section the section name string + * @param key the key name string + * @param defaultValue the value to return if the section, or key isn't valid + * @param overrideLazyAdd if true, ignores and replaces an existing key that was added lazily. If false, honors any previously-installed value + * @return the value + */ +int ConfigFile::getKeyInt(const char *section, const char *key, int defaultValue, bool overrideLazyAdds) +{ + NO_SPACE_SECTION(section); + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_INT(section, key, defaultValue); + + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + //validate arguments + NOT_NULL(section); + NOT_NULL(key); + Section *s = getSection(section); + if(!s) + { + s = createSection(section); + } + + Key *k = s->findKey(key); + + if (k && k->getLazyAdd() && overrideLazyAdds) + { + s->removeKey(key); + k = 0; + } + + if(!k) + { + s->addKey(key, FormattedString<32>().sprintf("%i", defaultValue), !overrideLazyAdds); + return defaultValue; + } + + return s->getKeyInt(key, k->getCount()-1, defaultValue); +} + +// ---------------------------------------------------------------------- +/** Gets a value as a bool + * This function returns the *last* key in the list. This should be the item entered last + * into the system (after basic includes, etc.) + * + * Since access to this function is usually macroed, provide direct access + * + * @param section the section name string + * @param key the key name string + * @param defaultValue the value to return if the section, or key isn't valid + * @param overrideLazyAdd if true, ignores and replaces an existing key that was added lazily. If false, honors any previously-installed value + * @return the value + */ +bool ConfigFile::getKeyBool(const char *section, const char *key, bool defaultValue, bool overrideLazyAdds) +{ + NO_SPACE_SECTION(section); + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_BOOL(section, key, defaultValue); + + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + //validate arguments + NOT_NULL(section); + NOT_NULL(key); + Section *s = getSection(section); + if(!s) + { + s = createSection(section); + } + + Key *k = s->findKey(key); + + if (k && k->getLazyAdd() && overrideLazyAdds) + { + s->removeKey(key); + k = 0; + } + + if(!k) + { + s->addKey(key, FormattedString<32>().sprintf("%s", defaultValue ? "1" : "0"), !overrideLazyAdds); + return defaultValue; + } + + return s->getKeyBool(key, k->getCount()-1, defaultValue); +} + +// ---------------------------------------------------------------------- +/** Gets a value as a float + * This function returns the *last* key in the list. This should be the item entered last + * into the system (after basic includes, etc.) + * + * Since access to this function is usually macroed, provide direct access + * + * @param section the section name string + * @param key the key name string + * @param defaultValue the value to return if the section, or key isn't valid + * @param overrideLazyAdd if true, ignores and replaces an existing key that was added lazily. If false, honors any previously-installed value + * @return the value + */ +float ConfigFile::getKeyFloat(const char *section, const char *key, float defaultValue, bool overrideLazyAdds) +{ + NO_SPACE_SECTION(section); + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_FLOAT(section, key, defaultValue); + + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + //validate arguments + NOT_NULL(section); + NOT_NULL(key); + Section *s = getSection(section); + if(!s) + { + s = createSection(section); + } + + Key *k = s->findKey(key); + + if (k && k->getLazyAdd() && overrideLazyAdds) + { + s->removeKey(key); + k = 0; + } + + if(!k) + { + s->addKey(key, FormattedString<32>().sprintf("%f", defaultValue), !overrideLazyAdds); + return defaultValue; + } + + return s->getKeyFloat(key, k->getCount()-1, defaultValue); +} + +// ---------------------------------------------------------------------- +/** Gets a value as a string (const char*). + * This function returns the *last* key in the list. This should be the item entered last + * into the system (after basic includes, etc.) + * + * Since access to this function is usually macroed, provide direct access + * + * @param section the section name string + * @param key the key name string + * @param defaultValue the value to return if the section, or key isn't valid + * @param overrideLazyAdd if true, ignores and replaces an existing key that was added lazily. If false, honors any previously-installed value + * @return the value + */ +const char *ConfigFile::getKeyString(const char *section, const char *key, const char *defaultValue, bool overrideLazyAdds) +{ + NO_SPACE_SECTION(section); + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_STRING(section, key, defaultValue); + + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + //validate arguments + NOT_NULL(section); + NOT_NULL(key); + Section *s = getSection(section); + if(!s) + return defaultValue; + Key *k = s->findKey(key); + + if (k && k->getLazyAdd() && overrideLazyAdds) + { + s->removeKey(key); + k = 0; + } + + if(!k) + { + if (defaultValue != 0) + s->addKey(key, defaultValue, !overrideLazyAdds); + return defaultValue; + } + + return s->getKeyString(key, k->getCount()-1, defaultValue); +} + +// ---------------------------------------------------------------------- +/** Gets a value as a string (const char*). + * This function returns the *last* key in the list. This should be the item entered last + * into the system (after basic includes, etc.) + * + * Since access to this function is usually macroed, provide direct access + * + * @param section the section name string + * @param key the key name string + * @param defaultValue the value to return if the section, or key isn't valid + * @param overrideLazyAdd if true, ignores and replaces an existing key that was added lazily. If false, honors any previously-installed value + * @return the value + */ + +Tag ConfigFile::getKeyTag(const char *section, const char *key, Tag defaultValue, bool overrideLazyAdds) +{ + NO_SPACE_SECTION(section); + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_TAG(section, key, defaultValue); + + DEBUG_FATAL(!ms_installed, ("ConfigFile not installed")); + //validate arguments + NOT_NULL(section); + NOT_NULL(key); + Section *s = getSection(section); + if(!s) + { + s = createSection(section); + } + + Key *k = s->findKey(key); + + if (k && k->getLazyAdd() && overrideLazyAdds) + { + s->removeKey(key); + k = 0; + } + + if(!k) + { + char buffer[6]; + ConvertTagToString(defaultValue, buffer); + s->addKey(key, buffer, !overrideLazyAdds); + return defaultValue; + } + + return s->getKeyTag(key, k->getCount()-1, defaultValue); +} + +// ====================================================================== +//ConfigFile::Element + +ConfigFile::Element::Element(void) +: + m_entry(NULL) +{} + +// ---------------------------------------------------------------------- + +ConfigFile::Element::Element(const char *entry) +: + m_entry(DuplicateString(entry)) +{} + +// ---------------------------------------------------------------------- + +ConfigFile::Element::~Element(void) +{ + delete[] m_entry; +} + +// ---------------------------------------------------------------------- + +ConfigFile::Element::Element(const Element &element) +: + m_entry(element.m_entry) +{} + +// ---------------------------------------------------------------------- + +ConfigFile::Element &ConfigFile::Element::operator =(const Element &element) +{ + if (this != &element) + { + delete[] m_entry; + m_entry = DuplicateString(element.m_entry); + } + return *this; +} + +// ---------------------------------------------------------------------- + +int ConfigFile::Element::getAsInt(void) const +{ + DEBUG_FATAL(!m_entry, ("ConfigFile::getAsIntno data")); + + if (m_entry[0] == '0' && m_entry[1] == 'x') + { + int result = 0; + for (const char *s = m_entry + 2; *s; ++s) + { + const int c = tolower(*s); + + if (c >= '0' && c <= '9') + result = (result << 4) | (c - '0'); + else + if (c >= 'a' && c <= 'f') + result = (result << 4) | (c - 'a' + 10); + else + break; + } + + return result; + } + + return atoi(m_entry); +} + +// ---------------------------------------------------------------------- + +bool ConfigFile::Element::getAsBool(void) const +{ + DEBUG_FATAL(!m_entry, ("ConfigFile::getAsBool no data")); + + if (_stricmp(m_entry, "true") == 0) + return true; + + if (_stricmp(m_entry, "false") == 0) + return false; + + if (_stricmp(m_entry, "yes") == 0) + return true; + + if (_stricmp(m_entry, "no") == 0) + return false; + + return getAsInt() != 0; +} + +// ---------------------------------------------------------------------- + +float ConfigFile::Element::getAsFloat(void) const +{ + DEBUG_FATAL(!m_entry, ("ConfigFile::getAsFloatno data")); + return static_cast(atof(m_entry)); +} + +// ---------------------------------------------------------------------- + +const char *ConfigFile::Element::getAsString(void) const +{ + DEBUG_FATAL(!m_entry, ("ConfigFile::getAsString no data")); + return m_entry; +} + +// ---------------------------------------------------------------------- + +Tag ConfigFile::Element::getAsTag(void) const +{ + DEBUG_FATAL(!m_entry, ("ConfigFile::getAsTag no data")); + return ConvertStringToTag(m_entry); +} + +// ====================================================================== +//ConfigFile::Key + +ConfigFile::Key::Key(const char *name, const char *value, bool lazyAdd) +: + m_elements(NULL), + m_name(NULL), + m_lazyAdd(lazyAdd) +{ + m_name = new char[strlen(name)+1]; + strcpy(m_name, name); + m_elements = new ElementList; + addValue(value); +} + +// ---------------------------------------------------------------------- + +ConfigFile::Key::~Key(void) +{ + if(m_elements) + { + for (std::list::iterator it = m_elements->begin(); it != m_elements->end(); ++it) + delete (*it); + delete m_elements; + } + delete[] m_name; +} + +// ---------------------------------------------------------------------- + +void ConfigFile::Key::addValue(const char *value) +{ + Element *element = new Element(value); + m_elements->push_back(element); +} //lint !e429 custodial pointer not freed or returned, we store it in a list we later clean out, so ignore this + +// ---------------------------------------------------------------------- + +const char *ConfigFile::Key::getName(void) const +{ + return m_name; +} + +// ---------------------------------------------------------------------- + +int ConfigFile::Key::getCount(void) const +{ + return static_cast(m_elements->size()); +} + +// ---------------------------------------------------------------------- + +bool ConfigFile::Key::getLazyAdd(void) const +{ + return m_lazyAdd; +} + +// ---------------------------------------------------------------------- + +int ConfigFile::Key::getAsInt(int index, int defaultValue) const +{ + DEBUG_FATAL(index < 0, ("ConfigFile::Key::getAsInt index < 0")); + int i = 0; + for (std::list::const_iterator it = m_elements->begin(); it != m_elements->end() && i <= index; ++it) + { + if (i == index) + return (*it)->getAsInt(); + ++i; + } + return defaultValue; +} + +// ---------------------------------------------------------------------- + +bool ConfigFile::Key::getAsBool(int index, bool defaultValue) const +{ + DEBUG_FATAL(index < 0, ("ConfigFile::Key::getAsInt index < 0")); + int i = 0; + for (std::list::const_iterator it = m_elements->begin(); it != m_elements->end() && i <= index; ++it) + { + if (i == index) + return (*it)->getAsBool(); + ++i; + } + return defaultValue; +} + +// ---------------------------------------------------------------------- + +float ConfigFile::Key::getAsFloat(int index, float defaultValue) const +{ + DEBUG_FATAL(index < 0, ("ConfigFile::Key::getAsInt index < 0")); + int i = 0; + for (std::list::const_iterator it = m_elements->begin(); it != m_elements->end() && i <= index; ++it) + { + if (i == index) + return (*it)->getAsFloat(); + ++i; + } + return defaultValue; +} + +// ---------------------------------------------------------------------- + +const char *ConfigFile::Key::getAsString(int index, const char *defaultValue) const +{ + DEBUG_FATAL(index < 0, ("ConfigFile::Key::getAsInt index < 0")); + int i = 0; + for (std::list::const_iterator it = m_elements->begin(); it != m_elements->end() && i <= index; ++it) + { + if (i == index) + return (*it)->getAsString(); + ++i; + } + return defaultValue; +} + +// ---------------------------------------------------------------------- + +Tag ConfigFile::Key::getAsTag(int index, Tag defaultValue) const +{ + DEBUG_FATAL(index < 0, ("ConfigFile::Key::getAsInt index < 0")); + int i = 0; + for (std::list::const_iterator it = m_elements->begin(); it != m_elements->end() && i <= index; ++it) + { + if (i == index) + return (*it)->getAsTag(); + ++i; + } + return defaultValue; +} + +// ---------------------------------------------------------------------- + +void ConfigFile::Key::dump(const char *keyName) const +{ + UNREF(keyName); +#ifdef _DEBUG + for (std::list::const_iterator it = m_elements->begin(); it != m_elements->end(); ++it) + DEBUG_REPORT_LOG_PRINT(true, ("\t%s=%s\n", keyName, (*it)->getAsString())); +#endif +} + +// ====================================================================== +//ConfigFile::Section + +ConfigFile::Section::Section(const char *name) +: + m_keys(NULL), + m_name(NULL) +{ + m_name = new char[strlen(name)+1]; + strcpy(m_name, name); + m_keys = new KeyMap; +} + +// ---------------------------------------------------------------------- + +ConfigFile::Section::~Section(void) +{ + if(m_keys) + { + for (KeyMap::iterator it = m_keys->begin(); it != m_keys->end(); ++it) + delete it->second; + delete m_keys; + } + delete[] m_name; +} + +// ---------------------------------------------------------------------- + +const char *ConfigFile::Section::getName(void) const +{ + return m_name; +} + +// ---------------------------------------------------------------------- + +ConfigFile::Key *ConfigFile::Section::findKey(const char *key) const +{ + KeyMap::const_iterator it = m_keys->find(key); + if (it != m_keys->end()) + return it->second; + + return NULL; +} + +// ---------------------------------------------------------------------- + +void ConfigFile::Section::addKey(const char *name, const char *value, bool lazyAdd) +{ + Key *newKey = new Key(name, value, lazyAdd); + (*m_keys)[newKey->getName()] = newKey; +} + +// ---------------------------------------------------------------------- + +void ConfigFile::Section::removeKey(const char *name) +{ + KeyMap::iterator it = m_keys->find(name); + if (it != m_keys->end()) + { + delete it->second; + m_keys->erase(it); + } +} + +// ---------------------------------------------------------------------- + +int ConfigFile::Section::getKeyInt(const char *key, int index, int defaultValue) const +{ + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_INT(m_name, key, defaultValue); + + KeyMap::const_iterator it = m_keys->find(key); + if (it != m_keys->end()) + return it->second->getAsInt(index, defaultValue); + + return defaultValue; +} + +// ---------------------------------------------------------------------- + +bool ConfigFile::Section::getKeyBool(const char *key, int index, bool defaultValue) const +{ + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_BOOL(m_name, key, defaultValue); + + KeyMap::const_iterator it = m_keys->find(key); + if (it != m_keys->end()) + return it->second->getAsBool(index, defaultValue); + + return defaultValue; +} + +// ---------------------------------------------------------------------- + +float ConfigFile::Section::getKeyFloat(const char *key, int index, float defaultValue) const +{ + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_FLOAT(m_name, key, defaultValue); + + KeyMap::const_iterator it = m_keys->find(key); + if (it != m_keys->end()) + return it->second->getAsFloat(index, defaultValue); + + return defaultValue; +} + +// ---------------------------------------------------------------------- + +const char *ConfigFile::Section::getKeyString(const char *key, int index, const char *defaultValue) const +{ + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_STRING(m_name, key, defaultValue); + + KeyMap::const_iterator it = m_keys->find(key); + if (it != m_keys->end()) + return it->second->getAsString(index, defaultValue); + + return defaultValue; +} + +// ---------------------------------------------------------------------- + +Tag ConfigFile::Section::getKeyTag(const char *key, int index, Tag defaultValue) const +{ + NO_SPACE_KEY(key); + + CONFIG_FILE_TEMPLATE_CREATE_TAG(m_name, key, defaultValue); + + KeyMap::const_iterator it = m_keys->find(key); + if (it != m_keys->end()) + return it->second->getAsTag(index, defaultValue); + + return defaultValue; +} + +// ---------------------------------------------------------------------- + +bool ConfigFile::Section::getKeyExists(const char *key) const +{ + NO_SPACE_KEY(key); + + KeyMap::const_iterator it = m_keys->find(key); + if (it != m_keys->end()) + return true; + + return false; +} + +// ---------------------------------------------------------------------- + +void ConfigFile::Section::dump(void) const +{ +#ifdef _DEBUG + for (KeyMap::const_iterator it = m_keys->begin(); it != m_keys->end(); ++it) + it->second->dump(it->first); +#endif +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/ConfigFile.h b/engine/shared/library/sharedFoundation/src/shared/ConfigFile.h new file mode 100644 index 00000000..a4c034ed --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/ConfigFile.h @@ -0,0 +1,181 @@ +// ====================================================================== +// +// ConfigFile.h +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef CONFIG_FILE_H +#define CONFIG_FILE_H + +// ====================================================================== + +class StringCompare; + +#include "sharedFoundation/Tag.h" + +// ====================================================================== + +/// Provide access to configuration file paramaters. +class ConfigFile +{ +public: + + /** Represents a single value of a key/value pair + * + * Stored as a string, but can be cast and returned as an int, bool, and float as well + */ + class Element + { + public: + Element(); + explicit Element(const char *entry); + virtual ~Element(void); + Element(const Element&); + Element &operator =(const Element&); + int getAsInt(void) const; + bool getAsBool(void) const; + float getAsFloat(void) const; + const char *getAsString(void) const; + Tag getAsTag(void) const; + + private: + /// a buffer holding the entry string, which may be recast to other types + char *m_entry; + }; + typedef stdlist::fwd ElementList; + + // ----------------------------------------------------------------------- + + ///Represents a single key, which may hold multiple ordered Elements as values + class Key + { + public: + Key (const char *name, const char *value, bool lazyAdd = false); + virtual ~Key(void); + const char *getName(void) const; + bool getLazyAdd(void) const; + int getAsInt(int index, int defaultValue) const; + bool getAsBool(int index, bool defaultValue) const; + float getAsFloat(int index, float defaultValue) const; + const char *getAsString(int index, const char *defaultValue) const; + Tag getAsTag(int index, Tag defaultValue) const; + int getCount(void) const; + void addValue(const char *value); + void dump(const char *keyName) const; + + private: + /// disabled + Key(void); + /// disabled + Key(const Key&); + /// disabled + Key &operator =(const Key&); + + private: + ///A list of element values, since are elements are unique and order is important + ElementList *m_elements; + ///String representation of the key's name + char* m_name; + /// track whether this was added lazily (not explicitly in the config file) + bool m_lazyAdd; + }; + typedef stdmap::fwd KeyMap; + + // ----------------------------------------------------------------------- + + /** A scoping mechanism for keys + * + * All keys exist inside a section, i.e. [Section] + * a = 5 + */ + class Section + { + public: + explicit Section (const char *name); + ~Section(void); + const char *getName(void) const; + Key *findKey(const char *key) const; + int getKeyInt (const char *key, int index, int defaultValue = 0) const; + bool getKeyBool (const char *key, int index, bool defaultValue = false) const; + float getKeyFloat (const char *key, int index, float defaultValue = 0.f) const; + const char *getKeyString(const char *key, int index, const char *defaultValue = NULL) const; + Tag getKeyTag (const char *key, int index, Tag defaultValue = 0) const; + int getKeyCount(const char *key) const; + void addKey(const char *keyName, const char *value, bool lazyAdd = false); + void removeKey(const char *key); + void dump(void) const; + bool getKeyExists(const char *key) const; + + private: + /// disabled + Section(void); + /// disabled + Section(const Section&); + /// disabled + Section &operator =(const Section&); + + private: + /** A map of the keys + * + * Use a map for speed, and since keys are unique + */ + KeyMap *m_keys; + ///String representation of the section's name + char* m_name; + }; + typedef stdmap::fwd SectionMap; + +public: + //public interface + static void install(void); + static bool isInstalled(void); + static bool isEmpty(); + static Section *getSection(const char *name); + static bool loadFile(char const * fileName); + static bool loadFromBuffer(char const * buffer, int length); + static bool loadFromCommandLine(const char *buffer); + static Section *createSection(const char *name); + static void removeSection(const char *name); + static void dump(void); + //accessors using indexes + static int getKeyInt (const char *section, const char *key, int index, int defaultValue); + static bool getKeyBool (const char *section, const char *key, int index, bool defaultValue); + static float getKeyFloat (const char *section, const char *key, int index, float defaultValue); + static const char *getKeyString(const char *section, const char *key, int index, const char *defaultValue); + static Tag getKeyTag (const char *section, const char *key, int index, Tag defaultValue); + //accessors defaulting to retrieving the last entered value + static DLLEXPORT int getKeyInt (const char *section, const char *key, int defaultValue, bool overrideLazyAdds = false); + static DLLEXPORT bool getKeyBool (const char *section, const char *key, bool defaultValue, bool overrideLazyAdds = false); + static float getKeyFloat (const char *section, const char *key, float defaultValue, bool overrideLazyAdds = false); + static const char *getKeyString(const char *section, const char *key, const char *defaultValue, bool overrideLazyAdds = false); + static Tag getKeyTag (const char *section, const char *key, Tag defaultValue, bool overrideLazyAdds = false); + +private: + /// disabled + ConfigFile(void); + /// disabled + ConfigFile(const ConfigFile &); + /// disabled + ConfigFile &operator =(const ConfigFile &); + +private: + //private functions + static void processLine(const char *line); + static void processKeys(const char *key); + static void remove(void); + +private: + //private data members + static SectionMap *ms_sections; + static Section *ms_currentSection; + static const char *ms_IncludeDelimiter; + static bool ms_installed; + static bool ms_logConfigSettings; +}; + +// ====================================================================== + +#endif + + diff --git a/engine/shared/library/sharedFoundation/src/shared/ConstCharCrcLowerString.cpp b/engine/shared/library/sharedFoundation/src/shared/ConstCharCrcLowerString.cpp new file mode 100644 index 00000000..0d297b94 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/ConstCharCrcLowerString.cpp @@ -0,0 +1,25 @@ +// ====================================================================== +// +// ConstCharCrcLowerString.cpp +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/ConstCharCrcLowerString.h" + +// ====================================================================== + +ConstCharCrcLowerString::ConstCharCrcLowerString(const char *string) +: CrcLowerString(string, PersistentCrcString::CC_true) +{ +} + +// ---------------------------------------------------------------------- + +ConstCharCrcLowerString::~ConstCharCrcLowerString() +{ +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/ConstCharCrcLowerString.h b/engine/shared/library/sharedFoundation/src/shared/ConstCharCrcLowerString.h new file mode 100644 index 00000000..884b6272 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/ConstCharCrcLowerString.h @@ -0,0 +1,27 @@ +// ====================================================================== +// +// ConstCharCrcLowerString.h +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ConstCharCrcLowerString_H +#define INCLUDED_ConstCharCrcLowerString_H + +// ====================================================================== + +#include "sharedFoundation/CrcLowerString.h" + +// ====================================================================== + +class ConstCharCrcLowerString : public CrcLowerString +{ +public: + ConstCharCrcLowerString(const char *string); + virtual ~ConstCharCrcLowerString(); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/ConstCharCrcString.cpp b/engine/shared/library/sharedFoundation/src/shared/ConstCharCrcString.cpp new file mode 100644 index 00000000..618700a6 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/ConstCharCrcString.cpp @@ -0,0 +1,76 @@ +// ====================================================================== +// +// ConstCharCrcString.cpp +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/ConstCharCrcString.h" + +// ====================================================================== + +ConstCharCrcString::ConstCharCrcString(const char *string) +: CrcString(), + m_buffer(string) +{ + calculateCrc (); +} + +// ---------------------------------------------------------------------- + +ConstCharCrcString::ConstCharCrcString(const char *string, uint32 crc) +: CrcString(), + m_buffer(string) +{ +#ifdef _DEBUG + calculateCrc(); + DEBUG_FATAL(m_crc != crc, ("calculated and specified crc values do not match")); +#endif + m_crc = crc; +} + +// ---------------------------------------------------------------------- + +ConstCharCrcString::ConstCharCrcString(ConstCharCrcString const &rhs) +: CrcString(rhs.m_crc), + m_buffer(rhs.m_buffer) +{ +} + +// ---------------------------------------------------------------------- + +ConstCharCrcString::~ConstCharCrcString() +{ +} + +// ---------------------------------------------------------------------- + +char const * ConstCharCrcString::getString() const +{ + return m_buffer; +} + +// ---------------------------------------------------------------------- + +void ConstCharCrcString::clear() +{ + DEBUG_FATAL(true, ("cannot clear a ConstCharCrcString")); +} + +// ---------------------------------------------------------------------- + +void ConstCharCrcString::set(char const *, bool) +{ + DEBUG_FATAL(true, ("cannot clear a ConstCharCrcString")); +} + +// ---------------------------------------------------------------------- + +void ConstCharCrcString::set(char const *, uint32) +{ + DEBUG_FATAL(true, ("cannot clear a ConstCharCrcString")); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/ConstCharCrcString.h b/engine/shared/library/sharedFoundation/src/shared/ConstCharCrcString.h new file mode 100644 index 00000000..ac444d99 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/ConstCharCrcString.h @@ -0,0 +1,45 @@ +// ====================================================================== +// +// ConstCharCrcString.h +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ConstCharCrcString_H +#define INCLUDED_ConstCharCrcString_H + +// ====================================================================== + +#include "sharedFoundation/CrcString.h" + +// ====================================================================== + +class ConstCharCrcString : public CrcString +{ +public: + + ConstCharCrcString(const char *string); + ConstCharCrcString(const char *string, uint32 crc); + ConstCharCrcString(ConstCharCrcString const &); + virtual ~ConstCharCrcString(); + + virtual char const * getString() const; + + virtual void clear(); + virtual void set(char const * string, bool applyNormalize); + virtual void set(char const * string, uint32 crc); + +private: + + ConstCharCrcString(); + ConstCharCrcString & operator =(ConstCharCrcString const &); + +private: + + char const * const m_buffer; +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/CrashReportInformation.cpp b/engine/shared/library/sharedFoundation/src/shared/CrashReportInformation.cpp new file mode 100644 index 00000000..920f1ffa --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CrashReportInformation.cpp @@ -0,0 +1,93 @@ +// ====================================================================== +// +// CrashReportInformation.cpp +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/CrashReportInformation.h" + +#include "sharedFoundation/ExitChain.h" + +#include +#include + +// ====================================================================== + +namespace CrashReportInformationNamespace +{ + typedef std::vector TextVector; + typedef std::vector ConstTextVector; + TextVector ms_staticText; + ConstTextVector ms_dynamicText; +} +using namespace CrashReportInformationNamespace; + +// ====================================================================== + +void CrashReportInformation::install() +{ + ExitChain::add(&remove, "CrashReportInformation::remove"); +} + +// ---------------------------------------------------------------------- + +void CrashReportInformation::remove() +{ + while (!ms_staticText.empty()) + { + delete [] ms_staticText.back(); + ms_staticText.pop_back(); + } + + ms_dynamicText.clear(); +} + +// ---------------------------------------------------------------------- + +void CrashReportInformation::addStaticText(char const * format, ...) +{ + va_list va; + + va_start(va, format); + + char buffer[256]; + vsnprintf(buffer, sizeof(buffer), format, va); + ms_staticText.push_back(DuplicateString(buffer)); + + va_end(va); +} + +// ---------------------------------------------------------------------- + +void CrashReportInformation::addDynamicText(char const * text) +{ + ms_dynamicText.push_back(text); +} + +// ---------------------------------------------------------------------- + +void CrashReportInformation::removeDynamicText(char const * text) +{ + ConstTextVector::iterator i = std::find(ms_dynamicText.begin(), ms_dynamicText.end(), text); + if (i != ms_dynamicText.end()) + ms_dynamicText.erase(i); +} + +// ---------------------------------------------------------------------- + +char const * CrashReportInformation::getEntry(int index) +{ + if (index < static_cast(ms_staticText.size())) + return ms_staticText[index]; + + index -= static_cast(ms_staticText.size()); + if (index < static_cast(ms_dynamicText.size())) + return ms_dynamicText[index]; + + return NULL; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/CrashReportInformation.h b/engine/shared/library/sharedFoundation/src/shared/CrashReportInformation.h new file mode 100644 index 00000000..0be9d899 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CrashReportInformation.h @@ -0,0 +1,36 @@ +// ====================================================================== +// +// CrashReportInformation.h +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CrashReportInformation_H +#define INCLUDED_CrashReportInformation_H + +// ====================================================================== + +class CrashReportInformation +{ +public: + + static void install(); + static void remove(); + + static DLLEXPORT void addStaticText(char const * format, ...); + + static void addDynamicText(char const * text); + static void removeDynamicText(char const * text); + + static char const * getEntry(int index); + +private: + CrashReportInformation(); + CrashReportInformation(CrashReportInformation const &); + CrashReportInformation & operator=(CrashReportInformation const &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/Crc.cpp b/engine/shared/library/sharedFoundation/src/shared/Crc.cpp new file mode 100644 index 00000000..4fddb3b8 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Crc.cpp @@ -0,0 +1,120 @@ +// ====================================================================== +// +// Crc.cpp +// +// adapted from Ross Williams' public domain crc code. +// +// Portions copyright 1998 Bootprint Entertainment +// Portions copyright 2002 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/Crc.h" + +#include "sharedFoundation/TemporaryCrcString.h" + +// ====================================================================== + +const uint32 Crc::crcNull = Crc::calculate (""); + +// ====================================================================== + +static const uint32 crctable[256] = +{ + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, + 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, + 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, + 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD, + 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, + 0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D, + 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95, + 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, + 0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, + 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, + 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, + 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, + 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692, + 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, + 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, + 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A, + 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, + 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, + 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B, + 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, + 0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B, + 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3, + 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, + 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, + 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, + 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, + 0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC, + 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654, + 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, + 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, + 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C, + 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4 +}; + +const uint32 CRC_INIT = 0xFFFFFFFF; + +const uint32 Crc::crcInit = CRC_INIT; + + +// ====================================================================== + +uint32 Crc::calculate(const char *string) +{ + uint32 crc; + + if (!string) + return 0; + + for (crc = CRC_INIT; *string; ++string) + crc = crctable[((crc>>24) ^ static_cast(*string)) & 0xFF] ^ (crc << 8); + + return (crc ^ CRC_INIT); +} + +// ---------------------------------------------------------------------- + +#if 0 + +uint32 Crc::calculateWithToLower(const char *string) +{ + uint32 crc; + + if (!string) + return 0; + + for (crc = CRC_INIT; *string; ++string) + crc = crctable[((crc>>24) ^ static_cast(tolower(*string))) & 0xFF] ^ (crc << 8); + + return (crc ^ CRC_INIT); +} + +#endif + +// ---------------------------------------------------------------------- + +uint32 Crc::calculate(const void *data, int length, uint32 initCrc) +{ + DEBUG_FATAL(!data, ("null data arg")); + + uint32 crc; + const byte *d = reinterpret_cast(data); + + for (crc = initCrc; length; --length, ++d) + crc = crctable[((crc>>24) ^ static_cast(*d)) & 0xFF] ^ (crc << 8); + + return (crc ^ initCrc); +} + +// ---------------------------------------------------------------------- + +uint32 Crc::normalizeAndCalculate(const char *string) +{ + return TemporaryCrcString(string, true).getCrc(); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/Crc.h b/engine/shared/library/sharedFoundation/src/shared/Crc.h new file mode 100644 index 00000000..91a8bff7 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Crc.h @@ -0,0 +1,35 @@ +// ====================================================================== +// +// Crc.h +// ala diaz +// +// copyright 1998 Bootprint Entertainment +// copyright 2002 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_Crc_H +#define INCLUDED_Crc_H + +// ====================================================================== + +// Functions that return the CRC value of either strings or blocks of data. + +class Crc +{ +public: + + // CRC of the empty string ("") + static const uint32 crcNull; + static const uint32 crcInit; + +public: + + static uint32 calculate(const char *string); + static uint32 calculate(const void *data, int len, uint32 initCrc = crcInit); + static uint32 normalizeAndCalculate(const char *string); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/CrcLowerString.cpp b/engine/shared/library/sharedFoundation/src/shared/CrcLowerString.cpp new file mode 100644 index 00000000..f973480b --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CrcLowerString.cpp @@ -0,0 +1,224 @@ +// ====================================================================== +// +// CrcLowerString.cpp +// Portions copyright 1998 Bootprint Entertainment +// Portions copyright 2002 Sony Online Entertainment +// All Rights Reserved +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/CrcLowerString.h" + +#include "sharedFoundation/TemporaryCrcString.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" + +// ====================================================================== + +const CrcLowerString CrcLowerString::empty("", PersistentCrcString::CC_true); + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(CrcLowerString, true, 0, 0, 0); + +// ====================================================================== +// Compute the CRC for a string +// +// Return value: +// +// The CRC for the specified string +// +// Remarks: +// +// This routine is provided so that other code can calculate the CRC for +// a CrcLowerString without having to create a CrcLowerString, enabling the user +// to call the compare(const char *, uint32) function. +// +// This routine currently simply calls CRC32::calculateWithToLower() on the specified +// string. + +uint32 CrcLowerString::calculateCrc(const char *newString) +{ + return TemporaryCrcString(newString, true).getCrc(); +} + +// ====================================================================== +/** + * Construct a new CrcLowerString, initialized with empty string. + * + * This function is provided to satisfy the requirements for a + * std::set and related STL containers. + */ + +CrcLowerString::CrcLowerString() +: PersistentCrcString() +{ +} + +// ---------------------------------------------------------------------- +// Construct a new CrcLowerString +// +// Remarks: +// +// The constructor will copy its argument into local memory, and then +// call CrcLowerString::calculateCrc() on the string to compute the CRC once. +// +// See Also: +// +// CrcLowerString::calculateCrc() + +CrcLowerString::CrcLowerString(const char *newString) +: PersistentCrcString(newString, true) +{ +} + +// ---------------------------------------------------------------------- +/** + * Construct a new CrcLowerString. + * + * The constructor will copy its argument into local memory. It will + * assume that the specified CRC is correct for the string. + * + * @param newString String to generate the CRC String from + * @param newCrc CRC for the string + */ + +CrcLowerString::CrcLowerString(const char *newString, uint32 newCrc) +: PersistentCrcString(newString, newCrc) +{ +} + +// ---------------------------------------------------------------------- +/** + * Copy construct a new CrcLowerString from an existing CrcLowerString. + * + * The constructor will copy its argument into local memory. + * + * This function normally would not be present since there shouldn't + * be much need to duplicate a crc-based string. However, the need + * arose to use a CrcLowerString as a key for a std::map, so the + * copy constructor was needed. + * + * @param rhs Existing CrcLowerString to copy + */ + +CrcLowerString::CrcLowerString(const CrcLowerString &rhs) +: PersistentCrcString(rhs) +{ +} + +// ---------------------------------------------------------------------- + +CrcLowerString::CrcLowerString(const char *newString, PersistentCrcString::ConstChar) +: PersistentCrcString(newString, PersistentCrcString::CC_true) +{ +} + +// ---------------------------------------------------------------------- +/** + * Destroy a CrcLowerString. + * + * This routine will free the resources associated with this CrcLowerString. + */ + +CrcLowerString::~CrcLowerString(void) +{ +} + +// ---------------------------------------------------------------------- +/** + * Set the new string for a CrcLowerString. + * + * This routine will delete the old string and reallocate the new string. + * It will also recompute the CRC for the string. + * + * @param newString The new value of the CrcLowerString + */ + +void CrcLowerString::setString(const char *newString) +{ + set(newString, true); +} + +// ---------------------------------------------------------------------- +/** + * Compare this CrcLowerString with a string and a CRC. + * + * The return value does not indicate the lexiographic ordering of the + * strings, because they are first compared using the CRC, and only if + * the CRC's match are they compared by strcmp(). + * + * @param otherString String to compare against + * @param otherCrc CRC of the string to compare against + * @return See Remarks section + */ + +int CrcLowerString::compare(const char *otherString, uint32 otherCrc) const +{ + NOT_NULL(otherString); + + const uint32 crc = getCrc(); + + if (crc < otherCrc) + return -1; + + if (crc > otherCrc) + return 1; + + char const *string = getString(); + for (int i = 0; ; ++i) + { + const int a = string[i]; + const int b = tolower(otherString[i]); + + if (!a || !b || a != b) + { + if (a < b) + return -1; + + if (a > b) + return 1; + + if (a == b) + return 0; + } + } +} + +// ---------------------------------------------------------------------- +/** + * Compare this CrcLowerString with another. + * + * The return value does not indicate the lexiographic ordering of the + * strings, because they are first compared using the CRC, and only if + * the CRC's match are they compared by strcmp(). + * + * @param otherString CrcLowerString to compare against + * @return See Remarks section + */ + +int CrcLowerString::compare(const CrcLowerString &otherString) const +{ + return compare(otherString.getString(), otherString.getCrc()); +} + +// ---------------------------------------------------------------------- +/** + * + * Perform an assignment of the CrcLowerString object. + * + * NOTE: use of this function during game runtime likely is an indication + * of a flawed design. This function was added to support tools where + * simplicity overrode efficiency concerns. + * + * @param rhs the source CrcLowerString object to copy into the left-hand-side object + */ + +CrcLowerString &CrcLowerString::operator =(const CrcLowerString &rhs) +{ + set(rhs.getString(), rhs.getCrc()); + return *this; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/CrcLowerString.h b/engine/shared/library/sharedFoundation/src/shared/CrcLowerString.h new file mode 100644 index 00000000..5398264f --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CrcLowerString.h @@ -0,0 +1,120 @@ +// ====================================================================== +// +// CrcLowerString.h +// Portions copyright 1998 Bootprint Entertainment +// Portions copyright 2002 Sony Online Entertainment +// All Rights Reserved +// +// ====================================================================== + +#ifndef INCLUDED_CrcLowerString_H +#define INCLUDED_CrcLowerString_H + +// ====================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedFoundation/PersistentCrcString.h" + +class MemoryBlockManager; + +// ====================================================================== +/** + * The CrcLowerString class is designed to permit faster case-insensitive + * string searching. The strings are first compared using CRC, and then + * compared using a lowercasing strcmp() call only if the CRC's match. + * + * Note that sorting strings by the return value of compare() will not + * sorted lexiographic manner, because the strings are first compared by + * their CRC which does not indicate lexiographic ordering of the strings. + * Even so, CRC strings may still be stored and searched upon by various + * high-performance search algorithms like a binary searches. + */ + +class CrcLowerString : public PersistentCrcString +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + +public: + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + struct LessPtrComparator + { + //-- returns true if a is less than b + bool operator ()(const CrcLowerString * a, const CrcLowerString * b) const; + }; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + /** + * Provide a predicate that compares CrcLowerString instances based on + * the underlying string lexicographical comparison (case sensitive). + * + * The standard CrcLowerString operator < compares efficiently based + * on the Crc value. Typically this is what you want, for presumably + * the user is using CrcLowerString instances to speed up comparisons. + * However, in the case where you want to sort CrcLowerString instances + * based on the lexicographical (ABC) ordering, use this function object. + * Sorts identically to strcmp(). + * + * Can be used as a predicate object (functor) in STL routines. + */ + + struct LessAbcOrderReferenceComparator + { + bool operator ()(const CrcLowerString &a, const CrcLowerString &b) const; + }; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +public: + + static uint32 calculateCrc(const char *newString); + +public: + + CrcLowerString(); + explicit CrcLowerString(const char *newString); + CrcLowerString(const char *newString, uint32 newCrc); + CrcLowerString(const CrcLowerString &rhs); + virtual ~CrcLowerString(void); + + void setString(const char *newString); + + int compare(const char *otherString, uint32 otherCrc) const; + int compare(const CrcLowerString &otherString) const; + + CrcLowerString &operator =(const CrcLowerString &rhs); + +public: + + /** + * A CrcLowerString representation of the empty string (i.e. ""). + */ + static const CrcLowerString empty; + +protected: + + CrcLowerString(const char *newString, PersistentCrcString::ConstChar); +}; + +// ====================================================================== +// class CrcLowerString::LessPtrComparator +// ====================================================================== + +inline bool CrcLowerString::LessPtrComparator::operator () (const CrcLowerString * a, const CrcLowerString * b) const +{ + return *a < *b; +} + +// ====================================================================== +// class CrcLowerString::LessAbcOrderReferenceComparator +// ====================================================================== + +inline bool CrcLowerString::LessAbcOrderReferenceComparator::operator ()(const CrcLowerString &a, const CrcLowerString &b) const +{ + return (strcmp(a.getString(), b.getString()) < 0); +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/CrcString.cpp b/engine/shared/library/sharedFoundation/src/shared/CrcString.cpp new file mode 100644 index 00000000..c833f440 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CrcString.cpp @@ -0,0 +1,157 @@ +// ====================================================================== +// +// CrcString.cpp +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/CrcString.h" + +#include "sharedFoundation/Crc.h" + +// ====================================================================== +/** + * Normalize a string. + * + * This function will clean up a string. All alpha characters will be + * changed to lower case, all backslashes will be converted to forward + * slashes, all dots following a slash will be removed, and consecutive + * slashes will be converted into a single slash. + */ + +void CrcString::normalize(char *output, const char *input) +{ + bool previousIsSlash = true; + for ( ; *input; ++input) + { + const char c = *input; + if (c == '\\' || c == '/') + { + if (!previousIsSlash) + { + // convert all backslashes to forward slashes and disallow multiple slashes in a row + *(output++) = '/'; + previousIsSlash = true; + } + } + else + if (c == '.') + { + // disallow dots after slashes. this will also handle multiple dots, and slashes following the dots + if (!previousIsSlash) + *(output++) = '.'; + } + else + { + // lowercase all other characters + *(output++) = static_cast(tolower(c)); + previousIsSlash = false; + } + } + + *output = '\0'; +} + +// ====================================================================== + +CrcString::CrcString() +: m_crc(Crc::crcNull) +{ +} + +// ---------------------------------------------------------------------- + +CrcString::CrcString(uint32 crc) +: m_crc(crc) +{ +} + +// ---------------------------------------------------------------------- + +CrcString::~CrcString() +{ +} + +// ---------------------------------------------------------------------- + +void CrcString::calculateCrc() +{ + m_crc = Crc::calculate(getString()); +} + +// ---------------------------------------------------------------------- + +bool CrcString::isEmpty() const +{ + const char * const str = getString (); + return !str || str[0] == '\0'; +} + +// ---------------------------------------------------------------------- + +void CrcString::set(CrcString const & rhs) +{ + if (this == &rhs) + return; + + if (rhs.isEmpty()) + clear(); + else + set(rhs.getString(), rhs.getCrc()); +} + +// ---------------------------------------------------------------------- + +bool CrcString::operator ==(CrcString const & rhs) const +{ + return !(*this != rhs); +} + +// ---------------------------------------------------------------------- + +bool CrcString::operator !=(CrcString const & rhs) const +{ + return m_crc != rhs.m_crc || strcmp(getString(), rhs.getString()) != 0; +} + +// ---------------------------------------------------------------------- + +bool CrcString::operator < (CrcString const & rhs) const +{ + if (m_crc < rhs.m_crc) + return true; + if (m_crc > rhs.m_crc) + return false; + + return strcmp(getString(), rhs.getString()) < 0; +} + +// ---------------------------------------------------------------------- + +bool CrcString::operator <=(CrcString const & rhs) const +{ + return !(*this > rhs); +} + +// ---------------------------------------------------------------------- + +bool CrcString::operator > (CrcString const & rhs) const +{ + if (m_crc > rhs.m_crc) + return true; + if (m_crc < rhs.m_crc) + return false; + + return strcmp(getString(), rhs.getString()) > 0; +} + +// ---------------------------------------------------------------------- + +bool CrcString::operator >=(CrcString const & rhs) const +{ + return !(*this < rhs); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/CrcString.h b/engine/shared/library/sharedFoundation/src/shared/CrcString.h new file mode 100644 index 00000000..16e3b9aa --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CrcString.h @@ -0,0 +1,66 @@ +// ====================================================================== +// +// CrcString.h +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CrcString_H +#define INCLUDED_CrcString_H + +// ====================================================================== + +class CrcString +{ +public: + + static void normalize(char *output, const char *input); + +public: + + virtual ~CrcString(); + + bool isEmpty() const; + uint32 getCrc() const; + + bool operator ==(CrcString const & rhs) const; + bool operator !=(CrcString const & rhs) const; + bool DLLEXPORT operator < (CrcString const & rhs) const; + bool operator <=(CrcString const & rhs) const; + bool operator > (CrcString const & rhs) const; + bool operator >=(CrcString const & rhs) const; + + virtual char const * getString() const = 0; + + virtual void clear() = 0; + virtual void set(char const * string, bool applyNormalize) = 0; + virtual void set(char const * string, uint32 crc) = 0; + void set(CrcString const & rhs); + +protected: + + CrcString(); + CrcString(uint32 crc); + void calculateCrc(); + +private: + + CrcString & operator =(CrcString const &); + CrcString(CrcString const &); + +protected: + + uint32 m_crc; +}; + +// ====================================================================== + +inline uint32 CrcString::getCrc() const +{ + return m_crc; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/CrcStringTable.cpp b/engine/shared/library/sharedFoundation/src/shared/CrcStringTable.cpp new file mode 100644 index 00000000..206f0dea --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CrcStringTable.cpp @@ -0,0 +1,195 @@ +// ====================================================================== +// +// CrcStringTable.cpp +// Copyright 2003, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/CrcStringTable.h" + +#include "sharedFile/Iff.h" +#include "sharedFoundation/Crc.h" +#include "sharedFoundation/ConstCharCrcString.h" + +#include + +// ====================================================================== + +namespace CrcStringTableNamespace +{ + const Tag TAG_CSTB = TAG(C,S,T,B); + const Tag TAG_CRCT = TAG(C,R,C,T); + const Tag TAG_STNG = TAG(S,T,N,G); + const Tag TAG_STRT = TAG(S,T,R,T); +} +using namespace CrcStringTableNamespace; + +// ====================================================================== + +CrcStringTable::CrcStringTable() +: + m_numberOfEntries(0), + m_crcTable(NULL), + m_stringsOffsetTable(NULL), + m_strings(NULL) +{ +} + +// ---------------------------------------------------------------------- + +CrcStringTable::CrcStringTable(char const * fileName) +: + m_numberOfEntries(0), + m_crcTable(NULL), + m_stringsOffsetTable(NULL), + m_strings(NULL) +{ + load(fileName); +} + +// ---------------------------------------------------------------------- + +CrcStringTable::~CrcStringTable() +{ + delete [] m_crcTable; + delete [] m_stringsOffsetTable; + delete [] m_strings; +} + +//---------------------------------------------------------------------- + +void CrcStringTable::load(char const * fileName) +{ + Iff iff; + bool result = iff.open(fileName, true); + if(!result) + { + if(fileName) + DEBUG_WARNING(true, ("Could not load CrcStringTable %s", fileName)); + else + DEBUG_WARNING(true, ("Could not load CrcStringTable, NULL file given")); + return; + } + + load(iff); + +#ifdef _DEBUG + for (int i = 0; i < m_numberOfEntries; ++i) + { + const char *string = m_strings + m_stringsOffsetTable[i]; + uint32 crc = Crc::calculate(string); + DEBUG_FATAL(m_crcTable[i] != crc, ("Crcs do not match for %s: %08x %08x", string, m_crcTable[i], crc)); + } +#endif +} + +// ---------------------------------------------------------------------- + +void CrcStringTable::load(Iff &iff) +{ + iff.enterForm(TAG_CSTB); + + switch (iff.getCurrentName()) + { + case TAG_0000: + load_0000(iff); + break; + + default: + { + char buffer[256]; + iff.formatLocation(buffer, sizeof(buffer)); + DEBUG_FATAL(true, ("Unknown crc string table version in %s", buffer)); + } + break; + } + + iff.exitForm(TAG_CSTB); +} + +// ---------------------------------------------------------------------- + +void CrcStringTable::load_0000(Iff &iff) +{ + iff.enterForm(TAG_0000); + + iff.enterChunk(TAG_DATA); + m_numberOfEntries = iff.read_int32(); + iff.exitChunk(TAG_DATA); + + iff.enterChunk(TAG_CRCT); + m_crcTable = iff.read_uint32(m_numberOfEntries); + iff.exitChunk(TAG_CRCT); + + iff.enterChunk(TAG_STRT); + m_stringsOffsetTable = iff.read_int32(m_numberOfEntries); + iff.exitChunk(TAG_STRT); + + iff.enterChunk(TAG_STNG); + m_strings = iff.readRest_char(); + iff.exitChunk(TAG_STNG); + + for (int i = 0; i < m_numberOfEntries; ++i) + m_crcTable[i] = Crc::calculate(m_strings + m_stringsOffsetTable[i]); + + iff.exitForm(TAG_0000); +} + +// ---------------------------------------------------------------------- + +ConstCharCrcString const CrcStringTable::lookUp(const char * string) const +{ + return lookUp(Crc::calculate(string)); +} + +// ---------------------------------------------------------------------- + +ConstCharCrcString const CrcStringTable::lookUp(uint32 crc) const +{ + int low = 0; + int high = m_numberOfEntries - 1; + + while (low <= high) + { + int const mid = (low + high) / 2; + uint32 const entry = m_crcTable[mid]; + if (crc == entry) + return ConstCharCrcString(m_strings + m_stringsOffsetTable[mid], crc); + else + if (crc > entry) + low = mid + 1; + else + high = mid - 1; + } + + return ConstCharCrcString("", 0); +} + +// ---------------------------------------------------------------------- + +void CrcStringTable::getAllStrings(stdvector::fwd & strings) const +{ + strings.reserve(strings.size() + m_numberOfEntries); + + for (int i = 0; i < m_numberOfEntries; ++i) + strings.push_back(m_strings + m_stringsOffsetTable[i]); +} + +// ---------------------------------------------------------------------- + +int CrcStringTable::getNumberOfStrings() const +{ + return m_numberOfEntries; +} + +// ---------------------------------------------------------------------- + +ConstCharCrcString const CrcStringTable::getString(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfStrings()); + return ConstCharCrcString(m_strings + m_stringsOffsetTable[index]); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/CrcStringTable.h b/engine/shared/library/sharedFoundation/src/shared/CrcStringTable.h new file mode 100644 index 00000000..16e7d0e2 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/CrcStringTable.h @@ -0,0 +1,55 @@ +// ====================================================================== +// +// CrcStringTable.h +// Copyright 2003, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CrcStringTable_H +#define INCLUDED_CrcStringTable_H + +// ====================================================================== + +class ConstCharCrcString; +class Iff; + +// ====================================================================== + +class CrcStringTable +{ +public: + + CrcStringTable(); + CrcStringTable(const char * fileName); + ~CrcStringTable(); + + void load(const char * fileName); + void load(Iff &iff); + + ConstCharCrcString const lookUp(const char * string) const; + ConstCharCrcString const lookUp(uint32 crc) const; + + void getAllStrings(stdvector::fwd & strings) const; + + int getNumberOfStrings() const; + ConstCharCrcString const getString(int index) const; + +private: + + CrcStringTable(CrcStringTable const &); + CrcStringTable & operator =(CrcStringTable const &); + + void load_0000(Iff &iff); + +private: + + int m_numberOfEntries; + uint32 * m_crcTable; + int32 * m_stringsOffsetTable; + char * m_strings; +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/DataResource.cpp b/engine/shared/library/sharedFoundation/src/shared/DataResource.cpp new file mode 100644 index 00000000..b02dbe8e --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/DataResource.cpp @@ -0,0 +1,69 @@ +// ====================================================================== +// +// DataResource.cpp - base class for template and other classes. +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/DataResource.h" + +#include "sharedFoundation/PersistentCrcString.h" + +// ====================================================================== + +DataResource::DataResource(const char* const filename) : + m_name(filename, true), + m_referenceCount(0) +{ +} + +// ---------------------------------------------------------------------- + +DataResource::~DataResource() +{ +} + +// ---------------------------------------------------------------------- + +const char *DataResource::getName() const +{ + return m_name.getString(); +} + +// ---------------------------------------------------------------------- + +int DataResource::getReferenceCount() const +{ + return m_referenceCount; +} + +// ---------------------------------------------------------------------- + +void DataResource::addReference() const +{ + ++m_referenceCount; +} + +// ---------------------------------------------------------------------- + +void DataResource::releaseReference() const +{ + DEBUG_FATAL(m_referenceCount <= 0, ("DataResource::releaseReference - reference count is already 0\n")); + if (m_referenceCount > 0 && --m_referenceCount == 0) + release(); +} + +// ---------------------------------------------------------------------- + +void DataResource::preloadAssets () const +{ +} + +// ---------------------------------------------------------------------- + +void DataResource::garbageCollect () const +{ +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/DataResource.h b/engine/shared/library/sharedFoundation/src/shared/DataResource.h new file mode 100644 index 00000000..93927248 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/DataResource.h @@ -0,0 +1,62 @@ +// ====================================================================== +// +// DataResource.h - base class for template and other classes. +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_DataResource_H +#define INCLUDED_DataResource_H + +// ====================================================================== + +#include "sharedFoundation/PersistentCrcString.h" + +// ====================================================================== + +class DataResource +{ +public: + + explicit DataResource(const char* filename); + virtual ~DataResource() = 0; + + const char *getName() const; + const CrcString &getCrcName() const; + + int getReferenceCount() const; + virtual void addReference() const; + virtual void releaseReference() const; + + virtual void preloadAssets () const; + virtual void garbageCollect () const; + +protected: + + virtual void release() const = 0; + +private: + + DataResource (); + DataResource(const DataResource &source); + DataResource &operator =(const DataResource &source); + +private: + + // resource name + const PersistentCrcString m_name; + + // how many times this resource has been loaded + mutable int m_referenceCount; +}; + +// ---------------------------------------------------------------------- + +inline const CrcString &DataResource::getCrcName() const +{ + return m_name; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/DataResourceList.h b/engine/shared/library/sharedFoundation/src/shared/DataResourceList.h new file mode 100644 index 00000000..b51f95c8 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/DataResourceList.h @@ -0,0 +1,423 @@ +//======================================================================== +// +// DataResourceList.h - factory method for creating classes derived from +// DataResource. +// +// copyright 2001 Sony Online Entertainment +// +//======================================================================== + +#ifndef _INCLUDED_DataResourceList_H +#define _INCLUDED_DataResourceList_H + +#include "sharedDebug/DataLint.h" +#include "sharedFile/Iff.h" +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedFoundation/CrcString.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/LessPointerComparator.h" +#include "sharedFoundation/Tag.h" +#include "sharedFoundation/TemporaryCrcString.h" + +#include +#include + +//======================================================================== + +// T should be derived from class DataResource +template +class DataResourceList +{ +public: + // DataResource registration function + typedef T * (*CreateDataResourceFunc)(const std::string & filename); + static void registerTemplate(Tag id, CreateDataResourceFunc createFunc); + + // functions to create a new DataResource + static T * fetch(Tag id); + static const T * fetch(Iff & source); + static const T * fetch(const CrcString & filename); + static const T * fetch(const std::string & filename); + static const T * fetch(const char * filename); + + static const bool isLoaded(const std::string & fileName); + + // function to reload a data resource with new data + static T * reload(Iff & source); + + // functions to reassign Tag->DataResource binding + static CreateDataResourceFunc assignBinding(Tag id, CreateDataResourceFunc createFunc); + static CreateDataResourceFunc removeBinding(Tag tag); + + static void install(void); + static void remove(void); + + // function to delete a DataResource + static void release(const T & dataResource); + + static void logLoadedResources(char const * classType); + + static void garbageCollect (); + +private: + + typedef std::map CreateDataResourceMap; + static CreateDataResourceMap *ms_bindings; + + typedef std::map LoadedDataResourceMap; + static LoadedDataResourceMap *ms_loaded; + +private: + // no copying templates + DataResourceList(void); + DataResourceList(const DataResourceList &source); + DataResourceList & operator =(const DataResourceList &source); +}; + +//---------------------------------------------------------------------- + +/** + * Sets up the maps to keep track of resources. + */ +template +inline void DataResourceList::install() +{ + if (ms_bindings == NULL) + { + ms_bindings = new CreateDataResourceMap(); + ms_loaded = new LoadedDataResourceMap(); + + ExitChain::add (remove, "DataResourceList::remove"); + } +} // DataResourceList::install + +//---------------------------------------------------------------------- + +/** + * Frees up memory associated with the list, and checks for resources still + * allocated. + */ +template +inline void DataResourceList::remove(void) +{ + if (ms_loaded != NULL) + { +#ifdef _DEBUG + if (!ms_loaded->empty()) + { + DEBUG_REPORT_LOG (true, ("Data resources still allocated:\n")); + for (typename LoadedDataResourceMap::const_iterator i = ms_loaded->begin (); i != ms_loaded->end (); ++i) + { + const T * const dataResource = (*i).second; + const int users = dataResource->getReferenceCount (); + const char* const name = dataResource->getName (); + DEBUG_REPORT_LOG (true, (" %3d %s\n", users, name)); + UNREF (users); + UNREF (name); + } + + DEBUG_WARNING (true, ("Data resources still allocated")); + return; + } +#endif // _DEBUG + + delete ms_loaded; + ms_loaded = NULL; + } + + if (ms_bindings != NULL) + { + delete ms_bindings; + ms_bindings = NULL; + } +} // DataResourceList::remove + +//---------------------------------------------------------------------- + +/** + * Maps a template Tag id to a function used to create a template. + * + * @param createFunc template creation function + * @param id id of the template + */ +template +inline void DataResourceList::registerTemplate(Tag id, + CreateDataResourceFunc createFunc) +{ + if (ms_bindings == NULL) + install(); + +#ifdef _DEBUG + // Added to help debug + char text[256]; + ConvertTagToString(id, text); +#endif // _DEBUG + + // check if that id was already registered and print a warning if it was + if (ms_bindings->find(id) != ms_bindings->end()) + { + char buffer[5]; + ConvertTagToString(id, buffer); + DEBUG_WARNING(true, ("DataResourceList::registerTemplate: re-installing tag %s!", buffer)); + } + (*ms_bindings)[id] = createFunc; +} // DataResourceList::registerTemplate + +//---------------------------------------------------------------------- + +/** + * Changes the default tag->create function binding. + * + * @param id the tag to change + * @param createFunc the creation function to associate with the id + * + * @return the old creation function associated with the tag + */ +template +inline typename DataResourceList::CreateDataResourceFunc DataResourceList::assignBinding( + Tag id, CreateDataResourceFunc createFunc) +{ + NOT_NULL(ms_bindings); + + CreateDataResourceFunc oldFunc = (*ms_bindings)[id]; + (*ms_bindings)[id] = createFunc; + return oldFunc; +} // DataResourceList::assignBinding + +//---------------------------------------------------------------------- + +/** + * Removes the default tag->create function binding. + * + * @param id the tag to remove + * + * @return the old creation function associated with the tag + */ +template +inline typename DataResourceList::CreateDataResourceFunc DataResourceList::removeBinding( + Tag id) +{ + NOT_NULL(ms_bindings); + + CreateDataResourceFunc oldFunc = (*ms_bindings)[id]; + ms_bindings->erase(id); + return oldFunc; +} // DataResourceList::removeBinding + +//---------------------------------------------------------------------- + +template +inline const T * DataResourceList::fetch(const std::string & filename) +{ + return fetch(TemporaryCrcString(filename.c_str(), true)); +} // DataResourceList::fetch(const std::string &) + +//---------------------------------------------------------------------- + +template +inline const T * DataResourceList::fetch(const char * filename) +{ + return fetch(TemporaryCrcString(filename, true)); +} // DataResourceList::fetch(const char *) + +//---------------------------------------------------------------------- + +/** + * Creates a data resource from a registered data resource id. The caller is + * responsible for deleting the data resource. + * + * @param id the iff tag for the data resource + * + * @return the blank data resource + */ +template +inline T * DataResourceList::fetch(Tag id) +{ + NOT_NULL(ms_bindings); + + typename CreateDataResourceMap::iterator iter = ms_bindings->find(id); + if (iter == ms_bindings->end()) + return NULL; + + return (*(*iter).second)(""); +} // DataResourceList::fetch(Tag) + +//---------------------------------------------------------------------- + +/** + * Loads a data resource from an iff file/buffer. + * + * @param source iff source to read from + * + * @return the data resource + */ +template +inline const T * DataResourceList::fetch(Iff &source) +{ + NOT_NULL(ms_bindings); + +#ifdef _DEBUG + DataLint::pushAsset(source.getFileName()); +#endif // _DEBUG + + // read the 1st form; based on the form id, create the template + Tag id = source.getCurrentName(); + typename CreateDataResourceMap::iterator createIter = ms_bindings->find(id); + if (createIter == ms_bindings->end()) + { + char buffer[5]; + ConvertTagToString(id, buffer); + DEBUG_WARNING(true, ("DataResourceList::fetch Iff: trying to fetch resource for unknown tag %s!", buffer)); + return NULL; + } + + T *newDataResource = (*(*createIter).second)(source.getFileName()); + if (newDataResource != NULL) + { + // initialize the data resource + newDataResource->loadFromIff(source); + } + +#ifdef _DEBUG + DataLint::popAsset(); +#endif // _DEBUG + + return newDataResource; +} // DataResourceList::fetch(Iff &) + +//---------------------------------------------------------------------- + +/** + * Loads a data resource from an iff file. + * + * @param filename the file to load from + * + * @return the data resource + */ +template +inline const T * DataResourceList::fetch(const CrcString &filename) +{ + NOT_NULL(ms_loaded); + + // see if we already have loaded the template + typename LoadedDataResourceMap::iterator iter = ms_loaded->find(&filename); + if (iter != ms_loaded->end()) + { + (*iter).second->addReference(); + return (*iter).second; + } + + // load the template + Iff iff; + if (!iff.open(filename.getString(), true)) + return NULL; + + // put the template in the loaded list + const T * const newDataResource = fetch(iff); + if (newDataResource != NULL) + { + newDataResource->addReference(); + ms_loaded->insert(std::make_pair(&newDataResource->getCrcName (), newDataResource)); + } + + // clean up + iff.close(); + return newDataResource; +} + +//---------------------------------------------------------------------- + +/** + * Checks the reference count of a resource, if it is 0, deletes it. + * + * @param dataResource the data resource to release + */ +template +inline void DataResourceList::release(const T & dataResource) +{ + NOT_NULL(ms_loaded); + + if (ms_loaded != NULL && dataResource.getReferenceCount() == 0) + { + typename LoadedDataResourceMap::iterator iter = ms_loaded->find(&dataResource.getCrcName()); + if (iter != ms_loaded->end()) + { + const T * const temp = (*iter).second; + (*iter).second = NULL; + ms_loaded->erase(iter); + delete temp; + } + } +} // DataResourceList::release + +//---------------------------------------------------------------------- + +/** + * Reloads a data resource from an iff file/buffer. + * + * @param source iff source to read from + * + * @return the data resource + */ +template +inline T * DataResourceList::reload(Iff &source) +{ + NOT_NULL(ms_loaded); + + const TemporaryCrcString sourceCrcString (source.getFileName(), true); + typename LoadedDataResourceMap::iterator iter = ms_loaded->find(&sourceCrcString); + if (iter == ms_loaded->end()) + { + DEBUG_WARNING(true, ("DataResourceList::reload: trying to reload unloaded resource %s!", source.getFileName())); + return NULL; + } + + T * const dataResource = const_cast((*iter).second); + if (dataResource != NULL) + { + // initialize the data resource + dataResource->loadFromIff(source); + } + return dataResource; +} // DataResourceList::reload(Iff &) + +//----------------------------------------------------------------------- + +template +inline const bool DataResourceList::isLoaded(const std::string & source) +{ + NOT_NULL(ms_loaded); + const TemporaryCrcString sourceCrcString (source.c_str (), true); + typename LoadedDataResourceMap::iterator iter = ms_loaded->find(&sourceCrcString); + return (iter != ms_loaded->end()); +} + +//----------------------------------------------------------------------- + +template +void DataResourceList::logLoadedResources(char const * classType) +{ + UNREF(classType); //necessary for release build + typename LoadedDataResourceMap::iterator const iterEnd = ms_loaded->end(); + DEBUG_REPORT_LOG_PRINT(true, ("Begin log of loaded %s\n", classType)); + + for (typename LoadedDataResourceMap::iterator iter = ms_loaded->begin(); iter != iterEnd; ++iter) + DEBUG_REPORT_LOG_PRINT(true, (" %d %s\n", iter->second->getReferenceCount(), iter->second->getName())); + + DEBUG_REPORT_LOG_PRINT(true, ("End log of loaded %s\n", classType)); +} + +//---------------------------------------------------------------------- + +template +void DataResourceList::garbageCollect () +{ + typename LoadedDataResourceMap::iterator end = ms_loaded->end (); + typename LoadedDataResourceMap::iterator iter = ms_loaded->begin (); + for (; iter != end; ++iter) + const_cast (iter->second)->garbageCollect (); +} + +//---------------------------------------------------------------------- + +#endif // _INCLUDED_DataResourceList_H diff --git a/engine/shared/library/sharedFoundation/src/shared/DebugInfoManager.cpp b/engine/shared/library/sharedFoundation/src/shared/DebugInfoManager.cpp new file mode 100644 index 00000000..13dea346 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/DebugInfoManager.cpp @@ -0,0 +1,127 @@ +// ====================================================================== +// +// DebugInfoManager.cpp +// Copyright 2005 Sony Online Entertainment Inc +// All Rights Reserved +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/DebugInfoManager.h" + +#include "sharedMath/Transform.h" +#include "sharedMath/Vector.h" + +#include "UnicodeUtils.h" + +#include + +// ====================================================================== + +namespace DebugInfoManagerNamespace +{ + char ms_buffer[256]; + + Unicode::String const cms_emptyQuotes(Unicode::narrowToWide("\"\"")); +} +using namespace DebugInfoManagerNamespace; + +// ====================================================================== + +void DebugInfoManager::addProperty(DebugInfoManager::PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, int const propertyValue) +{ + _itoa(propertyValue, ms_buffer, 10); + addProperty(propertyMap, section, propertyName, Unicode::narrowToWide(ms_buffer)); +} + +// ---------------------------------------------------------------------- + +void DebugInfoManager::addProperty(DebugInfoManager::PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, float const propertyValue) +{ + sprintf(ms_buffer, "%.2f", propertyValue); + addProperty(propertyMap, section, propertyName, Unicode::narrowToWide(ms_buffer)); +} + +// ---------------------------------------------------------------------- + +void DebugInfoManager::addProperty(DebugInfoManager::PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, unsigned int const propertyValue) +{ + sprintf(ms_buffer, "%u", propertyValue); + addProperty(propertyMap, section, propertyName, Unicode::narrowToWide(ms_buffer)); +} + +// ---------------------------------------------------------------------- + +void DebugInfoManager::addProperty(DebugInfoManager::PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, unsigned long const propertyValue) +{ + sprintf(ms_buffer, "%lu", propertyValue); + addProperty(propertyMap, section, propertyName, Unicode::narrowToWide(ms_buffer)); +} + +// ---------------------------------------------------------------------- + +void DebugInfoManager::addProperty(DebugInfoManager::PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, bool const propertyValue) +{ + addProperty(propertyMap, section, propertyName, Unicode::narrowToWide(propertyValue ? "true" : "false")); +} + +// ---------------------------------------------------------------------- + +void DebugInfoManager::addProperty(DebugInfoManager::PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, std::string const & propertyValue) +{ + addProperty(propertyMap, section, propertyName, Unicode::narrowToWide(propertyValue)); +} + +// ---------------------------------------------------------------------- + +void DebugInfoManager::addProperty(DebugInfoManager::PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, char const * const propertyValue) +{ + if(propertyValue) + addProperty(propertyMap, section, propertyName, Unicode::narrowToWide(propertyValue)); + else + addProperty(propertyMap, section, propertyName, Unicode::narrowToWide("")); +} + +// ---------------------------------------------------------------------- + +void DebugInfoManager::addProperty(DebugInfoManager::PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, Vector const & propertyValue) +{ + sprintf(ms_buffer, "(%.2f, %.2f, %.2f)", propertyValue.x, propertyValue.y, propertyValue.z); + addProperty(propertyMap, section, propertyName, Unicode::narrowToWide(ms_buffer)); +} + +// ---------------------------------------------------------------------- + +void DebugInfoManager::addProperty(DebugInfoManager::PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, Transform const & propertyValue) +{ + Transform::matrix_t const & matrix = propertyValue.getMatrix(); + sprintf(ms_buffer, "\n\t\t[[%.2f, %.2f, %.2f, %.2f]\n\t\t[%.2f, %.2f, %.2f, %.2f]\n\t\t[%.2f, %.2f, %.2f, %.2f]]", matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3], matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3], matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3]); + addProperty(propertyMap, section, propertyName, Unicode::narrowToWide(ms_buffer)); +} + +// ---------------------------------------------------------------------- + +void DebugInfoManager::addProperty(DebugInfoManager::PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, Unicode::String const & propertyValue) +{ + //okay to create entry if the section doesn't exist; + PropertySection sectionMap = propertyMap[section]; + + if(sectionMap.find(propertyName) == sectionMap.end()) + { + if(!propertyValue.empty()) + sectionMap[propertyName] = propertyValue; + else + sectionMap[propertyName] = cms_emptyQuotes; + } + else + { + if(!propertyValue.empty()) + sectionMap[propertyName + "_a"] = propertyValue; + else + sectionMap[propertyName + "_a"] = cms_emptyQuotes; + } + + propertyMap[section] = sectionMap; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/DebugInfoManager.h b/engine/shared/library/sharedFoundation/src/shared/DebugInfoManager.h new file mode 100644 index 00000000..757673a9 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/DebugInfoManager.h @@ -0,0 +1,46 @@ +// ====================================================================== +// +// DebugInfoManager.h +// Copyright 2004 Sony Online Entertainment Inc +// All Rights Reserved +// +// ====================================================================== + +#ifndef INCLUDED_DebugInfoManager_H +#define INCLUDED_DebugInfoManager_H + +// ====================================================================== + +class Transform; +class Vector; + +// ====================================================================== + +class DebugInfoManager +{ +public: + typedef stdmap::fwd PropertySection; + typedef stdmap::fwd PropertyMap; + +public: + static void addProperty(PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, int propertyValue); + static void addProperty(PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, unsigned int propertyValue); + static void addProperty(PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, unsigned long propertyValue); + static void addProperty(PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, float propertyValue); + static void addProperty(PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, bool propertyValue); + static void addProperty(PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, std::string const & propertyValue); + static void addProperty(PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, char const * propertyValue); + static void addProperty(PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, Transform const & propertyValue); + static void addProperty(PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, Vector const & propertyValue); + static void addProperty(PropertyMap & propertyMap, std::string const & section, std::string const & propertyName, Unicode::String const & propertyValue); + +private: + DebugInfoManager(); + ~DebugInfoManager(); + DebugInfoManager(DebugInfoManager const &); + DebugInfoManager & operator=(DebugInfoManager const &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/ExitChain.cpp b/engine/shared/library/sharedFoundation/src/shared/ExitChain.cpp new file mode 100644 index 00000000..3b1fb1bf --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/ExitChain.cpp @@ -0,0 +1,271 @@ +// ====================================================================== +// +// ExitChain.cpp +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/ExitChain.h" + +#include "sharedDebug/DebugFlags.h" +#include "sharedFoundation/PerThreadData.h" + +// ====================================================================== + +#ifdef _DEBUG +bool ExitChain::ms_debugReportFlag; +bool ExitChain::ms_debugLogFlag; +#endif + +// ====================================================================== + +void ExitChain::install() +{ +#ifdef _DEBUG + DebugFlags::registerFlag(ms_debugReportFlag, "SharedFoundation", "reportExitChain", &ExitChain::debugReport); + DebugFlags::registerFlag(ms_debugLogFlag, "SharedFoundation", "logExitChain"); +#endif +} + +// ---------------------------------------------------------------------- + +void ExitChain::quit() +{ + run(); +} + +// ====================================================================== +// Check if the ExitChain is running or not +// +// Return value: +// +// True if ExitChain::quit() or ExitChain::fatal() has been called +// +// Remarks: +// +// If the result is true, the application is terminating. +// +// See Also: +// +// ExitChain::quit(), ExitChain:fatal(), ExitChain::isFataling() + +bool ExitChain::isRunning(void) +{ + return PerThreadData::getExitChainRunning(); +} + +// ---------------------------------------------------------------------- +/** + * Check if the ExitChain is fataling or not. + * + * If the ExitChain is fataling, minimal cleanup work should be done to restore the users system to a usable + * state. If this routine returns true, ExitChain::isRunning() will also return true. + * + * @return True if the ExitChain::fatal() has been called + * @see ExitChain::isRunning() + */ + +bool ExitChain::isFataling(void) +{ + return PerThreadData::getExitChainFataling(); +} + +// ---------------------------------------------------------------------- +/** + * Add a function to the ExitChain to be called when the game exits. + * + * The order of the function calls depends on priority and the order in which they are added to the + * ExitChain. See the main ExitChain documentation for more details. + * + * @param function The function to call + * @param debugName Text description of the function (for debugging purposes only) + * @param priority Priority of the function for proper shutdown ordering + * @param critical Flag to indicate the function should be called even when fataling + * @see ExitChain + */ + +void ExitChain::add(Function function, const char *debugName, int priority, bool critical) +{ +#ifdef _DEBUG + //-- Verify that the entry doesn't already exist in the ExitChain + { + for (Entry * entry = PerThreadData::getExitChainFirstEntry(); entry; entry = entry->next) + { + if (entry->function == function) + { + DEBUG_WARNING(true, ("ExitChain::add: %s is already in the list", debugName)); + entry->m_callStack.debugLog(); + } + } + } +#endif + + Entry *entry, *back, *front; + + // create the new ExitChain entry + entry = new Entry; + entry->function = function; + entry->name = debugName; + entry->priority = priority; + entry->critical = critical; +#ifdef _DEBUG + entry->m_callStack.sample(); +#endif + + // linked list traversal with a back pointer + for (back = NULL, front = PerThreadData::getExitChainFirstEntry(); front && front->priority > priority; back = front, front = front->next) + ; + + // hook it into the linked list + entry->next = front; + if (back) + back->next = entry; + else + PerThreadData::setExitChainFirstEntry(entry); +} + +// ---------------------------------------------------------------------- +/** + * Remove a function from the ExitChain. + * + * The ExitChain will automatically remove a function from the ExitChain when it calls the function, so an + * exit function should not attempt to remove itself from the ExitChain. + * + * Calling this routine with a NULL pointer will cause this routine to call Fatal in debug compilations. + * + * Calling this routine with a function that is not on the ExitChain will cause this routine to call + * Fatal in debug compilations. + * + * @param function The function to remove from the ExitChain list + */ + +void ExitChain::remove(Function function) +{ + Entry *back, *front; + + if (function == NULL) + { + DEBUG_FATAL(true, ("ExitChain::remove NULL function")); + return; //lint !e527 // Warning -- Unreachable + } + + // linked list traversal with a back pointer + for (back = NULL, front = PerThreadData::getExitChainFirstEntry(); front && front->function != function; back = front, front = front->next) + ; + + // make sure it was found + if (!front) + { + DEBUG_FATAL(true, ("ExitChain::remove function not found %p", function)); + return; //lint !e527 // Warning -- Unreachable + } + + // remove from the linked list + if (back) + back->next = front->next; + else + PerThreadData::setExitChainFirstEntry(front->next); + + // free the memory associated with this entry + delete front; +} + +// ---------------------------------------------------------------------- +/** + * Process the exit chain. + * + * This routine is protected against re-entry so that the ExitChain routines can call Fatal and behave + * properly. + * + * @see Fatal() + */ + +void ExitChain::run(void) +{ + Entry *entry; + + if (isRunning()) + return; + + PerThreadData::setExitChainRunning(true); + + while ((entry = PerThreadData::getExitChainFirstEntry()) != NULL) + { + // remove the first entry off the ExitChain + PerThreadData::setExitChainFirstEntry(entry->next); + + // call the function if it's critical or we're not fataling + if (entry->critical || !isFataling()) + { + DEBUG_REPORT_LOG_PRINT(ms_debugLogFlag, ("ExitChain::run >> %s\n", entry->name)); + DEBUG_OUTPUT_CHANNEL("Foundation\\Exitchain", ("ExitChain::run >> %s\n", entry->name)); + entry->function(); + DEBUG_REPORT_LOG_PRINT(ms_debugLogFlag, ("ExitChain::run << %s\n", entry->name)); + DEBUG_OUTPUT_CHANNEL("Foundation\\Exitchain", ("ExitChain::run << %s\n", entry->name)); + } + + // free the memory if we're not fataling + if (!isFataling()) + delete entry; + } +} + +// ---------------------------------------------------------------------- +/** + * Clean up the game due to an abnormal condition. + * + * This routine should only be called by Fatal(). It is not intended for any other use. + * + * @see ExitChain::quit(), Fatal() + */ + +void ExitChain::fatal(void) +{ + if (PerThreadData::isThreadInstalled()) + { + PerThreadData::setExitChainFataling(true); + run(); + } +} + +// ---------------------------------------------------------------------- +/** + * Dump the contents of the ExitChain to the DebugMonitor. + * + * This routine is for debugging only. + * + * @param logMessage Log to the debugger as well + */ + +void ExitChain::debugReport(bool logMessage) +{ + UNREF(logMessage); + +#ifdef _DEBUG + + DEBUG_OUTPUT_STATIC_VIEW_BEGINFRAME("Foundation\\Exitchain"); + for (Entry *entry = PerThreadData::getExitChainFirstEntry(); entry; entry = entry->next) + { + DEBUG_REPORT(true, Report::RF_print | (logMessage ? Report::RF_log : 0), ("%4d=pri %d=crit %p=func %s\n", entry->priority, static_cast(entry->critical), entry->function, entry->name)); + DEBUG_OUTPUT_STATIC_VIEW("Foundation\\Exitchain", ("%4d=pri %d=crit %p=func %s\n", entry->priority, static_cast(entry->critical), entry->function, entry->name)); + } + DEBUG_OUTPUT_STATIC_VIEW_ENDFRAME("Foundation\\Exitchain"); +#endif +} + +// ---------------------------------------------------------------------- +/** + * Dump the contents of the ExitChain to the DebugMonitor. + * + * This routine is for debugging only. + */ + +void ExitChain::debugReport() +{ + debugReport(false); +} + +// ====================================================================== + diff --git a/engine/shared/library/sharedFoundation/src/shared/ExitChain.h b/engine/shared/library/sharedFoundation/src/shared/ExitChain.h new file mode 100644 index 00000000..83f74a6b --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/ExitChain.h @@ -0,0 +1,84 @@ +// ====================================================================== +// +// ExitChain.h +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// Maintains a list of functions to call at game exit time for cleanup. +// +// Functions are first in order of priority, with the higher interger priority functions being called +// first. For functions with the same priority, they are called in the opposite order that they were +// added to the ExitChain, in a last-in-first-out (LIFO) manner. +// +// When the ExitChain is running because fatal() was called, only the entries that have their critical flag +// set true will be called. +// +// ====================================================================== + +#ifndef EXIT_CHAIN_H +#define EXIT_CHAIN_H + +// ====================================================================== + +#include "sharedDebug/CallStack.h" + +// ====================================================================== + +class ExitChain +{ +public: + + typedef void (*Function)(void); + + struct Entry + { + Entry *next; + Function function; + const char *name; + int priority; + bool critical; +#ifdef _DEBUG + CallStack m_callStack; +#endif + }; + +protected: + + // disabled + ExitChain(void); + ExitChain(const ExitChain &); + ExitChain &operator =(const ExitChain &); + +private: + + static void run(void); + +private: + +#ifdef _DEBUG + static bool ms_debugReportFlag; + static bool ms_debugLogFlag; +#endif + +public: + + static void install(); + static void quit(); + static void fatal(); + + static void add(Function function, const char *debugName, int priority=0, bool critical=false); + static void remove(Function function); + + + static bool isRunning(void); + static DLLEXPORT bool isFataling(void); + + static void debugReport(); + static void debugReport(bool log); +}; + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedFoundation/src/shared/Fatal.cpp b/engine/shared/library/sharedFoundation/src/shared/Fatal.cpp new file mode 100644 index 00000000..5d2c7327 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Fatal.cpp @@ -0,0 +1,382 @@ +// ====================================================================== +// +// Fatal.cpp +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/Fatal.h" + +#include "sharedDebug/DataLint.h" +#include "sharedDebug/DebugHelp.h" +#include "sharedDebug/PixCounter.h" +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedFoundation/Crc.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/Os.h" +#include "sharedFoundation/PerThreadData.h" +#include "sharedFoundation/SetupSharedFoundation.h" +#include "sharedSynchronization/Mutex.h" + +#include +#include + +// ====================================================================== + +namespace FatalNamespace +{ + Mutex ms_criticalSection; + char ms_buffer[32 * 1024]; + bool ms_throwExceptions; + int ms_numberOfWarnings = 0; + bool ms_strict = false; + + WarningCallback s_warningCallback = NULL; + +#if PRODUCTION == 0 + PixCounter::ResetInteger ms_numberOfWarningsThisFrame; +#endif +} +using namespace FatalNamespace; + +// ====================================================================== + +void FatalInstall() +{ +#if PRODUCTION == 0 + ms_numberOfWarningsThisFrame.bindToCounter("Warnings"); +#endif +} + +// ====================================================================== + +static void formatMessage(char *buffer, int bufferLength, int stackDepth, const char *type, const char *format, va_list va) +{ + const int callStackOffset = 4; + const int maxStackDepth = 64; + + if (stackDepth > maxStackDepth) + stackDepth = maxStackDepth; + + // look up the call stack information + const int callStackSize = callStackOffset + stackDepth; + uint32 callStack[callStackOffset + maxStackDepth]; + + // allow complete disable of the call stack lookup + if (stackDepth < 0) + memset(callStack, 0, sizeof(callStack)); + else + DebugHelp::getCallStack(callStack, callStackOffset + stackDepth); + + // make sure the buffer is always null terminated + buffer[--bufferLength] = '\0'; + + // look up the caller's file and line + if (callStack[callStackOffset]) + { + char lib[4 * 1024] = { '\0' }; + char file[4 * 1024] = { '\0' }; + int line = 0; + if (ConfigSharedFoundation::getLookUpCallStackNames() && DebugHelp::lookupAddress(callStack[callStackOffset], lib, file, sizeof(file), line)) + snprintf(buffer, bufferLength, "%s(%d) : %s %08x: ", file, line, type, static_cast(Crc::calculate(format))); + else + snprintf(buffer, bufferLength, "unknown(0x%08X) : %s %08x: ", static_cast(callStack[callStackOffset]), type, static_cast(Crc::calculate(format))); + } + else + { + snprintf(buffer, bufferLength, "unknown location : %s %08x: ", type, static_cast(Crc::calculate(format))); + } + + { + const int length = strlen(buffer); + buffer += length; + bufferLength -= length; + } + + // add the user message + vsnprintf(buffer, bufferLength, format, va); + + { + const int length = strlen(buffer); + buffer += length; + bufferLength -= length; + } + + // add the newline + if (bufferLength) + { + *buffer = '\n'; + ++buffer; + --bufferLength; + *buffer = '\0'; + } + + if (stackDepth >= 0) + { + // add the call stack + for (int i = callStackOffset+1; i < callStackSize; ++i) + if (callStack[i]) + { + char lib[1024]; + char file[1024]; + int line = 0; + + if (ConfigSharedFoundation::getLookUpCallStackNames() && DebugHelp::lookupAddress(callStack[i], lib, file, sizeof(file), line)) + snprintf(buffer, bufferLength, " %s(%d) : caller %d\n", file, line, i-callStackOffset); + else + snprintf(buffer, bufferLength, " unknown(0x%08X) : caller %d\n", static_cast(callStack[i]), i-callStackOffset); + + const int length = strlen(buffer); + buffer += length; + bufferLength -= length; + } + } + + if (bufferLength == 0) + { + buffer[-2] = '+'; + buffer[-1] = '\n'; + } +} + +// ---------------------------------------------------------------------- +/** + * Terminate the game due to an abnormal condition. + * + * This routine does not return. + * + * This routine will call ExitChain::fatal() to clean up the system as appropriate. + * + * @param format printf-style formatting string + * @see PreFatal() + */ + +static void InternalFatal(const char *format, va_list va) +{ + // if the per-thread-data isn't installed, then we know we're single-threaded and can use the static buffer + ms_criticalSection.enter(); + const int bufferSize = sizeof(ms_buffer); + const int length = strlen(ms_buffer); + formatMessage(ms_buffer+length, bufferSize-length, ConfigSharedFoundation::getFatalCallStackDepth(), "FATAL", format, va); + ms_criticalSection.leave(); + + REPORT(true, Report::RF_print | Report::RF_log | Report::RF_fatal, ("%s", ms_buffer)); + + IGNORE_RETURN(Os::copyTextToClipboard(ms_buffer)); + + if (ms_throwExceptions) + throw FatalException(ms_buffer, FatalException::ZeroSourceString); //lint !e1549 // Function not declared to throw + +#ifdef _WIN32 + { + __asm int 3; + } +#endif + + DEBUG_OUTPUT_CHANNEL("Foundation\\Fatal", ("%s", ms_buffer)); + ExitChain::fatal(); + REPORT(true, Report::RF_fatal | Report::RF_dialog, ("%s", ms_buffer)); + Os::abort(); +} + +// ---------------------------------------------------------------------- + +static void InternalWarning(const char *format, int extraFlags, va_list va, int stackDepth = ConfigSharedFoundation::getWarningCallStackDepth()) +{ +#if PRODUCTION == 0 + ++ms_numberOfWarningsThisFrame; +#endif + + char buffer[4 * 1024]; + + if (NULL != s_warningCallback) + { + strcpy(buffer, "WARNING: "); + vsnprintf(buffer + 9, sizeof(buffer) - 9, format, va); + strcat(buffer, "\n"); + s_warningCallback(buffer); + } + + formatMessage(buffer, sizeof(buffer), stackDepth, "WARNING", format, va); + +#ifdef _DEBUG + if (DataLint::isInstalled()) + { + DataLint::logWarning(buffer); + return; + } +#endif + + ++ms_numberOfWarnings; + REPORT(true, Report::RF_print | Report::RF_log | Report::RF_warning | extraFlags, ("%s", buffer)); + DEBUG_OUTPUT_CHANNEL("Foundation\\Warning", ("%s", buffer)); +} + +//---------------------------------------------------------------------- + +void SetWarningCallback(WarningCallback warningCallback) +{ + s_warningCallback = warningCallback; +} + +// ====================================================================== + +FatalException::FatalException(char *newMessage, Zero zero) +: message(DuplicateString(newMessage)) +{ + UNREF(zero); + if (newMessage) + newMessage[0] = '\0'; +} + +// ---------------------------------------------------------------------- + +FatalException::FatalException(const FatalException &fatalException) +: message(DuplicateString(fatalException.message)) +{ +} + +// ---------------------------------------------------------------------- + +FatalException::~FatalException(void) +{ + delete [] message; +} + +// ---------------------------------------------------------------------- + +FatalException &FatalException::operator =(const FatalException &fatalException) +{ + if (&fatalException != this) + { + delete [] message; + message = DuplicateString(fatalException.message); + } + + return *this; +} + +// ---------------------------------------------------------------------- + +const char *FatalException::getMessage(void) const +{ + return message; +} + +// ====================================================================== + +void FatalSetVersionString(const char *string) +{ + strcat(ms_buffer, string); +} + +// ---------------------------------------------------------------------- + +void FatalSetThrowExceptions(bool throwExceptions) +{ + ms_throwExceptions = throwExceptions; +} + +// ---------------------------------------------------------------------- + +int GetNumberOfWarnings() +{ + return ms_numberOfWarnings; +} + +// ---------------------------------------------------------------------- + +void Fatal(const char *format, ...) +{ + va_list va; + va_start(va, format); + + InternalFatal(format, va); + + va_end(va); +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +void DebugFatal(const char *format, ...) +{ + va_list va; + va_start(va, format); + + InternalFatal(format, va); + + va_end(va); +} + +#endif + +// ---------------------------------------------------------------------- + +void Warning(const char *format, ...) +{ + va_list va; + va_start(va, format); + + InternalWarning(format, 0, va); + + va_end(va); +} + +// ---------------------------------------------------------------------- + +void WarningStackDepth(int stackDepth, const char *format, ...) +{ + va_list va; + va_start(va, format); + + InternalWarning(format, 0, va, stackDepth); + + va_end(va); +} + +// ---------------------------------------------------------------------- + +void ConsoleWarning(const char *format, ...) +{ + va_list va; + va_start(va, format); + + InternalWarning(format, Report::RF_console, va); + + va_end(va); +} + +// ---------------------------------------------------------------------- + +void SetWarningStrictFatal(bool strict) +{ + ms_strict = strict; +} + +// ---------------------------------------------------------------------- + +bool GetWarningStrictFatal() +{ + return ms_strict; +} + +// ---------------------------------------------------------------------- + +void WarningStrictFatal(const char *format, ...) +{ + va_list va; + va_start(va, format); + + if (ms_strict) + InternalFatal(format, va); + else + InternalWarning(format, 0, va); + + va_end(va); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/Fatal.h b/engine/shared/library/sharedFoundation/src/shared/Fatal.h new file mode 100644 index 00000000..aa25bd48 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Fatal.h @@ -0,0 +1,162 @@ +// ====================================================================== +// +// Fatal.h +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_Fatal_H +#define INCLUDED_Fatal_H + +// ====================================================================== + +void FatalInstall(); + +void FatalSetVersionString(const char *string); +void FatalSetThrowExceptions(bool throwExceptions); +DLLEXPORT void Fatal(const char *format, ...); + +DLLEXPORT void DebugFatal(const char *format, ...); + +int GetNumberOfWarnings(void); +DLLEXPORT void Warning(const char *format, ...); +DLLEXPORT void WarningStackDepth(int stackDepth, const char *format, ...); +DLLEXPORT void ConsoleWarning(const char *format, ...); + +void SetWarningStrictFatal(bool fatal); +bool GetWarningStrictFatal(); +DLLEXPORT void WarningStrictFatal(const char *format, ...); + +typedef void (*WarningCallback) (char const * const); +void SetWarningCallback(WarningCallback); + +// ====================================================================== + +#define FATAL(a, b) ((a) ? Fatal b : NOP) +#ifdef _DEBUG + #define DEBUG_FATAL(a, b) ((a) ? DebugFatal b : NOP) +#else + #define DEBUG_FATAL(a, b) NOP +#endif + +#define WARNING(a, b) ((a) ? Warning b : NOP) +#define WARNING_STACK_DEPTH(a, b) ((a) ? WarningStackDepth b : NOP) +#ifdef _DEBUG + #define DEBUG_WARNING(a, b) WARNING(a, b) +#else + #define DEBUG_WARNING(a, b) NOP +#endif + +#define CONSOLE_WARNING(a, b) ((a) ? ConsoleWarning b : NOP) +#ifdef _DEBUG + #define DEBUG_CONSOLE_WARNING(a, b) CONSOLE_WARNING(a, b) +#else + #define DEBUG_CONSOLE_WARNING(a, b) NOP +#endif + +#ifdef _DEBUG + #define WARNING_DEBUG_FATAL(a, b) DEBUG_FATAL(a, b) +#else + #define WARNING_DEBUG_FATAL(a, b) WARNING(a, b) +#endif + +#define WARNING_STRICT_FATAL(a, b) ((a) ? WarningStrictFatal b : NOP) + +#ifdef _DEBUG + + template + inline T *NonNull(T *pointer, const char *name) + { + FATAL(!pointer, ("%s pointer is null", name)); + return pointer; + } + + #define NON_NULL(a) NonNull(a, #a) + #define NOT_NULL(a) FATAL(!a, ("%s pointer is null", #a)) + + // FATAL if the specified pointer is not NULL (i.e. assert that the pointer is null, the opposite of NOT_NULL). + #define IS_NULL(a) FATAL(a, ("%s pointer is not null, unexpected.", #a)) + +#else + + #define NON_NULL(a) (a) + #define NOT_NULL(a) UNREF(a) + + #define IS_NULL(a) UNREF(a) + +#endif + +// ====================================================================== +/** + * Fatal if the specified var does not satisfy (low <= var < high). + * + * The parameter types must be integral and must be convertable to + * an int. + */ + +template +inline void ValidateRangeInclusiveExclusive(const T &low, const T &var, const T &high, const char *varName) +{ + FATAL(low > high, ("range check low [%d] > high [%d]", static_cast(low), static_cast(high))); + FATAL( (var < low) || (var >= high), ("%s [%d] out of valid range [%d..%d)", varName, static_cast(var), static_cast(low), static_cast(high))); +} + +#ifdef _DEBUG +#define VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(low, var, high) ValidateRangeInclusiveExclusive(low, var, high, #var) +#else +#define VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(low, var, high) NOP +#endif + +// ====================================================================== +/** + * Fatal if the specified var does not satisfy (low <= var <= high). + * + * The parameter types must be integral and must be convertable to + * an int. + */ + +template +inline void ValidateRangeInclusiveInclusive(const T &low, const T &var, const T &high, const char *varName) +{ + FATAL(low > high, ("range check low [%d] > high [%d]", static_cast(low), static_cast(high))); + FATAL( (var < low) || (var > high), ("%s [%d] out of valid range [%d..%d]", varName, static_cast(var), static_cast(low), static_cast(high))); +} + +#ifdef _DEBUG +#define VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(low, var, high) ValidateRangeInclusiveInclusive(low, var, high, #var) +#else +#define VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(low, var, high) NOP +#endif + +// ====================================================================== + +class FatalException +{ +public: + + enum Zero + { + ZeroSourceString + }; + +private: + + char *message; + +public: + + FatalException(char *newMessage, Zero zero); + FatalException(const FatalException &fatalException); + ~FatalException(void); + + FatalException &operator =(const FatalException &fatalException); + + const char *getMessage(void) const; +}; + +struct _EXCEPTION_POINTERS; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/FirstSharedFoundation.h b/engine/shared/library/sharedFoundation/src/shared/FirstSharedFoundation.h new file mode 100644 index 00000000..60793e0d --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/FirstSharedFoundation.h @@ -0,0 +1,86 @@ +// ====================================================================== +// +// FirstSharedFoundation.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_FirstSharedFoundation_H +#define INCLUDED_FirstSharedFoundation_H + +// ====================================================================== +// Set the different build debug levels + +#define DEBUG_LEVEL_RELEASE 0 +#define DEBUG_LEVEL_OPTIMIZED 1 +#define DEBUG_LEVEL_DEBUG 2 + +#define _CRT_SECURE_NO_DEPRECATE 1 + +#ifndef DEBUG_LEVEL + #ifdef _DEBUG + #define DEBUG_LEVEL DEBUG_LEVEL_DEBUG + #else + #define DEBUG_LEVEL DEBUG_LEVEL_RELEASE + #endif +#endif + +#if (DEBUG_LEVEL != DEBUG_LEVEL_RELEASE) && (DEBUG_LEVEL != DEBUG_LEVEL_OPTIMIZED) && (DEBUG_LEVEL != DEBUG_LEVEL_DEBUG) +#error DEBUG_LEVEL is not valid +#endif + +// ====================================================================== +// things we really have to have + +#include "sharedFoundationTypes/FoundationTypes.h" +#include "sharedFoundation/FirstPlatform.h" +#include "sharedMemoryManager/MemoryManager.h" + +// ====================================================================== + +#include + +// ====================================================================== +// deprecated stuff that should eventually go away + +typedef float real; + +#define CONST_REAL(a) static_cast(a) +#define RECIP(a) (1.0f / (a)) + +const float REAL_MIN = FLT_MIN; +const float REAL_MAX = FLT_MAX; + +// ====================================================================== + +#ifndef NULL +#define NULL 0 +#endif + +// @todo codereorg +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +// ====================================================================== +// things that are useful just about everywhere + +#include +#include +#include +#include + +#include "sharedFoundation/MacroFoundation.h" + +#include "sharedFoundation/Binary.h" +#include "sharedFoundation/Fatal.h" +#include "sharedFoundation/StlForwardDeclaration.h" +#include "sharedFoundation/Misc.h" +#include "sharedDebug/RemoteDebug.h" +#include "sharedDebug/Report.h" +#include "sharedFoundation/FloatMath.h" +#include "sharedFoundation/SafeCast.h" + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/FloatMath.h b/engine/shared/library/sharedFoundation/src/shared/FloatMath.h new file mode 100644 index 00000000..2649abfe --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/FloatMath.h @@ -0,0 +1,167 @@ +// ====================================================================== +// +// FloatMath.h +// Portions Copyright 1998 Bootprint Entertainment +// Portions Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_FloatMath_H +#define INCLUDED_FloatMath_H + +// ====================================================================== + +float const PI = 3.14159265358979323846f; +float const PI_TIMES_2 = PI * 2.0f; +float const PI_OVER_2 = PI / 2.0f; +float const PI_OVER_3 = PI / 3.0f; +float const PI_OVER_4 = PI / 4.0f; +float const PI_OVER_6 = PI / 6.0f; +float const PI_OVER_8 = PI / 8.0f; +float const PI_OVER_12 = PI / 12.0f; +float const PI_OVER_16 = PI / 16.0f; +float const PI_OVER_180 = PI / 180.0f; + +float const E = 2.7182818284590452f; + +// ====================================================================== + +#ifdef PLATFORM_WIN32 + +#if _MSC_VER < 1300 + +inline float abs(float f) +{ + return fabsf(f); +} + +inline float sqrt(float f) +{ + return sqrtf(f); +} + +inline float sin(float f) +{ + return sinf(f); +} + +inline float cos(float f) +{ + return cosf(f); +} + +inline float tan(float f) +{ + return tanf(f); +} + +inline float asin(float f) +{ + return asinf(f); +} + +inline float acos(float f) +{ + return acosf(f); +} + +inline float atan2(float y, float x) +{ + return atan2f(y, x); +} + +inline float pow(float x, float y) +{ + return powf(x, y); +} + +#endif // _MSC_VER < 1300 + +#else + +// @todo check standard, if cmath.h will not be deprecated, +// include cmath.h here and get rid of the redundant inlines. +#include + +#ifndef LINUX +// The Linux setup defines this in PlatformGlue.h +inline float abs(float f) +{ + return std::abs(f); +} +#endif + +inline float sqrt(float f) +{ + return std::sqrt(f); +} + +inline float sin(float f) +{ + return std::sin(f); +} + +inline float cos(float f) +{ + return std::cos(f); +} + +inline float tan(float f) +{ + return std::tan(f); +} + +inline float asin(float f) +{ + return std::asin(f); +} + +inline float acos(float f) +{ + return std::acos(f); +} + +inline float atan2(float y, float x) +{ + return std::atan2(y, x); +} + +inline float pow(float x, float y) +{ + return std::pow(x, y); +} + +#endif + +// ====================================================================== + +inline float convertDegreesToRadians (real degrees) +{ + return degrees * PI / 180.0f; +} + +inline float convertRadiansToDegrees (real radians) +{ + return radians * 180.0f / PI; +} + +inline float cot(float f) +{ + return RECIP(tanf(f)); +} + +inline float GaussianDistribution(float variate, float standardDeviation, float mean) +{ + // equation from http://mathworld.wolfram.com/NormalDistribution.html + return (1.0f / (standardDeviation * sqrt(2.0f * PI))) * pow(E, -(sqr(variate - mean) / (2.0f * sqr(standardDeviation)))); +} + +inline float withinEpsilon(float const rhs, float const lhs, float const epsilon = 1.0e-3f) +{ + return ((lhs - epsilon) <= rhs) && (rhs <= (lhs + epsilon)); +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/FormattedString.h b/engine/shared/library/sharedFoundation/src/shared/FormattedString.h new file mode 100644 index 00000000..e6e1fb26 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/FormattedString.h @@ -0,0 +1,83 @@ +// ====================================================================== +// +// FormattedString.h +// Copyright 2004 Sony Online Entertainment, Inc. +// +// ====================================================================== + +#ifndef INCLUDED_FormattedString_H +#define INCLUDED_FormattedString_H + +// ---------------------------------------------------------------------- +template +class FormattedString +{ +public: + + FormattedString(); + + char const * sprintf(char const * format, ...); + char const * vsprintf(char const * format, va_list const & va); + +private: + + char m_text[bufferSize]; + + // Disabled + + FormattedString(FormattedString const &); + FormattedString & operator =(FormattedString const &); +}; + +// ---------------------------------------------------------------------- +template +inline FormattedString::FormattedString() +{ + m_text[0] = '\0'; +} + +//----------------------------------------------------------------------------- +template +inline char const * FormattedString::sprintf(char const * const format, ...) +{ + char const * result = NULL; + va_list va; + + va_start(va, format); + { + result = vsprintf(format, va); + } + va_end(va); + + return result; +} + +// ---------------------------------------------------------------------- +template +inline char const * FormattedString::vsprintf(char const * const format, va_list const & va) +{ + // Format the string + + int const lastIndex = sizeof(m_text) - 1; + int const charactersWritten = vsnprintf(m_text, lastIndex, format, va); + + // vsnprintf returns the number of characters written, not including + // the terminating null character, or a negative value if an output error occurs. + // If the number of characters to write exceeds count, then count characters are + // written and -1 is returned. + + // Handle overflow + + if ( (charactersWritten == lastIndex) + || (charactersWritten == -1)) + { + m_text[lastIndex - 1] = '+'; + m_text[lastIndex] = '\0'; + } + + return m_text; +} + +#endif // INCLUDED_FormattedString_H + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/GameControllerMessage.def b/engine/shared/library/sharedFoundation/src/shared/GameControllerMessage.def new file mode 100644 index 00000000..ad6f9ace --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/GameControllerMessage.def @@ -0,0 +1,1041 @@ +// +// GameControllerMessage.def +// asommers 2-24-99 +// +// copyright 1999, bootprint entertainment +// +// data files should be including GameControllerMessage.def +// code files should be including GameControllerMessage.h +// +// don't put anything in here that would disturb miff (like pragmas, const, and other things) +// DO NOT REORDER ANY OF THE VALUES, only append values to the BOTTOM of the list +// AND PLEASE GROUP IN GROUPS OF FIVE FOR DEBUGGING EASE + +#ifndef GAMECONTROLLERMESSAGE_DEF +#define GAMECONTROLLERMESSAGE_DEF + +#ifndef GAMECONTROLLERMESSAGE_H +#error include GameControllerMessage.h instead of GameControllerMessage.def +#endif + +enum GameControllerMessage +{ + CM_nothing, + + CM_cameraYaw, + CM_cameraPitch, + CM_movePlayer, + CM_toggleLight, + + //----------------------------------------------------------------- + //-- ui commands + + CM_uiChatCollapse, //5 + CM_uiChatIconify, + CM_uiChatMaximize, + CM_uiChatTabEdit, + CM_uiChatTabKill, + + CM_uiChatTabNew, //10 + CM_uiChatTabNext, + CM_uiChatTabPrev, + CM_uiCombatAim, + CM_uiCombatAttack, + + CM_uiCombatTarget, + CM_uiPosture0, + CM_uiPosture1, + CM_uiPosture2, + CM_uiAttitude0, + CM_uiAttitude1, //20 + + CM_uiAttitude2, + CM_uiAttitude3, + CM_uiAttitude4, + CM_uiConversationResponse0, + CM_uiConversationResponse1, + + CM_uiConversationResponse2, + CM_uiConversationResponse3, + CM_uiConversationResponse4, + CM_uiConversationResponse5, + CM_uiConversationStart, //30 + + CM_uiConversationStop, + CM_uiDebugPrint, + CM_uiGameMenuActivate, + CM_uiInventoryClose, + CM_uiInventoryIconify, + + CM_uiInventoryMaximize, + CM_uiMfdIconify, + CM_uiMfdMaximize, + CM_uiMfdNext, + CM_uiMfdPrev, //40 + + CM_uiMissionBrowser, + CM_uiMissionCreation, + CM_uiPointerToggleDown, + CM_uiPointerToggleUp, + CM_uiRadarIconify, + + CM_uiRadarMaximize, + CM_uiRadarRangeDecrease, + CM_uiRadarRangeIncrease, + CM_uiRadarUpdate, + CM_uiSkills, //50 + + CM_uiDataStorage, + CM_uiStartChat, + CM_uiTargetsClearAll, + CM_uiTargetsClearSelected, + CM_uiTargetsIconify, + + CM_uiTargetsNext, + CM_uiTargetsPeaceAttackToggle, + CM_uiTargetsPrev, + CM_uiToggleChatBubblesMinimized, + CM_uiToggleHud, //60 + + CM_uiToolbarPaneNext, + CM_uiToolbarPanePrev, + CM_uiToolbarSlot0, + CM_uiToolbarSlot1, + CM_uiToolbarSlot2, + + CM_uiToolbarSlot3, + CM_uiToolbarSlot4, + CM_uiToolbarSlot5, + CM_uiToolbarSlot6, + CM_uiToolbarSlot7, //70 + + CM_uiToolbarSlot8, + CM_uiToolbarSlot9, + CM_uiToolbarSlot10, + CM_uiToolbarSlot11, + CM_uiPersistentMessageBrowser, + + CM_uiChatRoomBrowser, + CM_uiWorkspaceFrameClose, + CM_uiWorkspaceFrameIconify, + CM_uiWorkspaceFrameMaximize, + CM_uiWorkspaceFrameNext, //80 + + CM_uiWorkspaceFramePrev, + CM_left, + CM_right, + CM_up, + CM_down, //85 + + CM_buttonDeprecated, // 86 + CM_yaw, + CM_pitch, + CM_roll, + CM_cameraYawMouse, //90 + + CM_cameraPitchMouse, + CM_cameraZoom, + CM_cameraLock, + CM_cameraReset, + CM_exit, + + CM_cockpitCamera, + CM_chaseCamera, + CM_objectCamera, + CM_spinCamera, + CM_flybyCamera, //100 + + CM_trackCamera, + CM_increase, + CM_decrease, + CM_fullSpeed, + CM_fullStop, //105 + + CM_alt, + CM_shift, + CM_fireGun, + CM_toggleGun, + CM_cameraResetCursor, //110 + + CM_cycleTargets, + CM_netSpawn, + CM_netUpdateTransform, + CM_netFrag, + CM_netDeath, + + CM_netShoot, + CM_netMove, + CM_netChat, + CM_netDisconnect, + CM_headCamera, //120 + + CM_toggleShipState, + CM_SetTransform, + CM_idle, + CM_walk, + CM_freeCamera, + + CM_wear, + CM_setTransform, + CM_run, + CM_animationStateIdle, + CM_animationStateWalk, //130 + + CM_animationStateRun, + CM_setMemberData, // Message to set member data. Requires a submessage to describe what member data. + CM_applyDelta, // Message to modify member data. Requires a submessage to describe what member data. + CM_swoopCamera, + CM_setYaw, + + CM_turn, + CM_environmentPause, + CM_terrainShowLodBorderChunks, + CM_terrainFreeze, + CM_toggleEnvironment, //140 + + CM_toggleOcclusion, + CM_umbraExportFalse, + CM_umbraExportTrue, + CM_terrainToggleHeightBias, + CM_terrainShowLod, + + CM_terrainMultithreaded, + CM_fillMode, + CM_buildingIncreaseDesiredLevel, + CM_buildingDecreaseDesiredLevel, + CM_pause, //150 + + CM_panorama, + CM_screenShot360, + CM_toggleRunOn, + CM_toggleRunOff, + CM_moveLongitudinal, + + CM_moveLateral, + CM_toggleStrafe, + CM_cameraPivotYaw, + CM_cameraPivotPitch, + CM_cameraPivotTranslateX, //160 + + CM_cameraPivotTranslateY, + CM_cameraPivotZoom, + CM_cameraTranslateX, + CM_cameraTranslateY, + CM_cameraTranslateZ, + + CM_freeChaseCamera, + CM_mouseWheel, + CM_cameraSmarts, + CM_cameraSmartsAbove4Meters, + CM_cameraSwoopIn, //170 + + CM_cameraDoorway, + CM_emote1, + CM_emote2, + CM_emote3, + CM_emote4, + + CM_emote5, + CM_emote6, + CM_emote7, + CM_emote8, + CM_emote9, //180 + + CM_emote10, + CM_cycleRunAnimation, + CM_cycleRunAnimationBackward, + CM_cycleWalkAnimation, + CM_cycleWalkAnimationBackward, + + CM_animationStateRun2, + CM_animationStateRun3, + CM_animationStateRun4, + CM_animationStateRun5, + CM_animationStateRun6, //190 + + CM_animationStateRun7, + CM_animationStateRun8, + CM_animationStateRun9, + CM_animationStateRun10, + CM_animationStateWalk2, + + CM_animationStateWalk3, + CM_animationStateWalk4, + CM_animationStateWalk5, + CM_animationStateWalk6, + CM_animationStateWalk7, //200 + + CM_animationStateWalk8, + CM_animationStateWalk9, + CM_animationStateWalk10, + CM_combatAction, + CM_combatDamage, + + CM_combatDamageList, + CM_warpPlayerToFreeCamera, + CM_resourceAdd, + CM_activateInstallation, + CM_resourcePoolAddHarvester, //210 + + CM_resourceSetInstalledEfficiency, + CM_installationHarvest, + CM_resourcePoolCollectResource, + CM_resourceFinishHarvest, + CM_deactivateInstallation, + + CM_resourcePoolRemoveHarvester, + CM_resourcePoolDepleted, + CM_resourceTypeDepleted, + CM_resourceSpawnPool, + CM_resourceEmptyHopper, //220 + + CM_npcConversationStart, + CM_npcConversationStop, + CM_npcConversationMessage, + CM_npcConversationResponses, + CM_npcConversationSelect, + + CM_transferItem, + CM_opponentInfo, + CM_debugPortalCamera, + CM_clientResourceHarvesterActivate, + CM_clientResourceHarvesterDeactivate, //230 + + CM_clientResourceHarvesterListen, + CM_clientResourceHarvesterStopListening, + CM_clientResourceHarvesterGetResourceData, + CM_clientResourceHarvesterResourceData, + CM_clientResourceHarvesterResourceSelect, + + CM_clientResourceHarvesterSurvey, + CM_clientResourceHarvesterEmptyHopper, + CM_clientResourceHarvesterEmptyHopperResponse, + CM_clientObjectMenuRequest, + CM_clientObjectMenuSelect, //240 + + CM_netUpdateTransformWithParent, + CM_animationAction, + CM_spatialChatSend, + CM_spatialChatReceive, + CM_missionListRequest, + + CM_missionListResponse, + CM_missionDetailsRequest, + CM_missionDetailsResponse, + CM_missionAcceptRequest, + CM_missionAcceptResponse, //250 + + CM_missionRemoveRequest, + CM_missionRemoveResponse, + CM_missionPostRequest, + CM_missionPostResponse, + CM_missionCreateRequest, + + CM_missionCreateResponse, + CM_serverMissionAssign, + CM_draftSchematicsMessage, + CM_draftSlotsMessage, + CM_schematicAttribsMessage, //260 + + CM_ingredientsHopperMessage, + CM_experimentMessage, + CM_fillSchematicSlotMessage, + CM_emptySchematicSlotMessage, + CM_nextCraftingStage, + + CM_createPrototype, + CM_createManfSchematic, + CM_craftingResult, + CM_nextStageReady, + CM_selectDraftSchematic, //270 + + CM_requestCraftingSession, + CM_cancelCraftingSession, + CM_restartCraftingSession, + CM_schematicCustomizationsMessage, + CM_experimentResult, + + CM_getTokenForObject, + CM_secureTrade, + CM_commandQueueEnqueue, + CM_commandQueueRemove, + CM_commandQueueEnqueueFwd, //280 + + CM_commandQueueAlterWaitTimerFwd, + CM_commandQueueForceExecuteCommandFwd, + CM_pvpMessage, + CM_getWaypointForObject, + CM_uiPersistentMessageComposer, + + CM_uiChatRooms, + CM_uiSkillCommands, + CM_uiCharacterSheet, + CM_cameraPathNormal, + CM_cameraPathAddWaypoint, //290 + + CM_cameraPathPlayback, + CM_cameraPathDeleteLastWaypoint, + CM_scriptTrigger, + CM_clientLookAtTarget, + CM_combatAimToClient, //295 + + CM_vtuneResume, + CM_vtunePause, + CM_vtuneCounter, + CM_synchronizeScriptVars, + CM_clientMoodChange, //300 + + CM_transferObjectToCell, + CM_socialReceive, + CM_socialSend, + CM_uiChatTab, + CM_setPosture, + + CM_uiClientSocial, + CM_uiClientMood, + CM_combatSpam, + CM_uiCycleTargetInward, + CM_uiCycleTargetOutward, //310 + + CM_uiCycleTargetNext, + CM_uiCycleTargetPrev, + CM_attachScript, + CM_detachScript, + CM_sitOnObject, + + CM_uiCombatQueueCollapse, + CM_uiCombatQueueExpand, + CM_teleport, + CM_teleportAck, + CM_weaponRangesMessage, //320 + + CM_uiMissionDetails, + CM_missionAbort, + CM_setBuildingCityId, + CM_clientCommandParser, + CM_debugKeyContext1, + + CM_objectMenuRequest, + CM_objectMenuResponse, + CM_setState, + CM_setAttribute, + CM_setMaxAttribute, //330 + + CM_setMentalState, + CM_setMentalStateToward, + CM_setCover, + CM_setMentalStateTowardClampBehavior, + CM_setMaxMentalState, + + CM_setMentalStateDecay, + CM_setLocomotion, + CM_setAutoAttack, + CM_setOwnerId, + CM_setMaxHitPoints, //340 + + CM_setVisible, + CM_setInvulnerable, + CM_setCombatAttitude, + CM_addPlayerToSpawnQueue, + CM_removePlayerFromSpawnQueue, + + CM_setCustomizationData, + CM_groupSetName, + CM_groupAddMember, + CM_groupRemoveMember, + CM_groupDisband, //350 + + CM_setGroupInviter, + CM_setPerformanceType, + CM_setPerformanceListenTarget, + CM_setPerformanceWatchTarget, + CM_uiSurvey, + + CM_setPerformanceStartTime, + CM_forwardNpcConversationMessage, + CM_musicFlourish, + CM_commandQueueAdd, + CM_addNpcConversationResponse, //360 + + CM_removeNpcConversationResponse, + CM_sendNpcConversationResponses, + CM_playerResponseToNpcConversation, + CM_scriptTransferMoney, + CM_groupMakeLeader, + + CM_persistObject, + CM_setCacheVersion, + CM_setObjectName, + CM_setObjectNameStringId, + CM_teleportObject, //370 + + CM_updatePositionOnPlanetServer, + CM_setPlayerControlled, + CM_customize, + CM_permanentlyDestroy, + CM_transferAuthority, + + CM_addLocationTarget, + CM_removeLocationTarget, + CM_addLocationExitTarget, + CM_removeLocationExitTarget, + CM_setBuildingIsPublic, //380 + + CM_setInCombat, + CM_addAim, + CM_clearAims, + CM_alterHitPoints, + CM_addResource, + + CM_setCombatTarget, + CM_removeCombatTarget, + CM_setCraftedId, + CM_startCraftingSession, + CM_stopCraftingSession, //390 + + CM_addIngredientToHopper, + CM_removeIngredientFromHopper, + CM_addObjectToOutputSlot, + CM_setCraftingManufactureSchematic, + CM_clearCraftingManufactureSchematic, + + CM_setCraftingPrototype, + CM_clearCraftingPrototype, + CM_setVisibleComponents, + CM_setIsShield, + CM_resourcePoolDeductResource, //400 + + CM_debugKeyContext2, + CM_setAmmo, + CM_addAllowed, + CM_removeAllowed, + CM_addBanned, + + CM_removeBanned, + CM_setDefaultWeapon, + CM_setModValue, + CM_grantCommand, + CM_grantExperiencePoints, //410 + + CM_grantSkill, + CM_revokeCommand, + CM_revokeSkill, + CM_alterAttribute, + CM_addAttributeModifier, + + CM_removeAttributeModifiers, + CM_removeAllAttributeModifiers, + CM_applyDamageToArmor, + CM_setCombatTargets, + CM_setCurrentWeapon, //420 + + CM_setGroup, + CM_setMood, + CM_setIncapacitated, + CM_setSayMode, + CM_setAnimationMood, + + CM_setScaleFactor, + CM_setShockWounds, + CM_setLookAtTarget, + CM_setMovementStationary, + CM_setMovementWalk, //430 + + CM_setMovementRun, + CM_setSlopeModAngle, + CM_setSlopeModPercent, + CM_setWaterModPercent, + CM_setMovementPercent, + + CM_setTurnPercent, + CM_setAccelPercent, + CM_planetAddTravelPoint, + CM_planetRemoveTravelPoint, + CM_planetTravelPointNamesRequest, //440 + + CM_planetTravelPointNamesResponse, + CM_factoryAddObject, + CM_addSchematic, + CM_manufactureInstallationCreateObject, + CM_showFlyText, + + CM_nextCraftingStageResult, + CM_draftSlotsQueryResponse, + CM_setBattlefieldParticipant, + CM_clearBattlefieldParticipants, + CM_craftingSessionEnded, //450 + + CM_setIntDynamicVariable, + CM_setIntArrayDynamicVariable, + CM_setFloatDynamicVariable, + CM_setFloatArrayDynamicVariable, + CM_setStringDynamicVariable, + + CM_setStringArrayDynamicVariable, + CM_setObjIdDynamicVariable, + CM_setObjIdArrayDynamicVariable, + CM_setLocationDynamicVariable, + CM_setStringIdDynamicVariable, //460 + + CM_setStringIdArrayDynamicVariable, + CM_copyDynamicVariable, + CM_copyDynamicVariableToSubList, + CM_addNestedObjVarList, + CM_removeObjVarItem, + + CM_eraseObjVarListEntries, + CM_setObjVarItemVar, + CM_guildCreate, + CM_guildRemoveMember, + CM_guildSetMemberProfessionInfo, //470 + + CM_guildRemoveEnemy, + CM_guildSetEnemy, + CM_guildDisband, + CM_guildSetLeader, + CM_biographyRetrieved, + + CM_setLocationArrayDynamicVariable, + CM_guildSetName, + CM_guildSetAbbrev, + CM_replaceMe1, + CM_replaceMe2, //480 + + CM_replaceMe3, + CM_replaceMe4, + CM_replaceMe5, + CM_replaceMe6, + CM_replaceMe7, + + CM_replaceMe8, + CM_characterMatchRetrieved, + CM_initDecay, + CM_setDecay, + CM_setVolume, //490 + + CM_setMasterId, + CM_setCreatorId, + CM_setCreatorName, + CM_setCreatorXp, + CM_setCreatorXpType, + + CM_setCraftedType, + CM_radarZoom, + CM_autoRun, + CM_radarMap, + CM_setForcePower, //500 + + CM_setMaxForcePower, + CM_setWeather, + CM_addJedi, + CM_removeJedi, + CM_updateJedi, + + CM_requestJediBounty, + CM_removeJediBounty, + CM_startingLocations, + CM_startingLocationSelectionResult, + CM_synchronizeScriptVarDeltas, //510 + + CM_mouseWalkStart, + CM_mouseWalk, + CM_cancelAutoRun, + CM_directDamage, + CM_setMovementScale, + + CM_setAccelScale, + CM_disconnect, + CM_teleportNextFrame, + CM_resourceWeights, + CM_serverAddPlanetMapLocation, //520 + + CM_serverRemovePlanetMapLocation, + CM_setCondition, + CM_clearCondition, + CM_setHouse, + CM_setGroupMemberDifficulty, + + CM_setDifficulty, + CM_grantOfflineXp, + CM_cityCreate, + CM_citySetName, + CM_cityRemove, // 530 + + CM_citySetCitizen, + CM_cityRemoveCitizen, + CM_citySetStructure, + CM_cityRemoveStructure, + CM_setForceRegenRate, + + CM_updateJediLocation, + CM_setJediOffline, + CM_creatureSetBaseWalkSpeed, + CM_creatureSetBaseRunSpeed, + CM_emergencyDismountForRider, // 540 + + CM_detachRiderForMount, + CM_setDecayTime, + CM_clearDecayTime, + CM_citySetCityHall, + CM_citySetLocation, + + CM_citySetRadius, + CM_citySetLeader, + CM_citySetIncomeTax, + CM_citySetPropertyTax, + CM_citySetSalesTax, // 550 + + CM_citySetTravelInfo, + CM_citySetCloneInfo, + CM_modData, + CM_cancelMod, + CM_objectMenuDirty, + + CM_attributesDirty, + CM_setTransformDynamicVariable, + CM_setTransformArrayDynamicVariable, + CM_setVectorDynamicVariable, + CM_setVectorArrayDynamicVariable, // 560 + + CM_aiSetMovement, + CM_aiSetMovementWalk, + CM_updateJediBounties, + CM_setAppearanceFromObjectTemplate, + CM_aiSetMovementRun, + + CM_applyWound, + CM_setWound, + CM_imageDesignerChange, + CM_imageDesignerCancel, + CM_imageDesignerStart, // 570 + + CM_setJediState, + CM_updateJediState, + CM_makeDead, + CM_updateJediSpentJediSkillPoints, + CM_updateJediScriptData, + + CM_removeJediScriptData, + CM_removeAllJediBounties, + CM_updateJediFaction, + CM_setCurrentQuest, + CM_setRegenRate, // 580 + + CM_updateObserversCount, + CM_hideFromClient, + CM_setHibernationDelay, + CM_setAttackableOverride, + CM_modifyCurrentGcwPoints, + + CM_modifyCurrentGcwRating, + CM_modifyCurrentPvpKills, + CM_modifyLifetimeGcwPoints, + CM_modifyMaxGcwImperialRating, + CM_modifyMaxGcwRebelRating, // 590 + + CM_modifyLifetimePvpKills, + CM_modifyNextGcwRatingCalcTime, + CM_cancelMessageTo, + CM_clearSessionActivity, + CM_addSessionActivity, + + CM_addPassiveReveal, + CM_removePassiveReveal, + CM_removeAllPassiveReveal, + CM_modifyHologramType, + CM_modifyVisibleOnMapAndRadar, // 600 + + CM_setCoverVisibility, + CM_buffBuilderChange, + CM_buffBuilderCancel, + CM_buffBuilderStart, + CM_incubatorStart, + + CM_incubatorCommit, + CM_incubatorCancel, + CM_modifyCollectionSlotValue, + CM_removeCollection, + CM_adjustLotCount, // 610 + + CM_squelch, + CM_unsquelch, + CM_setPriviledgedTitle, + CM_collectionRequestServerFirst, + CM_collectionRevokeServerFirst, + + CM_addHateOverTime, + CM_setConnectedCharacterLfgData, + CM_removeConnectedCharacterData, + CM_setConnectedCharacterGroupData, + CM_setConnectedCharacterPlanetData, // 620 + + CM_setConnectedCharacterBiographyData, + CM_removeConnectedCharacterBiographyData, + CM_setGroupMemberProfession, + CM_setConnectedCharacterLevelData, + CM_setConnectedCharacterProfessionData, + + CM_setConnectedCharacterAnonymousData, + CM_setConnectedCharacterInterestsData, + CM_setConnectedCharacterRegionData, + CM_setGroupPickupTimer, + CM_setGroupPickupLocation, // 630 + + CM_setConnectedCharacterDisplayLocationInSearchResultsData, + CM_setConnectedCharacterPlayerCityData, + CM_addUniverseEvent, + CM_removeUniverseEvent, + CM_setConnectedCharacterSearchableByCtsSourceGalaxyData, + + CM_forceHateTarget, + CM_addUserToAccessList, + CM_removeUserFromAccessList, + CM_clearUserAccessList, + CM_guildUpdateGuildWarKillTrackingData, // 640 + + CM_guildSetGuildElectionEndTime, + CM_guildAddMemberRank, + CM_guildRemoveMemberRank, + CM_guildAddCreatorMember, + CM_guildAddSponsorMember, + + CM_guildSetMemberPermission, + CM_guildSetMemberTitle, + CM_guildSetMemberAllegiance, + CM_guildSetMemberPermissionAndAllegiance, + CM_guildSetMemberNameAndPermission, // 650 + + CM_citySetCreationTime, + CM_adjustGcwImperialScore, + CM_adjustGcwRebelScore, + CM_citySetCitizenProfessionInfo, + CM_citySetCitizenAddRank, + + CM_citySetCitizenRemoveRank, + CM_citySetCitizenTitle, + CM_adjustPgcRating, + CM_adjustPgcRatingData, + CM_setPgcRatingData, // 660 + + CM_fixPgcChroniclerName, + CM_citySetFaction, + CM_guildSetGuildFaction, + CM_guildSetGuildGcwDefenderRegion, + CM_citySetGcwDefenderRegion, + +//-- Space controller messages + CM_formDataForEdit = 1000, + CM_shipDynamicsYaw, + CM_shipDynamicsPitch, + CM_shipDynamicsRoll, + CM_shipFireWeaponAll, + + CM_shipFireWeapon0, //1005 + CM_shipFireWeapon1, + CM_shipFireWeapon2, + CM_shipFireWeapon3, + CM_shipFireWeapon4, + + CM_shipFireWeapon5, //1010 + CM_shipFireWeapon6, + CM_shipFireWeapon7, + CM_shipDamageMessage, + CM_serverAsteroidDebugData, + + CM_commPlayer, //1015 + CM_lightningHitShip, + CM_environmentHitShip, + CM_clientLookAtTargetComponent, + CM_uiCycleComponentTargetForward, + + CM_uiCycleComponentTargetBackward, //1020 + CM_updateShipOnCollision, + CM_aboutToHyperspace, + CM_playerTransitioningOut, + CM_playerTransitioningIn, + + CM_uiPlayEffect, //1025 + CM_shipThrottleChangeStart, + CM_shipThrottleChange, + CM_shipThrottleSetSlider, + CM_yawButton, + + CM_pitchButton, //1030 + CM_rollButton, + CM_shipThrottleSetAxis, + CM_spaceTargetClosestShip, + CM_spaceTargetClosestCapShip, + + CM_spaceTargetUnderReticle, //1035 + CM_spaceTargetNextFriendly, + CM_spaceTargetPreviousFriendly, + CM_spaceTargetNextEnemy, + CM_spaceTargetPreviousEnemy, + + CM_setGroupShipForMember, // 1040 + CM_setGroupShipFormationSlotForMember, + CM_addIgnoreIntersect, + CM_removeIgnoreIntersect, + CM_spaceTargetNextOnScreenUnderVariableReticle, + + CM_spaceTargetPreviousOnScreenUnderVariableReticle, // 1045 + CM_spaceTargetClosestPlayerShip, + CM_spaceTargetClosestNPCShip, + CM_joystickPovDirection, + CM_joystickPovCenter, + + CM_addGroupPOBShipAndOwner, //1050 + CM_removeGroupPOBShip, + CM_spaceTerminalRequest, + CM_spaceTerminalResponse, + CM_setThrottlePosition, + + CM_spaceTargetLastEnemyThatShotPlayer, //1055 + CM_spaceTargetClosestEnemy, + CM_spaceTargetClosestEnemyPlayer, + CM_spaceTargetClosestFriend, + CM_spaceTargetClosestFriendPlayer, + + CM_spaceTargetNextFriendlyPlayer, //1060 + CM_spaceTargetPreviousFriendlyPlayer, + CM_spaceTargetNextEnemyPlayer, + CM_spaceTargetPreviousEnemyPlayer, + CM_spaceTargetGroupLeader, + + CM_spaceTargetNextGroupMember, //1065 + CM_spaceTargetPreviousGroupMember, + CM_swapRollYawAxes, + CM_rearView, + CM_hyperspaceOrientShipToPointAndLockPlayerInput, + + CM_lockPlayerShipInputOnClient, // 1070 + CM_unlockPlayerShipInputOnClient, + CM_spaceTargetNext, + CM_spaceTargetPrevious, + CM_setSpecialAbility, + + CM_spaceShipHit, //1075 + CM_shipThrottleDeltaAxis, + CM_shipThrottleDeltaSlider, + CM_droidCommandProgramming, + CM_inviteOtherGroupMembersToLaunchIntoSpace, + + CM_askGroupMemberToLaunchIntoSpace, //1080 + CM_groupMemberInvitationToLaunchIntoSpaceResponse, + CM_relayGroupMemberInvitationToLaunchAnswer, +//-- End space controller messages + + CM_groupMakeLootMaster, + CM_groupSetLootRule, + + CM_groupOpenLotteryWindowOnClient, //1085 + CM_groupCloseLotteryWindowOnClient, + CM_groupLotteryWindowHeartbeat, + CM_groupLotteryWindowCloseResults, + CM_questTaskCounterData, + + CM_pushCreature, // 1090 + CM_setBioLink, + CM_questTaskTimerData, + CM_slowDownEffect, + CM_removeSlowDownEffect, + + CM_removeSlowDownEffectProxy, // 1095 + CM_commandTimer, + CM_addHate, + CM_setHate, + CM_removeHateTarget, + + CM_clearHateList, // 1100 + CM_changeRoleIconChoice, + CM_aiSetCreatureName, + CM_aiCreatureState, + CM_aiSetHomeLocation, + + CM_setLevel, // 1105 + CM_recalculateLevel, + CM_aiSetFrozen, + CM_aiSetRetreating, + CM_aiSetLogging, + + CM_aiEquipPrimaryWeapon, // 1110 + CM_aiEquipSecondaryWeapon, + CM_aiUnEquipWeapons, + CM_aiMarkCombatStartLocation, + CM_showCombatText, + + CM_setCurrentWorkingSkill, // 1115 + CM_setProfessionTemplate, + CM_resetHateTimer, + CM_autoExpireHateListTargetEnabled, + +//-- ep3 controller messages + CM_shipStopFiring = 1200, // use for ep3 + CM_cyberneticsOpen, + CM_cyberneticsChangeRequest, + CM_cyberneticsChangeRequestToNPC, + CM_spaceMiningSaleOpen, + + CM_detachAllRidersForMount, // 1205 + CM_spaceMiningSaleSellResource, + CM_requestActivateQuest, + CM_requestCompleteQuest, + CM_removeAllAllowed, + + CM_removeAllBanned, // 1210 +//-- End ep3 controller messages + + CM_staticLootItemData, + CM_showLootBox, + CM_questTaskLocationData, + CM_forceActivateQuest, + + CM_jump, // 1215 + CM_primaryAttack, + CM_secondaryAttack, + CM_primaryAction, + CM_primaryActionAndAttack, + + CM_setIntendedTarget, // 1220 + CM_clientIntendedTarget, + CM_toggleAutoAim, + CM_toggleRepeatPrimaryAttack, + CM_setIntendedAndSummonRadialMenu, + + CM_customizeFinished, // 1225 + CM_openCustomizationWindow, + CM_incrementKillMeter, + CM_untargetOnly, + CM_petToolbarSlot0, + + CM_petToolbarSlot1, // 1230 + CM_petToolbarSlot2, + CM_petToolbarSlot3, + CM_petToolbarSlot4, + CM_petToolbarSlot5, + + CM_petToolbarSlot6, // 1235 + CM_petToolbarSlot7, + CM_petToolbarSlot8, + CM_removeAllAttributeAndSkillmodModifiers, + CM_addBuff, + + CM_removeBuff, // 1240 + CM_clientMinigameOpen, + CM_clientMinigameClose, + CM_clientMinigameResult, + CM_createSaga, + + CM_openRatingWindow, // 1245 + CM_ratingFinished, + CM_abandonPlayerQuest, + CM_openRecipe, + CM_addObjectEffect, + + CM_removeObjectEffect, // 1250 + CM_removeAllObjectEffect, + + CM_COUNT +}; + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/GameControllerMessage.h b/engine/shared/library/sharedFoundation/src/shared/GameControllerMessage.h new file mode 100644 index 00000000..3f4264f3 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/GameControllerMessage.h @@ -0,0 +1,42 @@ +// +// GameControllerMessage.h +// asommers 2-24-99 +// +// copyright 1999, bootprint entertainment +// +// data files should be including GameControllerMessage.def +// code files should be including GameControllerMessage.h + +#ifndef GAMECONTROLLERMESSAGE_H +#define GAMECONTROLLERMESSAGE_H + +namespace GameControllerMessageFlags +{ + const uint32 NONE = 0x00000000; + const uint32 SEND = 0x00000001; // send should always be combined with one of the dest flags below + const uint32 RELIABLE = 0x00000002; + const uint32 SOURCE_REMOTE_SERVER = 0x00000004; + const uint32 DEST_AUTH_CLIENT = 0x00000008; + const uint32 DEST_PROXY_CLIENT = 0x00000010; + const uint32 DEST_AUTH_SERVER = 0x00000020; + const uint32 DEST_PROXY_SERVER = 0x00000040; + const uint32 DEST_SERVER = 0x00000080; + const uint32 SOURCE_REMOTE_CLIENT = 0x00000100; + + const uint32 DEST_ALL_CLIENT = DEST_AUTH_CLIENT | DEST_PROXY_CLIENT; + const uint32 DEST_ALL_SERVER = DEST_AUTH_SERVER | DEST_PROXY_SERVER; + const uint32 DEST_ALL = DEST_ALL_CLIENT | DEST_ALL_SERVER; + + const uint32 SOURCE_REMOTE = SOURCE_REMOTE_SERVER | SOURCE_REMOTE_CLIENT; + + //@todo remove DESTINATIONS and DEST_SERVER + const uint32 DESTINATIONS = DEST_AUTH_CLIENT | + DEST_PROXY_CLIENT | + DEST_AUTH_SERVER | + DEST_PROXY_SERVER | + DEST_SERVER; +} + +#include "sharedFoundation/GameControllerMessage.def" + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/LabelHash.cpp b/engine/shared/library/sharedFoundation/src/shared/LabelHash.cpp new file mode 100644 index 00000000..26848b94 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/LabelHash.cpp @@ -0,0 +1,132 @@ +// ====================================================================== +// +// LabelHash.cpp +// +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/LabelHash.h" + +#include +#include + +#include "sharedFoundation/Crc.h" + +typedef std::map< uint32, std::string > THashToStringMap; + +typedef THashToStringMap::value_type THashEntry; + +typedef std::map< std::string, THashToStringMap > TDomainMap; + +typedef TDomainMap::value_type TDomainEntry; + +TDomainMap gs_allDomains; + +void LabelHash::addLabel ( char const * const domain, char const * const label ) +{ + uint32 actualHash = Crc::calculate(label); + + checkLabel(domain,label,actualHash); +} + +uint32 LabelHash::hashLabel ( char const * const domain, char const * const label ) +{ + uint32 actualHash = Crc::calculate(label); + + checkLabel(domain,label,actualHash); + + return actualHash; +} + +uint32 LabelHash::checkLabel( char const * const domain, char const * const label, uint32 hashValue ) +{ + // First things first - make sure the label actually hashes to the given value + + uint32 actualHash = Crc::calculate(label); + + FATAL(actualHash != hashValue, ("LabelHash::checkLabel - Label [%s] hashes to [%d] and not [%d]\n",label,actualHash,hashValue)); + + // ---------- + + std::string domainString(domain); + std::string labelString(label); + + // Find the hash-to-label map for the given domain, or + // create a new one if there isn't one already. + + TDomainMap::iterator domainIt = gs_allDomains.find(domainString); + + if(domainIt == gs_allDomains.end()) + { + // Domain not found, create entry for it containing the label + + THashToStringMap newDomainMap; + + newDomainMap.insert( THashEntry(hashValue,labelString) ); + + gs_allDomains.insert( TDomainEntry(domainString,newDomainMap) ); + } + else + { + // Domain found, check for existing hash value + + THashToStringMap & domainLabels = (*domainIt).second; + + THashToStringMap::iterator labelIt = domainLabels.find(hashValue); + + if(labelIt == domainLabels.end()) + { + // Hash value not found, add it to the domain + + domainLabels.insert( THashEntry(hashValue,labelString) ); + } + else + { + // Hash value found, fatal if the string mapped to it doesn't match + // the given string + + std::string & currentLabel = (*labelIt).second; + + FATAL( currentLabel != labelString, ("LabelHash::checkLabel - Found a hash collision for domain [%s], label [%s] - two labels hashed to the same value\n",domain,label)); + } + } + + // All is good, hash is OK. + + return hashValue; +}; + + +const char * LabelHash::findLabel( char const * const domain, uint32 hashValue ) +{ + std::string domainString(domain); + + TDomainMap::iterator domainIt = gs_allDomains.find(domainString); + + if(domainIt == gs_allDomains.end()) + { + // Domain not found + + return NULL; + } + + // ---------- + // Domain found, check for existing hash value + + THashToStringMap & domainLabels = (*domainIt).second; + + THashToStringMap::iterator hashIt = domainLabels.find(hashValue); + + if(hashIt != domainLabels.end()) + { + return (*hashIt).second.c_str(); + } + + // ---------- + // String not found + + return NULL; +} + diff --git a/engine/shared/library/sharedFoundation/src/shared/LabelHash.h b/engine/shared/library/sharedFoundation/src/shared/LabelHash.h new file mode 100644 index 00000000..8b86800d --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/LabelHash.h @@ -0,0 +1,50 @@ +// ====================================================================== +// +// LabelHash.h +// +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_LabelHash_H +#define INCLUDED_LabelHash_H + +// ---------------------------------------------------------------------- + +class LabelHash +{ +public: + + typedef uint32 Id; + + static void addLabel ( char const * const domain, char const * const label ); + + static Id hashLabel ( char const * const domain, char const * const label ); + + static Id checkLabel ( char const * const domain, char const * const label, Id hashValue ); + + static const char * findLabel ( char const * const domain, Id hashValue ); +}; + +// ---------- + +//#define LABEL_HASH(domain,label) (LabelHash::hashLabel(#domain,#label)) + +// ---------- + +#if DEBUG_LEVEL == DEBUG_LEVEL_DEBUG + +// the ##u is so that the compiler interprets the value as an unsigned integer constant + +#define LABEL_HASH(domain,label,value) (LabelHash::checkLabel(#domain,#label,value##u)) + +#else + +#define LABEL_HASH(domain,label,value) (value##u) + +#endif + +// ---------------------------------------------------------------------- + +#endif // #ifndef INCLUDED_LabelHash_H + diff --git a/engine/shared/library/sharedFoundation/src/shared/LessPointerComparator.h b/engine/shared/library/sharedFoundation/src/shared/LessPointerComparator.h new file mode 100644 index 00000000..d420685e --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/LessPointerComparator.h @@ -0,0 +1,36 @@ +// ====================================================================== +// +// LessPointerComparator.h +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef LESS_POINTER_COMPARATOR_H +#define LESS_POINTER_COMPARATOR_H + +// ====================================================================== + +class LessPointerComparator +{ +public: + template + bool operator ()(PointerType lhs, PointerType rhs) const + { + return *lhs < *rhs; + } +}; + +//---------------------------------------------------------------------- + +template class LessPointerComparatorStatic +{ +public: + static bool compare(T * a, T * b) + { + return *a < *b; + } +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/MacroFoundation.h b/engine/shared/library/sharedFoundation/src/shared/MacroFoundation.h new file mode 100644 index 00000000..df3abd97 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/MacroFoundation.h @@ -0,0 +1,28 @@ +// ====================================================================== +// +// MacroFoundation.h +// copyright (c) 1998 Bootprint Entertainment +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_MacroFoundation_H +#define INCLUDED_MacroFoundation_H + +// ====================================================================== + +// No-operation +#define NOP (static_cast(0)) //lint !e1923 //could become const variable + +// To prevent "Unreference" compiler warning +#define UNREF(a) (static_cast(a)) + +// To prevent "Ignoring return value" lint warnings +#define IGNORE_RETURN(a) (static_cast(a)) + +// int version of the sizeof operator +#define isizeof(a) static_cast(sizeof(a)) + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/Md5.cpp b/engine/shared/library/sharedFoundation/src/shared/Md5.cpp new file mode 100644 index 00000000..9a149b05 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Md5.cpp @@ -0,0 +1,339 @@ +// ====================================================================== +// +// Md5.cpp +// +// Portions copyright 2003 Sony Online Entertainment +// Portions derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm +// Portions derived from Dan Gorman's implementation +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/Md5.h" + +#include + +// ====================================================================== + +Md5::Value::Value() +{ + memset(m_data, 0, sizeof(m_data)); +} + +// ---------------------------------------------------------------------- + +Md5::Value::Value(Value const &rhs) +{ + memcpy(m_data, rhs.m_data, sizeof(m_data)); +} + +// ---------------------------------------------------------------------- + +bool Md5::Value::operator ==(Value const &rhs) const +{ + return memcmp(m_data, rhs.m_data, sizeof(m_data)) == 0; +} + +// ---------------------------------------------------------------------- + +bool Md5::Value::operator !=(Value const &rhs) const +{ + return !(*this == rhs); +} + +// ---------------------------------------------------------------------- + +void Md5::Value::format(char *buffer, int bufferLength) const +{ + //not referenced in release build + UNREF(bufferLength); + DEBUG_FATAL(bufferLength < 33, ("PB: buffer must be at least 33 characters")); + sprintf(buffer, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", m_data[0], m_data[1], m_data[2], m_data[3], m_data[4], m_data[5], m_data[6], m_data[7], m_data[8], m_data[9], m_data[10], m_data[11], m_data[12], m_data[13], m_data[14], m_data[15]); +} + +// ====================================================================== + +Md5::Value Md5::calculate(const char *string) +{ + return calculate(string, strlen(string)); +} + +// ---------------------------------------------------------------------- + +Md5::Value Md5::calculate(void const *data, int length) +{ + Md5 md5; + md5.update(data, length); + md5.finish(); + return md5.getValue(); +} + +// ====================================================================== + +Md5::Md5() +: + m_bufferedBytes(0), + m_totalLength(0), + m_finished(false) +{ + reset(); +} + +// ---------------------------------------------------------------------- + +void Md5::reset() +{ + m_data[0] = 0x67452301; + m_data[1] = 0xefcdab89; + m_data[2] = 0x98badcfe; + m_data[3] = 0x10325476; + m_bufferedBytes = 0; + m_totalLength = 0; + m_finished = false; +} + +// ---------------------------------------------------------------------- + +void Md5::update(void const *data, int length) +{ + m_totalLength += length; + + byte const * byteData = reinterpret_cast(data); + while (length > 0) + { + // if there's no bytes pending from last time and we have a full block incoming transform it directly to avoid the copy + if (m_bufferedBytes == 0 && length >= BUFFER_SIZE) + { + transformBlock(byteData); + byteData += BUFFER_SIZE; + length -= BUFFER_SIZE; + } + else + { + // figure out how many bytes to copy into the temp buffer + int bytesToCopy = BUFFER_SIZE - m_bufferedBytes; + if (length < bytesToCopy) + bytesToCopy = length; + + // copy the data into the temp buffer + memmove(m_buffer + m_bufferedBytes, byteData, bytesToCopy); + m_bufferedBytes += bytesToCopy; + byteData += bytesToCopy; + length -= bytesToCopy; + + // if we've managed to fill the temp buffer, transform it + if (m_bufferedBytes == BUFFER_SIZE) + { + transformBlock(m_buffer); + m_bufferedBytes = 0; + } + } + } +} + +// ---------------------------------------------------------------------- + +void Md5::wordsToBytes(const uint32* words, size_t wordCnt, uint8* bytes) +{ + const int bytesPerWord = sizeof(*words)/sizeof(*bytes); + while ((wordCnt--) > 0) + { + uint32 wd = *(words++); + int cnt = bytesPerWord; + while (cnt-- > 0) + { + *(bytes++) = static_cast(wd & 0x0ff); + wd >>= 8; + } + } +} + +// ---------------------------------------------------------------------- + +void Md5::bytesToWords(const uint8* bytes, size_t byteCnt, uint32* words) +{ + const int bytesPerWord = sizeof(*words)/sizeof(*bytes); + size_t wdcnt = byteCnt/bytesPerWord; + while (wdcnt-- > 0) + { + uint32 wd = 0; + int cnt = bytesPerWord; + int shft = 0; + while (cnt-- > 0) + { + wd |= static_cast(*(bytes++) & 0x0ff) << shft; + shft += 8; + } + *(words++) = wd; + byteCnt -= bytesPerWord; + } +} + +// ---------------------------------------------------------------------- + +inline uint32 Md5::rotate_left(uint32 ival, uint32 shft) +{ + return ((ival << shft) | (ival >> (32-shft))); +} + +// ---------------------------------------------------------------------- + +inline uint32 Md5::round1(uint32 i, uint32 j, uint32 k, uint32 l, uint32 i1, uint32 j1, uint32 k1) +{ + i += ((j & k) | (~j & l)) + i1 + k1; + return rotate_left(i, j1) + j; +} + +// ---------------------------------------------------------------------- + +inline uint32 Md5::round2(uint32 i, uint32 j, uint32 k, uint32 l, uint32 i1, uint32 j1, uint32 k1) +{ + i += ((j & l) | (k & ~l)) + i1 + k1; + return rotate_left(i, j1) + j; +} + +// ---------------------------------------------------------------------- + +inline uint32 Md5::round3(uint32 i, uint32 j, uint32 k, uint32 l, uint32 i1, uint32 j1, uint32 k1) +{ + i += (j ^ k ^ l) + i1 + k1; + return rotate_left(i, j1) + j; +} + +// ---------------------------------------------------------------------- + +inline uint32 Md5::round4(uint32 i, uint32 j, uint32 k, uint32 l, uint32 i1, uint32 j1, uint32 k1) +{ + i += (k ^ (j | ~l)) + i1 + k1; + return rotate_left(i, j1) + j; +} + +// ---------------------------------------------------------------------- + +void Md5::transformBlock(void const * data) +{ + // pack the bytes into 32-bit little endian words + uint32 work[64 / 4]; + bytesToWords(reinterpret_cast(data), 64, work); + //uint32 const * work = reinterpret_cast(data); + + uint32 j = m_data[0]; + uint32 k = m_data[1]; + uint32 l = m_data[2]; + uint32 m = m_data[3]; + + j = round1(j, k, l, m, work[0], 7, 0xd76aa478); + m = round1(m, j, k, l, work[1], 12, 0xe8c7b756); + l = round1(l, m, j, k, work[2], 17, 0x242070db); + k = round1(k, l, m, j, work[3], 22, 0xc1bdceee); + j = round1(j, k, l, m, work[4], 7, 0xf57c0faf); + m = round1(m, j, k, l, work[5], 12, 0x4787c62a); + l = round1(l, m, j, k, work[6], 17, 0xa8304613); + k = round1(k, l, m, j, work[7], 22, 0xfd469501); + j = round1(j, k, l, m, work[8], 7, 0x698098d8); + m = round1(m, j, k, l, work[9], 12, 0x8b44f7af); + l = round1(l, m, j, k, work[10], 17, 0xffff5bb1); + k = round1(k, l, m, j, work[11], 22, 0x895cd7be); + j = round1(j, k, l, m, work[12], 7, 0x6b901122); + m = round1(m, j, k, l, work[13], 12, 0xfd987193); + l = round1(l, m, j, k, work[14], 17, 0xa679438e); + k = round1(k, l, m, j, work[15], 22, 0x49b40821); + + j = round2(j, k, l, m, work[1], 5, 0xf61e2562); + m = round2(m, j, k, l, work[6], 9, 0xc040b340); + l = round2(l, m, j, k, work[11], 14, 0x265e5a51); + k = round2(k, l, m, j, work[0], 20, 0xe9b6c7aa); + j = round2(j, k, l, m, work[5], 5, 0xd62f105d); + m = round2(m, j, k, l, work[10], 9, 0x02441453); + l = round2(l, m, j, k, work[15], 14, 0xd8a1e681); + k = round2(k, l, m, j, work[4], 20, 0xe7d3fbc8); + j = round2(j, k, l, m, work[9], 5, 0x21e1cde6); + m = round2(m, j, k, l, work[14], 9, 0xc33707d6); + l = round2(l, m, j, k, work[3], 14, 0xf4d50d87); + k = round2(k, l, m, j, work[8], 20, 0x455a14ed); + j = round2(j, k, l, m, work[13], 5, 0xa9e3e905); + m = round2(m, j, k, l, work[2], 9, 0xfcefa3f8); + l = round2(l, m, j, k, work[7], 14, 0x676f02d9); + k = round2(k, l, m, j, work[12], 20, 0x8d2a4c8a); + + j = round3(j, k, l, m, work[5], 4, 0xfffa3942); + m = round3(m, j, k, l, work[8], 11, 0x8771f681); + l = round3(l, m, j, k, work[11], 16, 0x6d9d6122); + k = round3(k, l, m, j, work[14], 23, 0xfde5380c); + j = round3(j, k, l, m, work[1], 4, 0xa4beea44); + m = round3(m, j, k, l, work[4], 11, 0x4bdecfa9); + l = round3(l, m, j, k, work[7], 16, 0xf6bb4b60); + k = round3(k, l, m, j, work[10], 23, 0xbebfbc70); + j = round3(j, k, l, m, work[13], 4, 0x289b7ec6); + m = round3(m, j, k, l, work[0], 11, 0xeaa127fa); + l = round3(l, m, j, k, work[3], 16, 0xd4ef3085); + k = round3(k, l, m, j, work[6], 23, 0x04881d05); + j = round3(j, k, l, m, work[9], 4, 0xd9d4d039); + m = round3(m, j, k, l, work[12], 11, 0xe6db99e5); + l = round3(l, m, j, k, work[15], 16, 0x1fa27cf8); + k = round3(k, l, m, j, work[2], 23, 0xc4ac5665); + + j = round4(j, k, l, m, work[0], 6, 0xf4292244); + m = round4(m, j, k, l, work[7], 10, 0x432aff97); + l = round4(l, m, j, k, work[14], 15, 0xab9423a7); + k = round4(k, l, m, j, work[5], 21, 0xfc93a039); + j = round4(j, k, l, m, work[12], 6, 0x655b59c3); + m = round4(m, j, k, l, work[3], 10, 0x8f0ccc92); + l = round4(l, m, j, k, work[10], 15, 0xffeff47d); + k = round4(k, l, m, j, work[1], 21, 0x85845dd1); + j = round4(j, k, l, m, work[8], 6, 0x6fa87e4f); + m = round4(m, j, k, l, work[15], 10, 0xfe2ce6e0); + l = round4(l, m, j, k, work[6], 15, 0xa3014314); + k = round4(k, l, m, j, work[13], 21, 0x4e0811a1); + j = round4(j, k, l, m, work[4], 6, 0xf7537e82); + m = round4(m, j, k, l, work[11], 10, 0xbd3af235); + l = round4(l, m, j, k, work[2], 15, 0x2ad7d2bb); + k = round4(k, l, m, j, work[9], 21, 0xeb86d391); + + m_data[0] += j; + m_data[1] += k; + m_data[2] += l; + m_data[3] += m; +} + +// ---------------------------------------------------------------------- + +void Md5::finish() +{ + DEBUG_FATAL(m_finished, ("PB: MD5 already finished")); + + uint64 messageLengthInBits = m_totalLength * 8; + + // we always have to append a trailing bit + { + byte append = 0x80; + update(&append, 1); + } + + // how much to pad to existing bytes to come out to an even 64 byte multiple, yet leave room at the end for the count. + while (m_bufferedBytes != (BUFFER_SIZE - 8)) + { + byte append = 0x00; + update(&append, 1); + } + + // append the length of the source message in bits + uint8 countAsBytes[8]; + wordsToBytes(reinterpret_cast(&(messageLengthInBits)), 2, countAsBytes); + update(countAsBytes, 8); + + m_finished = true; +} + +// ---------------------------------------------------------------------- + +Md5::Value Md5::getValue() const +{ + DEBUG_FATAL(!m_finished, ("PB: did not finish MD5 before calling getValue")); + + Value v; + wordsToBytes(m_data, 4, v.m_data); + return v; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/Md5.h b/engine/shared/library/sharedFoundation/src/shared/Md5.h new file mode 100644 index 00000000..d5cc8d32 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Md5.h @@ -0,0 +1,99 @@ +// ====================================================================== +// +// Md5.h +// +// copyright 2003 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_Md5_H +#define INCLUDED_Md5_H + +// ====================================================================== + +class Md5 +{ +public: + + class Value + { + friend class Md5; + + public: + + enum + { + cms_dataSize = 16 + }; + + public: + + Value(); + Value(Value const &rhs); + + bool operator ==(Value const &rhs) const; + bool operator !=(Value const &rhs) const; + void format(char *buffer, int bufferLength) const; + + void *getData(); + + private: + + uint8 m_data[cms_dataSize]; + }; + +public: + + static Value calculate(const char *string); + static Value calculate(const void *data, int len); + +public: + + Md5(); + + void reset(); + void update(void const *data, int len); + void finish(); + Value getValue() const; + +private: + + static void wordsToBytes(const uint32* words, size_t wordCnt, uint8* bytes); + static void bytesToWords(const uint8* bytes, size_t byteCnt, uint32* words); + static uint32 rotate_left(uint32 ival, uint32 shft); + static uint32 round1(uint32 i, uint32 j, uint32 k, uint32 l, uint32 i1, uint32 j1, uint32 k1); + static uint32 round2(uint32 i, uint32 j, uint32 k, uint32 l, uint32 i1, uint32 j1, uint32 k1); + static uint32 round3(uint32 i, uint32 j, uint32 k, uint32 l, uint32 i1, uint32 j1, uint32 k1); + static uint32 round4(uint32 i, uint32 j, uint32 k, uint32 l, uint32 i1, uint32 j1, uint32 k1); + + void transformBlock(void const *data); + +private: + + enum + { + BUFFER_SIZE = 64 + }; + + uint32 m_data[4]; + byte m_buffer[BUFFER_SIZE]; + int m_bufferedBytes; + int m_totalLength; + bool m_finished; + +public: + + Md5(Md5 const &); + Md5 & operator =(Md5 const &); +}; + +// ====================================================================== + +inline void * Md5::Value::getData() +{ + return m_data; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/MemoryBlockManager.cpp b/engine/shared/library/sharedFoundation/src/shared/MemoryBlockManager.cpp new file mode 100644 index 00000000..2ded12c9 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/MemoryBlockManager.cpp @@ -0,0 +1,636 @@ +// ====================================================================== +// +// MemoryBlockManager.cpp +// copyright 1998 Bootprint Entertainment +// copyright 2002 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/MemoryBlockManager.h" + +#include "sharedDebug/DebugFlags.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedSynchronization/Mutex.h" + +#include +#include + +#define PASS_THROUGH_TO_GLOBAL_MEMORY_MANAGER 0 + +// ====================================================================== + +class MemoryBlockManager::Allocator +{ +public: + + Allocator(int elementSize); + Allocator(int elementSize, int elementsPerBlock, int minimumBlocks, int maximumNumberOfBlocks); + ~Allocator(); + + int getElementSize(); + + void fetch(); + bool release(); + int getReferenceCount(); + + bool isFull() const; + int getNumberOfAllocatedElements(); + void *allocate(); + void free(void *pointer); + +#ifdef _DEBUG + void debugDump () const; +#endif + +private: + + struct Block + { + Block *next; + byte *data; + }; + + struct Element + { + Element *next; + }; + + void *realAlloc(); + void realFree(void *pointer); + + void placeOnFreeList(Element *element); + void allocateNewBlock(); + +private: + + Allocator(); + Allocator(Allocator const &); + Allocator &operator =(Allocator const &); + +private: + + int m_referenceCount; + + // first block on the allocated block list + Block *m_firstBlock; + + // first free element + Element *m_firstFreeElement; + + // size of each element + int m_elementSize; + + // number of elements per block + int m_elementsPerBlock; + + // current number of blocks in existance + int m_currentNumberOfBlocks; + + // current number of blocks that are allowed to exist, 0 for unliminted + int m_maximumNumberOfBlocks; + + // number of outstanding allocations + int m_numberOfAllocatedElements; + +#ifdef _DEBUG + int m_lifetimeAllocatedElements; +#endif +}; + +// ====================================================================== + +namespace MemoryBlockManagerNamespace +{ + bool ms_debugDumpOnRemove = false; + bool ms_forceAllNonShared = false; +#ifdef _DEBUG + bool ms_debugReport = false; + int ms_debugNumberOfAllocations = 0; + int ms_debugNumberOfBytes = 0; + bool ms_debugDumpAllNextFrame = false; + typedef std::vector MemoryBlockManagerList; + MemoryBlockManagerList ms_memoryBlockManagerList; +#endif + + typedef std::map Allocators; + Allocators ms_allocators; + + Mutex ms_globalCriticalSection; + +#ifdef _DEBUG + bool m_usingMemoryBlockManager = false; +#endif + + void remove(); +#ifdef _DEBUG + void debugReport(); + void debugDumpAll (); +#endif +} + +using namespace MemoryBlockManagerNamespace; + +// ====================================================================== + +MemoryBlockManager::Allocator::Allocator(const int elementSize) +: + m_referenceCount(0), + m_firstBlock(NULL), + m_firstFreeElement(NULL), + m_elementSize(elementSize), + m_elementsPerBlock(64), + m_currentNumberOfBlocks(0), + m_maximumNumberOfBlocks(0), + m_numberOfAllocatedElements(0) +#ifdef _DEBUG + , + m_lifetimeAllocatedElements(0) +#endif +{ +} + +// ---------------------------------------------------------------------- + +MemoryBlockManager::Allocator::Allocator(int elementSize, int elementsPerBlock, int minimumBlocks, int maximumNumberOfBlocks) +: + m_referenceCount(0), + m_firstBlock(NULL), + m_firstFreeElement(NULL), + m_elementSize(elementSize), + m_elementsPerBlock(elementsPerBlock), + m_currentNumberOfBlocks(0), + m_maximumNumberOfBlocks(maximumNumberOfBlocks), + m_numberOfAllocatedElements(0) +#ifdef _DEBUG + , + m_lifetimeAllocatedElements(0) +#endif +{ + for (int i = 0; i < minimumBlocks; ++i) + allocateNewBlock(); +} + +// ---------------------------------------------------------------------- + +MemoryBlockManager::Allocator::~Allocator() +{ + if (ExitChain::isFataling()) + return; + + while (m_firstBlock) + { + Block * block = m_firstBlock; + m_firstBlock = m_firstBlock->next; + delete [] block->data; + delete block; + } + + m_firstBlock = NULL; + m_firstFreeElement = NULL; +} + +// ---------------------------------------------------------------------- + +void MemoryBlockManager::Allocator::fetch() +{ + ++m_referenceCount; +} + +// ---------------------------------------------------------------------- + +bool MemoryBlockManager::Allocator::release() +{ + if (--m_referenceCount <= 0) + { + DEBUG_FATAL(m_referenceCount < 0, ("reference count went negative")); + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- + +inline int MemoryBlockManager::Allocator::getElementSize() +{ + return m_elementSize; +} + +// ---------------------------------------------------------------------- + +int MemoryBlockManager::Allocator::getReferenceCount() +{ + return m_referenceCount; +} + +// ---------------------------------------------------------------------- + +bool MemoryBlockManager::Allocator::isFull() const +{ + return m_maximumNumberOfBlocks && m_numberOfAllocatedElements >= m_elementsPerBlock * m_maximumNumberOfBlocks; +} + +// ---------------------------------------------------------------------- + +int MemoryBlockManager::Allocator::getNumberOfAllocatedElements() +{ + return m_numberOfAllocatedElements; +} + +// ---------------------------------------------------------------------- + +void *MemoryBlockManager::Allocator::allocate() +{ + void *result = 0; + + // check if there are any free elements + if (!m_firstFreeElement) + allocateNewBlock(); + + result = m_firstFreeElement; + m_firstFreeElement = m_firstFreeElement->next; + ++m_numberOfAllocatedElements; + +#ifdef _DEBUG + m_lifetimeAllocatedElements += 1; + ms_debugNumberOfAllocations += 1; + ms_debugNumberOfBytes += getElementSize(); +#endif + + return result; +} + +// ---------------------------------------------------------------------- + +void MemoryBlockManager::Allocator::free(void *pointer) +{ + DEBUG_FATAL(m_numberOfAllocatedElements <= 0, ("freeing an element when already empty")); + Element *element = reinterpret_cast(pointer); + placeOnFreeList(element); + --m_numberOfAllocatedElements; +} + +// ---------------------------------------------------------------------- +/** + * Places an element on the free element list + */ + +void MemoryBlockManager::Allocator::placeOnFreeList(Element *element) +{ + NOT_NULL(element); + element->next = m_firstFreeElement; + m_firstFreeElement = element; +} + +// ---------------------------------------------------------------------- +/** + * Get a new block and put its elements on the free list. + * + * Will not allocate a new block if the maximum number of blocks has already + * been reached. + */ + +void MemoryBlockManager::Allocator::allocateNewBlock() +{ + // allocate a new block + Block *block = new Block; + block->data = new byte[static_cast(m_elementSize * m_elementsPerBlock)]; + + // put the block on the block list + block->next = m_firstBlock; + m_firstBlock = block; + + // put all the new block elements on the free list + { + int i; + byte *data; + + for (i = m_elementsPerBlock, data = block->data; i; --i, data += m_elementSize) + placeOnFreeList(reinterpret_cast(data)); //lint !e826 // suspicious pointer conversion (area too small) + } + + // count the new block + ++m_currentNumberOfBlocks; +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG +void MemoryBlockManager::Allocator::debugDump() const +{ + const int currentUsageInKilobytes = m_numberOfAllocatedElements * m_elementSize / 1024; + const int totalUsageInKilobytes = (m_currentNumberOfBlocks * m_elementsPerBlock * m_elementSize) / 1024; + const int percent = totalUsageInKilobytes ? ((currentUsageInKilobytes * 100) / totalUsageInKilobytes) : 0; + DEBUG_REPORT_LOG(true, ("MBMA elementSize=%d elements=%d elementsPerBlock=%d blocks=%d mem=%dk full=%d%%\n", m_elementSize, m_numberOfAllocatedElements, m_elementsPerBlock, m_currentNumberOfBlocks, totalUsageInKilobytes, percent)); +} +#endif + +// ====================================================================== + +void MemoryBlockManager::install(bool debugDumpOnRemove) +{ + ms_debugDumpOnRemove = debugDumpOnRemove; + +#if PASS_THROUGH_TO_GLOBAL_MEMORY_MANAGER + DEBUG_WARNING(true, ("MemoryBlockManager enabled PASS_THROUGH_TO_GLOBAL_MEMORY_MANAGER")); +#endif + +#ifdef _DEBUG + m_usingMemoryBlockManager = ConfigSharedFoundation::getUseMemoryBlockManager(); +#endif +#if PASS_THROUGH_TO_GLOBAL_MEMORY_MANAGER + m_usingMemoryBlockManager = false; +#endif + + DebugFlags::registerFlag(ms_forceAllNonShared, "SharedFoundation", "memoryBlockManagerForceAllNonShared"); + REPORT_LOG(ms_forceAllNonShared, ("MemoryBlockManager enabled memoryBlockManagerForceAllNonShared\n")); + +#ifdef _DEBUG + DebugFlags::registerFlag(ms_debugReport, "SharedFoundation", "reportMemoryBlockManager", debugReport); + DebugFlags::registerFlag(ms_debugDumpAllNextFrame, "SharedFoundation", "memoryBlockManagerDebugDumpAllNextFrame", debugDumpAll); +#endif + + ExitChain::add(MemoryBlockManagerNamespace::remove, "MemoryBlockManager::remove"); +} + +// ---------------------------------------------------------------------- + +void MemoryBlockManagerNamespace::remove() +{ + ms_globalCriticalSection.enter(); + + Allocators::iterator iEnd = ms_allocators.end(); + for (Allocators::iterator i = ms_allocators.begin(); i != iEnd; ++i) + { + DEBUG_WARNING(true, ("Unfreed MBM %d=size %d=ref %d=items", i->second->getElementSize(), i->second->getReferenceCount(), i->second->getNumberOfAllocatedElements())); + } + +#ifdef _DEBUG + if (ms_debugDumpOnRemove) + { + debugDumpAll(); + } +#endif + + ms_globalCriticalSection.leave(); +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG +void MemoryBlockManagerNamespace::debugReport() +{ + ms_globalCriticalSection.enter(); + int const numberOfAllocations = ms_debugNumberOfAllocations; + ms_debugNumberOfAllocations = 0; + int const numberOfBytes = ms_debugNumberOfBytes; + ms_debugNumberOfBytes = 0; + ms_globalCriticalSection.leave(); + + DEBUG_REPORT_PRINT(true, ("mbm %d=alloc %d=bytes\n", numberOfAllocations, numberOfBytes)); +} +#endif + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG +void MemoryBlockManagerNamespace::debugDumpAll () +{ + { + // dump the memory block managers and their private allocators + uint i; + for (i = 0; i < ms_memoryBlockManagerList.size (); ++i) + ms_memoryBlockManagerList [i]->debugDump (); + } + + { + // dump the shared allocators + ms_globalCriticalSection.enter(); + + Allocators::iterator iEnd = ms_allocators.end(); + for (Allocators::iterator i = ms_allocators.begin(); i != iEnd; ++i) + i->second->debugDump(); + + ms_globalCriticalSection.leave(); + } + + ms_debugDumpAllNextFrame = false; +} +#endif + +// ====================================================================== + +MemoryBlockManager::MemoryBlockManager(char const * name, bool shared, int elementSize, int elementsPerBlock, int minimumNumberOfBlocks, int maximumNumberOfBlocks) +: m_name(name), + m_shared(shared), + m_currentNumberOfElements(0), + m_allocator(NULL) +{ + //-- Handle config option where we force all MemoryBlockManagers to be non-shared. + if (shared && ms_forceAllNonShared) + { + m_shared = false; + shared = false; + + if (elementsPerBlock <= 0) + { + //-- Adjust elements per block: caller specified as 0 because it thought it was going to be shared. + elementsPerBlock = 100; + } + } + + if (elementSize < isizeof(void*)) + elementSize = isizeof(void*); + + if (m_shared) + { + DEBUG_FATAL(elementsPerBlock, ("elementsPerBlock must be 0 if shared")); + DEBUG_FATAL(minimumNumberOfBlocks, ("minimumNumberOfBlocks must be 0 if shared")); + DEBUG_FATAL(maximumNumberOfBlocks, ("maximumNumberOfBlocks must be 0 if shared")); + + ms_globalCriticalSection.enter(); + + Allocators::iterator i = ms_allocators.find(elementSize); + if (i == ms_allocators.end()) + { + // construct it and put it on the map + i = ms_allocators.insert(Allocators::value_type(elementSize, new Allocator(elementSize))).first; + } + + m_allocator = i->second; + m_allocator->fetch(); + + ms_globalCriticalSection.leave(); + } + else + { + ms_globalCriticalSection.enter(); + + DEBUG_FATAL(elementsPerBlock == 0, ("elementsPerBlock may not be 0 if shared")); + m_allocator = new Allocator(elementSize, elementsPerBlock, minimumNumberOfBlocks, maximumNumberOfBlocks); + m_allocator->fetch(); + + ms_globalCriticalSection.leave(); + } + +#ifdef _DEBUG + { + ms_globalCriticalSection.enter(); + + ms_memoryBlockManagerList.push_back (this); + + ms_globalCriticalSection.leave(); + } +#endif +} + +// ---------------------------------------------------------------------- + +MemoryBlockManager::~MemoryBlockManager() +{ + if (ExitChain::isFataling()) + return; + + ms_globalCriticalSection.enter(); + +#ifdef _DEBUG + { + MemoryBlockManagerList::iterator iter = std::find (ms_memoryBlockManagerList.begin (), ms_memoryBlockManagerList.end (), this); + if (iter != ms_memoryBlockManagerList.end ()) + ms_memoryBlockManagerList.erase (iter); + } +#endif + + if (m_currentNumberOfElements) + { + DEBUG_WARNING(!ConfigSharedFoundation::getDemoMode(), ("MemoryBlockManager::~ %d elements still allocated in %s", m_currentNumberOfElements, m_name)); + ms_globalCriticalSection.leave(); + return; + } + + if (m_allocator->release()) + { + if (m_shared) + { + Allocators::iterator i = ms_allocators.find(getElementSize()); + DEBUG_FATAL(i == ms_allocators.end(), ("Allocator not found")); + DEBUG_FATAL(i->second != m_allocator, ("wrong allocator")); + ms_allocators.erase(i); + } + + delete m_allocator; + } + + ms_globalCriticalSection.leave(); + + m_allocator = 0; + m_name = 0; +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG +void MemoryBlockManager::debugDump() const +{ + DEBUG_REPORT_LOG(true, ("MBM %s: size=%d elements=%d\n", m_name ? m_name : "", m_allocator->getElementSize(), m_currentNumberOfElements)); + if (!m_shared) + m_allocator->debugDump(); +} +#endif + +// ---------------------------------------------------------------------- + +int MemoryBlockManager::getElementSize() const +{ + return m_allocator->getElementSize(); +} + +// ---------------------------------------------------------------------- + +int MemoryBlockManager::getElementCount() const +{ +#ifdef _DEBUG + if(!m_usingMemoryBlockManager) + { + return 0; + } +#endif + ms_globalCriticalSection.enter(); + int const result = m_currentNumberOfElements; + ms_globalCriticalSection.leave(); + return result; +} + +// ---------------------------------------------------------------------- + +bool MemoryBlockManager::isFull() const +{ +#ifdef _DEBUG + if(!m_usingMemoryBlockManager) + { + return false; + } +#endif + ms_globalCriticalSection.enter(); + const bool result = m_allocator->isFull(); + ms_globalCriticalSection.leave(); + return result; +} + +// ---------------------------------------------------------------------- + +void *MemoryBlockManager::allocate(bool returnNullOnFailure) +{ + UNREF(returnNullOnFailure); + +#ifdef _DEBUG + if(!m_usingMemoryBlockManager) + { + return operator new(getElementSize()); + } +#endif + ms_globalCriticalSection.enter(); + + if (m_allocator->isFull()) + { + ms_globalCriticalSection.leave(); + DEBUG_FATAL(!returnNullOnFailure, ("MBM %s is full %d", m_name, m_currentNumberOfElements)); + return NULL; + } + + ++m_currentNumberOfElements; + void * result = m_allocator->allocate(); + + ms_globalCriticalSection.leave(); + + return result; + +} + +// ---------------------------------------------------------------------- + +void MemoryBlockManager::free(void *pointer) +{ + if (pointer) + { +#ifdef _DEBUG + if(!m_usingMemoryBlockManager) + { + operator delete(pointer); + return; + } +#endif + ms_globalCriticalSection.enter(); + + if (--m_currentNumberOfElements < 0) + DEBUG_FATAL(true, ("MBM %s number of allocated elements went negative", m_name)); + m_allocator->free(pointer); + + ms_globalCriticalSection.leave(); + + } +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/MemoryBlockManager.h b/engine/shared/library/sharedFoundation/src/shared/MemoryBlockManager.h new file mode 100644 index 00000000..bb3ab1e1 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/MemoryBlockManager.h @@ -0,0 +1,69 @@ +// ====================================================================== +// +// MemoryBlockManager.h +// +// Portions copyright 1998 Bootprint Entertainment +// Portions copyright 2000-2002 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_MemoryBlockManager_H +#define INCLUDED_MemoryBlockManager_H + +// ====================================================================== + +class MemoryBlockManager +{ +public: + + static void install(bool debugDumpOnRemove); + +public: + + DLLEXPORT MemoryBlockManager(char const * name, bool shared, int elementSize, int elementsPerBlock, int minimumNumberOfBlocks, int maximumNumberOfBlocks); + DLLEXPORT ~MemoryBlockManager(); + + const char * getName() const; + + bool isFull() const; + DLLEXPORT int getElementSize() const; + int getElementCount() const; + + DLLEXPORT void * allocate(bool returnNullOnFailure=false); + DLLEXPORT void free(void * pointer); + +public: + +#ifdef _DEBUG + void debugDump() const; +#endif + +protected: + + // disable these routines + MemoryBlockManager(); + MemoryBlockManager(const MemoryBlockManager &); + MemoryBlockManager &operator =(const MemoryBlockManager &); + +public: + + class Allocator; + +private: + + char const * m_name; + bool m_shared; + int m_currentNumberOfElements; + Allocator * m_allocator; +}; + +// ====================================================================== + +inline char const * MemoryBlockManager::getName() const +{ + return m_name; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/MemoryBlockManagerMacros.h b/engine/shared/library/sharedFoundation/src/shared/MemoryBlockManagerMacros.h new file mode 100644 index 00000000..b105f207 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/MemoryBlockManagerMacros.h @@ -0,0 +1,107 @@ +// ====================================================================== +// +// MemoryBlockManagerMacros.h +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_MemoryBlockManagerMacros_H +#define INCLUDED_MemoryBlockManagerMacros_H + +// ====================================================================== + +class MemoryBlockManager; + +// ====================================================================== + +#define MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL \ + public: \ + static void install(); \ + static void * operator new(size_t size); \ + static void * operator new(size_t size, void * placement); \ + static void operator delete(void * pointer); \ + private: \ + static void remove(); \ + static MemoryBlockManager * ms_memoryBlockManager + +// ---------------------------------------------------------------------- + +#define MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(className, shared, elementsPerBlock, minimumNumberOfBlocks, maximumNumberOfBlocks) \ + void className::install() \ + { \ + ms_memoryBlockManager = new MemoryBlockManager( #className " memoryBlockManager", shared, sizeof(className), elementsPerBlock, minimumNumberOfBlocks, maximumNumberOfBlocks); \ + ExitChain::add(&remove, #className "::remove"); \ + } \ + void className::remove() \ + { \ + DEBUG_FATAL(!ms_memoryBlockManager,(#className " is not installed")); \ + delete ms_memoryBlockManager; \ + ms_memoryBlockManager = 0; \ + } \ + void * className::operator new(size_t size) \ + { \ + UNREF(size); \ + DEBUG_FATAL(size != sizeof(className),("Incorrect allocation size for class " #className ": %d/%d", size, sizeof(className))); \ + DEBUG_FATAL(!ms_memoryBlockManager, (#className " is not installed")); \ + return ms_memoryBlockManager->allocate(); \ + } \ + void * className::operator new(size_t, void * placement) \ + { \ + return placement; \ + }\ + void className::operator delete(void * pointer) \ + { \ + DEBUG_FATAL(!ms_memoryBlockManager,(#className " is not installed")); \ + if (pointer) \ + ms_memoryBlockManager->free(pointer); \ + } \ + MemoryBlockManager * className::ms_memoryBlockManager + +// ====================================================================== + +#define MEMORY_BLOCK_MANAGER_INTERFACE_WITHOUT_INSTALL \ + public: \ + static void * operator new(size_t size); \ + static void * operator new(size_t size, void * placement); \ + static void operator delete(void * pointer); \ + private: \ + static void installMemoryBlockManager(); \ + static void removeMemoryBlockManager(); \ + static MemoryBlockManager * ms_memoryBlockManager + +// ---------------------------------------------------------------------- + +#define MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITHOUT_INSTALL(className, shared, elementsPerBlock, minimumNumberOfBlocks, maximumNumberOfBlocks) \ + void className::installMemoryBlockManager() \ + { \ + ms_memoryBlockManager = new MemoryBlockManager( #className " memoryBlockManager", shared, sizeof(className), elementsPerBlock, minimumNumberOfBlocks, maximumNumberOfBlocks); \ + } \ + void className::removeMemoryBlockManager() \ + { \ + DEBUG_FATAL(!ms_memoryBlockManager,(#className " is not installed")); \ + delete ms_memoryBlockManager; \ + ms_memoryBlockManager = 0; \ + } \ + void * className::operator new(size_t size) \ + { \ + UNREF(size); \ + DEBUG_FATAL(size != sizeof(className),("Incorrect allocation size for class " #className ": %d/%d", size, sizeof(className))); \ + DEBUG_FATAL(!ms_memoryBlockManager, (#className " is not installed")); \ + return ms_memoryBlockManager->allocate(); \ + } \ + void * className::operator new(size_t, void * placement) \ + { \ + return placement; \ + }\ + void className::operator delete(void * pointer) \ + { \ + DEBUG_FATAL(!ms_memoryBlockManager,(#className " is not installed")); \ + if (pointer) \ + ms_memoryBlockManager->free(pointer); \ + } \ + MemoryBlockManager * className::ms_memoryBlockManager + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/MessageQueue.cpp b/engine/shared/library/sharedFoundation/src/shared/MessageQueue.cpp new file mode 100644 index 00000000..18d1215b --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/MessageQueue.cpp @@ -0,0 +1,319 @@ +// ====================================================================== +// +// MessageQueue.cpp +// Portions copyright 1998 Bootprint Entertainment. +// Portions copyright 2000-2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/MessageQueue.h" + +#include + +// ====================================================================== +// PUBLIC MessageQueue::Data +// ====================================================================== + +MessageQueue::Data::Data() +{ +} + +// ---------------------------------------------------------------------- + +MessageQueue::Data::~Data() +{ +} + +// ====================================================================== +// PUBLIC MessageQueue::Notification +// ====================================================================== + +MessageQueue::Notification::Notification() +{ +} + +// ---------------------------------------------------------------------- + +MessageQueue::Notification::~Notification() +{ +} + +// ====================================================================== +// PRIVATE MessageQueue::Message +// ====================================================================== + +MessageQueue::Message::Message() : + m_message(0), + m_value(0), + m_data(0), + m_flags(0) +{ +} + +//---------------------------------------------------------------------- + +MessageQueue::Message::~Message() +{ + m_data = 0; +} + +// ====================================================================== +// PUBLIC MessageQueue +// ====================================================================== + +MessageQueue::MessageQueue(const int initialSize) : + m_messageQueue1(new MessageList), + m_messageQueue2(new MessageList), + m_messageQueueRead(m_messageQueue1), + m_messageQueueWrite(m_messageQueue2), + m_notification(0) +{ + DEBUG_WARNING(initialSize < 0, ("initialSize < 0")); + m_messageQueue1->reserve(static_cast(std::max(initialSize, 0))); + m_messageQueue2->reserve(static_cast(std::max(initialSize, 0))); +} + +// ---------------------------------------------------------------------- +/** + * Destroy the MessageQueue. + */ + +MessageQueue::~MessageQueue() +{ + clearDataFromMessageList(*m_messageQueue1, true); + clearDataFromMessageList(*m_messageQueue2, true); + delete m_messageQueue1; + delete m_messageQueue2; + m_messageQueueRead = 0; + m_messageQueueWrite = 0; + m_notification = 0; +} + +// ---------------------------------------------------------------------- + +void MessageQueue::clearDataFromMessageList(MessageList &messageList, bool destructor) +{ + UNREF(destructor); + MessageList::iterator iEnd = messageList.end(); + for (MessageList::iterator i = messageList.begin(); i != iEnd; ++i) + { + Message & message = *i; + if (message.m_data) + { + DEBUG_WARNING(!destructor, ("clearing message data from beginFrame")); + delete message.m_data; + message.m_data = NULL; + } + } +} + +// ---------------------------------------------------------------------- +/** + * Get a message from the MessageQueue. + * + * The message index ranges from 0 to getNumberOfMessages()-1. + * + * @param index [In ] The index of the message to retrieve + * @param message [Out] The message received + * @param value [Out] Argument for the message + * @param flags [Out] User flags for this message + * @see MessageQueue::getNumberOfMessages() + */ + +void MessageQueue::getMessage(const int index, int *const message, float *const value, uint32 *const flags) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfMessages()); + NOT_NULL(message); + NOT_NULL(value); + NOT_NULL(m_messageQueueRead); + + const Message ¤tMessage = (*m_messageQueueRead)[static_cast(index)]; + *message = currentMessage.m_message; + *value = currentMessage.m_value; + if (flags) + *flags = currentMessage.m_flags; +} + +// ---------------------------------------------------------------------- +/** + * Get a message from the MessageQueue. + * + * The message index ranges from 0 to getNumberOfMessages()-1. + * + * @param index [In ] The index of the message to retrieve + * @param message [Out] The message received + * @param value [Out] Argument for the message + * @param data [Out] Data for the message + * @param flags [Out] User flags for this message + * @see MessageQueue::getNumberOfMessages() + */ + +void MessageQueue::getMessage(const int index, int *const message, float *const value, Data **const data, uint32 *const flags) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfMessages()); + NOT_NULL(message); + NOT_NULL(value); + NOT_NULL(data); + NOT_NULL(m_messageQueueRead); + + const Message & currentMessage = (*m_messageQueueRead)[static_cast(index)]; + *message = currentMessage.m_message; + *value = currentMessage.m_value; + *data = currentMessage.m_data; + + if (flags) + *flags = currentMessage.m_flags; +} + +// ---------------------------------------------------------------------- +/** + * Sets message flags in the MessageQueue. + * + * The message index ranges from 0 to getNumberOfMessages()-1. + * + * @see MessageQueue::getNumberOfMessages() + */ + +void MessageQueue::setMessageFlags(const int index, const uint32 flags) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfMessages()); + + (*m_messageQueueRead)[static_cast(index)].m_flags = flags; +} + +// ---------------------------------------------------------------------- +/** + * Clear a message in the MessageQueue. + * + * The message index ranges from 0 to getNumberOfMessages()-1. + * + * @param index [In] The index of the message to clear + * @see MessageQueue::getNumberOfMessages() + */ + +void MessageQueue::clearMessage(const int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfMessages()); + + Message& message = (*m_messageQueueRead)[static_cast(index)]; + DEBUG_WARNING(message.m_data, ("MessageQueue::clearMessage - clearing message with non-null data")); + message.m_message = 0; +} + +// ---------------------------------------------------------------------- +/** + * Clear a message in the MessageQueue. + * + * The message index ranges from 0 to getNumberOfMessages()-1. + * + * @param index [In] The index of the message data to clear + * @see MessageQueue::getNumberOfMessages() + */ + +void MessageQueue::clearMessageData(const int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfMessages()); + + Message& message = (*m_messageQueueRead)[static_cast(index)]; + message.m_data = 0; +} + +// ---------------------------------------------------------------------- +/** + * Append a new message to the MessageQueue. + * + * The message will not be retrievable until the next call to endFrame(). + * + * @param message [In] Message to add to the MessageQueue + * @param value [In] Value to be associated with the message + * @param data [In] Data to be associated with the message + * @param flags [In] User flags for this message + */ + +void MessageQueue::appendMessage(const int message, const float value, Data *const data, const uint32 flags) +{ + if (message == 0) + { + WARNING_STRICT_FATAL(true, ("bad message")); + return; + } + +#ifdef _DEBUG + //-- check to see if any message with data is already in the list + if (data) + { + for (MessageList::iterator iter = m_messageQueueWrite->begin(); iter != m_messageQueueWrite->end(); ++iter) + WARNING_STRICT_FATAL(iter->m_data == data, ("message queue data already in message queue")); + } +#endif + + Message newMessage; + newMessage.m_message = message; + newMessage.m_value = value; + newMessage.m_data = data; + newMessage.m_flags = flags; + m_messageQueueWrite->push_back(newMessage); + + if (m_notification) + m_notification->onChanged(); +} + +// ---------------------------------------------------------------------- +/** + * Append a new message to the MessageQueue. + * + * The message will not be retrievable until the next call to endFrame(). + * + * @param message [In] Message to add to the MessageQueue + * @param value [In] Value to be associated with the message + * @param flags [In] User flags for this message + */ + +void MessageQueue::appendMessage(const int message, const float value, const uint32 flags) +{ + appendMessage(message, value, 0, flags); +} + +// ---------------------------------------------------------------------- +// Get the number of messages in the current frame +// +// Return value: +// +// The number of messages in the current frame for the MessageQueue. +// +// Remarks: +// +// getMessage() will take as indices the values from 0 the value returned +// by this routine inclusive. +// +// See also: +// +// MessageQueue::getMessage() + +int MessageQueue::getNumberOfMessages() const +{ + return static_cast(m_messageQueueRead->size()); +} + +// ---------------------------------------------------------------------- + +void MessageQueue::beginFrame() +{ + //-- swap read and write + std::swap (m_messageQueueRead, m_messageQueueWrite); + + //-- clear write + clearDataFromMessageList(*m_messageQueueWrite, false); + m_messageQueueWrite->clear (); +} + +// ---------------------------------------------------------------------- + +void MessageQueue::setNotification(Notification* notification) +{ + m_notification = notification; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/MessageQueue.h b/engine/shared/library/sharedFoundation/src/shared/MessageQueue.h new file mode 100644 index 00000000..46b67b8e --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/MessageQueue.h @@ -0,0 +1,97 @@ +// ====================================================================== +// +// MessageQueue.h +// Portions copyright 1998 Bootprint Entertainment. +// Portions copyright 2000-2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_MessageQueue_H +#define INCLUDED_MessageQueue_H + +// ====================================================================== + +class MessageQueue +{ +public: + + class Data + { + public: + + Data(); + virtual ~Data()=0; + }; + + class Notification + { + public: + + Notification(); + virtual ~Notification()=0; + + virtual void onChanged() const=0; + }; + +public: + + explicit MessageQueue(int initialSize=0); + ~MessageQueue(); + + int getNumberOfMessages() const; + void getMessage(int index, int *message, float *value, uint32 *flags=0) const; + void getMessage(int index, int *message, float *value, Data **data, uint32 *flags=0) const; + + void setMessageFlags(int index, uint32 flags); + + void clearMessage(int index); + void clearMessageData(int index); + + void appendMessage(int message, float value, uint32 flags=0); + void appendMessage(int message, float value, Data *data, uint32 flags=0); + + void beginFrame(); + + void setNotification(Notification* notification); + +private: + + struct Message + { + public: + + Message(); + ~Message(); + + public: + + int m_message; + float m_value; + Data *m_data; + uint32 m_flags; + }; + +private: + + typedef stdvector::fwd MessageList; + +private: + + MessageQueue(const MessageQueue &); + MessageQueue &operator =(const MessageQueue &); + + void clearDataFromMessageList(MessageList &messageList, bool destructor); + +private: + + MessageList *const m_messageQueue1; + MessageList *const m_messageQueue2; + MessageList *m_messageQueueRead; + MessageList *m_messageQueueWrite; + Notification *m_notification; +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/MessageQueueDataTemplate.cpp b/engine/shared/library/sharedFoundation/src/shared/MessageQueueDataTemplate.cpp new file mode 100644 index 00000000..8f9fb78a --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/MessageQueueDataTemplate.cpp @@ -0,0 +1,18 @@ +//====================================================================== +// +// MessageQueueDataTemplate.cpp +// copyright (c) 2002 Sony Online Entertainment +// +//====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/MessageQueueDataTemplate.h" + +#include + +//====================================================================== + +MessageQueueDataTemplate it; +MessageQueueDataTemplate st; + +//====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/MessageQueueDataTemplate.h b/engine/shared/library/sharedFoundation/src/shared/MessageQueueDataTemplate.h new file mode 100644 index 00000000..8d1f995f --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/MessageQueueDataTemplate.h @@ -0,0 +1,57 @@ +//====================================================================== +// +// MessageQueueDataTemplate.h +// copyright (c) 2002 Sony Online Entertainment +// +//====================================================================== + +#ifndef INCLUDED_MessageQueueDataTemplate_H +#define INCLUDED_MessageQueueDataTemplate_H + +#include "sharedFoundation/MessageQueue.h" + +//====================================================================== + +template class MessageQueueDataTemplate : +public MessageQueue::Data +{ +public: + + MessageQueueDataTemplate () : + MessageQueue::Data (), + m_data () + { + } + + explicit MessageQueueDataTemplate (const T & t) : + MessageQueue::Data (), + m_data (t) + { + } + + const T & getData () const + { + return m_data; + } + + T & getData () + { + return m_data; + } + + void setData (const T & t) const + { + m_data = t; + } + +private: + + MessageQueueDataTemplate (const MessageQueueDataTemplate & rhs); + MessageQueueDataTemplate & operator= (const MessageQueueDataTemplate & rhs); + + T m_data; +}; + +//====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/Misc.h b/engine/shared/library/sharedFoundation/src/shared/Misc.h new file mode 100644 index 00000000..326d3341 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Misc.h @@ -0,0 +1,394 @@ +// ====================================================================== +// +// Misc.h +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#ifndef MISC_H +#define MISC_H + +// ====================================================================== +/** + * Return the square of a number. + * + * This routine is templated, and implemented in terms of the * operator. + * + * @return The square of its argument + */ +template +inline T sqr( + const T &t // The number to square + ) +{ + return (t * t); +} + +// ---------------------------------------------------------------------- +/** + * Make sure value is between two values. + * + * This routine is templated, and implemented in terms of the > and > operators. + * + * @param minT Minimum variable + * @param t Variable to clamp against min and max + * @param maxT Minimum variable + * @return If t is less than min, return min; if t is greater than max, return max + * otherwise, return t + */ + +templateinline const T clamp(const T &minT, const T &t, const T &maxT) +{ + DEBUG_FATAL(maxT < minT, ("clamp error: max value is less than min value")); + return (t < minT) ? minT : ((t > maxT) ? maxT : t); +} + +// ---------------------------------------------------------------------- +/** + * returns whether a value is within a given range, including the range end points. + * + * This routine will fatal in debug builds if max is less than min. + * + * @return True if value falls within the range min .. max, including min and max, + * false otherwise. + */ + +templateinline bool WithinRangeInclusiveInclusive(const T &rangeMin, const T &value, const T &rangeMax) +{ + DEBUG_FATAL(rangeMax < rangeMin, ("range error: max value is less than min value")); + return (value >= rangeMin) && (value <= rangeMax); +} + +// ---------------------------------------------------------------------- +/** + * returns whether a value is within a given range, excluding the range end points. + * + * This routine will fatal in debug builds if max is less than min. + * + * @return True if value falls within the range min .. max, not including min and max, + * false otherwise. + */ + +templateinline bool WithinRangeExclusiveExclusive(const T &rangeMin, const T &value, const T &rangeMax) +{ + DEBUG_FATAL(rangeMax < rangeMin, ("range error: max value is less than min value")); + return (value > rangeMin) && (value < rangeMax); +} + +// ---------------------------------------------------------------------- +/** + * returns true if a value falls within the range (base - epsilon) .. (base + epsilon), + * including range endpoints. + * + * This routine will fatal during debug builds if epsilon is less than zero. + * + * @return true if value is within the range (base - epsilon) .. (base + epsilon), including + * the range endpoints. Otherwise returns false. + */ + +templateinline bool WithinEpsilonInclusive(const T &base, const T &value, const T &epsilon) +{ + DEBUG_FATAL(epsilon < static_cast(0), ("error: epsilon is less than zero")); + return (value >= base - epsilon) && (value <= base + epsilon); +} + +// ---------------------------------------------------------------------- +/** + * returns true if a value falls within the range (base - epsilon) .. (base + epsilon), + * excluding range endpoints. + * + * This routine will fatal during debug builds if epsilon is less than zero. + * + * @return true if value is within the range (base - epsilon) .. (base + epsilon), including + * the range endpoints. Otherwise returns false. + */ + +templateinline bool WithinEpsilonExclusive(const T &base, const T &value, const T &epsilon) +{ + DEBUG_FATAL(epsilon < static_cast(0), ("error: epsilon is less than zero")); + return (value > base - epsilon) && (value < base + epsilon); +} + +// ---------------------------------------------------------------------- +/** + * Zero out an object. + * + * This routine is templated. + * + * This routine will byte-zero fill the object which is passed to it. + * + * @param t The object to zero out + */ + +templateinline void Zero(T &t) +{ + memset(&t, 0, sizeof(t)); +} + +// ---------------------------------------------------------------------- +/** + * Duplicate a string. + * + * This routine allocates memory for a copy of its argument, copies + * the source string into the new memory, and then returns a pointer to + * the new memory. + * + * This routine will return NULL if called with NULL. + * + * @param source The string to copy + * @return A pointer to a copy of the source argument + */ + +inline char *DuplicateString(const char *source) +{ + if (!source) + return NULL; + + const uint length = strlen(source)+1; + char *result = NON_NULL (new char[length]); + memcpy(result, source, length); + return result; +} + +// ---------------------------------------------------------------------- +/** + * Duplicate a string. + * + * This routine allocates memory for a copy of its argument, copies + * the source string into the new memory, and then returns a pointer to + * the new memory. + * + * This routine will return NULL if called with NULL. + * + * @param source The string to copy + * @return A pointer to a copy of the source argument + */ + +inline char *DuplicateStringWithToLower(const char *source) +{ + if (!source) + return NULL; + + const uint length = strlen(source)+1; + char *result = NON_NULL (new char[length]); + + for (uint i = 0; i < length; ++i) + result[i] = static_cast(tolower(source[i])); + + return result; +} + +// ---------------------------------------------------------------------- +/** + * memset with a integer length. + * + * This routine will + * + * @param data Location to fill at + * @param value Vvalue to fill with + * @param length Number of bytes to fill + */ + +inline void imemset(void *data, int value, int length) +{ + DEBUG_FATAL(!data, ("null data arg")); + memset(data, value, static_cast(length)); +} + +// ---------------------------------------------------------------------- +/** + * memcpy with a integer length. + * + * This routine will + * + * @param destination Location to copy to + * @param source Location to copy from + * @param length Number of bytes to copy + */ + +inline void imemcpy(void *destination, const void *source, int length) +{ + DEBUG_FATAL(!destination, ("null destination arg")); + DEBUG_FATAL(!source, ("null source arg")); + memcpy(destination, source, static_cast(length)); +} + +// ---------------------------------------------------------------------- +/** + * memmove with a integer length. + * + * This routine will + * + * @param destination Location to copy to + * @param source Location to copy from + * @param length Number of bytes to copy + */ + +inline void *memmove(void *destination, const void *source, int length) +{ + DEBUG_FATAL(!destination, ("null destination arg")); + DEBUG_FATAL(!source, ("null source arg")); + return memmove(destination, source, static_cast(length)); +} + +// ---------------------------------------------------------------------- +/** + * Returns the length of the string as an int. + * + * @param string String to compute the length + * @return The length of the string as an int + */ + +inline int istrlen(const char *string) +{ + DEBUG_FATAL(!string, ("null string arg")); + return static_cast(strlen(string)); +} + +// ---------------------------------------------------------------------- +/** + * Determine if a number is a power of two. + * + * This routine runs in O(1) time. + * + * @param value Value to see if it is a power of two + * @return True if the value is a power of two, otherwise false + */ + +template inline bool IsPowerOfTwo(T value) +{ + return ((value - 1) & (value)) == 0; +} + +// ---------------------------------------------------------------------- +/** + * Returns the number of bits set in an integral type. + * + * Type T must provide integral-type bitwise operations and semantics. + * + * @param value Value to count the number of bits + */ + +template inline int GetBitCount(T value) +{ + int count = 0; + while (value) + { + value &= (value-1); + ++count; + } + + return count; +} + +// ---------------------------------------------------------------------- +/** + * Returns the index of the first bit set in an integral type. + * + * Type T must provide integral-type bitwise operations and semantics. + * + * @param value Value to find the first set bit + * @return Returns the zero-based index of the first bit set in an + * integral type, with the least significant byte being index 0. + * + * Returns -1 if no bits are set in the value. + */ + +templateinline int GetFirstBitSet(T value) +{ + if (!value) + return -1; + + int count; + for (count = 0; !(value & static_cast(0x01)); ++count, value >>= 1) + {} + + return count; +} + +// ---------------------------------------------------------------------- +/** + * Calculate the factorial of the specified value. + * + * This routine takes O(n) time to compute. + * + * @param number The number to compute the factorial of + * @return The factorial of the specified value + */ + +inline int factorial(int number) +{ + int i, result; + + for (result = 1, i = 2; i <= number; ++i) + result *= i; + + return result; +} + +// ---------------------------------------------------------------------- +/** + * Calculate the number of combinations of i elements taken from a set of n elements. + * + * This routine computes: n! / (i! * (n-i)!). + * + * @param n Number of elements in the set + * @param i Number of elements to pick from the set + * @return The number of distinct combinations + */ + +inline int choose(int n, int i) +{ + return factorial(n) / (factorial(i) * factorial(n - i)); +} + +// ---------------------------------------------------------------------- +/** + * Linear interpolate from start to end along t, where t is from 0..1. + * + * t must be from 0..1 + * + * @return A value from start to end + */ + +template const T linearInterpolate (const T& start, const T& end, const real t) +{ + return static_cast((end - start) * t) + start; +} + +// ---------------------------------------------------------------------- +/** + * A non-linear, smooth interpolation from start to end along t, where t is from 0..1. + * + * (-2 * (end - start) * t^3) + (3 * (end - start) * t^2) + start + * + * t must be from 0..1 + * + * @return A value from start to end + */ + +template const T cubicInterpolate(const T& start, const T& end, const real t) +{ + real const tSquared = sqr(t); + real const tCubed = tSquared * t; + T const & diff = end - start; + return static_cast((diff * (tCubed * static_cast(-2))) + (diff * (tSquared * static_cast(3))) + start); +} + +// ---------------------------------------------------------------------- +/** + * A lint-friendly boolean compare. + * + * @return A value from start to end + */ + +inline bool boolEqual(bool const lhs, bool const rhs) +{ + return (lhs && rhs) || (!lhs && !rhs); +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/NetworkId.cpp b/engine/shared/library/sharedFoundation/src/shared/NetworkId.cpp new file mode 100644 index 00000000..3db80ec8 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/NetworkId.cpp @@ -0,0 +1,110 @@ +// ====================================================================== +// +// NetworkId.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/NetworkId.h" + +#include +#include + +// ====================================================================== + +const NetworkId NetworkId::cms_invalid(static_cast(0)); + +// buildout network id occupies the sign bit in the 8 byte signed NetworkId (i.e. buildout network id is negative) +// 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 + +// client side fake network id (in ClientObject.cpp) occupies the highest non-sign bit location in the 8 byte signed NetworkId +// 01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 + +// the 8 bit cluster id occupies these bit locations in the 8 byte NetworkId +// 00111111 11000000 00000000 00000000 00000000 00000000 00000000 00000000 + +// other network id will occupy the remaining bits +// 00000000 00111111 11111111 11111111 11111111 11111111 11111111 11111111 +const NetworkId::NetworkIdType NetworkId::cms_maxNetworkIdWithoutClusterId(0x3FFFFFFFFFFFFFll); +const NetworkId::NetworkIdType NetworkId::cms_networkIdWithoutClusterIdMask(0x403FFFFFFFFFFFFFll); +const NetworkId::NetworkIdType NetworkId::cms_clusterIdMask(0x3FC0000000000000ll); + +// ====================================================================== + +NetworkId::NetworkId() : +m_value(0) +{ +} + +// ----------------------------------------------------------------------- + +NetworkId::NetworkId(NetworkIdType value) : +m_value(value) +{ +} + +// ----------------------------------------------------------------------- + +NetworkId::NetworkId(const NetworkId& source) : +m_value(source.getValue()) +{ +} + +// ----------------------------------------------------------------------- + + +NetworkId::~NetworkId() +{ +} + +// ----------------------------------------------------------------------- + +std::string NetworkId::getValueString() const +{ + char tmp[256]; + sprintf(tmp,INT64_FORMAT_SPECIFIER,m_value); + return tmp; +} + +// ---------------------------------------------------------------------- + +NetworkId::NetworkId(const std::string &value) : + m_value(0) +{ + sscanf(value.c_str(),INT64_FORMAT_SPECIFIER,&m_value); +} + +// ---------------------------------------------------------------------- + +NetworkId::NetworkIdType NetworkId::getValueWithClusterId(uint8 const clusterId, NetworkIdType const validForConversionMin, NetworkIdType const validForConversionMax) const +{ + if ((m_value < validForConversionMin) || (m_value > validForConversionMax) || (clusterId == 0) || (m_value == 0)) + return m_value; + + uint64 const uint64ClusterId = static_cast(clusterId); + return static_cast((uint64ClusterId << 54) | static_cast(m_value)); +} + +// ---------------------------------------------------------------------- + +NetworkId::NetworkIdType NetworkId::getValueWithoutClusterId() const +{ + if (m_value <= cms_maxNetworkIdWithoutClusterId) + return m_value; + + return static_cast(static_cast(cms_networkIdWithoutClusterIdMask) & static_cast(m_value)); +} + +// ---------------------------------------------------------------------- + +uint8 NetworkId::getValueClusterId() const +{ + if (m_value <= cms_maxNetworkIdWithoutClusterId) + return 0; + + return static_cast((static_cast(cms_clusterIdMask) & static_cast(m_value)) >> 54); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/NetworkId.h b/engine/shared/library/sharedFoundation/src/shared/NetworkId.h new file mode 100644 index 00000000..1f42fc60 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/NetworkId.h @@ -0,0 +1,168 @@ +// ====================================================================== +// +// NetworkId.h +// Portions copyright 1999 Bootprint Entertainment +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_NetworkId_H +#define INCLUDED_NetworkId_H + +namespace DB +{ + class BindableNetworkId; +} + +// ====================================================================== + +class NetworkId +{ +public: + + typedef int64 NetworkIdType; + + static const NetworkId cms_invalid; + static const NetworkIdType cms_maxNetworkIdWithoutClusterId; + static const NetworkIdType cms_networkIdWithoutClusterIdMask; + static const NetworkIdType cms_clusterIdMask; + struct Hash; + friend struct NetworkId::Hash; + +public: + + NetworkId(); + explicit NetworkId(NetworkIdType value); + explicit NetworkId(const std::string &value); + NetworkId(const NetworkId&); + + ~NetworkId(); + + NetworkIdType getValueWithClusterId(uint8 clusterId, NetworkIdType validForConversionMin, NetworkIdType validForConversionMax) const; + NetworkIdType getValueWithoutClusterId() const; + uint8 getValueClusterId() const; + NetworkIdType getValue() const; + std::string getValueString() const; + + NetworkId& operator= (const NetworkId&); + bool operator< (const NetworkId& rhs) const; + bool operator== (const NetworkId& rhs) const; + bool operator!= (const NetworkId& rhs) const; + size_t getHashValue() const; + + bool isValid() const; + bool operator !() const; + + struct Hash + { + size_t operator()(const NetworkId & source) const + { + return source.getHashValue(); //TODO: make better hash function + }; + }; + +private: + NetworkIdType m_value; + + friend class DB::BindableNetworkId; + + private: + explicit NetworkId(int value); // catch people who incorrectly try to construct one of these from an int + // also makes constructing one of these from any other incorrect numeric type ambiguous +}; + +// ----------------------------------------------------------------------- + +inline NetworkId::NetworkIdType NetworkId::getValue() const +{ + return m_value; +} + +// ----------------------------------------------------------------------- + +inline NetworkId& NetworkId::operator= (const NetworkId& rhs) +{ + m_value = rhs.m_value; + return *this; +} + +// ----------------------------------------------------------------------- + +inline bool NetworkId::operator< (const NetworkId& rhs) const +{ + return m_value < rhs.m_value; +} + +// ----------------------------------------------------------------------- + +inline bool NetworkId::operator== (const NetworkId& rhs) const +{ + return m_value == rhs.m_value; +} + +// ----------------------------------------------------------------------- + +inline bool NetworkId::operator!= (const NetworkId& rhs) const +{ + return m_value != rhs.m_value; +} + +// ----------------------------------------------------------------------- + +inline bool NetworkId::isValid () const +{ + return m_value != 0; +} + +// ----------------------------------------------------------------------- + +inline bool NetworkId::operator! () const +{ + return m_value == 0; +} + +//------------------------------------------------------------------------ + +inline size_t NetworkId::getHashValue () const +{ + static uint32 const cs_randomValues[] = + { + 0x904618ec, + 0x95c2f264, + 0xe55c30fe, + 0x2c92d2d1, + 0x8376930b, + 0x17662d70, + 0x2a785b31, + 0x1e7c7281, + 0x60bc4645, + 0x9a0cdf8f, + 0xa9bc133d, + 0x0e9a17ec, + 0xcd768a0d, + 0xe03e104f, + 0xecfab1bd, + 0x764a3a6f + }; + + uint32 a = static_cast< uint32 >( m_value >> 32 ); + uint32 b = static_cast< uint32 >( m_value & 0xffffffff ); + return ( ( b * 0x10001 ) ^ a ) ^ cs_randomValues[ b & 0xf ] ; // multiply lower 32 by a large prime then XOR a then XOR some random value from table +} + +// ----------------------------------------------------------------------- + +// STL standard hash function +namespace std +{ + +template <> +struct hash // stl standard hash +{ + size_t operator()(const NetworkId &x) const { return x.getHashValue(); } +}; + +} + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/NetworkIdArchive.cpp b/engine/shared/library/sharedFoundation/src/shared/NetworkIdArchive.cpp new file mode 100644 index 00000000..fc5478be --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/NetworkIdArchive.cpp @@ -0,0 +1,69 @@ +// ====================================================================== +// +// NetworkIdArchive.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/NetworkIdArchive.h" + +#include "Archive/ByteStream.h" +#include "sharedFoundation/NetworkId.h" + +// ====================================================================== + +namespace Archive +{ + //----------------------------------------------------------------------- + + void get(ReadIterator & source, uint64 & target) + { + source.get(&target, 8); + } + + //----------------------------------------------------------------------- + + void put(ByteStream & target, const uint64 & source) + { + target.put(&source, 8); + } + + //----------------------------------------------------------------------- + + void get(ReadIterator & source, int64 & target) + { + source.get(&target, 8); + } + + //----------------------------------------------------------------------- + + void put(ByteStream & target, const int64 & source) + { + target.put(&source, 8); + } + + //----------------------------------------------------------------------- + + void get(ReadIterator & source, NetworkId & target) + { + int64 id; // Using int64 instead of NetworkIdType so that we get a compile error if we change it + //source.get(&id,8); // because this line hard-codes the size + get(source, id); + target = NetworkId(id); + } + + //----------------------------------------------------------------------- + + void put(ByteStream & target, const NetworkId & source) + { + //uint64 tmp = source.getValue(); + put(target, source.getValue()); + //target.put(&tmp,8); + } + + //----------------------------------------------------------------------- +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/NetworkIdArchive.h b/engine/shared/library/sharedFoundation/src/shared/NetworkIdArchive.h new file mode 100644 index 00000000..3b6388a7 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/NetworkIdArchive.h @@ -0,0 +1,33 @@ +// ====================================================================== +// +// NetworkIdArchive.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_NetworkIdArchive_H +#define INCLUDED_NetworkIdArchive_H + +// ====================================================================== + +class NetworkId; + +// ====================================================================== + +namespace Archive +{ + class ReadIterator; + class ByteStream; + + void get(ReadIterator & source, uint64 & target); + void put(ByteStream & target, const uint64 & source); + void get(ReadIterator & source, int64 & target); + void put(ByteStream & target, const int64 & source); + void get(ReadIterator & source, NetworkId & target); + void put(ByteStream & target, const NetworkId & source); +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/PersistentCrcString.cpp b/engine/shared/library/sharedFoundation/src/shared/PersistentCrcString.cpp new file mode 100644 index 00000000..7de5a7d3 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/PersistentCrcString.cpp @@ -0,0 +1,259 @@ +// ====================================================================== +// +// PersistentCrcString.cpp +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/PersistentCrcString.h" + +#include "sharedFoundation/Crc.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedFoundation/Os.h" + +// ====================================================================== + +namespace PersistentCrcStringNamespace +{ + void remove(); + + MemoryBlockManager * ms_fakeConstCharMemoryBlockManager = reinterpret_cast(0x01); + MemoryBlockManager * ms_memoryBlockManager8; + MemoryBlockManager * ms_memoryBlockManager16; + MemoryBlockManager * ms_memoryBlockManager32; + MemoryBlockManager * ms_memoryBlockManager48; + MemoryBlockManager * ms_memoryBlockManager64; +} +using namespace PersistentCrcStringNamespace; + +// ====================================================================== + +PersistentCrcString const PersistentCrcString::empty("", CC_true); + +// ====================================================================== + +void PersistentCrcString::install() +{ + ms_memoryBlockManager8 = new MemoryBlockManager("PersistentCrcString8", true, 8, 0, 0, 0); + ms_memoryBlockManager16 = new MemoryBlockManager("PersistentCrcString16", true, 16, 0, 0, 0); + ms_memoryBlockManager32 = new MemoryBlockManager("PersistentCrcString32", true, 32, 0, 0, 0); + ms_memoryBlockManager48 = new MemoryBlockManager("PersistentCrcString48", true, 48, 0, 0, 0); + ms_memoryBlockManager64 = new MemoryBlockManager("PersistentCrcString64", true, 64, 0, 0, 0); + ExitChain::add(PersistentCrcStringNamespace::remove, "PersistentCrcStringNamespace::remove"); +} + +// ---------------------------------------------------------------------- + +void PersistentCrcStringNamespace::remove() +{ + delete ms_memoryBlockManager8; + ms_memoryBlockManager8 = NULL; + delete ms_memoryBlockManager16; + ms_memoryBlockManager16 = NULL; + delete ms_memoryBlockManager32; + ms_memoryBlockManager32 = NULL; + delete ms_memoryBlockManager48; + ms_memoryBlockManager48 = NULL; + delete ms_memoryBlockManager64; + ms_memoryBlockManager64 = NULL; +} + +// ====================================================================== + +PersistentCrcString::PersistentCrcString() +: CrcString(), + m_memoryBlockManager(NULL), + m_buffer(NULL) +{ + DEBUG_FATAL(!ms_memoryBlockManager8, ("Constructing a PersistentCrcString before the class is installed")); +} + +// ---------------------------------------------------------------------- + +PersistentCrcString::PersistentCrcString(CrcString const &rhs) +: CrcString(), + m_memoryBlockManager(NULL), + m_buffer(NULL) +{ + DEBUG_FATAL(!ms_memoryBlockManager8, ("Constructing a PersistentCrcString before the class is installed")); + + if (!rhs.isEmpty()) + PersistentCrcString::set(rhs.getString(), rhs.getCrc()); +} + +// ---------------------------------------------------------------------- + +PersistentCrcString::PersistentCrcString(PersistentCrcString const &rhs) +: CrcString(), //lint !e1738 // non copy constructor used to initialize base class // this appears to be intentional. + m_memoryBlockManager(NULL), + m_buffer(NULL) +{ + DEBUG_FATAL(!ms_memoryBlockManager8, ("Constructing a PersistentCrcString before the class is installed")); + + if (!rhs.isEmpty()) + PersistentCrcString::set(rhs.getString(), rhs.getCrc()); +} + +// ---------------------------------------------------------------------- + +PersistentCrcString::PersistentCrcString(char const * string, bool applyNormalize) +: CrcString(), + m_memoryBlockManager(NULL), + m_buffer(NULL) +{ + DEBUG_FATAL(!ms_memoryBlockManager8, ("Constructing a PersistentCrcString before the class is installed")); + + if (string) + PersistentCrcString::set(string, applyNormalize); +} + +// ---------------------------------------------------------------------- + +PersistentCrcString::PersistentCrcString(char const * string, uint32 crc) +: CrcString(), + m_memoryBlockManager(NULL), + m_buffer(NULL) +{ + DEBUG_FATAL(!ms_memoryBlockManager8, ("Constructing a PersistentCrcString before the class is installed")); + + NOT_NULL(string); + PersistentCrcString::set(string, crc); +} + +// ---------------------------------------------------------------------- + +PersistentCrcString::PersistentCrcString(char const * string, ConstChar) +: CrcString(), + m_memoryBlockManager(ms_fakeConstCharMemoryBlockManager), + m_buffer(const_cast(string)) +{ +#ifdef _DEBUG + DEBUG_FATAL(strlen(string)+1 >= Os::MAX_PATH_LENGTH, ("source string too long %d/%d",strlen(string)+1, Os::MAX_PATH_LENGTH)); + char buffer[Os::MAX_PATH_LENGTH]; + normalize(buffer, string); + DEBUG_FATAL(strcmp(string, buffer) != 0, ("source string was not normalized")); +#endif + + calculateCrc(); +} + +// ---------------------------------------------------------------------- + +PersistentCrcString::~PersistentCrcString() +{ + if (!ms_memoryBlockManager8 && m_memoryBlockManager && m_memoryBlockManager != ms_fakeConstCharMemoryBlockManager) + { + DEBUG_FATAL(true, ("Destructing a PersistentCrcString after the class was removed")); + } + + internalFree(); +} + +// ---------------------------------------------------------------------- + +char const * PersistentCrcString::getString() const +{ + return m_buffer ? m_buffer : ""; +} + +// ---------------------------------------------------------------------- + +void PersistentCrcString::internalFree() +{ + if (m_buffer) + { + if (m_memoryBlockManager) + { + if (m_memoryBlockManager == ms_fakeConstCharMemoryBlockManager) + { + m_memoryBlockManager = NULL; + } + else + { + m_memoryBlockManager->free(m_buffer); + m_memoryBlockManager = NULL; + } + } + else + delete [] m_buffer; + + m_buffer = NULL; + } +} + +// ---------------------------------------------------------------------- + +void PersistentCrcString::clear() +{ + internalFree(); + m_crc = Crc::crcNull; +} + +// ---------------------------------------------------------------------- + +void PersistentCrcString::internalSet(char const * string, bool applyNormalize) +{ + internalFree(); + + const int stringLength = istrlen(string) + 1; + DEBUG_FATAL(stringLength > Os::MAX_PATH_LENGTH, ("string too long for a filename")); + + m_memoryBlockManager = NULL; + if (stringLength <= 8) + m_memoryBlockManager = ms_memoryBlockManager8; + else + if (stringLength <= 16) + m_memoryBlockManager = ms_memoryBlockManager16; + else + if (stringLength <= 32) + m_memoryBlockManager = ms_memoryBlockManager32; + else + if (stringLength <= 48) + m_memoryBlockManager = ms_memoryBlockManager48; + else + if (stringLength <= 64) + m_memoryBlockManager = ms_memoryBlockManager64; + + if (m_memoryBlockManager) + m_buffer = reinterpret_cast(m_memoryBlockManager->allocate()); + else + m_buffer = new char[static_cast(stringLength)]; + + if (applyNormalize) + normalize(m_buffer, string); + else + strcpy(m_buffer, string); +} + +// ---------------------------------------------------------------------- + +void PersistentCrcString::set(char const * string, bool applyNormalize) +{ + NOT_NULL(string); + internalSet(string, applyNormalize); + calculateCrc(); +} + +// ---------------------------------------------------------------------- + +void PersistentCrcString::set(char const * string, uint32 crc) +{ + NOT_NULL(string); + internalSet(string, false); + m_crc = crc; +} + +//---------------------------------------------------------------------- + +PersistentCrcString const & PersistentCrcString::operator=(PersistentCrcString const & rhs) +{ + if (this != &rhs) + CrcString::set(rhs); + + return *this; +} //lint !e1539 //m_buffer not assigned + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/PersistentCrcString.h b/engine/shared/library/sharedFoundation/src/shared/PersistentCrcString.h new file mode 100644 index 00000000..239b7a1a --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/PersistentCrcString.h @@ -0,0 +1,69 @@ +// ====================================================================== +// +// PersistentCrcString.h +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_PersistentCrcString_H +#define INCLUDED_PersistentCrcString_H + +// ====================================================================== + +class MemoryBlockManager; +#include "sharedFoundation/CrcString.h" + +// ====================================================================== + +class PersistentCrcString : public CrcString +{ +public: + + static PersistentCrcString const empty; + +public: + + static void install(); + +public: + + PersistentCrcString(); + DLLEXPORT explicit PersistentCrcString(CrcString const & rhs); + PersistentCrcString(PersistentCrcString const & rhs); + PersistentCrcString(char const * string, bool applyNormalize); + PersistentCrcString(char const * string, uint32 crc); + + virtual DLLEXPORT ~PersistentCrcString(); + + virtual char const * getString() const; + + virtual void clear(); + virtual void set(char const * string, bool applyNormalize); + virtual void set(char const * string, uint32 crc); + + PersistentCrcString const & operator=(PersistentCrcString const & rhs); + +protected: + + enum ConstChar + { + CC_true + }; + + PersistentCrcString(char const * string, ConstChar); + +private: + + void internalFree(); + void internalSet(char const * string, bool applyNormalize); + +private: + + MemoryBlockManager * m_memoryBlockManager; + char * m_buffer; +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/PointerDeleter.h b/engine/shared/library/sharedFoundation/src/shared/PointerDeleter.h new file mode 100644 index 00000000..4571d3b0 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/PointerDeleter.h @@ -0,0 +1,85 @@ +// ====================================================================== +// +// PointerDeleter.h +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef POINTER_DELETER_H +#define POINTER_DELETER_H + +// ====================================================================== + +#include + +// ====================================================================== +/** + * Delete the argument. + * + * The argument must be a pointer type. + */ + +class PointerDeleter +{ +public: + template + void operator ()(PointerType pointer) const + { + delete pointer; + } +}; + +// ====================================================================== +/** + * Delete the argument using array-style deletion (i.e. delete [] object). + * + * The argument must be a pointer type. + */ + +class ArrayPointerDeleter +{ +public: + template + void operator ()(PointerType pointer) const + { + delete [] pointer; + } +}; + +// ====================================================================== +/** + * Delete the argument's second member variable. + * + * The passed in argument must be of template type std::pair. + */ + +class PointerDeleterPairSecond +{ +public: + template + void operator ()(std::pair &pairArgument) const + { + delete pairArgument.second; + } +}; + +// ====================================================================== +/** + * Delete the argument's second member variable using array-style deletion. + * + * The passed in argument must be of template type std::pair. + */ + +class ArrayPointerDeleterPairSecond +{ +public: + template + void operator ()(std::pair &pairArgument) const + { + delete [] pairArgument.second; + } +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/Production.h b/engine/shared/library/sharedFoundation/src/shared/Production.h new file mode 100644 index 00000000..b9e70ea8 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Production.h @@ -0,0 +1,21 @@ +//=================================================================== +// +// Production.h +// copyright 2002, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_Production_H +#define INCLUDED_Production_H + +//=================================================================== + +#if DEBUG_LEVEL == 0 +#define PRODUCTION 1 //-- production +#else +#define PRODUCTION 0 //-- development +#endif + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/SafeCast.h b/engine/shared/library/sharedFoundation/src/shared/SafeCast.h new file mode 100644 index 00000000..ad2f5f12 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/SafeCast.h @@ -0,0 +1,35 @@ +// ====================================================================== +// +// SafeCast.h +// Copyright 2001, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_SafeCast_H +#define INCLUDED_SafeCast_H + +// ====================================================================== + +#if DEBUG_LEVEL == DEBUG_LEVEL_RELEASE + + #define safe_cast static_cast + +#else + + template + T safe_cast(U u) + { + if (!u) + return 0; + + T t = dynamic_cast(u); + NOT_NULL(t); + return t; + } + +#endif + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/Scheduler.cpp b/engine/shared/library/sharedFoundation/src/shared/Scheduler.cpp new file mode 100644 index 00000000..e5e3d57e --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Scheduler.cpp @@ -0,0 +1,203 @@ +// ====================================================================== +// +// Scheduler.cpp +// Copyright 2000 - 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/Scheduler.h" +#include "sharedFoundation/StaticCallbackEntry.h" + +#include +#include +#include + +//----------------------------------------------------------------------- +/** @brief construct a new Scheduler object + + A system may have any number of schedulers running. Periodically + invoke update(const unsigned long) on the Scheduler instance to + trigger callback events. + + \code + class MyWorld + { + public: + static void update() + { + instance().worldScheduler.update(Clock::timeMs()); + } + private: + static MyWorld & instance() + { + static MyWorld world; + return world; + } + Scheduler worldScheduler; + }; + + inst main(int, char **) + { + while(true) + { + MyWorld::update(); + } + return 0; + } + \endcode + + @author Justin Randall +*/ +Scheduler::Scheduler() : +deferredCallbackEntryAdditions(new std::vector), +callbackQueue(new std::priority_queue >, StaticCallbackEntry::Compare>), +currentCount(0), +updating(false) +{ +} + +//----------------------------------------------------------------------- + +Scheduler::~Scheduler() +{ + StaticCallbackEntry * c; + while(!callbackQueue->empty()) + { + c = callbackQueue->top(); + delete c; + callbackQueue->pop(); + } + delete callbackQueue; + + std::vector::iterator i = deferredCallbackEntryAdditions->begin(); + for (; i != deferredCallbackEntryAdditions->end(); ++i) + { + delete *i; + } + deferredCallbackEntryAdditions->clear(); + + delete deferredCallbackEntryAdditions; +} + +//----------------------------------------------------------------------- +/** + @brief Register a callback entry with the priority queue + + Used internally in a few places to register StaticCallbackEntry object + pointers with the CallbackEntrySet priority queue. + + @param callback A StaticCallbackEntry object that contains callback + information such as a callback function pointer and + expire count. + + @author Justin Randall +*/ +void Scheduler::addCallback(StaticCallbackEntry * callback) +{ + // if the scheduler is in the middle of an update, ensure that + // the callback is not added THIS frame (prevent infiniet callback loops + // through long loop times or zero callback times) + if(updating) + deferredCallbackEntryAdditions->push_back(callback); + else + callbackQueue->push(callback); +} + +//----------------------------------------------------------------------- +/** + @brief The guts of the Scheduler. Request the next callback request + for a static function. + + The Scheduler may make callbacks on object member function pointers + as well as static function pointers. When the Scheduler is updated + with a value greater than (when + Scheduler::currentCount) it will + invoke the supplied function. + + @param cb a static function pointer + @param context the context for the callback function. + @param delay Used to calculate the expire count/time for the + callback. The current count of the scheduler is + added to 'delay', then the callback is inserted + into the scheduler's priority queue, sorted by + the calculated absolute time. + + \code + Scheduler globalScheduler; + + void foo() + { + globalScheduler.setCallback(bar, 1000); + } + + void bar() + { + globalScheduler.setCallback(foo, 500); + } + \encode + + @author Justin Randall + +*/ +void Scheduler::setCallback(Callback cb, const void *context, unsigned long delay) +{ + addCallback(new StaticCallbackEntry(getCurrentCount() + delay, cb, context)); +} + +//----------------------------------------------------------------------- +/** @brief Trigger pending callbacks + + A scheduler must be periodically updated to trigger callback events + that are enqueued. A single unsigned long parameter is passed to the + Scheduler indicating the current "time" or "frame" or some other + value that ensures all callbacks with an expireCount value less than + t will be triggered. + + @param t The "time" or "frame" that triggers callbacks with expireCounts + less than t. + + \code + int main(int, char **) + { + Scheduler s; + while(1) + { + s.update(Clock::timeMs()); + } + return 0; + } + \endcode + + @author Justin Randall +*/ +void Scheduler::update(const unsigned long t) +{ + // prevent recursive updates on a scheduler + if(!updating) + { + updating = true; + currentCount = t; + StaticCallbackEntry * c; + while( (!callbackQueue->empty()) && (c = callbackQueue->top())->getExpireCount() <= currentCount) + { + c->expired(); + delete c; + callbackQueue->pop(); + } + + updating = false; + + if(!deferredCallbackEntryAdditions->empty()) + { + std::vector::iterator i; + for(i = deferredCallbackEntryAdditions->begin(); i != deferredCallbackEntryAdditions->end(); ++i) + { + addCallback((*i)); + } + deferredCallbackEntryAdditions->clear(); + } + } +} + +//----------------------------------------------------------------------- diff --git a/engine/shared/library/sharedFoundation/src/shared/Scheduler.h b/engine/shared/library/sharedFoundation/src/shared/Scheduler.h new file mode 100644 index 00000000..97a2aaee --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Scheduler.h @@ -0,0 +1,121 @@ +// ====================================================================== +// +// Scheduler.h +// Copyright 2000 - 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef _INCLUDED_Scheduler_H +#define _INCLUDED_Scheduler_H + +// ====================================================================== + +#include "sharedFoundation/StaticCallbackEntry.h" + +//----------------------------------------------------------------------- +/** @brief Engine scheduler + A scheduler is a priority queue containing callbacks, which in turn + contain pointers to member functions which are executed when the + callback is ready for processing. + + The scheduler is updated with an arbitrary, unsigned long value. This + value is used to examine a priority queue of callback entries. If + the top element in the priority queue has an expireCount member that + is less than the current count (passed to the scheduler update()), + it is popped. If the object it refers to (or static callback function) + is valid, it will invoke the requested callback. + + This process is repeated until the top element in the priority queue + has an expireCount greater than the current count. + + To avoid infinite loops, a callback is never re-inserted in the + queue during the queue update. If the Scheduler instance is updating, + re-insertions are deferred, and the next earliest opportunity a + callback could occur is during the NEXT update to the scheduler. + + \code + class MyObject : public Object + { + public: + MyObject::MyObject() : + { + World::getObjectScheduler().setCallback(this, &MyObject::myExpireFunction, 1000); + } + + MyObject::~MyObject() + { + } + + private: + void myExpireFunction() + { + World::killObject(this); // destroy this object now! + } + }; + + void World::update() + { + // each MyObject will put itself on the world kill list + // 1000 milliseconds after creation. They will be placed on + // the list during the scheduler update when MyObject::myExpireFunction + // is invoked. + World::objectScheduler.update(Clock::timeMs()); + } + \endcode + + @author Justin Randall +*/ +class Scheduler +{ +public: + + typedef void (*Callback)(const void*); + +public: + + Scheduler(); + ~Scheduler (); + + void setCallback (Callback cb, const void *context, unsigned long delay); + const unsigned long getCurrentCount () const; + void update (const unsigned long currentCount); + +private: + + void addCallback(StaticCallbackEntry * callback); + + // Disabled. + Scheduler & operator = (const Scheduler & rhs); + Scheduler(const Scheduler & source); + +private: + + stdvector::fwd * deferredCallbackEntryAdditions; + stdpriority_queue >, StaticCallbackEntry::Compare>::fwd * callbackQueue; + +private: + + unsigned long currentCount; + bool updating; + +}; + +//----------------------------------------------------------------------- +/** @brief Return the current expire counter for the current/most recent + update frame. + + currentCount is updated when Scheduler::update() is invoked. It is set + to the value of the update parameter. This value is used to determine + which items in the priority queue should be executed next. + + @author Justin Randall +*/ +inline const unsigned long Scheduler::getCurrentCount() const +{ + return currentCount; +} + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_Scheduler_H diff --git a/engine/shared/library/sharedFoundation/src/shared/StaticCallbackEntry.cpp b/engine/shared/library/sharedFoundation/src/shared/StaticCallbackEntry.cpp new file mode 100644 index 00000000..98a41c5e --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/StaticCallbackEntry.cpp @@ -0,0 +1,45 @@ +// ====================================================================== +// +// StaticCallbackEntry.cpp +// Copyright 2000 - 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/StaticCallbackEntry.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(StaticCallbackEntry, true, 0, 0, 0); + +// ====================================================================== + +StaticCallbackEntry::StaticCallbackEntry(unsigned long when, Callback cb, const void *context) : +m_expireCount(when), +m_staticCallbackFunction(cb), +m_context(context) +{ +} + +//----------------------------------------------------------------------- + +StaticCallbackEntry::~StaticCallbackEntry() +{ + // This instance doesn't own these pointers. + m_staticCallbackFunction = 0; + m_context = 0; +} + +//----------------------------------------------------------------------- + +void StaticCallbackEntry::expired() const +{ + if(m_staticCallbackFunction) + m_staticCallbackFunction(m_context); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/StaticCallbackEntry.h b/engine/shared/library/sharedFoundation/src/shared/StaticCallbackEntry.h new file mode 100644 index 00000000..110a0368 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/StaticCallbackEntry.h @@ -0,0 +1,88 @@ +// ====================================================================== +// +// StaticCallbackEntry.h +// Copyright 2000 - 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef _INCLUDED_StaticCallbackEntry_H +#define _INCLUDED_StaticCallbackEntry_H + +// ====================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" + +class MemoryBlockManager; + +// ====================================================================== +/** @brief A class used by Scheduler to invoke a callback on a static + function. +*/ + +class StaticCallbackEntry +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + +public: + + typedef void (*Callback)(const void *context); + + struct Compare + { + bool operator ()(const StaticCallbackEntry * lhs, const StaticCallbackEntry * rhs) const; + }; + +public: + + StaticCallbackEntry(unsigned long when, Callback cb, const void *context); + ~StaticCallbackEntry(); + + unsigned long getExpireCount() const; + void expired() const; + +private: + + struct StaticCallbackEntryFreeList; + friend struct StaticCallbackEntryFreeList; + +private: + + static stdvector::fwd & getStaticCallbackFreeList(); + +private: + + // Disabled. + StaticCallbackEntry(const StaticCallbackEntry &); + StaticCallbackEntry & operator = (const StaticCallbackEntry &); + +private: + + unsigned long m_expireCount; + Callback m_staticCallbackFunction; + const void *m_context; + +}; + +// ====================================================================== + +/** @return the expiration count ("time", "frame", whatever) of the callback. +*/ +inline unsigned long StaticCallbackEntry::getExpireCount() const +{ + return m_expireCount; +} + +// ====================================================================== + +inline bool StaticCallbackEntry::Compare::operator ()(const StaticCallbackEntry * lhs, const StaticCallbackEntry * rhs) const +{ + NOT_NULL(lhs); + NOT_NULL(rhs); + + return lhs->getExpireCount() > rhs->getExpireCount(); +} + +// ====================================================================== + +#endif // _INCLUDED_StaticCallbackEntry_H diff --git a/engine/shared/library/sharedFoundation/src/shared/StationId.h b/engine/shared/library/sharedFoundation/src/shared/StationId.h new file mode 100644 index 00000000..a0d7872c --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/StationId.h @@ -0,0 +1,17 @@ +// ====================================================================== +// +// StationId.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_StationId_H +#define INCLUDED_StationId_H + +// ====================================================================== + +typedef uint32 StationId; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/StlForwardDeclaration.h b/engine/shared/library/sharedFoundation/src/shared/StlForwardDeclaration.h new file mode 100644 index 00000000..60e8fbaf --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/StlForwardDeclaration.h @@ -0,0 +1,131 @@ +// ====================================================================== +// +// StlForwardDeclaration.h +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_StlForwardDeclaration_H +#define INCLUDED_StlForwardDeclaration_H + +// ====================================================================== + +// Setup handling for template value defaults that require accessing the +// {template type}::fwd value. gcc 3.2 requires typename here, gcc 2.95 +// optionally accepts typename here, msvc 6 will not accept it here. + +#if defined(PLATFORM_WIN32) || defined(WIN32) + +#define FORWARD_TYPENAME + +#elif defined(PLATFORM_LINUX) + +#define FORWARD_TYPENAME typename + +#else + +#error unsupported platform + +#endif + +// ====================================================================== + +// grab stlport configuration +#include "stl/_config.h" + +namespace std +{ + template struct less; + template struct equal_to; + template struct pair; + template struct hash; + template class allocator; + template class basic_string; + template class char_traits; + + template class bitset; + template class deque; + template class list; + template class queue; + template class vector; + template class stack; + template class priority_queue; + template class map; + template class hash_map; + template class multimap; + template class set; + template class hash_set; + template class multiset; + + typedef basic_string, allocator > string; +} + +template > struct stddeque +{ + typedef std::deque<_Tp, _Alloc> fwd; +}; + +template > struct stdlist +{ + typedef std::list<_Tp, _Alloc> fwd; +}; + +template , class _Alloc = std::allocator< std::pair > > struct stdmap +{ + typedef std::map<_Key, _Tp, _Compare, _Alloc> fwd; +}; + +template , class _Compare = std::equal_to<_Key>, class _Alloc = std::allocator< std::pair > > struct stdhash_map +{ + typedef std::hash_map<_Key, _Tp, _HashFcn, _Compare, _Alloc> fwd; +}; + +template , class _Alloc = std::allocator< std::pair > > struct stdmultimap +{ + typedef std::multimap<_Key, _Tp, _Compare, _Alloc> fwd; +}; + +template , class _Alloc = std::allocator<_Key> > struct stdset +{ + typedef std::set<_Key, _Compare, _Alloc> fwd; +}; + +template , class _Compare = std::equal_to<_Key>, class _Alloc = std::allocator<_Key> > struct stdhash_set +{ + typedef std::hash_set<_Key, _HashFcn, _Compare, _Alloc> fwd; +}; + +template , class _Alloc = std::allocator<_Key> > struct stdmultiset +{ + typedef std::multiset<_Key, _Compare, _Alloc> fwd; +}; + +template > struct stdvector +{ + typedef std::vector<_Tp, _Alloc> fwd; +}; + +template ::fwd, class _Compare = std::less > struct stdpriority_queue +{ + typedef std::priority_queue<_Tp, _Container, _Compare> fwd; +}; + +template ::fwd > struct stdqueue +{ + typedef std::queue<_Tp, _Sequence> fwd; +}; + +template ::fwd > struct stdstack +{ + typedef std::stack<_Tp, _Sequence> fwd; +}; + +namespace Unicode +{ + typedef unsigned short unicode_char_t; + typedef std::basic_string, std::allocator > String; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/StringCompare.h b/engine/shared/library/sharedFoundation/src/shared/StringCompare.h new file mode 100644 index 00000000..7d9db70c --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/StringCompare.h @@ -0,0 +1,45 @@ +// ====================================================================== +// +// StringCompare.h +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_StringCompare_H +#define INCLUDED_StringCompare_H + +// ====================================================================== + +#include + +// ====================================================================== + +/// A functor used to allow storing of char* in maps with value lookups +class StringCompare +{ +public: + inline bool operator() (const char*, const char*) const; +}; + +inline bool StringCompare::operator() (const char *lhs, const char *rhs) const +{ + return static_cast(strcmp(lhs, rhs) < 0); +} + +// ====================================================================== + +/// A functor used to allow storing of case insensitive char* in maps with value lookups +class StringCaseCompare +{ +public: + inline bool operator() (const char*, const char*) const; +}; + +inline bool StringCaseCompare::operator() (const char *lhs, const char *rhs) const +{ + return static_cast(_stricmp(lhs, rhs) < 0); +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/Tag.h b/engine/shared/library/sharedFoundation/src/shared/Tag.h new file mode 100644 index 00000000..82a4f393 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Tag.h @@ -0,0 +1,289 @@ +// ====================================================================== +// +// Tag.h +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#ifndef TAG_H +#define TAG_H + +// ====================================================================== + +#define TAG_DIGIT_NULL 00 +#define TAG_DIGIT_SPACE 20 + +#define TAG_DIGIT_0 30 +#define TAG_DIGIT_1 31 +#define TAG_DIGIT_2 32 +#define TAG_DIGIT_3 33 +#define TAG_DIGIT_4 34 +#define TAG_DIGIT_5 35 +#define TAG_DIGIT_6 36 +#define TAG_DIGIT_7 37 +#define TAG_DIGIT_8 38 +#define TAG_DIGIT_9 39 + +#define TAG_DIGIT_A 41 +#define TAG_DIGIT_B 42 +#define TAG_DIGIT_C 43 +#define TAG_DIGIT_D 44 +#define TAG_DIGIT_E 45 +#define TAG_DIGIT_F 46 +#define TAG_DIGIT_G 47 +#define TAG_DIGIT_H 48 +#define TAG_DIGIT_I 49 +#define TAG_DIGIT_J 4A +#define TAG_DIGIT_K 4B +#define TAG_DIGIT_L 4C +#define TAG_DIGIT_M 4D +#define TAG_DIGIT_N 4E +#define TAG_DIGIT_O 4F +#define TAG_DIGIT_P 50 +#define TAG_DIGIT_Q 51 +#define TAG_DIGIT_R 52 +#define TAG_DIGIT_S 53 +#define TAG_DIGIT_T 54 +#define TAG_DIGIT_U 55 +#define TAG_DIGIT_V 56 +#define TAG_DIGIT_W 57 +#define TAG_DIGIT_X 58 +#define TAG_DIGIT_Y 59 +#define TAG_DIGIT_Z 5A + +#define TAG_DIGIT__ 5f + +#define TAG_DIGIT_a 61 +#define TAG_DIGIT_b 62 +#define TAG_DIGIT_c 63 +#define TAG_DIGIT_d 64 +#define TAG_DIGIT_e 65 +#define TAG_DIGIT_f 66 +#define TAG_DIGIT_g 67 +#define TAG_DIGIT_h 68 +#define TAG_DIGIT_i 69 +#define TAG_DIGIT_j 6A +#define TAG_DIGIT_k 6B +#define TAG_DIGIT_l 6C +#define TAG_DIGIT_m 6D +#define TAG_DIGIT_n 6E +#define TAG_DIGIT_o 6F +#define TAG_DIGIT_p 70 +#define TAG_DIGIT_q 71 +#define TAG_DIGIT_r 72 +#define TAG_DIGIT_s 73 +#define TAG_DIGIT_t 74 +#define TAG_DIGIT_u 75 +#define TAG_DIGIT_v 76 +#define TAG_DIGIT_w 77 +#define TAG_DIGIT_x 78 +#define TAG_DIGIT_y 79 +#define TAG_DIGIT_z 7A + +// ====================================================================== + +typedef uint32 Tag; + +// ====================================================================== + +#define TAG_B(a,b,c,d) 0x ## a ## b ## c ## d +#define TAG_A(a,b,c,d) static_cast(TAG_B(a,b,c,d)) +#define TAG(a,b,c,d) TAG_A(TAG_DIGIT_ ## a, TAG_DIGIT_ ## b, TAG_DIGIT_ ## c, TAG_DIGIT_ ## d) + +#define TAG3(a,b,c) TAG_A(TAG_DIGIT_ ## a, TAG_DIGIT_ ## b, TAG_DIGIT_ ## c, TAG_DIGIT_SPACE) +#define TAG2(a,b) TAG_A(TAG_DIGIT_ ## a, TAG_DIGIT_ ## b, TAG_DIGIT_SPACE, TAG_DIGIT_SPACE) +#define TAG1(a) TAG_A(TAG_DIGIT_ ## a, TAG_DIGIT_SPACE, TAG_DIGIT_SPACE, TAG_DIGIT_SPACE) + +#define TAG03(a,b,c) TAG_A(TAG_DIGIT_ ## a, TAG_DIGIT_ ## b, TAG_DIGIT_ ## c, TAG_DIGIT_NULL) +#define TAG02(a,b) TAG_A(TAG_DIGIT_ ## a, TAG_DIGIT_ ## b, TAG_DIGIT_NULL, TAG_DIGIT_NULL) +#define TAG01(a) TAG_A(TAG_DIGIT_ ## a, TAG_DIGIT_NULL, TAG_DIGIT_NULL, TAG_DIGIT_NULL) + +// ====================================================================== +/** + * Convert a text string to a Tag + * + * This routine will convert a text string, such as "ABCD", to the tag value 'ABCD'. + * If the string is less than 4 characters long, it will be padded with spaces. + * If the string is greater than 4 characters long, it will be truncated. + * + * @param value string to convert to a Tag. + */ + +inline Tag ConvertStringToTag(const char *value) +{ + Tag result = 0; + + const int length = strlen(value); + for (int i = 0; i < 4; ++i) + { + const uint32 ch = static_cast((i >= length) ? ' ' : value[i]); + result = (result << 8) | ch; + } + + return result; +} + +// ---------------------------------------------------------------------- +/** + * Convert an integer to a Tag + * + * This routine will convert an int, such as 4, to the tag value '0004'. + * + * @param value value to convert to tag format + */ + +inline Tag ConvertIntToTag(int value) +{ + Tag result = 0; + + DEBUG_FATAL(value < 0 || value > 9999, ("value out of range 0/%d/9999", value)); + + for (int i = 0; i < 4; ++i) + { + const uint digit = static_cast(static_cast(value % 10)); + value /= 10; + result |= (digit + '0') << (i * 8); + } + + return result; +} + +// ---------------------------------------------------------------------- +/** + * Print the specified tag into a text buffer. + * + * This routine will fill the first four characters of the specified character + * array with the name of the specified tag. If a character of the tag + * is not printable, it will be replaced with a question mark. + * + * A null-character will be appended to the output buffer. + * + * This routine assumes the specified character buffer is at least 5 characters + * in length. + * + * @param tag Tag to format + * @param buffer Character array to format the tag into + */ + +inline void ConvertTagToString(Tag tag, char *buffer) +{ + int i, j, ch; + + DEBUG_FATAL(!buffer, ("buffer is null")); + + for (i = 0, j = 24; i < 4; ++i, j -= 8) + { + ch = (static_cast(tag) >> j) & 0xff; //lint !e702 // shift right of a signed quantity + if (isprint(ch)) + buffer[i] = static_cast(ch); + else + buffer[i] = '?'; + } + + buffer[4] = 0; +} + +// ---------------------------------------------------------------------- +/** + * Convert the specified tag to an int. + * + * This routine will attempt to create an integer using as + * many of least significant bytes of the tag as possible. + * + * Example: TAG(0,1,0,0) == 100 + * Example: TAG(1,R,1,0) == 10 + * Example: TAG(1,R,1,X) == 0 + * + * @param tag Tag to format + * @return Integer form of tag string. + */ + +inline int ConvertTagSuffixToInt(Tag tag) +{ + int returnValue=0; + for (int i=24;i>=0;i-=8) + { + const int c = (tag>>i) & 0xff; + if (c>='0' && c<='9') + { + returnValue = returnValue*10 + int(c) -'0'; + } + else + { + returnValue=0; + } + } + return returnValue; +} + +// ---------------------------------------------------------------------- +/** + * Convert the specified tag to an int. + * + * This routine will attempt to create an integer from + * a tag containing only numeric characters. If non-numeric + * characters are detected, 0 is returned. + * + * Example: TAG(0,1,0,0) == 100 + * Example: TAG(1,R,1,0) == 0 + * Example: TAG(1,R,1,X) == 0 + * + * @param tag Tag to format + * @return Integer form of tag string. + */ + +inline int ConvertTagToInt(Tag tag) +{ + int returnValue=0; + for (int i=24;i>=0;i-=8) + { + const int c = (tag>>i) & 0xff; + if (c>='0' && c<='9') + { + returnValue = returnValue*10 + int(c) -'0'; + } + else + { + return 0; + } + } + return returnValue; +} + +// ====================================================================== + +const Tag TAG_0000 = TAG(0,0,0,0); +const Tag TAG_0001 = TAG(0,0,0,1); +const Tag TAG_0002 = TAG(0,0,0,2); +const Tag TAG_0003 = TAG(0,0,0,3); +const Tag TAG_0004 = TAG(0,0,0,4); +const Tag TAG_0005 = TAG(0,0,0,5); +const Tag TAG_0006 = TAG(0,0,0,6); +const Tag TAG_0007 = TAG(0,0,0,7); +const Tag TAG_0008 = TAG(0,0,0,8); +const Tag TAG_0009 = TAG(0,0,0,9); +const Tag TAG_0010 = TAG(0,0,1,0); +const Tag TAG_0011 = TAG(0,0,1,1); +const Tag TAG_0012 = TAG(0,0,1,2); +const Tag TAG_0013 = TAG(0,0,1,3); +const Tag TAG_0014 = TAG(0,0,1,4); +const Tag TAG_0015 = TAG(0,0,1,5); + +const Tag TAG_DATA = TAG(D,A,T,A); +const Tag TAG_ENTR = TAG(E,N,T,R); +const Tag TAG_FORM = TAG(F,O,R,M); +const Tag TAG_INFO = TAG(I,N,F,O); + +const Tag TAG_ARRY = TAG(A,R,R,Y); +const Tag TAG_NAME = TAG(N,A,M,E); +const Tag TAG_PARM = TAG(P,A,R,M); + +//-- please do not add any Tags to this file unless they are generic +//-- and expected to be used in many different contexts + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedFoundation/src/shared/TemporaryCrcString.cpp b/engine/shared/library/sharedFoundation/src/shared/TemporaryCrcString.cpp new file mode 100644 index 00000000..5b6fcb27 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/TemporaryCrcString.cpp @@ -0,0 +1,110 @@ +// ====================================================================== +// +// TemporaryCrcString.cpp +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/TemporaryCrcString.h" + +#include "sharedFoundation/Os.h" +#include "sharedFoundation/Crc.h" + +// ====================================================================== + +TemporaryCrcString::TemporaryCrcString() +: CrcString() +{ + // this is to avoid including Os in the header file + DEBUG_FATAL(static_cast(BUFFER_SIZE) != static_cast(Os::MAX_PATH_LENGTH), ("Os::MAX_PATH_LENGTH and BUFFER_SIZE differ")); + + m_buffer[0] = '\0'; +} + +// ---------------------------------------------------------------------- +/** + * Copy constructor. + * + * TRF needed this to allow useful sanity checking with std::set. + */ +TemporaryCrcString::TemporaryCrcString(const TemporaryCrcString &rhs) +: CrcString() +{ + set(rhs.getString(), rhs.getCrc()); +} + +// ---------------------------------------------------------------------- + +TemporaryCrcString::TemporaryCrcString(char const * string, bool applyNormalize) +: CrcString() +{ + // this is to avoid including Os in the header file + DEBUG_FATAL(static_cast(BUFFER_SIZE) != static_cast(Os::MAX_PATH_LENGTH), ("Os::MAX_PATH_LENGTH and BUFFER_SIZE differ")); + + set(string, applyNormalize); +} + +// ---------------------------------------------------------------------- + +TemporaryCrcString::TemporaryCrcString(char const * string, uint32 crc) +: CrcString() +{ + // this is to avoid including Os in the header file + DEBUG_FATAL(static_cast(BUFFER_SIZE) != static_cast(Os::MAX_PATH_LENGTH), ("Os::MAX_PATH_LENGTH and BUFFER_SIZE differ")); + + set(string, crc); +} + +// ---------------------------------------------------------------------- + +TemporaryCrcString::~TemporaryCrcString() +{ +} + +// ---------------------------------------------------------------------- + +char const * TemporaryCrcString::getString() const +{ + return m_buffer; +} + +// ---------------------------------------------------------------------- + +void TemporaryCrcString::clear() +{ + m_buffer[0] = '\0'; + m_crc = Crc::crcNull; +} + +// ---------------------------------------------------------------------- + +void TemporaryCrcString::internalSet(char const * string, bool applyNormalize) +{ + DEBUG_FATAL(strlen(string)+1 > BUFFER_SIZE, ("string too long %d/%d", strlen(string)+1, BUFFER_SIZE)); + if (applyNormalize) + normalize(m_buffer, string); + else + strcpy(m_buffer, string); +} + +// ---------------------------------------------------------------------- + +void TemporaryCrcString::set(char const * string, bool applyNormalize) +{ + NOT_NULL(string); + internalSet(string, applyNormalize); + calculateCrc(); +} + +// ---------------------------------------------------------------------- + +void TemporaryCrcString::set(char const * string, uint32 crc) +{ + NOT_NULL(string); + internalSet(string, false); + m_crc = crc; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/TemporaryCrcString.h b/engine/shared/library/sharedFoundation/src/shared/TemporaryCrcString.h new file mode 100644 index 00000000..d9785f49 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/TemporaryCrcString.h @@ -0,0 +1,55 @@ +// ====================================================================== +// +// TemporaryCrcString.h +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_TemporaryCrcString_H +#define INCLUDED_TemporaryCrcString_H + +// ====================================================================== + +#include "sharedFoundation/CrcString.h" + +// ====================================================================== + +class TemporaryCrcString : public CrcString +{ +public: + + TemporaryCrcString(); + TemporaryCrcString(const TemporaryCrcString &); + DLLEXPORT TemporaryCrcString(const char *string, bool applyNormalize); + TemporaryCrcString(const char *string, uint32 crc); + + virtual DLLEXPORT ~TemporaryCrcString(); + + virtual const char *getString() const; + + virtual void clear(); + virtual void set(const char *string, bool applyNormalize); + virtual void set(const char *string, uint32 crc); + +private: + + TemporaryCrcString & operator =(const TemporaryCrcString &); + + void internalSet(const char *string, bool applyNormalize); + +private: + + enum + { + BUFFER_SIZE = 512 + }; + +private: + + char m_buffer[BUFFER_SIZE]; +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/Timer.cpp b/engine/shared/library/sharedFoundation/src/shared/Timer.cpp new file mode 100644 index 00000000..bc40567e --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Timer.cpp @@ -0,0 +1,20 @@ +// ====================================================================== +// +// Timer.cpp +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/Timer.h" + +// ====================================================================== + +void Timer::setElapsedTime(float seconds) +{ + time = seconds; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/Timer.h b/engine/shared/library/sharedFoundation/src/shared/Timer.h new file mode 100644 index 00000000..4cbb17be --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Timer.h @@ -0,0 +1,309 @@ +// ====================================================================== +// +// Timer.h +// Copyright 1998 Bootprint Entertainment +// Copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_Timer_H +#define INCLUDED_Timer_H + +// ====================================================================== + +/** + * Convienent countdown timer class. + * + * Timer objects do not automatically update off the clock. They must be + * told that time is elapsing by calling one of the update*() functions. + * The update routine will return true when the timer expires. + */ + +class Timer +{ +public: + + Timer(); + explicit Timer(real seconds); + Timer(const Timer &rhs); + Timer &operator =(const Timer &rhs); + + void setExpireTime(real seconds); + void extendExpireTime(real seconds); + + void reset(); + void setElapsedTime(float seconds); + + bool updateNoReset(real elapsedTime); + bool updateZero(real elapsedTime); + bool updateSubtract(real elapsedTime); + + bool isExpired() const; + real getExpireTime() const; + real getElapsedRatio() const; + real getRemainingRatio() const; + real getExpirationOvershoot() const; + real getRemainingTime() const; + +private: + + real expireTime; + real time; +}; + +// ====================================================================== +/** Construct a timer object + * + * The timer is constructed with the belief that no time has elapsed. + * This constructor will set the expire-time to 0. + */ + +inline Timer::Timer() +: expireTime(0), + time(0) +{ +} + +// ---------------------------------------------------------------------- +/** + * Construct a timer object. + * + * The timer is constructed with the belief that no time has elapsed. + * + * @param seconds Time (in seconds) that the timer should expire at + */ + +inline Timer::Timer(real seconds) +: expireTime(seconds), + time(0) +{ +} + +// ---------------------------------------------------------------------- +/** + * Construct a timer object. + * + * Copy constructor. + */ + +inline Timer::Timer(const Timer &rhs) +: expireTime(rhs.expireTime), + time(rhs.time) +{ +} + +// ---------------------------------------------------------------------- +/** + * Assignment operator. + * + * Assignment operator. + */ + +inline Timer &Timer::operator =(const Timer &rhs) +{ +// if (this != &rhs) + { + expireTime = rhs.expireTime; + time = rhs.time; + } + + return *this; +} + +// ---------------------------------------------------------------------- +/** + * Set a new expire time for the timer. + * + * This routine changes the time at which the timer will expire. It has + * no effect on the amount of time that the timer believes has already + * elapsed. + * + * @param seconds Time (in seconds) that the timer should expire at + */ + +inline void Timer::setExpireTime(real seconds) +{ + expireTime = seconds; +} + +// ---------------------------------------------------------------------- +/** + * Extends the expire time for the timer. + * + * This routine changes the time at which the timer will expire. It has + * no effect on the amount of time that the timer believes has already + * elapsed. + * + * @param seconds Time (in seconds) to add to the current expire time + */ + +inline void Timer::extendExpireTime(real seconds) +{ + expireTime += seconds; +} + +// ---------------------------------------------------------------------- +/** + * Reset the timer. + * + * This resets the timer to believe that no time has elapsed. + */ + +inline void Timer::reset() +{ + time = 0.0f; +} + +// ---------------------------------------------------------------------- +/** + * Inform the timer that time has elapsed, but not not reset the timer. + * + * When the timer expires, it will remain expired until reset() is called + * or one of the update*() functions is called that will reduce the amount + * of elapsed time. + * + * @param elapsedTime Amount of time (in seconds) that has elapsed + * @return True if the timer has expired, false otherwise. + * @see Timer::reset(), Timer::updateZero(), Timer::updateSubtract() + */ + +inline bool Timer::updateNoReset(real elapsedTime) +{ + time += elapsedTime; + return (time >= expireTime); +} + +// ---------------------------------------------------------------------- +/** + * Inform the timer that time has elapsed, and reset the time if it expired. + * + * When this routine detects the timer has expired, it will reset the timer. + * This will guarentee at least the amount of time has passed between + * expirations, but will not necessarily behave properly over an extended + * period of time. + * + * @return True if the timer has expired, false otherwise. + * @see Timer::reset(), Timer::updateNoReset(), Timer::updateSubtract() + */ + +inline bool Timer::updateZero(real elapsedTime) +{ + if (updateNoReset(elapsedTime)) + { + reset(); + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- +/** + * Inform the timer that time has elapsed, and reduce the time if it expired. + * + * When this routine detects the timer has expired, it will subtract the + * timer expiration time from the current time value. This routine will + * tend to remain more accurate over a longer period of time, but will + * not necessarily guarentee that the specified time will elapse before the + * next expiration (because of carry-over from the previous update). + * + * @return True if the timer has expired, false otherwise. + * @see Timer::reset(), Timer::updateNoReset(), Timer::updateSubtract() + */ + +inline bool Timer::updateSubtract(real elapsedTime) +{ + if (updateNoReset(elapsedTime)) + { + time -= expireTime; + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- +/** + * Check if the timer is expired. + * + * This routine does not update the timer's current time. + * + * @return true if the timer has expired, otherwise false. + */ + +inline bool Timer::isExpired() const +{ + return time >= expireTime; +} + +// ---------------------------------------------------------------------- +/** + * Return the expire time + * + * @return expire time + */ + +inline real Timer::getExpireTime() const +{ + return expireTime; +} + +// ---------------------------------------------------------------------- +/** + * Calculate ratio (from 0 to 1) of time elapsed. + * + * Should not be called if the expire time has not been set, as the result + * is undefined. + * + * @return ratio (from 0 to 1) of time elapsed + */ + +inline real Timer::getElapsedRatio() const +{ + return expireTime != 0.0f ? time / expireTime : 0.0f; +} + +// ---------------------------------------------------------------------- +/** + * Calculate ratio (from 0 to 1) of time remaining. + * + * Should not be called if the expire time has not been set, as the result + * is undefined. + * + * @return ratio (from 0 to 1) of time remaining + */ + +inline real Timer::getRemainingRatio() const +{ + return expireTime != 0.0f ? ((expireTime - time) / expireTime) : 0.0f; +} + +// ---------------------------------------------------------------------- +/** + * Return the amount of time beyond the expiration time we are. + * + * The value returned is negative if we haven't expired yet. + * + * @return the overshoot time + */ + +inline real Timer::getExpirationOvershoot() const +{ + return time - expireTime; +} + +// ---------------------------------------------------------------------- +/** + * Return the amount of time until expiration. + * + * @return the overshoot time + */ + +inline real Timer::getRemainingTime() const +{ + return expireTime - time; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/VoidBindSecond.h b/engine/shared/library/sharedFoundation/src/shared/VoidBindSecond.h new file mode 100644 index 00000000..40c02698 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/VoidBindSecond.h @@ -0,0 +1,48 @@ +// ====================================================================== +// +// VoidBindSecond.h +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include + +// ====================================================================== + +template +class VoidBinderSecond: public std::unary_function +{ +private: + + typename Operation::second_argument_type m_boundValue; + Operation m_operation; + +public: + + VoidBinderSecond(const Operation& operation, const typename Operation::second_argument_type &boundValue) + : m_operation(operation), m_boundValue(boundValue) {} + + void operator()(const typename Operation::first_argument_type& argument) const + { + m_operation(argument, m_boundValue); + } +}; + +// ====================================================================== +/** + * works just like std::bind2nd() when return value of function is void. + * + * this is necessary since our STL breaks under MSVC 6 when using void functions + * with bind2nd. + */ + + +template +inline VoidBinderSecond VoidBindSecond(const Operation& operation, const BindArgumentType &bindArgument) +{ + typedef typename Operation::second_argument_type SecondArgumentType; + + return VoidBinderSecond(operation, SecondArgumentType(bindArgument)); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/VoidMemberFunction.h b/engine/shared/library/sharedFoundation/src/shared/VoidMemberFunction.h new file mode 100644 index 00000000..d10a5c33 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/VoidMemberFunction.h @@ -0,0 +1,133 @@ +// ====================================================================== +// +// VoidMemberFunction.h +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef VOID_MEMBER_FUNCTION_H +#define VOID_MEMBER_FUNCTION_H + +// ====================================================================== + +#include + +// ====================================================================== +/** + * Replace the broken std::mem_fun under MSVC when return type is void. + * + * Note: this can disappear as soon as we have class partial specialization + * support in all our environments. + * + * This should only be used when the client wants to use std::mem_fun + * where the return value of the member function is void. Use just lik + * std::mem_fun(). + */ + +template +class VoidConstMemberFunctionNoArg: public std::unary_function +{ +private: + + typedef void (Class:: *Function)(void) const; + +public: + + explicit VoidConstMemberFunctionNoArg(Function function) : m_function(function) {} + void operator ()(const Class* classArgument) const { (classArgument->*m_function)(); } + +private: + Function m_function; +}; + +// ---------------------------------------------------------------------- + +template +class VoidMemberFunctionNoArg: public std::unary_function +{ +private: + + typedef void (Class:: *Function)(void); + +public: + + explicit VoidMemberFunctionNoArg(Function function) : m_function(function) {} + void operator ()(Class* classArgument) const { (classArgument->*m_function)(); } + +private: + + Function m_function; +}; + +// ---------------------------------------------------------------------- + +template +class VoidConstMemberFunctionOneArg: public std::binary_function +{ +private: + + typedef void (Class:: *Function)(ArgumentType) const; + +public: + + explicit VoidConstMemberFunctionOneArg(Function function) : m_function(function) {} + void operator ()(const Class* classArgument, ArgumentType argument) const { (classArgument->*m_function)(argument); } + +private: + Function m_function; +}; + +// ---------------------------------------------------------------------- + +template +class VoidMemberFunctionOneArg: public std::binary_function +{ +private: + + typedef void (Class:: *Function)(ArgumentType); + +public: + + explicit VoidMemberFunctionOneArg(Function function) : m_function(function) {} + void operator ()(Class* classArgument, ArgumentType argument) const { (classArgument->*m_function)(argument); } + +private: + Function m_function; +}; + + +// ====================================================================== + +template +inline VoidConstMemberFunctionNoArg VoidMemberFunction(void (Class::*function)() const) +{ + return VoidConstMemberFunctionNoArg(function); +} + +// ---------------------------------------------------------------------- + +template +inline VoidMemberFunctionNoArg VoidMemberFunction(void (Class::*function)()) +{ + return VoidMemberFunctionNoArg(function); +} + +// ---------------------------------------------------------------------- + +template +inline VoidConstMemberFunctionOneArg VoidMemberFunction(void (Class::*function)(ArgumentType) const) +{ + return VoidConstMemberFunctionOneArg(function); +} + +// ---------------------------------------------------------------------- + +template +inline VoidMemberFunctionOneArg VoidMemberFunction(void (Class::*function)(ArgumentType)) +{ + return VoidMemberFunctionOneArg(function); +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/Watcher.cpp b/engine/shared/library/sharedFoundation/src/shared/Watcher.cpp new file mode 100644 index 00000000..3ca86728 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Watcher.cpp @@ -0,0 +1,154 @@ +// ====================================================================== +// +// Watcher.cpp +// copyright 1998 Bootprint Entertainment +// Copyright 2000-01 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/Watcher.h" + +#include "sharedFoundation/ExitChain.h" + +#include + +// ====================================================================== + +namespace WatchedByListNamespace +{ + typedef stdvector::fwd List; + typedef stdvector::fwd ListList; + + ListList ms_listList; + + void remove(); + List * newList(); + void deleteList(List * list); +} + +using namespace WatchedByListNamespace; + +// ====================================================================== + +void WatchedByListNamespace::remove() +{ + while (!ms_listList.empty()) + { + delete ms_listList.back(); + ms_listList.pop_back(); + } +} + +// ---------------------------------------------------------------------- + +List * WatchedByListNamespace::newList() +{ + if (ms_listList.empty()) + { + for (int i = 0; i < 256; ++i) + ms_listList.push_back(new List); + } + + List * const result = ms_listList.back(); + ms_listList.pop_back(); + + return result; +} + +// ---------------------------------------------------------------------- + +void WatchedByListNamespace::deleteList(List * const list) +{ + if (ms_listList.size() < 256) + { + DEBUG_FATAL(!list->empty(), ("list is not empty")); + list->clear(); + ms_listList.push_back(list); + } + else + delete list; +} + +// ====================================================================== + +void WatchedByList::install() +{ + ExitChain::add(WatchedByListNamespace::remove, "WatchedByListNamespace::remove"); +} + +// ====================================================================== +/** + * Destroy a WatchedByList. + * + * All watchers currently watching the owner of this object will be reset to NULL. + */ + +WatchedByList::~WatchedByList() +{ + nullWatchers(); + + if (m_list) + { + deleteList(m_list); + m_list = NULL; + } +} + +// ---------------------------------------------------------------------- + +void WatchedByList::nullWatchers() +{ + if (m_list) + { + const List::iterator end = m_list->end(); + for (List::iterator i = m_list->begin(); i != end; ++i) + (*i)->reset(); + + m_list->clear(); + } +} + +// ---------------------------------------------------------------------- +/** + * Add a watcher to the WatchedByList. + * + * If the list hasn't yet been created, create it. + * + * @internal + */ + +void WatchedByList::add(BaseWatcher &watcher) +{ + if (!m_list) + m_list = newList(); + m_list->push_back(&watcher); +} + +// ---------------------------------------------------------------------- +/** + * Remove a Watcher from the WatchedByList. + * + * @internal + * @todo Consider resizing the vector down to conserve memory. + * @todo Cconsider deleting the vector if it becomes empty. + */ + +void WatchedByList::remove(BaseWatcher &watcher) +{ + DEBUG_FATAL(!m_list, ("remove from empty list")); + + const List::iterator end = m_list->end(); + List::iterator i = m_list->begin(); + for (; i != end && *i != &watcher; ++i) + {} + + DEBUG_FATAL(i == end, ("did not find watcher on list")); + + // move the last element down to this slot + *i = *(end-1); + m_list->pop_back(); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/Watcher.h b/engine/shared/library/sharedFoundation/src/shared/Watcher.h new file mode 100644 index 00000000..ca637a79 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/Watcher.h @@ -0,0 +1,606 @@ +// ====================================================================== +// +// Watcher.h +// copyright 1998 Bootprint Entertainment +// Copyright 2000-01 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// @todo How do I get this into doxygen? It's information that really spans multiple classes +// +// The Watcher system allows pointers to objects to be automatically +// reset to NULL when the object watching them is destoyed. +// +// For something to be watchable, it must provide a routine of the form: +// +// WatchedByList &T::getWatchedByList() const; +// +// This allows things to be watchable without having to derive from a common +// base class. The WatchedByList returned by the object must have exactly +// the same lifespan as the object itself. The easiest way to accomplish +// that is to make the WatchedByList a member of the object. Since it is +// possible to watch const objects, it's very likely that the member variable +// will need to be made mutable. +// +// ====================================================================== + +#ifndef INCLUDED_Watcher_H +#define INCLUDED_Watcher_H + +// ====================================================================== + +class WatchedByList; + +// ====================================================================== + +// Base class for Watcher and ConstWatcher. This should never be used +// directly by the application. +class BaseWatcher +{ + friend class WatchedByList; + +protected: + + explicit BaseWatcher(void *newValue); + virtual ~BaseWatcher(); + + void reset(); + void addTo(WatchedByList &watchedByList); + void removeFrom(WatchedByList &watchedByList); + +private: + + /// Disabled + BaseWatcher(); + + /// Disabled + BaseWatcher(const BaseWatcher &); + +protected: + + void *m_data; +}; + +// Watcher to a non-const object. +template +class Watcher : public BaseWatcher +{ +public: + + explicit Watcher(T *data=NULL); + Watcher(const Watcher &newValue); + ~Watcher(); //lint !e1509 // Warning -- base class destructor for class is not virtual + + Watcher & operator = (T *newValue); + Watcher & operator = (const Watcher &); + + // Equality and less operators for watchers. Without these operators, + // std::find will coerce the pointer type to a watcher and the resulting constructor + // call will add an element to the watched object's watchedBy list, potentially + // causing a reallocation. Then, when the find is done, the temporary object is + // destroyed and the watcher is removed from the watchedBy list. + + bool operator == ( T const * const rhs ) const; + bool operator < ( T const * const rhs ) const; + + bool operator == ( Watcher const & rhs ) const; + bool operator < ( Watcher const & rhs ) const; + + T *getPointer() const; + operator T*() const; + T *operator ->() const; +}; + +// Watcher to a const object. +template +class ConstWatcher : public BaseWatcher +{ +public: + + explicit ConstWatcher(const T *data=NULL); + ConstWatcher(const ConstWatcher &newValue); + ~ConstWatcher(); //lint !e1509 // Warning -- base class destructor for class is not virtual + + ConstWatcher &operator =(const T *newValue); + ConstWatcher &operator =(const ConstWatcher &); + + // Equality and less operators for watchers. Without these operators, + // std::find will coerce the pointer type to a watcher and the resulting constructor + // call will add an element to the watched object's watchedBy list, potentially + // causing a reallocation. Then, when the find is done, the temporary object is + // destroyed and the watcher is removed from the watchedBy list. + + bool operator == ( T const * const rhs ) const; + bool operator < ( T const * const rhs ) const; + + bool operator == ( ConstWatcher const & rhs ) const; + bool operator < ( ConstWatcher const & rhs ) const; + + const T *getPointer() const; + operator const T*() const; + const T *operator ->() const; +}; + +// Keeps track of whom is watching it. +class WatchedByList +{ + friend class BaseWatcher; + +public: + + static void install(); + +public: + + WatchedByList(); + ~WatchedByList(); + + void nullWatchers(); + +protected: + + void add(BaseWatcher &baseWatcher); + void remove(BaseWatcher &baseWatcher); + +private: + + /// Disabled + WatchedByList(const WatchedByList &); + + /// Disabled + WatchedByList &operator &(const WatchedByList &); + +private: + + typedef stdvector::fwd List; + +private: + + List *m_list; +}; + +// ====================================================================== +/** + * Construct a BaseWatcher + */ + +inline BaseWatcher::BaseWatcher(void *data) +: m_data(data) +{ +} + +// ---------------------------------------------------------------------- +/** + * Reset a BaseWatcher. + * + * This routine is only called when the object being pointed to is being destroyed. + */ + +inline void BaseWatcher::reset() +{ + m_data = NULL; +} + +// ---------------------------------------------------------------------- +/** + * Destroy a BaseWatcher + * + * This routine will walk the singly linked list of watchers and remove + * this watcher from the list. + */ + +inline BaseWatcher::~BaseWatcher() +{ + m_data = NULL; +} + +// ---------------------------------------------------------------------- +/** + * Add this BaseWatcher to the WatchedByList. + * + * This routine exists so we don't need make Watcher a friend of WatchedByList. + * @internal + */ + +inline void BaseWatcher::addTo(WatchedByList &watchedByList) +{ + watchedByList.add(*this); +} + +// ---------------------------------------------------------------------- +/** + * Remove this BaseWatcher from the WatchedByList. + * + * This routine exists so we don't need make Watcher a friend of WatchedByList. + * @internal + */ + +inline void BaseWatcher::removeFrom(WatchedByList &watchedByList) +{ + watchedByList.remove(*this); +} + +// ====================================================================== +/** + * Convert the data pointer to the object pointer type. + * + * @return Pointer to the object the Watcher points to + */ + +template +inline T *Watcher::getPointer() const +{ + return reinterpret_cast(m_data); +} + +// ---------------------------------------------------------------------- +/** + * Construct a Watcher. + * + * @param data Initial value for the data pointer. + */ + +template +inline Watcher::Watcher(T *data) +: BaseWatcher(data) +{ + if (m_data) + addTo(getPointer()->getWatchedByList()); +} + +// ---------------------------------------------------------------------- +/** + * Copy-construct a Watcher. + * + * @param rhs Watcher to copy the data pointer from. + */ + +template +inline Watcher::Watcher(const Watcher &rhs) +: BaseWatcher(rhs.m_data) +{ + if (m_data) + addTo(getPointer()->getWatchedByList()); +} + +// ---------------------------------------------------------------------- +/** + * Destroy a Watcher. + */ + +template +inline Watcher::~Watcher() +{ + if (m_data) + removeFrom(getPointer()->getWatchedByList()); +} + +// ---------------------------------------------------------------------- +/** + * Set the value of Watcher from a pointer. + * + * @param newValue Pointer to copy the data from. + * @return The watcher itself. + */ + +template +inline Watcher & Watcher::operator = (T *data) +{ + if (data != m_data) + { + if (m_data) + removeFrom(getPointer()->getWatchedByList()); + + m_data = data; + + if (m_data) + addTo(getPointer()->getWatchedByList()); + } + + return *this; +} + +// ---------------------------------------------------------------------- +/** + * Assign one watcher to another, effectively making the assignee watch + * the same object as the assigner. + * + * @return The object itself + */ + +template +inline Watcher & Watcher::operator = (const Watcher & rhs) +{ + return operator = (rhs.getPointer()); +} + +// ---------------------------------------------------------------------- +/** + * Equality operator for watchers, which allows us to compare a watcher + * and a pointer without coercing the pointer to a watcher also. + * + * A watcher is considered to be equal to a pointer P if it's watching + * the object pointed to by P. + * + * @return True if the watcher is watching the object pointed to by rhs. + */ + +template +inline bool Watcher::operator == ( T const * const rhs ) const +{ + return getPointer() == rhs; +} + +// ---------------------------------------------------------------------- +/** + * Less operator for watchers, which allows us to compare a watcher + * and a pointer without coercing the pointer to a watcher also. + * + * Asking if a watcher is less than a pointer doesn't make much sense, + * but it's required by the STL associative containers. + * + * @return True if the watcher's pointer is numerically less than rhs + */ + +template +inline bool Watcher::operator < ( T const * const rhs ) const +{ + return getPointer() < rhs; +} + +// ---------------------------------------------------------------------- +/** + * Equality operator for watchers. + * + * Two watchers are considered to be equal if they watch the same object. + * + * @return True if the two watchers are watching the same object + */ + +template +inline bool Watcher::operator == ( Watcher const & rhs ) const +{ + return getPointer() == rhs.getPointer(); +} + +// ---------------------------------------------------------------------- +/** + * Less operator for watchers. + * + * Asking if a watcher is less than another watcher doesn't make much + * sense, but it's required by the STL associative containers. + * + * @return True if the watcher's pointer is numerically less than rhs + */ + +template +inline bool Watcher::operator < ( Watcher const & rhs ) const +{ + return getPointer() < rhs.getPointer(); +} + +// ---------------------------------------------------------------------- +/** + * Cast the Watcher to the object pointer type. + * + * @return Pointer to the object the Watcher points to. + */ + +template +inline Watcher::operator T *() const +{ + return reinterpret_cast(m_data); +} + +// ---------------------------------------------------------------------- +/** + * Dereference the Watcher to the object. + * + * @return Pointer to the object the watcher points to. + */ + +template +inline T *Watcher::operator ->() const +{ + return reinterpret_cast(m_data); +} + +// ====================================================================== +/** + * Convert the data pointer to the object pointer type. + * + * @return Pointer to the object the ConstWatcher points to + */ + +template +inline const T *ConstWatcher::getPointer() const +{ + return reinterpret_cast(m_data); +} + +// ---------------------------------------------------------------------- +/** + * Construct a Watcher. + * + * @param data Initial value for the data pointer. + */ + +template +inline ConstWatcher::ConstWatcher(const T *data) +: BaseWatcher(const_cast(reinterpret_cast(data))) +{ + if (m_data) + addTo(getPointer()->getWatchedByList()); +} + +// ---------------------------------------------------------------------- +/** + * Copy-construct a ConstWatcher. + * + * @param rhs ConstWatcher to copy the data pointer from. + */ + +template +inline ConstWatcher::ConstWatcher(const ConstWatcher &rhs) +: BaseWatcher(rhs.m_data) +{ + if (m_data) + addTo(getPointer()->getWatchedByList()); +} + +// ---------------------------------------------------------------------- +/** + * Destroy a ConstWatcher. + */ + +template +inline ConstWatcher::~ConstWatcher() +{ + if (m_data) + removeFrom(getPointer()->getWatchedByList()); +} + +// ---------------------------------------------------------------------- +/** + * Set the value of ConstWatcher from a pointer. + * + * @param newValue Pointer to copy the data from. + * @return The ConstWatcher itself. + */ + +template +inline ConstWatcher &ConstWatcher::operator =(const T *data) +{ + if (m_data != static_cast(data)) + { + if (m_data) + removeFrom(getPointer()->getWatchedByList()); + + m_data = const_cast(reinterpret_cast(data)); + + if (m_data) + addTo(getPointer()->getWatchedByList()); + } + + return *this; +} + +// ---------------------------------------------------------------------- +/** + * Assign one ConstWatcher to another, effectively making the assignee watch + * the same object as the assigner. + * + * @return The object itself + */ + +template +inline ConstWatcher & ConstWatcher::operator = (const ConstWatcher & rhs) +{ + return operator = (rhs.getPointer()); +} + +// ---------------------------------------------------------------------- +/** + * Equality operator for watchers, which allows us to compare a watcher + * and a pointer without coercing the pointer to a watcher also. + * + * A watcher is considered to be equal to a pointer P if it's watching + * the object pointed to by P. + * + * @return True if the watcher is watching the object pointed to by rhs. + */ + +template +inline bool ConstWatcher::operator == ( T const * const rhs ) const +{ + return getPointer() == rhs; +} + +// ---------------------------------------------------------------------- +/** + * Less operator for watchers, which allows us to compare a watcher + * and a pointer without coercing the pointer to a watcher also. + * + * Asking if a watcher is less than a pointer doesn't make much sense, + * but it's required by the STL associative containers. + * + * @return True if the watcher's pointer is numerically less than rhs + */ + +template +inline bool ConstWatcher::operator < ( T const * const rhs ) const +{ + return getPointer() < rhs; +} + +// ---------------------------------------------------------------------- +/** + * Equality operator for watchers. + * + * Two watchers are considered to be equal if they watch the same object. + * + * @return True if the two watchers are watching the same object + */ + +template +inline bool ConstWatcher::operator == ( ConstWatcher const & rhs ) const +{ + return getPointer() == rhs.getPointer(); +} + +// ---------------------------------------------------------------------- +/** + * Less operator for watchers. + * + * Asking if a watcher is less than another watcher doesn't make much + * sense, but it's required by the STL associative containers. + * + * @return True if the watcher's pointer is numerically less than rhs + */ + +template +inline bool ConstWatcher::operator < ( ConstWatcher const & rhs ) const +{ + return getPointer() < rhs.getPointer(); +} + +// ---------------------------------------------------------------------- +/** + * Cast the ConstWatcher to the object pointer type. + * + * @return Pointer to the object the ConstWatcher points to. + */ + +template +inline ConstWatcher::operator const T *() const +{ + return reinterpret_cast(m_data); +} + +// ---------------------------------------------------------------------- +/** + * Dereference the ConstWatcher to the object. + * + * @return Pointer to the object the ConstWatcher points to. + */ + +template +inline const T *ConstWatcher::operator ->() const +{ + return reinterpret_cast(m_data); +} + +// ---------------------------------------------------------------------- +/** + * Construct a WatchedByList. + * + * This list of watchers remains NULL until someone first watches the object. + */ + +inline WatchedByList::WatchedByList() +: m_list(NULL) +{ +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariable.cpp b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariable.cpp new file mode 100644 index 00000000..f11c603e --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariable.cpp @@ -0,0 +1,1466 @@ +//======================================================================== +// +// DynamicVariable.cpp - generic name->data mapping system +// +// copyright 2001 Sony Online Entertainment +// +//======================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/DynamicVariable.h" + +#include "StringId.h" +#include "sharedFoundation/DynamicVariableList.h" +#include "sharedFoundation/DynamicVariableLocationData.h" +#include "sharedFoundation/NetworkId.h" +#include "sharedFoundation/NetworkIdArchive.h" +#include "sharedMath/Quaternion.h" +#include "sharedMath/Transform.h" +#include "sharedMathArchive/VectorArchive.h" +#include "unicodeArchive/UnicodeArchive.h" +#include "UnicodeUtils.h" + +//======================================================================== + +namespace DynamicVariableNamespace +{ + typedef void (*pf) (void const * const); + + void freeIntArray(void const * const data) + { + delete reinterpret_cast const *>(data); + } + + void freeRealArray(void const * const data) + { + delete reinterpret_cast const *>(data); + } + + void freeStdString(void const * const data) + { + delete reinterpret_cast(data); + } + + void freeUnicodeStringArray(void const * const data) + { + delete reinterpret_cast const *>(data); + } + + void freeStdStringArray(void const * const data) + { + delete reinterpret_cast const *>(data); + } + + void freeNetworkIdArray(void const * const data) + { + delete reinterpret_cast const *>(data); + } + + void freeLocation(void const * const data) + { + delete reinterpret_cast(data); + } + + void freeLocationArray(void const * const data) + { + delete reinterpret_cast const *>(data); + } + + void freeStringId(void const * const data) + { + delete reinterpret_cast(data); + } + + void freeStringIdArray(void const * const data) + { + delete reinterpret_cast const *>(data); + } + + void freeTransform(void const * const data) + { + delete reinterpret_cast(data); + } + + void freeTransformArray(void const * const data) + { + delete reinterpret_cast const *>(data); + } + + void freeVector(void const * const data) + { + delete reinterpret_cast(data); + } + + void freeVectorArray(void const * const data) + { + delete reinterpret_cast const *>(data); + } +}; + +//======================================================================== +// class DynamicVariable + +DynamicVariable::DynamicVariable() : +m_type(INT), +m_value(), +m_position(-1), +m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; +} + +// ---------------------------------------------------------------------- + +DynamicVariable::~DynamicVariable() +{ + // release cache + if (m_cachedValue[1] && (m_type != NETWORK_ID)) + { + DynamicVariableNamespace::pf f; + *(reinterpret_cast(&f)) = m_cachedValue[1]; + (*f)(m_cachedValue[0]); + } +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const DynamicVariable &rhs) : + m_type(rhs.m_type), + m_value(rhs.m_value), + m_position(rhs.m_position), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariableType DynamicVariable::getType(void) const +{ + return m_type; +} + +// ---------------------------------------------------------------------- + +DynamicVariable& DynamicVariable::operator=(const DynamicVariable &rhs) +{ + // release cache if type is changing + if (m_cachedValue[1]) + { + if (m_type != rhs.m_type) + { + if (m_type != NETWORK_ID) + { + DynamicVariableNamespace::pf f; + *(reinterpret_cast(&f)) = m_cachedValue[1]; + (*f)(m_cachedValue[0]); + } + + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + } + } + + m_type = rhs.m_type; + m_value = rhs.m_value; + m_position = rhs.m_position; + m_cachedValueDirty = true; + + return *this; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::operator!=(const DynamicVariable &rhs) const +{ + return ((m_type != rhs.m_type) || (m_value != rhs.m_value)); +} + +// ---------------------------------------------------------------------- + +const Unicode::String &DynamicVariable::getPackedValueString() const +{ + return m_value; +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::load(int position, int typeId, const Unicode::String &packedValueString) +{ + // release cache if type is changing + if (m_cachedValue[1]) + { + if (m_type != static_cast(typeId)) + { + if (m_type != NETWORK_ID) + { + DynamicVariableNamespace::pf f; + *(reinterpret_cast(&f)) = m_cachedValue[1]; + (*f)(m_cachedValue[0]); + } + + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + } + } + + m_position = position; + m_type = static_cast(typeId); + m_value = packedValueString; + m_cachedValueDirty = true; +} + +// ---------------------------------------------------------------------- + +int DynamicVariable::getPosition() const +{ + return m_position; +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::setPosition(int newPosition) +{ + m_position = newPosition; +} + +// ====================================================================== +// DynamicVariable Constructors + +DynamicVariable::DynamicVariable(int value) : + m_type(INT), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const std::vector & value) : + m_type(INT_ARRAY), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(float value) : + m_type(REAL), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const std::vector & value) : + m_type(REAL_ARRAY), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const Unicode::String &value) : + m_type(STRING), + m_value(value), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const std::string &value) : + m_type(STRING), + m_value(Unicode::utf8ToWide(value)), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const std::vector & value) : + m_type(STRING_ARRAY), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const NetworkId & value) : + m_type(NETWORK_ID), + m_value(Unicode::narrowToWide(value.getValueString())), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const std::vector & value) : + m_type(NETWORK_ID_ARRAY), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const DynamicVariableLocationData & value) : + m_type(LOCATION), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const std::vector & value) : + m_type(LOCATION_ARRAY), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const StringId &value) : + m_type(STRING_ID), + m_value(Unicode::narrowToWide(value.getTable() + ' ' + value.getText())), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const std::vector &value) : + m_type(STRING_ID_ARRAY), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const Transform &value) : + m_type(TRANSFORM), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const std::vector &value) : + m_type(TRANSFORM_ARRAY), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const Vector &value) : + m_type(VECTOR), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariable(const std::vector &value) : + m_type(VECTOR_ARRAY), + m_value(), + m_position(-1), + m_cachedValueDirty(true) +{ + m_cachedValue[0] = NULL; + m_cachedValue[1] = NULL; + + pack(value, m_value); +} + +// ====================================================================== +// DynamicVariable getters + +bool DynamicVariable::get(int & value) const +{ + if (m_type != INT) + return false; + + if (m_cachedValueDirty) + { +#ifdef _DEBUG + FATAL((sizeof(int) > sizeof(m_cachedValue[0])),("DynamicVariable cache size mismatch for type INT")); +#endif + + *(reinterpret_cast(&(m_cachedValue[0]))) = atoi(Unicode::wideToNarrow(m_value).c_str()); + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast(&(m_cachedValue[0]))); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(std::vector &value) const +{ + if (m_type != INT_ARRAY) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new std::vector(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeIntArray; + } + + std::vector & cachedValue = *(reinterpret_cast *>(m_cachedValue[0])); + cachedValue.clear(); + + static const int BUFSIZE = 15; + char buffer[BUFSIZE]; + char *bufpos=buffer; + std::string packedString=Unicode::wideToNarrow(m_value); + + for(std::string::const_iterator i = packedString.begin(); + i != packedString.end() && bufpos < buffer + BUFSIZE; ++i) + { + if ((*i)==':') + { + *bufpos='\0'; + cachedValue.push_back(atoi(buffer)); + bufpos=buffer; + } + else + { + *(bufpos++)=*i; + } + } + if (bufpos >= buffer + BUFSIZE) + { + WARNING_STRICT_FATAL(true, ("DynamicVariable::get int array, " + "tried to overrun buffer!")); + value.clear(); + return false; + } + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast *>(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(float & value) const +{ + if (m_type != REAL) + return false; + + if (m_cachedValueDirty) + { +#ifdef _DEBUG + FATAL((sizeof(float) > sizeof(m_cachedValue[0])),("DynamicVariable cache size mismatch for type REAL")); +#endif + + sscanf(Unicode::wideToNarrow(m_value).c_str(),"%f",&value); + *(reinterpret_cast(&(m_cachedValue[0]))) = value; + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast(&(m_cachedValue[0]))); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(std::vector & value) const +{ + if (m_type != REAL_ARRAY) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new std::vector(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeRealArray; + } + + std::vector & cachedValue = *(reinterpret_cast *>(m_cachedValue[0])); + cachedValue.clear(); + + static const int BUFSIZE = 30; + char buffer[BUFSIZE]; + char *bufpos=buffer; + std::string packedString=Unicode::wideToNarrow(m_value); + + for(std::string::iterator i = packedString.begin(); + i != packedString.end() && bufpos < buffer + BUFSIZE; ++i) + { + if ((*i)==':') + { + *bufpos='\0'; + real temp; + sscanf(buffer,"%f",&temp); + cachedValue.push_back(temp); + bufpos=buffer; + } + else + { + *(bufpos++)=*i; + } + } + if (bufpos >= buffer + BUFSIZE) + { + WARNING_STRICT_FATAL(true, ("DynamicVariable::get float array, " + "tried to overrun buffer!")); + value.clear(); + return false; + } + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast *>(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(Unicode::String & value) const +{ + if (m_type != STRING) + return false; + + value = m_value; + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(std::string & value) const +{ + if (m_type != STRING) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new std::string(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeStdString; + } + + std::string & cachedValue = *(reinterpret_cast(m_cachedValue[0])); + cachedValue = Unicode::wideToUTF8(m_value); + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(std::vector & value) const +{ + if (m_type != STRING_ARRAY) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new std::vector(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeUnicodeStringArray; + } + + std::vector & cachedValue = *(reinterpret_cast *>(m_cachedValue[0])); + cachedValue.clear(); + + Unicode::String buffer; + for(Unicode::String::const_iterator i=m_value.begin(); i!=m_value.end(); ++i) + { + if ((*i)=='\\') + { + ++i; + buffer+=*i; + } + else if ((*i)==':') + { + cachedValue.push_back(buffer); + buffer.clear(); + } + else + { + buffer+=*i; + } + } + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast *>(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(NetworkId & value) const +{ + if (m_type != NETWORK_ID) + return false; + + if (m_cachedValueDirty) + { +#ifdef _DEBUG + FATAL((sizeof(NetworkId::NetworkIdType) > sizeof(m_cachedValue)),("DynamicVariable cache size mismatch for type NETWORK_ID")); +#endif + + value = NetworkId(Unicode::wideToNarrow(m_value)); + *(reinterpret_cast(&(m_cachedValue[0]))) = value.getValue(); + + m_cachedValueDirty = false; + } + + value = NetworkId(*(reinterpret_cast(&(m_cachedValue[0])))); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(std::vector & value) const +{ + if (m_type != NETWORK_ID_ARRAY) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new std::vector(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeNetworkIdArray; + } + + std::vector & cachedValue = *(reinterpret_cast *>(m_cachedValue[0])); + cachedValue.clear(); + + static const int BUFSIZE = 32; + char buffer[BUFSIZE]; + char *bufpos=buffer; + std::string packedString=Unicode::wideToNarrow(m_value); + + for (std::string::iterator i = packedString.begin(); + i != packedString.end() && bufpos < buffer + BUFSIZE; ++i) + { + if ((*i)==':') + { + *bufpos='\0'; + cachedValue.push_back(NetworkId(buffer)); + bufpos=buffer; + } + else + { + *(bufpos++)=*i; + } + } + if (bufpos >= buffer + BUFSIZE) + { + WARNING_STRICT_FATAL(true, ("DynamicVariable::get networkId array, " + "tried to overrun buffer!")); + value.clear(); + return false; + } + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast *>(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(DynamicVariableLocationData & value) const +{ + if (m_type != LOCATION) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new DynamicVariableLocationData(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeLocation; + } + + DynamicVariableLocationData & cachedValue = *(reinterpret_cast(m_cachedValue[0])); + + static const int BUFSIZE = 256; + char tempScene[BUFSIZE]; + char tempCell[BUFSIZE]; + std::string data(Unicode::wideToNarrow(m_value)); + const char * bufptrStart = data.c_str(); + char * bufptrEnd = NULL; + cachedValue.pos.x = static_cast(strtod(bufptrStart, &bufptrEnd)); + bufptrStart = bufptrEnd; + while (*bufptrStart != '\0' && isspace(*bufptrStart)) + ++bufptrStart; + cachedValue.pos.y = static_cast(strtod(bufptrStart, &bufptrEnd)); + bufptrStart = bufptrEnd; + while (*bufptrStart != '\0' && isspace(*bufptrStart)) + ++bufptrStart; + cachedValue.pos.z = static_cast(strtod(bufptrStart, &bufptrEnd)); + bufptrStart = bufptrEnd; + + // handle an empty scene name + if (*bufptrStart != '\0' && isspace(*bufptrStart) && isspace(*(bufptrStart+1))) + { + tempScene[0] = '\0'; + + while (*bufptrStart != '\0' && isspace(*bufptrStart)) + ++bufptrStart; + } + else + { + while (*bufptrStart != '\0' && isspace(*bufptrStart)) + ++bufptrStart; + bufptrEnd = const_cast(strchr(bufptrStart, ' ')); + if (bufptrEnd == NULL || bufptrEnd - bufptrStart >= BUFSIZE) + { + WARNING_STRICT_FATAL(true, ("DynamicVariable::get location buffer overflow in scene")); + return false; + } + memcpy(tempScene, bufptrStart, bufptrEnd - bufptrStart); + tempScene[bufptrEnd - bufptrStart] = '\0'; + bufptrStart = bufptrEnd + 1; + } + + int cellLen = strlen(bufptrStart); + if (cellLen >= BUFSIZE) + { + WARNING_STRICT_FATAL(true, ("DynamicVariable::get location buffer overflow in cell")); + return false; + } + memcpy(tempCell, bufptrStart, cellLen); + tempCell[cellLen] = '\0'; + + cachedValue.scene = tempScene; + cachedValue.cell = NetworkId(tempCell); + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(std::vector & value) const +{ + if (m_type != LOCATION_ARRAY) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new std::vector(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeLocationArray; + } + + std::vector & cachedValue = *(reinterpret_cast *>(m_cachedValue[0])); + cachedValue.clear(); + + static const int BUFSIZE = 256; + static const int VARBUFSIZE = BUFSIZE * 3; + char buffer[VARBUFSIZE]; + char *bufpos=buffer; + std::string packedString=Unicode::wideToNarrow(m_value); + + for(std::string::iterator i = packedString.begin(); + i != packedString.end() && bufpos < buffer + VARBUFSIZE; ++i) + { + if ((*i)==':') + { + *bufpos='\0'; + DynamicVariableLocationData temp; + char tempScene[BUFSIZE]; + char tempCell[BUFSIZE]; + + const char * bufptrStart = buffer; + char * bufptrEnd = NULL; + temp.pos.x = static_cast(strtod(bufptrStart, &bufptrEnd)); + bufptrStart = bufptrEnd; + while (*bufptrStart != '\0' && isspace(*bufptrStart)) + ++bufptrStart; + temp.pos.y = static_cast(strtod(bufptrStart, &bufptrEnd)); + bufptrStart = bufptrEnd; + while (*bufptrStart != '\0' && isspace(*bufptrStart)) + ++bufptrStart; + temp.pos.z = static_cast(strtod(bufptrStart, &bufptrEnd)); + bufptrStart = bufptrEnd; + + // handle an empty scene name + if (*bufptrStart != '\0' && isspace(*bufptrStart) && isspace(*(bufptrStart+1))) + { + tempScene[0] = '\0'; + + while (*bufptrStart != '\0' && isspace(*bufptrStart)) + ++bufptrStart; + } + else + { + while (*bufptrStart != '\0' && isspace(*bufptrStart)) + ++bufptrStart; + bufptrEnd = const_cast(strchr(bufptrStart, ' ')); + if (bufptrEnd == NULL || bufptrEnd - bufptrStart >= BUFSIZE) + { + WARNING_STRICT_FATAL(true, ("DynamicVariable::get location array buffer overflow in scene")); + return false; + } + memcpy(tempScene, bufptrStart, bufptrEnd - bufptrStart); + tempScene[bufptrEnd - bufptrStart] = '\0'; + bufptrStart = bufptrEnd + 1; + } + + int cellLen = strlen(bufptrStart); + if (cellLen >= BUFSIZE) + { + WARNING_STRICT_FATAL(true, ("DynamicVariable::get location array buffer overflow in cell")); + return false; + } + memcpy(tempCell, bufptrStart, cellLen); + tempCell[cellLen] = '\0'; + + temp.scene = tempScene; + temp.cell = NetworkId(tempCell); + cachedValue.push_back(temp); + bufpos=buffer; + } + else + { + *(bufpos++)=*i; + } + } + if (bufpos >= buffer + VARBUFSIZE) + { + WARNING_STRICT_FATAL(true, ("DynamicVariable::get location array, " + "tried to overrun buffer!")); + value.clear(); + return false; + } + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast *>(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(StringId &value) const +{ + if (m_type != STRING_ID) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new StringId(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeStringId; + } + + StringId & cachedValue = *(reinterpret_cast(m_cachedValue[0])); + std::string temp(Unicode::wideToNarrow(m_value)); + size_t space=temp.find(' '); + cachedValue=StringId(temp.substr(0,space),temp.substr(space+1)); + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(std::vector &value) const +{ + if (m_type != STRING_ID_ARRAY) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new std::vector(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeStringIdArray; + } + + std::vector & cachedValue = *(reinterpret_cast *>(m_cachedValue[0])); + cachedValue.clear(); + + std::string packedString(Unicode::wideToNarrow(m_value)); + + for (size_t pos=0; pos < packedString.length();) + { + size_t const space=packedString.find(' ',pos); + std::string table(packedString,pos,(space-pos)); + size_t const colon=packedString.find(':',space); + std::string text(packedString,space+1,(colon-space-1)); + pos=colon+1; + + cachedValue.push_back(StringId(table,text)); + } + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast *>(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(Transform &value) const +{ + if (m_type != TRANSFORM) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new Transform(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeTransform; + } + + Transform & cachedValue = *(reinterpret_cast(m_cachedValue[0])); + Quaternion q; + Vector p; + sscanf(Unicode::wideToNarrow(m_value).c_str(), "%f %f %f %f %f %f %f", &q.w, &q.x, &q.y, &q.z, &p.x, &p.y, &p.z); + cachedValue.setPosition_p(p); + q.getTransformPreserveTranslation(&cachedValue); + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(std::vector & value) const +{ + if (m_type != TRANSFORM_ARRAY) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new std::vector(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeTransformArray; + } + + std::vector & cachedValue = *(reinterpret_cast *>(m_cachedValue[0])); + cachedValue.clear(); + + static const int BUFSIZE = 256; + char buffer[BUFSIZE]; + char *bufpos = buffer; + std::string packedString = Unicode::wideToNarrow(m_value); + + for (std::string::iterator i = packedString.begin(); + i != packedString.end() && bufpos < buffer + BUFSIZE; ++i) + { + if ((*i) == ':') + { + *bufpos = '\0'; + Quaternion q; + Vector p; + sscanf(buffer, "%f %f %f %f %f %f %f", &q.w, &q.x, &q.y, &q.z, &p.x, &p.y, &p.z); + Transform temp; + temp.setPosition_p(p); + q.getTransformPreserveTranslation(&temp); + cachedValue.push_back(temp); + bufpos = buffer; + } + else + { + *(bufpos++) = *i; + } + } + if (bufpos >= buffer + BUFSIZE) + { + WARNING_STRICT_FATAL(true, ("DynamicVariable::get transform array, " + "tried to overrun buffer!")); + value.clear(); + return false; + } + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast *>(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(Vector &value) const +{ + if (m_type != VECTOR) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new Vector(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeVector; + } + + Vector & cachedValue = *(reinterpret_cast(m_cachedValue[0])); + sscanf(Unicode::wideToNarrow(m_value).c_str(), "%f %f %f", &cachedValue.x, &cachedValue.y, &cachedValue.z); + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariable::get(std::vector & value) const +{ + if (m_type != VECTOR_ARRAY) + return false; + + if (m_cachedValueDirty) + { + if (!m_cachedValue[0]) + { + m_cachedValue[0] = new std::vector(); + m_cachedValue[1] = (void*)DynamicVariableNamespace::freeVectorArray; + } + + std::vector & cachedValue = *(reinterpret_cast *>(m_cachedValue[0])); + cachedValue.clear(); + + static const int BUFSIZE = 256; + char buffer[BUFSIZE]; + char *bufpos = buffer; + std::string packedString = Unicode::wideToNarrow(m_value); + + for (std::string::iterator i = packedString.begin(); + i != packedString.end() && bufpos < buffer + BUFSIZE; ++i) + { + if ((*i) == ':') + { + *bufpos = '\0'; + Vector temp; + sscanf(buffer, "%f %f %f", &temp.x, &temp.y, &temp.z); + cachedValue.push_back(temp); + bufpos = buffer; + } + else + { + *(bufpos++) = *i; + } + } + if (bufpos >= buffer + BUFSIZE) + { + WARNING_STRICT_FATAL(true, ("DynamicVariable::get vector array, " + "tried to overrun buffer!")); + value.clear(); + return false; + } + + m_cachedValueDirty = false; + } + + value = *(reinterpret_cast *>(m_cachedValue[0])); + return true; +} + +// ---------------------------------------------------------------------- + +int DynamicVariable::getUTF8Length() const +{ + std::string utf8; + Unicode::wideToUTF8(m_value, utf8); + return utf8.size(); +} + +// ---------------------------------------------------------------------- + +#define GET_UTF_LENGTH(T) \ +int DynamicVariable::getUTF8Length(const T &value) \ +{ \ + Unicode::String packedData; \ + pack(value, packedData); \ + std::string utf8; \ + IGNORE_RETURN(Unicode::wideToUTF8(packedData, utf8)); \ + return utf8.size(); \ +} + +GET_UTF_LENGTH(int) +GET_UTF_LENGTH(std::vector) +GET_UTF_LENGTH(float) +GET_UTF_LENGTH(std::vector) +GET_UTF_LENGTH(Unicode::String) +GET_UTF_LENGTH(std::string) +GET_UTF_LENGTH(std::vector) +GET_UTF_LENGTH(NetworkId) +GET_UTF_LENGTH(std::vector) +GET_UTF_LENGTH(DynamicVariableLocationData) +GET_UTF_LENGTH(std::vector) +GET_UTF_LENGTH(StringId) +GET_UTF_LENGTH(std::vector) +GET_UTF_LENGTH(Transform) +GET_UTF_LENGTH(std::vector) +GET_UTF_LENGTH(Vector) +GET_UTF_LENGTH(std::vector) + + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(int value, Unicode::String & packedData) +{ + char buffer[30]; + _itoa(value,buffer,10); + packedData = Unicode::narrowToWide(buffer); +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const std::vector & value, Unicode::String & packedData) +{ + packedData.clear(); + char buffer[15]; + for(std::vector::const_iterator i = value.begin(); i != value.end(); ++i) + { + sprintf(buffer,"%i:",*i); + packedData += Unicode::narrowToWide(buffer); + } +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(float value, Unicode::String & packedData) +{ + char buffer[30]; + sprintf(buffer,"%f",value); + packedData = Unicode::narrowToWide(buffer); +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const std::vector & value, Unicode::String & packedData) +{ + packedData.clear(); + char buffer[30]; + for(std::vector::const_iterator i = value.begin(); i != value.end(); ++i) + { + sprintf(buffer,"%f:",*i); + packedData += Unicode::narrowToWide(buffer); + } +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const Unicode::String &value, Unicode::String & packedData) +{ + packedData = value; +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const std::string &value, Unicode::String & packedData) +{ + packedData = Unicode::utf8ToWide(value); +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const std::vector & value, Unicode::String & packedData) +{ + packedData.clear(); + for(std::vector::const_iterator i = value.begin(); i != value.end(); ++i) + { + for (Unicode::String::const_iterator j =(*i).begin(); j!= (*i).end(); ++j) + { + if ((*j)==':') + packedData += Unicode::narrowToWide("\\:"); + else if ((*j)=='\\') + packedData += Unicode::narrowToWide("\\\\"); + else + packedData += (*j); + } + packedData += ':'; + } +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const NetworkId & value, Unicode::String & packedData) +{ + packedData = Unicode::narrowToWide(value.getValueString()); +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const std::vector & value, Unicode::String & packedData) +{ + std::string temp; + for(std::vector::const_iterator i = value.begin(); i != value.end(); ++i) + { + temp += (*i).getValueString()+':'; + } + packedData = Unicode::narrowToWide(temp); +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const DynamicVariableLocationData & value, Unicode::String & packedData) +{ + char temp[256]; + sprintf(temp,"%f %f %f %s %s",value.pos.x, value.pos.y,value.pos.z, value.scene.c_str(), value.cell.getValueString().c_str()); + temp[255] = '\0'; + packedData = Unicode::narrowToWide(temp); +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const std::vector & value, Unicode::String & packedData) +{ + packedData.clear(); + for (std::vector::const_iterator i = value.begin(); i != value.end(); ++i) + { + char temp[256]; + sprintf(temp,"%f %f %f %s %s",(*i).pos.x, (*i).pos.y,(*i).pos.z, (*i).scene.c_str(), (*i).cell.getValueString().c_str()); + temp[255] = '\0'; + packedData += Unicode::narrowToWide(std::string(temp)+':'); + } +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const StringId &value, Unicode::String & packedData) +{ + packedData = Unicode::narrowToWide(value.getTable() + ' ' + value.getText()); +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const std::vector &value, Unicode::String & packedData) +{ + packedData.clear(); + for(std::vector::const_iterator i = value.begin(); i != value.end(); ++i) + packedData += Unicode::narrowToWide(i->getTable()+' '+i->getText()+':'); +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const Transform &value, Unicode::String & packedData) +{ + Quaternion q(value); + Vector p(value.getPosition_p()); + char temp[256]; + snprintf(temp, 255, "%.12g %.12g %.12g %.12g %.12g %.12g %.12g", + static_cast(q.w), static_cast(q.x), static_cast(q.y), static_cast(q.z), + static_cast(p.x), static_cast(p.y), static_cast(p.z)); + temp[255] = '\0'; + packedData = Unicode::narrowToWide(temp); +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const std::vector &value, Unicode::String & packedData) +{ + packedData.clear(); + for (std::vector::const_iterator i = value.begin(); i != value.end(); ++i) + { + Quaternion q(*i); + Vector p((*i).getPosition_p()); + char temp[256]; + snprintf(temp, 255, "%.12g %.12g %.12g %.12g %.12g %.12g %.12g:", + static_cast(q.w), static_cast(q.x), static_cast(q.y), static_cast(q.z), + static_cast(p.x), static_cast(p.y), static_cast(p.z)); + temp[255] = '\0'; + packedData += Unicode::narrowToWide(temp); + } +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const Vector &value, Unicode::String & packedData) +{ + char temp[256]; + snprintf(temp, 255, "%.12g %.12g %.12g", static_cast(value.x), static_cast(value.y), static_cast(value.z)); + temp[255] = '\0'; + packedData = Unicode::narrowToWide(temp); +} + +// ---------------------------------------------------------------------- + +void DynamicVariable::pack(const std::vector &value, Unicode::String & packedData) +{ + packedData.clear(); + for (std::vector::const_iterator i = value.begin(); i != value.end(); ++i) + { + char temp[256]; + snprintf(temp, 255, "%.12g %.12g %.12g:", static_cast((*i).x), static_cast((*i).y), static_cast((*i).z)); + temp[255] = '\0'; + packedData += Unicode::narrowToWide(temp); + } +} + +// ====================================================================== +// DynamicVariable Archive + +namespace Archive +{ + void get(ReadIterator & source, DynamicVariable & target) + { + int typeInt; + get(source,typeInt); + + // release cache if type is changing + if (target.m_cachedValue[1]) + { + if (target.m_type != static_cast(typeInt)) + { + if (target.m_type != DynamicVariable::NETWORK_ID) + { + DynamicVariableNamespace::pf f; + *(reinterpret_cast(&f)) = target.m_cachedValue[1]; + (*f)(target.m_cachedValue[0]); + } + + target.m_cachedValue[0] = NULL; + target.m_cachedValue[1] = NULL; + } + } + + target.m_type = static_cast(typeInt); + get(source,target.m_value); + get(source,target.m_position); + target.m_cachedValueDirty = true; + } + + void put(ByteStream & target, const DynamicVariable & source) + { + put(target,static_cast(source.m_type)); + put(target,source.m_value); + put(target,source.m_position); + } + + void get(ReadIterator & source, DynamicVariableLocationData & target) + { + Archive::get(source, target.pos); + Archive::get(source, target.scene); + Archive::get(source, target.cell); + } + + void put(ByteStream & target, const DynamicVariableLocationData & source) + { + Archive::put(target, source.pos); + Archive::put(target, source.scene); + Archive::put(target, source.cell); + } +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariable.h b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariable.h new file mode 100644 index 00000000..fae07703 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariable.h @@ -0,0 +1,171 @@ +//======================================================================== +// +// DynamicVariable.h - generic name->data mapping system +// +// copyright 2001 Sony Online Entertainment +// +//======================================================================== + +#ifndef _INCLUDED_DynamicVariable_H +#define _INCLUDED_DynamicVariable_H + +#include "Unicode.h" + +class DynamicVariable; +class DynamicVariableLocationData; +class NetworkId; +class StringId; +class Transform; +class Vector; + +//======================================================================== + +namespace Archive +{ + class ReadIterator; + class ByteStream; + + void get(ReadIterator & source, DynamicVariable & target); + void put(ByteStream & target, const DynamicVariable & source); +} + +//======================================================================== +// class DynamicVariable - base class for dynamic variables + +class DynamicVariable +{ + public: + enum status {OK, BAD_TYPE, NOT_PRESENT}; + enum DynamicVariableType { + INT, INT_ARRAY, //lint !e578 INT hides INT in windef.h + REAL, REAL_ARRAY, + STRING, STRING_ARRAY, + NETWORK_ID, NETWORK_ID_ARRAY, + LOCATION, LOCATION_ARRAY, + LIST, + STRING_ID, STRING_ID_ARRAY, + TRANSFORM, TRANSFORM_ARRAY, + VECTOR, VECTOR_ARRAY + }; + enum { MAX_DYNAMIC_VARIABLE_NAME_LEN = 128 }; // this includes final '\0' + enum { MAX_DYNAMIC_VARIABLE_STRING_VALUE_LEN = 128 }; // this includes final '\0' + enum { MAX_DYNAMIC_VARIABLE_UTF8_LENGTH = 1000 }; + + public: + DynamicVariable(); + ~DynamicVariable(); + DynamicVariable(const DynamicVariable &rhs); + DynamicVariable& operator=(const DynamicVariable &rhs); + bool operator!=(const DynamicVariable &rhs) const; + + int getPosition() const; + void setPosition(int newPosition); + + explicit DynamicVariable(int value); + explicit DynamicVariable(const stdvector::fwd & value); + explicit DynamicVariable(float value); + explicit DynamicVariable(const stdvector::fwd & value); + explicit DynamicVariable(const Unicode::String &value); + explicit DynamicVariable(const std::string &value); + explicit DynamicVariable(const stdvector::fwd & value); + explicit DynamicVariable(const NetworkId & value); + explicit DynamicVariable(const stdvector::fwd & value); + explicit DynamicVariable(const DynamicVariableLocationData & value); + explicit DynamicVariable(const stdvector::fwd & value); + explicit DynamicVariable(const StringId &value); + explicit DynamicVariable(const stdvector::fwd &value); + explicit DynamicVariable(const Transform &value); + explicit DynamicVariable(const stdvector::fwd &value); + explicit DynamicVariable(const Vector &value); + explicit DynamicVariable(const stdvector::fwd &value); + + bool get(int & value) const; + bool get(stdvector::fwd & value) const; + bool get(float & value) const; + bool get(stdvector::fwd & value) const; + bool get(Unicode::String & value) const; + bool get(std::string & value) const; + bool get(stdvector::fwd & value) const; + bool get(NetworkId & value) const; + bool get(stdvector::fwd & value) const; + bool get(DynamicVariableLocationData & value) const; + bool get(stdvector::fwd & value) const; + bool get(StringId &value) const; + bool get(stdvector::fwd &value) const; + bool get(Transform &value) const; + bool get(stdvector::fwd &value) const; + bool get(Vector &value) const; + bool get(stdvector::fwd &value) const; + + int getUTF8Length() const; + static int getUTF8Length(const int & value); + static int getUTF8Length(const stdvector::fwd & value); + static int getUTF8Length(const float & value); + static int getUTF8Length(const stdvector::fwd & value); + static int getUTF8Length(const Unicode::String &value); + static int getUTF8Length(const std::string &value); + static int getUTF8Length(const stdvector::fwd & value); + static int getUTF8Length(const NetworkId & value); + static int getUTF8Length(const stdvector::fwd & value); + static int getUTF8Length(const DynamicVariableLocationData & value); + static int getUTF8Length(const stdvector::fwd & value); + static int getUTF8Length(const StringId &value); + static int getUTF8Length(const stdvector::fwd &value); + static int getUTF8Length(const Transform &value); + static int getUTF8Length(const stdvector::fwd &value); + static int getUTF8Length(const Vector &value); + static int getUTF8Length(const stdvector::fwd &value); + +public: + // functions used for persistence: + DynamicVariableType getType() const; + const Unicode::String &getPackedValueString() const; + void load(int position, int typeId, const Unicode::String &packedValueString); + +private: + + static void pack(int value, Unicode::String & packedData); + static void pack(const stdvector::fwd & value, Unicode::String & packedData); + static void pack(float value, Unicode::String & packedData); + static void pack(const stdvector::fwd & value, Unicode::String & packedData); + static void pack(const Unicode::String &value, Unicode::String & packedData); + static void pack(const std::string &value, Unicode::String & packedData); + static void pack(const stdvector::fwd & value, Unicode::String & packedData); + static void pack(const NetworkId & value, Unicode::String & packedData); + static void pack(const stdvector::fwd & value, Unicode::String & packedData); + static void pack(const DynamicVariableLocationData & value, Unicode::String & packedData); + static void pack(const stdvector::fwd & value, Unicode::String & packedData); + static void pack(const StringId &value, Unicode::String & packedData); + static void pack(const stdvector::fwd &value, Unicode::String & packedData); + static void pack(const Transform &value, Unicode::String & packedData); + static void pack(const stdvector::fwd &value, Unicode::String & packedData); + static void pack(const Vector &value, Unicode::String & packedData); + static void pack(const stdvector::fwd &value, Unicode::String & packedData); + +private: + DynamicVariableType m_type; + Unicode::String m_value; + int m_position; + + // caching the value so we don't constantly convert them from the string representation + // + // if the value can fit in m_cachedValue, we directly store it there + // int uses m_cachedValue[0], m_cachedValue[1] = NULL + // float uses m_cachedValue[0], m_cachedValue[1] = NULL + // NetworkId uses both m_cachedValue[0] and m_cachedValue[1] + // + // if not, we allocate storage for the value and store the pointer to it + // in m_cachedValue[0] and store the pointer to the function to free the + // storage in m_cachedValue[1] + // + mutable bool m_cachedValueDirty; + mutable void * m_cachedValue[2]; + + friend void Archive::get(ReadIterator & source, DynamicVariable & target); + friend void Archive::put(ByteStream & target, const DynamicVariable & source); +}; + +//======================================================================== + +#endif // _INCLUDED_DynamicVariable_H + diff --git a/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableList.cpp b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableList.cpp new file mode 100644 index 00000000..d0cda873 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableList.cpp @@ -0,0 +1,377 @@ +//======================================================================== +// +// DynamicVariableList.cpp +// +// copyright 2001 Sony Online Entertainment +// +//======================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/DynamicVariableList.h" +#include "sharedFoundation/DynamicVariableListNestedList.h" + +// ====================================================================== + +namespace DynamicVariableNamespace +{ + static const int s_numPositions = 20; + static const int s_positionMasks[20] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288}; + static const int s_allPositionsSet = 1048575; + static const size_t s_maxPackedStringLength = 50; + static const int s_initialRevision = -1; +} +using namespace DynamicVariableNamespace; + +// ====================================================================== + +DynamicVariableList::DynamicVariableList() : + m_map(), + m_freePositions(s_allPositionsSet), + m_revision(s_initialRevision) +{ +} + +// ---------------------------------------------------------------------- + +DynamicVariableList::~DynamicVariableList() +{ +} + +// ---------------------------------------------------------------------- + +bool DynamicVariableList::removeItemByName(const std::string &name) +{ + if (name == ".") + { + for(MapType::const_iterator it = begin(); it != end(); ++it) + { + if (it->second.getPosition() != -1) + releasePosition(it->second.getPosition()); + } + m_map.clear(); + updateRevision(); + return true; + } + + MapType::const_iterator i=lower_bound(name); + if (i==end()) + return false; + if (i->first == name) + { + if (i->second.getPosition() != -1) + releasePosition(i->second.getPosition()); + m_map.erase(i); // exact match + updateRevision(); + return true; + } + else + { + // check whether it's the first part of a nested item + if ((name+'.') == i->first.substr(0,name.length()+1)) // TODO: better STL function? + { + NestedList sublist(*this,name); + while (sublist.isInList(i)) + { + MapType::const_iterator next(i); + ++next; + if (i->second.getPosition() != -1) + releasePosition(i->second.getPosition()); + m_map.erase(i); + i = next; + } + updateRevision(); + return true; + } + else + return false; // no matching sublist + } +} + +// ---------------------------------------------------------------------- + +bool DynamicVariableList::hasItem(const std::string &name) const +{ + MapType::const_iterator i=m_map.lower_bound(name); + if (i==m_map.end()) + return false; + if (i->first == name) + return true; // exact match + else + { + // check whether it's the first part of a nested item + return ((name+'.') == i->first.substr(0,name.length()+1)); // TODO: better STL function? + } +} + +// --------------------------------------------------------------------------- + +/*void DynamicVariableList::debugPrint(std::string &output) const +{ + for (MapType::const_iterator i=m_map.begin(); i!=m_map.end(); ++i) + i->second.debugPrint(output); +}*/ + +// ---------------------------------------------------------------------- + +void DynamicVariableList::addToPackage(Archive::AutoDeltaByteStream & bs, Archive::AutoDeltaByteStream & bs_np) +{ + bs.addVariable(m_freePositions); + bs.addVariable(m_map); + bs_np.addVariable(m_revision); +} + +// ---------------------------------------------------------------------- + +DynamicVariableList::MapType::const_iterator DynamicVariableList::lower_bound(const std::string &name) const +{ + return m_map.lower_bound(name); +} + +// ---------------------------------------------------------------------- + +DynamicVariableList::MapType::const_iterator DynamicVariableList::begin() const +{ + return m_map.begin(); +} + +// ---------------------------------------------------------------------- + +DynamicVariableList::MapType::const_iterator DynamicVariableList::end() const +{ + return m_map.end(); +} + +// ---------------------------------------------------------------------- + +DynamicVariable::DynamicVariableType DynamicVariableList::getType(const std::string &name) const +{ + MapType::const_iterator i=m_map.find(name); + if (i!=m_map.end()) + return i->second.getType(); + else + // for compatibility with the old interface, no exact match == (possibly empty) nested list + return DynamicVariable::LIST; +} + +// ---------------------------------------------------------------------- + +DynamicVariableList::MapType::const_iterator DynamicVariableList::find(const std::string &name) const +{ + return m_map.find(name); +} + +// ---------------------------------------------------------------------- + +void DynamicVariableList::copy(const std::string &destObjvarName, const DynamicVariableList &sourceList, const std::string &sourceObjvarName) +{ + if (sourceList.getType(sourceObjvarName)==DynamicVariable::LIST) + { + std::string oldPrefix(sourceObjvarName+'.'); + std::string newPrefix(destObjvarName+'.'); + for (MapType::const_iterator i=sourceList.lower_bound(oldPrefix); (i!=sourceList.end()) && (i->first.substr(0,oldPrefix.length()) == oldPrefix); ++i) + { + setItem(newPrefix + i->first.substr(oldPrefix.length(),static_cast(std::string::npos)),i->second); // static_cast needed for Windows + } + } + else + { + MapType::const_iterator sourceObjvar(sourceList.m_map.find(sourceObjvarName)); + if (sourceObjvar != sourceList.m_map.end()) + setItem(destObjvarName,sourceObjvar->second); + } +} + +// ====================================================================== +// DynamicVariableList::const_iterator + +/*DynamicVariableList::const_iterator::const_iterator(const MapType::const_iterator &source) : + MapType::const_iterator (source) +{ +} + +// ---------------------------------------------------------------------- + +std::string DynamicVariableList::const_iterator::getName() const +{ + size_t dotpos = getNameWithPath().rfind('.'); + if (dotpos == std::string::npos) + return getNameWithPath(); + return getNameWithPath().substr(dotpos+1,std::string::npos); +} + +// ---------------------------------------------------------------------- + +const std::string &DynamicVariableList::const_iterator::getNameWithPath() const +{ + return operator*().first; +}*/ + +// ====================================================================== +// DynamicVariableList getters +// Using a macro because VC couldn't handle it when I tried a template member function + +#define GET_ITEM(T) \ +bool DynamicVariableList::getItem(const std::string &name, T &value) const \ +{ \ + MapType::const_iterator i=m_map.find(name); \ + if (i==m_map.end()) \ + return false; \ + else \ + return (i->second.get(value)); \ +} + +GET_ITEM(int) +GET_ITEM(stdvector::fwd) +GET_ITEM(float) +GET_ITEM(stdvector::fwd) +GET_ITEM(Unicode::String) +GET_ITEM(std::string) +GET_ITEM(stdvector::fwd) +GET_ITEM(NetworkId) +GET_ITEM(stdvector::fwd) +GET_ITEM(DynamicVariableLocationData) +GET_ITEM(stdvector::fwd) +GET_ITEM(StringId) +GET_ITEM(stdvector::fwd) +GET_ITEM(Transform) +GET_ITEM(stdvector::fwd) +GET_ITEM(Vector) +GET_ITEM(stdvector::fwd) + +// ====================================================================== +// DynamicVariableList setters +// Using a macro because VC couldn't handle it when I tried a template member function + +#define SET_ITEM(T) \ +bool DynamicVariableList::setItem(const std::string &name, const T &value) \ +{ \ + setItem(name,DynamicVariable(value)); \ + return true; \ +} + +SET_ITEM(int) +SET_ITEM(stdvector::fwd) +SET_ITEM(float) +SET_ITEM(stdvector::fwd) +SET_ITEM(Unicode::String) +SET_ITEM(std::string) +SET_ITEM(stdvector::fwd) +SET_ITEM(NetworkId) +SET_ITEM(stdvector::fwd) +SET_ITEM(DynamicVariableLocationData) +SET_ITEM(stdvector::fwd) +SET_ITEM(StringId) +SET_ITEM(stdvector::fwd) +SET_ITEM(Transform) +SET_ITEM(stdvector::fwd) +SET_ITEM(Vector) +SET_ITEM(stdvector::fwd) + +bool DynamicVariableList::setItem(const std::string &name, DynamicVariable value) +{ + if (name.empty()) + { + WARNING_STRICT_FATAL(true,("Attepted to set an object variable with no name")); + return false; + } + + size_t length = value.getUTF8Length(); + if (length > DynamicVariable::MAX_DYNAMIC_VARIABLE_UTF8_LENGTH) + { + WARNING_STRICT_FATAL(true, ("DynamicVariableList tried to set objvar %s to too long a value", name.c_str())); + return false; + } + + bool canUsePosition = true; + if ((name.length() > s_maxPackedStringLength) || (length > s_maxPackedStringLength)) + canUsePosition = false; // objvar can't use a packed position if it is too long + + MapType::const_iterator i=m_map.find(name); + if (i==m_map.end()) + { + if (canUsePosition) + value.setPosition(getFreePosition()); + else + value.setPosition(-1); + + updateRevision(); + } + else + { + if (value != i->second) + updateRevision(); + + if ((i->second.getPosition() != -1) && !canUsePosition) + { + // old value was using a packed position, but the new value can't. + releasePosition(i->second.getPosition()); + value.setPosition(-1); + m_map.erase(name); // send the delta as an erase and an add, so that the DB handles it correctly + + updateRevision(); + } + else + { + // use the same packed position, if any + value.setPosition(i->second.getPosition()); + } + } + + m_map.set(name,value); + return true; +} + +// ---------------------------------------------------------------------- + +int DynamicVariableList::getFreePosition() +{ + if (m_freePositions.get() == 0) + return -1; + + for (int i=0; i< s_numPositions; ++i) + { +// DEBUG_REPORT_LOG(true,("i=%i, m_freePositions=%i, positionMasks[i]=%i\n",i, m_freePositions.get(),positionMasks[i])); + if ((m_freePositions.get() & s_positionMasks[i]) != 0) + { +// DEBUG_REPORT_LOG(true,("Picking position %i\n",i)); + m_freePositions=m_freePositions.get() - s_positionMasks[i]; + return i; + } + } + return -1; +} + +// ---------------------------------------------------------------------- + +void DynamicVariableList::releasePosition(int positionId) +{ + DEBUG_FATAL(positionId < 0 || positionId >= s_numPositions, ("Position number out of range.")); + DEBUG_FATAL(((m_freePositions.get() & s_positionMasks[positionId]) != 0),("Attempted to release a position that was not in use")); + + m_freePositions= m_freePositions.get() + s_positionMasks[positionId]; +} + +// ---------------------------------------------------------------------- + +size_t DynamicVariableList::size() const +{ + return m_map.size(); +} + +// ---------------------------------------------------------------------- + +int DynamicVariableList::getRevision() const +{ + return m_revision.get(); +} + +// ---------------------------------------------------------------------- + +void DynamicVariableList::updateRevision() +{ + m_revision.set(m_revision.get() + 1); +} + + + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableList.h b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableList.h new file mode 100644 index 00000000..6a5a22c3 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableList.h @@ -0,0 +1,110 @@ +//======================================================================== +// +// DynamicVariableList.h +// +// copyright 2001 Sony Online Entertainment +// +//======================================================================== + +#ifndef _INCLUDED_DynamicVariableList_H +#define _INCLUDED_DynamicVariableList_H + +//======================================================================== +// class DynamicVariableList - a list of DynamicVariables + +#include "Archive/AutoDeltaMap.h" +#include "sharedFoundation/DynamicVariable.h" + +//@todo: this should be removed +#include "sharedFoundation/DynamicVariableListNestedList.h" + +const char LIST_SEPARATOR = '.'; +class DynamicVariableListNestedList; +class NetworkId; +class StringId; +class Transform; +class Vector; + +// ====================================================================== + +/** + * A DynamicVariableList is a map of name, value pairs. The values can have many different types. + */ +class DynamicVariableList +{ +public: + typedef Archive::AutoDeltaMap MapType; + typedef DynamicVariableListNestedList NestedList; + +public: + DynamicVariableList(); + ~DynamicVariableList(); + + MapType::const_iterator begin () const; + MapType::const_iterator end () const; + MapType::const_iterator lower_bound (const std::string &name) const; + MapType::const_iterator find (const std::string &name) const; + void copy (const std::string &destObjvarName, const DynamicVariableList &sourceList, const std::string &sourceObjvarName); + bool removeItemByName (const std::string &name); + bool hasItem (const std::string &name) const; + DynamicVariable:: DynamicVariableType getType (const std::string &name) const; // for compatibility, should return LIST if the item is a sublist + void addToPackage (Archive::AutoDeltaByteStream & bs, Archive::AutoDeltaByteStream & bs_np); + size_t size() const; + + bool getItem(const std::string &name,int & value) const; + bool getItem(const std::string &name,stdvector::fwd & value) const; + bool getItem(const std::string &name,float & value) const; + bool getItem(const std::string &name,stdvector::fwd & value) const; + bool getItem(const std::string &name,Unicode::String & value) const; + bool getItem(const std::string &name,std::string & value) const; + bool getItem(const std::string &name,stdvector::fwd & value) const; + bool getItem(const std::string &name,NetworkId & value) const; + bool getItem(const std::string &name,stdvector::fwd & value) const; + bool getItem(const std::string &name,DynamicVariableLocationData & value) const; + bool getItem(const std::string &name,stdvector::fwd & value) const; + bool getItem(const std::string &name,StringId &value) const; + bool getItem(const std::string &name,stdvector::fwd &value) const; + bool getItem(const std::string &name,Transform &value) const; + bool getItem(const std::string &name,stdvector::fwd &value) const; + bool getItem(const std::string &name,Vector &value) const; + bool getItem(const std::string &name,stdvector::fwd &value) const; + + bool setItem(const std::string &name, const int & value); + bool setItem(const std::string &name, const stdvector::fwd & value); + bool setItem(const std::string &name, const float & value); + bool setItem(const std::string &name, const stdvector::fwd & value); + bool setItem(const std::string &name, const Unicode::String & value); + bool setItem(const std::string &name, const std::string & value); + bool setItem(const std::string &name, const stdvector::fwd & value); + bool setItem(const std::string &name, const NetworkId & value); + bool setItem(const std::string &name, const stdvector::fwd & value); + bool setItem(const std::string &name, const DynamicVariableLocationData & value); + bool setItem(const std::string &name, const stdvector::fwd & value); + bool setItem(const std::string &name, const StringId &value); + bool setItem(const std::string &name, const stdvector::fwd &value); + bool setItem(const std::string &name, const Transform &value); + bool setItem(const std::string &name, const stdvector::fwd &value); + bool setItem(const std::string &name, const Vector &value); + bool setItem(const std::string &name, const stdvector::fwd &value); + bool setItem(const std::string &name, DynamicVariable value); + + int getRevision() const; + void updateRevision(); + +private: + MapType m_map; + Archive::AutoDeltaVariable m_freePositions; + Archive::AutoDeltaVariable m_revision; + + int getFreePosition(); + void releasePosition(int positionId); + +private: + DynamicVariableList &operator=(const DynamicVariableList &); // disable + + friend class DynamicVariableListNestedList; +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableListNestedList.cpp b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableListNestedList.cpp new file mode 100644 index 00000000..dc905c32 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableListNestedList.cpp @@ -0,0 +1,327 @@ +//====================================================================== +// +// DynamicVariableListNestedList.cpp +// copyright (c) 2003 Sony Online Entertainment +// +//====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/DynamicVariableListNestedList.h" + +#include "sharedFoundation/DynamicVariableList.h" + +//====================================================================== + +// ====================================================================== +// DynamicVariableListNestedList + +DynamicVariableListNestedList::DynamicVariableListNestedList (const DynamicVariableList &dvList, const std::string &sublistName) : + m_list(dvList), + m_sublistName(sublistName.empty() ? sublistName : sublistName + '.') +{ +} + +// ---------------------------------------------------------------------- + +DynamicVariableListNestedList::DynamicVariableListNestedList (const DynamicVariableList &dvList) : + m_list(dvList), + m_sublistName() +{ +} + +// ---------------------------------------------------------------------- + +DynamicVariableListNestedList::DynamicVariableListNestedList (const DynamicVariableListNestedList &parentList, const std::string &sublistName) : + m_list(parentList.m_list), + m_sublistName(parentList.getContextName()+sublistName + '.') +{ + DEBUG_FATAL(sublistName.empty(),("Programmer bug: passed empty sublist name to NestedList::NestedList.\n")); +} + +// ---------------------------------------------------------------------- + +/** + * The name of the list, including all parents. + */ +const std::string DynamicVariableListNestedList::getNameWithPath() const +{ + if (m_sublistName.empty()) + return std::string(); + else + // strip off trailing '.' + return m_sublistName.substr(0,m_sublistName.length()-1); +} + +// ---------------------------------------------------------------------- + +/** + * The string to append to get variables in this list. + */ +const std::string &DynamicVariableListNestedList::getContextName() const +{ + return m_sublistName; +} + +// ---------------------------------------------------------------------- + +const std::string DynamicVariableListNestedList::getName() const +{ + if (m_sublistName.empty()) + return std::string(); + + size_t lastDot = m_sublistName.rfind('.'); + DEBUG_FATAL(lastDot==std::string::npos,("Programmer bug: NestedList name \"%s\" was non-empty but did not a dot.\n",m_sublistName.c_str())); + size_t nextToLastDot = m_sublistName.rfind('.',lastDot-1); + return m_sublistName.substr(nextToLastDot+1,lastDot-nextToLastDot-1); +} + +// ---------------------------------------------------------------------- + +int DynamicVariableListNestedList::getCount() const +{ + int count=0; + for (const_iterator i(begin()); i!=end(); ++i) + ++count; + return count; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariableListNestedList::empty() const +{ + return (begin() == end()); +} + +// ---------------------------------------------------------------------- + +DynamicVariableListNestedList::const_iterator DynamicVariableListNestedList::begin() const +{ + DynamicVariableList::MapType::const_iterator i=m_list.lower_bound(getContextName()); + return const_iterator(*this,i,!isInList(i)); +} + +// ---------------------------------------------------------------------- + +DynamicVariableListNestedList::const_iterator DynamicVariableListNestedList::end() const +{ + return const_iterator(*this,m_list.end(),true); +} + +// ---------------------------------------------------------------------- + +/** + * Returns true if the specified iterator is within the nested list + */ +bool DynamicVariableListNestedList::isInList(const DynamicVariableList::MapType::const_iterator &i) const +{ + // the first part of the item's name must == the sublist name + // TODO: there is a better STL function for this -- look it up + + if (i == m_list.m_map.end()) + return false; + return (getContextName() == i->first.substr(0,getContextName().length())); +} + +// ---------------------------------------------------------------------- + +/** + * Returns true if we have an item matching the name, or if there is an + * item in a nested list beginning with the name. + */ +bool DynamicVariableListNestedList::hasItem(const std::string &name) const +{ + std::string effectiveName(getContextName()+name); + DynamicVariableList::MapType::const_iterator i=m_list.lower_bound(effectiveName); + if (i->first == effectiveName) + return true; // exact match + else + { + // check whether it's the first part of a nested item + effectiveName+='.'; + return (effectiveName == getNameWithPath().substr(0,effectiveName.length())); // TODO: better STL function? + } +} + +// ---------------------------------------------------------------------- + +bool DynamicVariableListNestedList::operator== (const DynamicVariableListNestedList &rhs) const +{ + return ((&m_list == &rhs.m_list) && (m_sublistName == rhs.m_sublistName)); +} + +// ---------------------------------------------------------------------- + +DynamicVariableListNestedList::const_iterator DynamicVariableListNestedList::getItemByPosition(int position) const +{ + DynamicVariableListNestedList::const_iterator i(begin()); + for (; (i!=end()) && (position>0); ++i) + --position; + return i; +} + +// ---------------------------------------------------------------------- + +DynamicVariableListNestedList::DynamicVariableListNestedList(const DynamicVariableListNestedList &parentList, int sublistIndex) : + m_list(parentList.m_list), + m_sublistName() +{ + const_iterator i(parentList.getItemByPosition(sublistIndex)); + DEBUG_FATAL(i==end(),("Programmer bug: called NestedList(NestedList&, int) with an index that was too large.\n")); + // want this to be const, but couldn't initialize it without the iterator + const_cast(&m_sublistName)->operator=(parentList.getContextName()+i.getName()+'.'); +} + +// ====================================================================== +// DynamicVariableListNestedList item getters +// VC couldn't handle this as a templated member function, so using a +// macro instead + +#define NESTED_LIST_GET_ITEM(T) \ +bool DynamicVariableListNestedList::getItem(const std::string &name, T &value) const \ +{ \ + return m_list.getItem(getContextName()+name,value); \ +} + +NESTED_LIST_GET_ITEM(int) +NESTED_LIST_GET_ITEM(stdvector::fwd) +NESTED_LIST_GET_ITEM(float) +NESTED_LIST_GET_ITEM(stdvector::fwd) +NESTED_LIST_GET_ITEM(Unicode::String) +NESTED_LIST_GET_ITEM(std::string) +NESTED_LIST_GET_ITEM(stdvector::fwd) +NESTED_LIST_GET_ITEM(NetworkId) +NESTED_LIST_GET_ITEM(stdvector::fwd) +NESTED_LIST_GET_ITEM(DynamicVariableLocationData) +NESTED_LIST_GET_ITEM(stdvector::fwd) +NESTED_LIST_GET_ITEM(StringId) +NESTED_LIST_GET_ITEM(stdvector::fwd) +NESTED_LIST_GET_ITEM(Transform) +NESTED_LIST_GET_ITEM(stdvector::fwd) +NESTED_LIST_GET_ITEM(Vector) +NESTED_LIST_GET_ITEM(stdvector::fwd) + +// ====================================================================== +// DynamicVariableListNestedList::const_iterator + +DynamicVariableListNestedList::const_iterator::const_iterator(const DynamicVariableListNestedList &context, const DynamicVariableList::MapType::const_iterator &position, bool atEnd) : + m_context(context), + m_current(position), + m_atEnd(atEnd) +{ +} + +// ---------------------------------------------------------------------- + +/** + * Get the type of the item currently pointed to, or LIST if the item is a nested list. + */ +DynamicVariable::DynamicVariableType DynamicVariableListNestedList::const_iterator::getType() const +{ + size_t start = m_context.getContextName().length(); + size_t dotpos = m_current->first.find('.',start); + + if (dotpos == std::string::npos) + // simple item -- get it's type + return m_current->second.getType(); + else + // nested item + return DynamicVariable::LIST; +} + +// ---------------------------------------------------------------------- + +const std::string DynamicVariableListNestedList::const_iterator::getNameWithPath() const +{ + return m_context.getContextName() + getName(); +} + +// ---------------------------------------------------------------------- + +DynamicVariableListNestedList::const_iterator & DynamicVariableListNestedList::const_iterator::operator++() +{ + // Advance until the name changes or we leave the nested list + std::string currentName(getName()); + for (++m_current; (m_context.isInList(m_current)) && (getName() == currentName); ++m_current) + ; + + if (!m_context.isInList(m_current)) + m_atEnd = true; + + return *this; +} + +// ---------------------------------------------------------------------- + +bool DynamicVariableListNestedList::const_iterator::operator==(const const_iterator &rhs) const +{ + return ((m_atEnd && rhs.m_atEnd) || (m_current == rhs.m_current && m_context == rhs.m_context)); +} + +// ---------------------------------------------------------------------- + +bool DynamicVariableListNestedList::const_iterator::operator!=(const const_iterator &rhs) const +{ + return !(operator==(rhs)); +} + +// ---------------------------------------------------------------------- + +DynamicVariableListNestedList DynamicVariableListNestedList::const_iterator::getNestedList() const +{ + return DynamicVariableListNestedList(m_context,getName()); +} + +// ---------------------------------------------------------------------- + +const std::string DynamicVariableListNestedList::const_iterator::getName() const +{ + if (m_atEnd) + return std::string(); + + DEBUG_FATAL(!m_context.isInList(m_current),("Programmer bug: called getName() on an iterator that was not in the NestedList.\n")); + + size_t start = m_context.getContextName().length(); + size_t dotpos = m_current->first.find('.',start); + + return m_current->first.substr(start,dotpos != std::string::npos ? dotpos-start : std::string::npos); +} + +// ---------------------------------------------------------------------- + +int DynamicVariableListNestedList::const_iterator::getPackedPosition() const +{ + if (m_atEnd) + return -1; + + DEBUG_FATAL(!m_context.isInList(m_current),("Programmer bug: called getPackedPosition() on an iterator that was not in the NestedList.\n")); + + return m_current->second.getPosition(); +} + +// ====================================================================== +// DynamicVariableListNestedList::const_iterator getters + +#define NESTED_LIST_CONST_ITERATOR_GET_VALUE(T) \ +bool DynamicVariableListNestedList::const_iterator::getValue(T &value) const \ +{ \ + return m_current->second.get(value); \ +} + +NESTED_LIST_CONST_ITERATOR_GET_VALUE(int) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(stdvector::fwd) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(float) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(stdvector::fwd) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(Unicode::String) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(std::string) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(stdvector::fwd) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(NetworkId) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(stdvector::fwd) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(DynamicVariableLocationData) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(stdvector::fwd) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(StringId) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(stdvector::fwd) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(Transform) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(stdvector::fwd) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(Vector) +NESTED_LIST_CONST_ITERATOR_GET_VALUE(stdvector::fwd) +//====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableListNestedList.h b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableListNestedList.h new file mode 100644 index 00000000..2d321764 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableListNestedList.h @@ -0,0 +1,133 @@ +//====================================================================== +// +// DynamicVariableListNestedList.h +// copyright (c) 2003 Sony Online Entertainment +// +//====================================================================== + +#ifndef INCLUDED_DynamicVariableListNestedList_H +#define INCLUDED_DynamicVariableListNestedList_H + +#include "Archive/AutoDeltaMap.h" +#include "sharedFoundation/DynamicVariable.h" +#include + +class DynamicVariableList; + +//====================================================================== +/** +* A bookmark to a nested list. +* +* DynamicVariableList is a flat map of name -> value, but it can be organized into logical nested lists. Nested lists are +* identified using ".". For example, if a variable name is "deed.build_time", it is considered to be in a logial nested +* list called "deed". +* +* The class NestedList represents a logical nested list, i.e. context in which operations can be performed on the DynamicVariableList. +*/ +class DynamicVariableListNestedList +{ +public: + + typedef Archive::AutoDeltaMap MapType; + + /** + * An iterator for a nested list. + * + * NestedList::const_iterator traverses things at the level of the NestedList. If the NestedList contains sublists, + * const_iterator will hit each sublist, but will not recurse into the items within the list. For example, suppose + * the DynamicVariableList contains this: + * deed.location.x 40 + * deed.location.y 50 + * deed.build_time 60 + * Suppose a NestedList is created referring to "deed". Calling getName() on a const_iterator on that NestedList + * as it traverses the nested list will return "location" and "build_time". + */ + + class const_iterator + { + public: + const_iterator (const DynamicVariableListNestedList &context, const MapType::const_iterator &position, bool atEnd); + + const std::string getName () const; + const std::string getNameWithPath () const; + DynamicVariableListNestedList getNestedList () const; + DynamicVariable::DynamicVariableType getType () const; + int getPackedPosition() const; + const_iterator & operator++ (); + bool operator== (const const_iterator &rhs) const; + bool operator!= (const const_iterator &rhs) const; + + bool getValue (int & value) const; + bool getValue (stdvector::fwd & value) const; + bool getValue (float & value) const; + bool getValue (stdvector::fwd & value) const; + bool getValue (Unicode::String & value) const; + bool getValue (std::string & value) const; + bool getValue (stdvector::fwd & value) const; + bool getValue (NetworkId & value) const; + bool getValue (stdvector::fwd & value) const; + bool getValue (DynamicVariableLocationData & value) const; + bool getValue (stdvector::fwd & value) const; + bool getValue (StringId &value) const; + bool getValue (stdvector::fwd &value) const; + bool getValue (Transform &value) const; + bool getValue (stdvector::fwd &value) const; + bool getValue (Vector &value) const; + bool getValue (stdvector::fwd &value) const; + + private: + const DynamicVariableListNestedList & m_context; + MapType::const_iterator m_current; + bool m_atEnd; + + private: + const_iterator &operator=(const const_iterator &rhs); //disable + }; + +public: + DynamicVariableListNestedList (const DynamicVariableList &dvList, const std::string &sublistName); + DynamicVariableListNestedList (const DynamicVariableList &dvList); + DynamicVariableListNestedList (const DynamicVariableListNestedList &parentList, const std::string &sublistName); + DynamicVariableListNestedList (const DynamicVariableListNestedList &parentList, int sublistIndex); + + const std::string getNameWithPath () const; + const std::string getName () const; + const std::string & getContextName () const; + bool isInList (const MapType::const_iterator &i) const; + int getCount () const; + bool empty () const; + bool hasItem (const std::string &name) const; + bool operator== (const DynamicVariableListNestedList &rhs) const; + const_iterator begin () const; + const_iterator end () const; + const_iterator getItemByPosition (int position) const; + + bool getItem (const std::string &name,int & value) const; + bool getItem (const std::string &name,stdvector::fwd & value) const; + bool getItem (const std::string &name,float & value) const; + bool getItem (const std::string &name,stdvector::fwd & value) const; + bool getItem (const std::string &name,Unicode::String & value) const; + bool getItem (const std::string &name,std::string & value) const; + bool getItem (const std::string &name,stdvector::fwd & value) const; + bool getItem (const std::string &name,NetworkId & value) const; + bool getItem (const std::string &name,stdvector::fwd & value) const; + bool getItem (const std::string &name,DynamicVariableLocationData & value) const; + bool getItem (const std::string &name,stdvector::fwd & value) const; + bool getItem (const std::string &name,StringId &value) const; + bool getItem (const std::string &name,stdvector::fwd &value) const; + bool getItem (const std::string &name,Transform &value) const; + bool getItem (const std::string &name,stdvector::fwd &value) const; + bool getItem (const std::string &name,Vector &value) const; + bool getItem (const std::string &name,stdvector::fwd &value) const; + +private: + const DynamicVariableList & m_list; + const std::string m_sublistName; + +private: + DynamicVariableListNestedList &operator=(const DynamicVariableListNestedList &rhs); //disable +}; + +//====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableLocationData.h b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableLocationData.h new file mode 100644 index 00000000..d3220bfe --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariableLocationData.h @@ -0,0 +1,53 @@ +//======================================================================== +// +// DynamicVariableLocationData.h +// +// copyright 2001 Sony Online Entertainment +// +//======================================================================== + +#ifndef _INCLUDED_DynamicVariableLocationData_H +#define _INCLUDED_DynamicVariableLocationData_H + +#include "sharedFoundation/NetworkId.h" +#include "sharedMath/Vector.h" + + +class DynamicVariableLocationData +{ +public: + Vector pos; + std::string scene; + NetworkId cell; + + DynamicVariableLocationData(); + DynamicVariableLocationData(const Vector & _pos, const std::string & _scene, const NetworkId & _cell); +}; + + +inline DynamicVariableLocationData::DynamicVariableLocationData() : + pos(), + scene(), + cell() +{ +} + +inline DynamicVariableLocationData::DynamicVariableLocationData(const Vector & _pos, + const std::string & _scene, const NetworkId & _cell) : + pos(_pos), + scene(_scene), + cell(_cell) +{ +} + +// ====================================================================== + +namespace Archive +{ + void get(ReadIterator & source, DynamicVariableLocationData & target); + void put(ByteStream & target, const DynamicVariableLocationData & source); +} + +//======================================================================== + +#endif // _INCLUDED_DynamicVariableLocationData_H diff --git a/engine/shared/library/sharedFoundation/src/win32/ByteOrder.cpp b/engine/shared/library/sharedFoundation/src/win32/ByteOrder.cpp new file mode 100644 index 00000000..12add8e5 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/ByteOrder.cpp @@ -0,0 +1,58 @@ +// ====================================================================== +// +// ByteOrder.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/ByteOrder.h" + +// ====================================================================== + +// I'm using the arguments, but the compiler can't tell that +#pragma warning(disable: 4100) + +__declspec(naked) ulong ntohl(ulong netLong) +{ + _asm + { + mov eax, [esp+4] + bswap eax + ret + } +} //lint !e533 !e715 // function should return a value, argument not referenced + +__declspec(naked) ulong htonl(ulong hostLong) +{ + _asm + { + mov eax, [esp+4] + bswap eax + ret + } +} //lint !e533 !e715 // function should return a value, argument not referenced + +__declspec(naked) ushort ntohs(ushort netShort) +{ + _asm + { + mov eax, [esp+4] + bswap eax + shr eax, 16 + ret + } +} //lint !e533 !e715 // function should return a value, argument not referenced + +__declspec(naked) ushort htons(ushort hostShort) +{ + _asm + { + mov eax, [esp+4] + bswap eax + shr eax, 16 + ret + } +} //lint !e533 !e715 // function should return a value, argument not referenced + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/win32/ByteOrder.h b/engine/shared/library/sharedFoundation/src/win32/ByteOrder.h new file mode 100644 index 00000000..4e478703 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/ByteOrder.h @@ -0,0 +1,22 @@ +// ====================================================================== +// +// ByteOrder.h +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef BYTE_ORDER_H +#define BYTE_ORDER_H + +// ====================================================================== + +ulong __cdecl ntohl(ulong netLong); +ushort __cdecl ntohs(ushort netShort); + +ulong __cdecl htonl(ulong hostLong); +ushort __cdecl htons(ushort hostShort); + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/win32/ConfigSharedFoundation.cpp b/engine/shared/library/sharedFoundation/src/win32/ConfigSharedFoundation.cpp new file mode 100644 index 00000000..9498c256 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/ConfigSharedFoundation.cpp @@ -0,0 +1,324 @@ +// ====================================================================== +// +// ConfigSharedFoundation.cpp +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/ConfigSharedFoundation.h" + +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/Production.h" + +// ====================================================================== + +#define KEY_INT(a,b) (ms_ ## a = ConfigFile::getKeyInt("SharedFoundation", #a, b)) +#define KEY_BOOL(a,b) (ms_ ## a = ConfigFile::getKeyBool("SharedFoundation", #a, b)) +#define KEY_FLOAT(a,b) (ms_ ## a = ConfigFile::getKeyFloat("SharedFoundation", #a, b)) +#define KEY_STRING(a,b) (ms_ ## a = ConfigFile::getKeyString("SharedFoundation", #a, b)) + +// ====================================================================== + +const int c_defaultFatalCallStackDepth = 32; +const int c_defaultWarningCallStackDepth = PRODUCTION ? -1 : 8; + +// ====================================================================== + +namespace ConfigSharedFoundationNamespace +{ + bool ms_noExceptionHandling; + + bool ms_fpuExceptionPrecision; + bool ms_fpuExceptionUnderflow; + bool ms_fpuExceptionOverflow; + bool ms_fpuExceptionZeroDivide; + bool ms_fpuExceptionDenormal; + bool ms_fpuExceptionInvalid; + + bool ms_demoMode; + + real ms_frameRateLimit; + real ms_minFrameRate; + + bool ms_useRemoteDebug; + int ms_defaultRemoteDebugPort; + + bool ms_profilerExpandAllBranches; + + bool ms_memoryManagerReportAllocations; + bool ms_memoryManagerReportOnOutOfMemory; + + bool ms_useMemoryBlockManager; + bool ms_memoryBlockManagerDebugDumpOnRemove; + + int ms_fatalCallStackDepth; + int ms_warningCallStackDepth; + bool ms_lookUpCallStackNames; + + int ms_processPriority; + + bool ms_verboseHardwareLogging; + bool ms_verboseWarnings; + + bool ms_causeAccessViolation; + + float ms_debugReportLongFrameTime; +} + +using namespace ConfigSharedFoundationNamespace; + +// ====================================================================== +// Determine the Platform-specific configuration information +// +// Remarks: +// +// This routine inspects the ConfigFile class to set some variables for rapid access +// by the rest of the engine. + +void ConfigSharedFoundation::install (const Defaults &defaults) +{ + KEY_BOOL(noExceptionHandling, false); + + KEY_BOOL(fpuExceptionPrecision, false); + KEY_BOOL(fpuExceptionUnderflow, false); + KEY_BOOL(fpuExceptionOverflow, false); + KEY_BOOL(fpuExceptionZeroDivide, false); + KEY_BOOL(fpuExceptionDenormal, false); + KEY_BOOL(fpuExceptionInvalid, false); + + KEY_BOOL(demoMode, defaults.demoMode); + +#if defined (WIN32) && PRODUCTION == 1 + // In production builds, force our frame rate limit to be the application defined limit + ms_frameRateLimit = defaults.frameRateLimit; +#else + KEY_FLOAT(frameRateLimit, defaults.frameRateLimit); +#endif + + KEY_FLOAT(minFrameRate, 1.0f); + + KEY_BOOL(useRemoteDebug, false); + KEY_INT(defaultRemoteDebugPort, 4445); + + KEY_BOOL(profilerExpandAllBranches, false); + KEY_BOOL(memoryManagerReportAllocations, true); + KEY_BOOL(memoryManagerReportOnOutOfMemory, true); + KEY_BOOL(useMemoryBlockManager, true); + KEY_BOOL(memoryBlockManagerDebugDumpOnRemove, false); + + KEY_INT(fatalCallStackDepth, c_defaultFatalCallStackDepth); + KEY_INT(warningCallStackDepth, PRODUCTION ? -1 : c_defaultWarningCallStackDepth); + KEY_BOOL(lookUpCallStackNames, true); + + KEY_INT(processPriority, 0); + + KEY_BOOL(verboseHardwareLogging, false); + KEY_BOOL(verboseWarnings, defaults.verboseWarnings); + + KEY_BOOL(causeAccessViolation, false); + + KEY_FLOAT(debugReportLongFrameTime, 0.25f); +} + +// ---------------------------------------------------------------------- +/** + * Return whether to run with exception handling enabled. + * + * @return True to run without exception handling + */ + +bool ConfigSharedFoundation::getNoExceptionHandling() +{ + return ms_noExceptionHandling; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getFpuExceptionPrecision() +{ + return ms_fpuExceptionPrecision; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getFpuExceptionUnderflow() +{ + return ms_fpuExceptionUnderflow; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getFpuExceptionOverflow() +{ + return ms_fpuExceptionOverflow; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getFpuExceptionZeroDivide() +{ + return ms_fpuExceptionZeroDivide; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getFpuExceptionDenormal() +{ + return ms_fpuExceptionDenormal; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getFpuExceptionInvalid() +{ + return ms_fpuExceptionInvalid; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getDemoMode() +{ + return ms_demoMode; +} + +// ---------------------------------------------------------------------- +/** + * Return the frame rate limit value for the game. + * + * @return The initial frame rate limiter value + */ + +real ConfigSharedFoundation::getFrameRateLimit() +{ + return ms_frameRateLimit; +} + +// ---------------------------------------------------------------------- +/** + * Return the minimum frame rate value for the game. Frames that take longer + * will log a warning and be hard set to the given value. + * + * @return The initial min frame rate value + */ + +real ConfigSharedFoundation::getMinFrameRate() +{ + return ms_minFrameRate; +} + +// ---------------------------------------------------------------------- + +int ConfigSharedFoundation::getDefaultRemoteDebugPort() +{ + return ms_defaultRemoteDebugPort; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getUseRemoteDebug() +{ + return ms_useRemoteDebug; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getProfilerExpandAllBranches() +{ + return ms_profilerExpandAllBranches; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getMemoryManagerReportAllocations() +{ + return ms_memoryManagerReportAllocations; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getMemoryManagerReportOnOutOfMemory() +{ + return ms_memoryManagerReportOnOutOfMemory; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getUseMemoryBlockManager() +{ + return ms_useMemoryBlockManager; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getMemoryBlockManagerDebugDumpOnRemove () +{ + return ms_memoryBlockManagerDebugDumpOnRemove; +} + +// ---------------------------------------------------------------------- + +int ConfigSharedFoundation::getFatalCallStackDepth() +{ + return ms_fatalCallStackDepth; +} + +// ---------------------------------------------------------------------- + +int ConfigSharedFoundation::getWarningCallStackDepth() +{ + return ms_warningCallStackDepth; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getLookUpCallStackNames() +{ + return ms_lookUpCallStackNames; +} + +// ---------------------------------------------------------------------- + +int ConfigSharedFoundation::getProcessPriority() +{ + return ms_processPriority; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getVerboseHardwareLogging() +{ + return ms_verboseHardwareLogging; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getVerboseWarnings() +{ + return ms_verboseWarnings; +} + +// ---------------------------------------------------------------------- + +void ConfigSharedFoundation::setVerboseWarnings(bool const verboseWarnings) +{ + ms_verboseWarnings = verboseWarnings; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedFoundation::getCauseAccessViolation() +{ + return ms_causeAccessViolation; +} + + +// ---------------------------------------------------------------------- + +float ConfigSharedFoundation::getDebugReportLongFrameTime() +{ + return ms_debugReportLongFrameTime; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/win32/ConfigSharedFoundation.h b/engine/shared/library/sharedFoundation/src/win32/ConfigSharedFoundation.h new file mode 100644 index 00000000..6efa3840 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/ConfigSharedFoundation.h @@ -0,0 +1,74 @@ +// ====================================================================== +// +// ConfigSharedFoundation.h +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_ConfigSharedFoundation_H +#define INCLUDED_ConfigSharedFoundation_H + +// ====================================================================== + +class ConfigSharedFoundation +{ +public: + + struct Defaults + { + int screenHeight; + int screenWidth; + bool windowed; + real frameRateLimit; + bool demoMode; + bool verboseWarnings; + }; + +public: + + static void install(const Defaults &defaults); + + static bool getNoExceptionHandling(); + + static bool getFpuExceptionPrecision(); + static bool getFpuExceptionUnderflow(); + static bool getFpuExceptionOverflow(); + static bool getFpuExceptionZeroDivide(); + static bool getFpuExceptionDenormal(); + static bool getFpuExceptionInvalid(); + + static bool getDemoMode(); + + static real getFrameRateLimit(); + static real getMinFrameRate(); + + static bool getUseRemoteDebug(); + static int getDefaultRemoteDebugPort(); + + static bool getProfilerExpandAllBranches(); + + static bool getMemoryManagerReportAllocations(); + static bool getMemoryManagerReportOnOutOfMemory(); + + static bool getUseMemoryBlockManager(); + static bool getMemoryBlockManagerDebugDumpOnRemove(); + + static int getFatalCallStackDepth(); + static int getWarningCallStackDepth(); + static bool getLookUpCallStackNames(); + + static int getProcessPriority(); + + static DLLEXPORT bool getVerboseHardwareLogging(); + static bool getVerboseWarnings(); + static void setVerboseWarnings(bool verboseWarnings); + + static bool getCauseAccessViolation(); + + static float getDebugReportLongFrameTime(); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/win32/FirstPlatform.h b/engine/shared/library/sharedFoundation/src/win32/FirstPlatform.h new file mode 100644 index 00000000..f743afac --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/FirstPlatform.h @@ -0,0 +1,76 @@ +// ====================================================================== +// +// FirstPlatform.h +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_FirstPlatform_H +#define INCLUDED_FirstPlatform_H + +// ====================================================================== + +// C4127 conditional expression is constant +// C4291 no matching operator delete found; memory will not be freed if initialization throws an exception +// C4503 decorated name length exceeded, name was truncated +// C4514 unreferenced inline function has been removed +// C4702 unreachable code +// C4710 inline function not expanded +// C4786 identifier was truncated to 'number' characters in the debug + +#pragma warning(disable: 4127 4291 4503 4514 4702 4710 4786) + +// ====================================================================== +// If we haven't defined this yet, then we're not compiling a DLL + +#ifndef COMPILE_DLL +#define COMPILE_DLL 0 +#endif + +#if COMPILE_DLL +#define DLLEXPORT __declspec(dllimport) +#else +#define DLLEXPORT __declspec(dllexport) +#endif + +// ====================================================================== + +template +inline int ComGetReferenceCount(T *t) +{ + t->AddRef(); + return t->Release(); +} + +// ====================================================================== +// forward declare some windows stuff to avoid having to include here + +struct HCURSOR__; +struct HICON__; +struct HINSTANCE__; +struct HWND__; + +typedef void *HANDLE; +typedef HICON__ *HCURSOR; +typedef HICON__ *HICON; +typedef HINSTANCE__ *HINSTANCE; +typedef HWND__ *HWND; + +// @todo codereorg still working on this +#include "sharedFoundation/WindowsWrapper.h" + +// ====================================================================== +// convienent fatal macros that check windows HRESULT codes + +#define FATAL_HR(a,b) FATAL(FAILED(b), (a, HRESULT_CODE(b))) +#define DEBUG_FATAL_HR(a,b) DEBUG_FATAL(FAILED(b), (a, HRESULT_CODE(b))) + +// ====================================================================== +// include anything we need to replace missing functionality that other platforms provide + +#include "sharedFoundation/PlatformGlue.h" + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/win32/FirstSharedFoundation.cpp b/engine/shared/library/sharedFoundation/src/win32/FirstSharedFoundation.cpp new file mode 100644 index 00000000..1cfb9020 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/FirstSharedFoundation.cpp @@ -0,0 +1,8 @@ +// ====================================================================== +// +// FirstFoundation.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" diff --git a/engine/shared/library/sharedFoundation/src/win32/FloatingPointUnit.cpp b/engine/shared/library/sharedFoundation/src/win32/FloatingPointUnit.cpp new file mode 100644 index 00000000..f303e0eb --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/FloatingPointUnit.cpp @@ -0,0 +1,257 @@ +// ====================================================================== +// +// FloatingPointUnit.cpp +// copyright 1999 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/FloatingPointUnit.h" + +#include "sharedFoundation/ConfigSharedFoundation.h" + +// ====================================================================== + +int FloatingPointUnit::updateNumber; +ushort FloatingPointUnit::status; +FloatingPointUnit::Precision FloatingPointUnit::precision; +FloatingPointUnit::Rounding FloatingPointUnit::rounding; +bool FloatingPointUnit::exceptionEnabled[E_max]; + +// ====================================================================== + +const WORD PRECISION_MASK = BINARY4(0000,0011,0000,0000); +const WORD PRECISION_24 = BINARY4(0000,0000,0000,0000); +const WORD PRECISION_53 = BINARY4(0000,0010,0000,0000); +const WORD PRECISION_64 = BINARY4(0000,0011,0000,0000); + +const WORD ROUND_MASK = BINARY4(0000,1100,0000,0000); +const WORD ROUND_NEAREST = BINARY4(0000,0000,0000,0000); +const WORD ROUND_CHOP = BINARY4(0000,1100,0000,0000); +const WORD ROUND_DOWN = BINARY4(0000,0100,0000,0000); +const WORD ROUND_UP = BINARY4(0000,1000,0000,0000); + +const WORD EXCEPTION_PRECISION = BINARY4(0000,0000,0010,0000); +const WORD EXCEPTION_UNDERFLOW = BINARY4(0000,0000,0001,0000); +const WORD EXCEPTION_OVERFLOW = BINARY4(0000,0000,0000,1000); +const WORD EXCEPTION_ZERO_DIVIDE = BINARY4(0000,0000,0000,0100); +const WORD EXCEPTION_DENORMAL = BINARY4(0000,0000,0000,0010); +const WORD EXCEPTION_INVALID = BINARY4(0000,0000,0000,0001); +const WORD EXCEPTION_ALL = BINARY4(0000,0000,0011,1111); + +// ====================================================================== + +void FloatingPointUnit::install(void) +{ + precision = P_24; + rounding = R_roundToNearestOrEven; + memset(exceptionEnabled, 0, sizeof(exceptionEnabled)); + + // preserve all other bits + status = getControlWord(); + status &= ~(PRECISION_MASK | ROUND_MASK | EXCEPTION_ALL); + + // set to single precision, rounding, and all exceptions masked + status |= PRECISION_24 | ROUND_NEAREST | EXCEPTION_ALL; + + // check the config platform flags to see if we should enable some exceptions + if (ConfigSharedFoundation::getFpuExceptionPrecision()) + { + exceptionEnabled[E_precision] = true; + status &= ~EXCEPTION_PRECISION; + } + + if (ConfigSharedFoundation::getFpuExceptionUnderflow()) + { + exceptionEnabled[E_underflow] = true; + status &= ~EXCEPTION_UNDERFLOW; + } + + if (ConfigSharedFoundation::getFpuExceptionOverflow()) + { + exceptionEnabled[E_overflow] = true; + status &= ~EXCEPTION_OVERFLOW; + } + + if (ConfigSharedFoundation::getFpuExceptionZeroDivide()) + { + exceptionEnabled[E_zeroDivide] = true; + status &= ~EXCEPTION_ZERO_DIVIDE; + } + + if (ConfigSharedFoundation::getFpuExceptionDenormal()) + { + exceptionEnabled[E_denormal] = true; + status &= ~EXCEPTION_DENORMAL; + } + + if (ConfigSharedFoundation::getFpuExceptionInvalid()) + { + exceptionEnabled[E_invalid] = true; + status &= ~EXCEPTION_INVALID; + } + + setControlWord(status); +} + +// ---------------------------------------------------------------------- + +void FloatingPointUnit::update(void) +{ + WORD currentStatus = getControlWord(); + + if (currentStatus != status) + { +// DEBUG_REPORT_LOG_PRINT(true, ("FPU: update=%d, in mode=%04x, should be in mode=%04x\n", updateNumber, static_cast(currentStatus), static_cast(status))); + setControlWord(status); + } + + ++updateNumber; +} + +// ---------------------------------------------------------------------- + +WORD FloatingPointUnit::getControlWord(void) +{ + WORD controlWord = 0; + + __asm fnstcw controlWord; + return controlWord; +} + +// ---------------------------------------------------------------------- + +void FloatingPointUnit::setControlWord(WORD controlWord) +{ + UNREF(controlWord); + __asm fldcw controlWord; +} + +// ---------------------------------------------------------------------- + +void FloatingPointUnit::setPrecision(Precision newPrecision) +{ + WORD bits = 0; + + switch (precision) + { + case P_24: + bits = PRECISION_24; + break; + + case P_53: + bits = PRECISION_53; + break; + + case P_64: + bits = PRECISION_64; + break; + + case P_max: + default: + DEBUG_FATAL(true, ("bad case")); + } + + // record the current state + precision = newPrecision; + + // set the proper bit pattern + status &= ~PRECISION_MASK; + status |= bits; + + // slam it into the FPU + setControlWord(status); +} + +// ---------------------------------------------------------------------- + +void FloatingPointUnit::setRounding(Rounding newRounding) +{ + WORD bits = 0; + + switch (newRounding) + { + case R_roundToNearestOrEven: + bits = ROUND_NEAREST; + break; + + case R_chop: + bits = ROUND_CHOP; + break; + + case R_roundDown: + bits = ROUND_DOWN; + break; + + case R_roundUp: + bits = ROUND_UP; + break; + + case R_max: + default: + DEBUG_FATAL(true, ("bad case")); + } + + // record the current state + rounding = newRounding; + + // set the proper bit pattern + status &= ~ROUND_MASK; + status |= bits; + + // slam it into the FPU + setControlWord(status); +} + +// ---------------------------------------------------------------------- + +void FloatingPointUnit::setExceptionEnabled(Exception exception, bool enabled) +{ + WORD bits = 0; + + switch (exception) + { + case E_precision: + bits = EXCEPTION_PRECISION; + break; + + case E_underflow: + bits = EXCEPTION_UNDERFLOW; + break; + + case E_overflow: + bits = EXCEPTION_OVERFLOW; + break; + + case E_zeroDivide: + bits = EXCEPTION_ZERO_DIVIDE; + break; + + case E_denormal: + bits = EXCEPTION_DENORMAL; + break; + + case E_invalid: + bits = EXCEPTION_INVALID; + break; + + case E_max: + default: + DEBUG_FATAL(true, ("bad case")); + } + + // record the current state + exceptionEnabled[exception] = enabled; + + // twiddle the bit appropriately. these bits masks, so set the bit to disable the exception, clear the bit to enable it. + if (enabled) + status &= ~bits; + else + status |= bits; + + // slam it into the FPU + setControlWord(status); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/win32/FloatingPointUnit.h b/engine/shared/library/sharedFoundation/src/win32/FloatingPointUnit.h new file mode 100644 index 00000000..9cda070d --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/FloatingPointUnit.h @@ -0,0 +1,104 @@ +// ====================================================================== +// +// FloatingPointUnit.h +// jeff grills +// +// copyright 1999 Bootprint Entertainment +// +// ====================================================================== + +#ifndef FLOATING_POINT_UNIT_H +#define FLOATING_POINT_UNIT_H + +// ====================================================================== + +class FloatingPointUnit +{ +public: + + typedef unsigned short WORD; + + enum Precision + { + P_24, + P_53, + P_64, + + P_max + }; + + enum Rounding + { + R_roundToNearestOrEven, + R_chop, + R_roundDown, + R_roundUp, + + R_max + }; + + enum Exception + { + E_precision, + E_underflow, + E_overflow, + E_zeroDivide, + E_denormal, + E_invalid, + + E_max + }; + +private: + + static int updateNumber; + static WORD status; + static Precision precision; + static Rounding rounding; + static bool exceptionEnabled[E_max]; + +public: + + static WORD getControlWord(void); + static void setControlWord(WORD controlWord); + +public: + + static void install(void); + + static void update(void); + + static void setPrecision(Precision newPrecision); + static void setRounding(Rounding newRounding); + static void setExceptionEnabled(Exception exception, bool enabled); + + static Precision getPrecision(void); + static Rounding getRounding(void); + static bool getExceptionEnabled(Exception exception); +}; + +// ====================================================================== + +inline FloatingPointUnit::Precision FloatingPointUnit::getPrecision(void) +{ + return precision; +} + +// ---------------------------------------------------------------------- + +inline FloatingPointUnit::Rounding FloatingPointUnit::getRounding(void) +{ + return rounding; +} + +// ---------------------------------------------------------------------- + +inline bool FloatingPointUnit::getExceptionEnabled(Exception theException) +{ + DEBUG_FATAL(static_cast(theException) < 0 || static_cast(theException) >= static_cast(E_max), ("exception out of range")); //lint !e568 // non-negative quantity is never less than 0 + return exceptionEnabled[theException]; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/win32/Os.cpp b/engine/shared/library/sharedFoundation/src/win32/Os.cpp new file mode 100644 index 00000000..ec7e370e --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/Os.cpp @@ -0,0 +1,1634 @@ +// ====================================================================== +// +// Os.cpp +// +// Portions copyright 1998 Bootprint Entertainment +// Portions copyright 2000-2002 Sony Online Entertainment +// All Rights Reserved +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/Os.h" + +#include "sharedDebug/DebugFlags.h" +#include "sharedDebug/DebugKey.h" +#include "sharedDebug/DebugMonitor.h" +#include "sharedDebug/Profiler.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedFoundation/CrashReportInformation.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/FloatingPointUnit.h" +#include "sharedFoundation/Production.h" +#include "sharedFoundation/StringCompare.h" +#include "sharedFoundation/WindowsWrapper.h" +#include "shellapi.h" + +#include +#include +#include +#include + +// ====================================================================== + +namespace OsNamespace +{ + void applyWindowChanges(); + void updateMousePosition(int x, int y); + + const int PROGRAM_NAME_SIZE = 512; + + bool ms_installed; + bool ms_processMessagePump = true; + +#if PRODUCTION == 0 + bool ms_validateGuardPatterns; + bool ms_validateFreePatterns; + bool ms_allowPopupDebugMenu; +#endif + + int ms_numberOfUpdates; + HWND ms_window; + HCURSOR ms_cursorArrow; + bool ms_engineOwnsWindow; + bool ms_wasFocusLost; + bool ms_gameOver; + bool ms_shouldReturnFromAbort; + bool ms_wantPopupDebugMenu; + bool ms_threadDied; + bool ms_mouseMoveInClient; + bool ms_clickToMove; + char ms_programName[PROGRAM_NAME_SIZE]; + char *ms_shortProgramName; + char ms_programStartupDirectory[MAX_PATH]; + Os::ThreadId ms_mainThreadId; + Os::IsGdiVisibleHookFunction ms_isGdiVisibleHookFunction; + Os::LostFocusHookFunction ms_lostFocusHookFunction; + Os::AcquiredFocusHookFunction ms_acquiredFocusHookFunction; + Os::AcquiredFocusHookFunction ms_acquiredFocusHookFunction2; + Os::QueueCharacterHookFunction ms_queueCharacterHookFunction; + Os::SetSystemMouseCursorPositionHookFunction ms_setSystemMouseCursorPositionHookFunction; + Os::SetSystemMouseCursorPositionHookFunction ms_setSystemMouseCursorPositionHookFunction2; + Os::GetHardwareMouseCursorEnabled ms_getHardwareMouseCursorEnabled; + Os::GetOtherAdapterRectsHookFunction ms_getOtherAdapterRectsHookFunction; + Os::WindowPositionChangedHookFunction ms_windowPositionChangedHookFunction; + Os::DisplayModeChangedHookFunction ms_displayModeChangedHookFunction; + Os::InputLanguageChangedHookFunction ms_inputLanguageChangedHookFunction; + Os::IMEHookFunction ms_IMEHookFunction; + Os::QueueKeyDownHookFunction ms_queueKeyDownHookFunction; + + int ms_processorCount; + int ms_debugKeyIndex; + int ms_SystemMouseCursorPositionX; + int ms_SystemMouseCursorPositionY; + + std::vector ms_otherAdapterRects; + + char ms_keyboardLayout[KL_NAMELENGTH]; + + bool ms_focused; + + int const ms_hotKeyId = 0xBEEF; + + extern "C" WINBASEAPI BOOL WINAPI IsDebuggerPresent(VOID); +}; + +using namespace OsNamespace; + + +static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +// ====================================================================== +/** + * Install the Os subsystem for games + * + * This routine is supported for all platforms, although different platforms may + * require different arguments to this routine. + * + * This routine registers the window class and creates the window for the application. + * + * This routine will add Os::remove to the ExitChain. + * + * @param instance Handle to the instance for this application + * @param windowName Name for the window title bar + * @paran normalIcon Normal icon for the game + * @param smallIcon Small icon for the task bar + * @see Os::remove() + */ + +void Os::install(HINSTANCE instance, const char *windowName, HICON normalIcon, HICON smallIcon) +{ + installCommon(); + + // setup the window class + WNDCLASSEX wclass; + Zero(wclass); + wclass.cbSize = sizeof(wclass); + wclass.style = CS_BYTEALIGNCLIENT; + wclass.lpfnWndProc = WindowProc; + wclass.hInstance = instance; + wclass.hIcon = normalIcon; + wclass.hCursor = NULL; + wclass.hbrBackground = reinterpret_cast(GetStockObject(BLACK_BRUSH)); + wclass.lpszClassName = windowName; + wclass.hIconSm = smallIcon; + + // register the window class + ATOM atom = RegisterClassEx(&wclass); + FATAL(atom == 0, ("RegisterClassEx failed")); + + // create the window + ms_window = CreateWindow( + windowName, // pointer to registered class name + windowName, // pointer to window name + WS_POPUP, // window style + 0, // horizontal position of window + 0, // vertical position of window + 640, // window width + 480, // window height + NULL, // handle to parent or owner window + NULL, // handle to menu or child-window identifier + instance, // handle to application instance + NULL); // pointer to window-creation data + FATAL(!ms_window, ("CreateWindow failed")); + ms_engineOwnsWindow = true; + + // load the arrow cursor + ms_cursorArrow = LoadCursor(NULL, IDC_ARROW); + FATAL(ms_cursorArrow == NULL, ("LoadCursor failed")); +} + +// ---------------------------------------------------------------------- +/** + * Install the Os subsystem for non-games. + * + * This routine is supported for all platforms, although different platforms may + * require different arguments to this routine.F + * + * This routine will add Os::remove to the ExitChain. + * + * @see Os::remove() + */ + +void Os::install(HWND newWindow, bool newProcessMessagePump) +{ + installCommon(); + ms_window = newWindow; + ms_processMessagePump = newProcessMessagePump; +} + +// ---------------------------------------------------------------------- +/** + * Install the Os subsystem for non-games. + * + * This routine is supported for all platforms, although different platforms may + * require different arguments to this routine. + * + * This routine will add Os::remove to the ExitChain. + * + * @see Os::remove() + */ + +void Os::install() +{ + installCommon(); +} + +// ---------------------------------------------------------------------- +/** + * This routine will remove the Os subsystem. + * + * This routine should not be called directly. It will be called from the ExitChain. + * + * @see Os::install() + */ + +void Os::remove() +{ + DEBUG_FATAL(!ms_installed, ("not installed")); + ms_installed = false; +} + +// ---------------------------------------------------------------------- + +void Os::installCommon() +{ + DEBUG_FATAL(ms_installed, ("already installed")); + + ExitChain::add(Os::remove, "Os::remove", 0, true); + + // get startup folder. + GetCurrentDirectory(sizeof(ms_programStartupDirectory), ms_programStartupDirectory); + + ms_numberOfUpdates = 0; + ms_mainThreadId = GetCurrentThreadId(); + setThreadName(ms_mainThreadId, "Main"); + +#if PRODUCTION == 0 + ms_allowPopupDebugMenu = ConfigFile::getKeyBool("SharedFoundation", "allowPopupDebugMenu", false); +#endif + + // get the name of the executable + DWORD result = GetModuleFileName(NULL, ms_programName, sizeof(ms_programName)); + FATAL(result == 0, ("GetModuleFileName failed")); + + // get the file name without the path + ms_shortProgramName = strrchr(ms_programName, '\\'); + if (ms_shortProgramName) + ++ms_shortProgramName; + else + ms_shortProgramName = ms_programName; + + // switch into single-precision floating point mode + FloatingPointUnit::install(); + + // get the amount of memory + MEMORYSTATUS memoryStatus; + GlobalMemoryStatus(&memoryStatus); + CrashReportInformation::addStaticText("Ram: %dmb\n", memoryStatus.dwTotalPhys / (1024 * 1024)); + + // log the os information + { + OSVERSIONINFO versionInfo; + Zero(versionInfo); + versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&versionInfo); + CrashReportInformation::addStaticText("Os1: %d.%d.%d\n", versionInfo.dwMajorVersion, versionInfo.dwMinorVersion, versionInfo.dwBuildNumber); + + char const * os = "Unknown"; + if (versionInfo.dwMajorVersion == 4 && versionInfo.dwMinorVersion == 10) + os = "Windows 98"; + else + if (versionInfo.dwMajorVersion == 4 && versionInfo.dwMinorVersion == 90) + os = "Windows Me"; + else + if (versionInfo.dwMajorVersion == 5 && versionInfo.dwMinorVersion == 0) + os = "Windows 2000"; + else + if (versionInfo.dwMajorVersion == 5 && versionInfo.dwMinorVersion == 1) + os = "Windows XP"; + else + if (versionInfo.dwMajorVersion == 5 && versionInfo.dwMinorVersion == 2) + os = "Windows Server 2003"; + else + if (versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion == 0) + os = "Windows Vista"; + + + + CrashReportInformation::addStaticText("Os2: %s %s\n", os, versionInfo.szCSDVersion); + } + + // get the number of processors + SYSTEM_INFO si; + GetSystemInfo(&si); + ms_processorCount = static_cast(si.dwNumberOfProcessors); + REPORT_LOG (ConfigSharedFoundation::getVerboseHardwareLogging(), ("Processor Count: %i\n", ms_processorCount)); + CrashReportInformation::addStaticText("NumProc: %d\n", ms_processorCount); + + { + HKEY key; + LONG result = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_EXECUTE, &key); + + if (result == ERROR_SUCCESS) + { + DWORD data; + DWORD type = REG_DWORD; + DWORD size = sizeof (data); + result = RegQueryValueEx (key, "~MHz", NULL, &type, reinterpret_cast (&data), &size); + if ((result == ERROR_SUCCESS) && (size > 0)) + REPORT_LOG (ConfigSharedFoundation::getVerboseHardwareLogging(), ("Processor Speed: %i MHz\n", data)); + + RegCloseKey (key); + } + } + + if (!GetKeyboardLayoutName(ms_keyboardLayout)) + ms_keyboardLayout[0] = '\0'; + + ms_installed = true; + +#if PRODUCTION == 0 + DebugFlags::registerFlag(ms_validateGuardPatterns, "SharedFoundation", "validateGuardPatterns"); + DebugFlags::registerFlag(ms_validateFreePatterns, "SharedFoundation", "validateFreePatterns"); +#endif + + switch (ConfigSharedFoundation::getProcessPriority()) + { + case -1: + setProcessPriority(P_low); + break; + + case 0: + setProcessPriority(P_normal); + break; + + case 1: + setProcessPriority(P_high); + break; + + default: + DEBUG_WARNING(true, ("invalid process priority, %d should be betweein [-1..1]", ConfigSharedFoundation::getProcessPriority())); + break; + } +} + +// ====================================================================== +// Return the window handle +// +// Return value: +// +// Handle to the window for this application +// +// Remarks: +// +// This routine is only supported on the Win* platforms, and should not be used by the +// game or the engine if portability is required. + +HWND Os::getWindow() +{ + return ms_window; +} + +// ---------------------------------------------------------------------- + +bool Os::engineOwnsWindow() +{ + return ms_engineOwnsWindow; +} + +// ---------------------------------------------------------------------- +/** + * Return the full name of the running executable. + * + * The program name will include the path as well. + * + * @return The full name of the running executable + * @see Os::getShortProgramName() + */ + +const char *Os::getProgramName() +{ + return ms_programName; +} + +// ---------------------------------------------------------------------- +/** + * Return the short name of the running executable. + * + * The program name will not include the path, but will just be the file name. + * + * @return The short name of the running executable + * @see Os::getProgramName() + */ + +const char *Os::getShortProgramName() +{ + return ms_shortProgramName; +} + +// ---------------------------------------------------------------------- +/** + * Return the current working directory when the program was started. + * + */ + +const char *Os::getProgramStartupDirectory() +{ + return ms_programStartupDirectory; +} + +// ---------------------------------------------------------------------- +/** + * Cause Os::abort() to return instead of abort the process. + * + * This routine should not be called directly by users. + * + * This routine is provided so that structured exception handling can catch + * an exception, call Fatal to run the ExitChain, and rethrow the exception + * so that the debugger will catch it. + */ + +void Os::returnFromAbort() +{ + ms_shouldReturnFromAbort = true; +} + +// ---------------------------------------------------------------------- +/** + * Check if the Os knows the game needs to shut down. + * + * The Os can decide that the game need to end for a number of reasons, + * including closing the application or shutting the machine down. + * + * @return True if the game should quit, otherwise false + */ + +bool Os::isGameOver() +{ + return ms_gameOver; +} + +// ---------------------------------------------------------------------- +/** + * Return the number of updates that the have occurred. + * + * @return This value is updated during the Os::update() routine. + */ + +int Os::getNumberOfUpdates() +{ + return ms_numberOfUpdates; +} + +// ---------------------------------------------------------------------- +/** + * Indicate whether or not the application was paused. + * + * @return True if the application was in the background (paused), otherwise false + */ + +bool Os::wasFocusLost() +{ + return ms_wasFocusLost; +} + +// ---------------------------------------------------------------------- +/** + * Return a flag indicating whether we are running a multiprocessor machine or not. + * + * @return True if the machine has more than one processor, false if not. + */ + +bool Os::isMultiprocessor() +{ + return ms_processorCount > 1; +} + +// ---------------------------------------------------------------------- +/** + * Return the number of processors. + * + * @return The number of processors in the machine. + */ + +int Os::getProcessorCount() +{ + return ms_processorCount; +} + +// ---------------------------------------------------------------------- + +bool Os::isMainThread() +{ + // if the Os class hasn't been installed, then assume we are the main thread. + // otherwise, check to see if our thread id is the main thread id + return !ms_installed || (GetCurrentThreadId() == ms_mainThreadId); +} + +// ---------------------------------------------------------------------- +/** + * Terminate the application because of an error condition. + * + * This routine is supported for all platforms. + * + * This routine should not be called directly. The engine and game should use the + * FATAL macro to terminate the application because of an error. + * + * Calling Os::returnFromAbort() will cause the routine to do nothing but return + * immediately. + * + * @see Os::returnFromAbort(), FATAL() + */ + +void Os::abort() +{ + if (!isMainThread()) + { + ms_threadDied = true; + ExitThread(1); + } + + if (!ms_shouldReturnFromAbort) + { + // let the C runtime deal with the abnormal termination + ::abort(); + } +} + +// ---------------------------------------------------------------------- + +void Os::setLostFocusHookFunction(LostFocusHookFunction lostFocusHookFunction) +{ + ms_lostFocusHookFunction = lostFocusHookFunction; +} + +// ---------------------------------------------------------------------- + +void Os::setIsGdiVisibleHookFunction(IsGdiVisibleHookFunction isGdiVisibleHookFunction) +{ + ms_isGdiVisibleHookFunction = isGdiVisibleHookFunction; +} + +// ---------------------------------------------------------------------- + +void Os::setQueueCharacterHookFunction(QueueCharacterHookFunction queueCharacterHookFunction) +{ + ms_queueCharacterHookFunction = queueCharacterHookFunction; +} + +// ---------------------------------------------------------------------- + +void Os::setSetSystemMouseCursorPositionHookFunction(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction) +{ + ms_setSystemMouseCursorPositionHookFunction = setSystemMouseCursorPositionHookFunction; +} + +// ---------------------------------------------------------------------- + +void Os::setSetSystemMouseCursorPositionHookFunction2(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction) +{ + ms_setSystemMouseCursorPositionHookFunction2 = setSystemMouseCursorPositionHookFunction; +} + +// ---------------------------------------------------------------------- + +void Os::setAcquiredFocusHookFunction(AcquiredFocusHookFunction acquiredFocusHookFunction) +{ + ms_acquiredFocusHookFunction = acquiredFocusHookFunction; +} + +// ---------------------------------------------------------------------- + +void Os::setAcquiredFocusHookFunction2(AcquiredFocusHookFunction acquiredFocusHookFunction) +{ + ms_acquiredFocusHookFunction2 = acquiredFocusHookFunction; +} + +// ---------------------------------------------------------------------- + +void Os::setGetHardwareMouseCursorEnabled(GetHardwareMouseCursorEnabled getHardwareMouseCursorEnabled) +{ + ms_getHardwareMouseCursorEnabled = getHardwareMouseCursorEnabled; +} + +// ---------------------------------------------------------------------- + +void Os::setGetOtherAdapterRectsHookFunction(GetOtherAdapterRectsHookFunction getOtherAdapterRectsHookFunction) +{ + ms_getOtherAdapterRectsHookFunction = getOtherAdapterRectsHookFunction; +} + +// ---------------------------------------------------------------------- + +void Os::setWindowPositionChangedHookFunction(WindowPositionChangedHookFunction windowPositionChangedHookFunction) +{ + ms_windowPositionChangedHookFunction = windowPositionChangedHookFunction; +} + +//----------------------------------------------------------------- + +void Os::setDisplayModeChangedHookFunction(DisplayModeChangedHookFunction displayModeChangedHookFunction) +{ + ms_displayModeChangedHookFunction = displayModeChangedHookFunction; +} + +//----------------------------------------------------------------- + +void Os::setInputLanguageChangedHookFunction(InputLanguageChangedHookFunction inputLanguageChangedHookFunction) +{ + ms_inputLanguageChangedHookFunction = inputLanguageChangedHookFunction; +} + +//----------------------------------------------------------------- +// rls - In IME mode, the F5 key can cause the IME pad window to open up. +// This causes the Japanese player to essentially lock-up because of +// context issues. There is probably a better way to handle this, but be +// warned: the SWG input system may not work properly. +void Os::setIMEHookFunction(IMEHookFunction imeHookFunction) +{ + if (ms_IMEHookFunction) + { + UnregisterHotKey(ms_window, ms_hotKeyId); + } + + ms_IMEHookFunction = imeHookFunction; + + // do not install the hotkey fix if the debugger is present. + if (ms_IMEHookFunction && !IsDebuggerPresent()) + { + RegisterHotKey(ms_window, ms_hotKeyId, 0, VK_F5); + } +} + +//----------------------------------------------------------------- + +void Os::setQueueKeyDownHookFunction(QueueKeyDownHookFunction queueKeyDownHookFunction) +{ + ms_queueKeyDownHookFunction = queueKeyDownHookFunction; +} + +//----------------------------------------------------------------- +/** +* Create the specified directory and all of it's parents. +* @param directory the path to a directory +* @return always true currently +*/ + +bool Os::createDirectories (const char *directory) +{ + //-- construct list of subdirectories all the way down to root + std::stack directoryStack; + + std::string currentDirectory = directory; + + static const char path_seps [] = { '\\', '/', 0 }; + + // build the stack + while (!currentDirectory.empty()) + { + // remove trailing backslash + if (currentDirectory[currentDirectory.size()-1] == '\\' || currentDirectory[currentDirectory.size()-1] == '/') + IGNORE_RETURN(currentDirectory.erase(currentDirectory.size()-1)); + + if (currentDirectory[currentDirectory.size()-1] == ':') + { + // we've hit something like c: + break; + } + + if (!currentDirectory.empty()) + directoryStack.push(currentDirectory); + + // now strip off current directory + const size_t previousDirIndex = currentDirectory.find_last_of (path_seps); + if (static_cast(previousDirIndex) == currentDirectory.npos) + break; + else + IGNORE_RETURN(currentDirectory.erase(previousDirIndex)); + } + + //-- build all directories specified by the initial directory + while (!directoryStack.empty()) + { + // get the directory + currentDirectory = directoryStack.top(); + directoryStack.pop(); + + // try to create it (don't pass any security attributes) + IGNORE_RETURN (CreateDirectory(currentDirectory.c_str(), NULL)); + } + + return true; +} + +// ---------------------------------------------------------------------- +/** + * Write out a file. + * + * The file name and where the file is written is system-dependent. + * + * @param fileName Name of the file to write + * @param data Data buffer to write to the file + */ + +bool Os::writeFile(const char *fileName, const void *data, int length) // Length of the data bufferto write +{ + BOOL result; + HANDLE handle; + DWORD written; + + // open the file for writing + handle = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + // check if it was opened + if (handle == INVALID_HANDLE_VALUE) + { + WARNING (true, ("Os::writeFile unable to create file [%s] for writing.", fileName)); + return false; + } + + // attempt to write the data + result = WriteFile(handle, data, static_cast(length), &written, NULL); + + // make sure the data was written okay + if (!result || written != static_cast(length)) + { + WARNING (true, ("Os::writeFile error writing file [%s]. Wrote %d, attempted to write %d.", fileName, written, length)); + static_cast(CloseHandle(handle)); + return false; + } + + // close the file + result = CloseHandle(handle); + + // make sure the close was sucessful + if (!result) + { + WARNING (true, ("Os::writeFile error closing file [%s].", fileName)); + return false; + } + + return true; +} + +// ---------------------------------------------------------------------- +/** + * Check to see if any child threads have Fataled. + * + * This routine will + */ + +void Os::checkChildThreads() +{ + FATAL(ms_threadDied, ("child thread died")); +} + +// ---------------------------------------------------------------------- +/** + * Change the priority of this process. + * + */ + +void Os::setProcessPriority(Priority priority) +{ + switch (priority) + { + case P_low: + SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS); + break; + + case P_normal: + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); + break; + + case P_high: + SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); + break; + + default: + DEBUG_FATAL(true, ("Invalid priority")); + break; + } +} + +// ---------------------------------------------------------------------- +/** + * Update the Os subsystem. + * + * This routine is supported for all platforms. + * + * For the Win* platforms, this routine will process the windows message pump. + */ + +bool Os::update() +{ + MSG msg; + int result; + + FloatingPointUnit::update(); + + ms_wasFocusLost = false; + ++ms_numberOfUpdates; + +#if PRODUCTION == 0 + + if (ms_validateGuardPatterns || ms_validateFreePatterns) + { + PROFILER_AUTO_BLOCK_DEFINE ("validate heap"); + MemoryManager::verify(ms_validateGuardPatterns, ms_validateFreePatterns); + } + +#endif + + if (ms_processMessagePump) + { + do + { + checkChildThreads(); + + // while there are messages in the queue + while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) + { + result = GetMessage(&msg, NULL, 0, 0); + + if (result < 0) + { + // error, ignore GetMessage + } + else + // get the message + if (result > 0) + { + static_cast(TranslateMessage(&msg)); + static_cast(DispatchMessage(&msg)); + } + else + { + // WM_QUIT handled here + ms_gameOver = true; + return false; + } + } + + // may need to reprocess the message queue now + } while (handleDebugMenu()); + } + + Clock::update(); + + return true; +} + +// ---------------------------------------------------------------------- +/** + * Formats a message error using GetLastError() and FormatMessge(). + * + * The buffer returned from this function is dynamically allocated to prevent + * issues with this routine being called from multiple threads. The caller + * must delete the buffer when it is done. + * + * @return A dynamically allocated buffer containing the error message + */ + +char *Os::getLastError() +{ + char buffer[2048]; + + const DWORD result = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, sizeof(buffer), NULL); + + if (result == 0) + return NULL; + + return DuplicateString(buffer); +} + +// ---------------------------------------------------------------------- + +bool Os::handleDebugMenu() +{ +#if PRODUCTION == 0 + + // pop up the menu if it is wanted and GDI is actually visible + if (ms_wantPopupDebugMenu && ms_isGdiVisibleHookFunction && ms_isGdiVisibleHookFunction()) + { + ms_focused = false; + // unaquire all the dinput devices + if (ms_lostFocusHookFunction) + ms_lostFocusHookFunction(); + + BOOL b; + POINT p; + + // get the upper left corner of the client space in screen coordinates + p.x = 0; + p.y = 0; + b = ClientToScreen(ms_window, &p); + DEBUG_FATAL(!b, ("ClientToScreen failed")); + + typedef std::map Map; + Map map; + + // create the menu + HMENU menu = CreatePopupMenu(); + const char *lastSection = ""; + HMENU lastSubmenu = NULL; + int index = 1; + DebugFlags::FlagVector::const_iterator end = DebugFlags::ms_flagsSortedByName.end(); + for (DebugFlags::FlagVector::const_iterator i = DebugFlags::ms_flagsSortedByName.begin(); i != end; ++i, ++index) + { + const DebugFlags::Flag &flag = *i; + + // check if we are starting a new section + if (strcmp(lastSection, flag.section) != 0) + { + lastSection = flag.section; + + char buffer[512]; + strcpy(buffer, lastSection); + char *start = buffer; + char *slash = NULL; + lastSubmenu = menu; + while ((slash = strchr(start, '/')) != NULL) + { + *slash = '\0'; + + Map::iterator entry = map.find(buffer); + if (entry == map.end()) + { + const int numberOfItems = GetMenuItemCount(lastSubmenu); + int insertLocation = 0; + for (insertLocation = 0; insertLocation < numberOfItems && GetSubMenu(lastSubmenu, insertLocation); ++insertLocation) + ; + + HMENU newMenu = CreatePopupMenu(); + static_cast(InsertMenu(lastSubmenu, insertLocation, MF_BYPOSITION | MF_POPUP, reinterpret_cast(newMenu), start)); + lastSubmenu = newMenu; + map.insert(Map::value_type(DuplicateString(buffer), lastSubmenu)); + } + else + lastSubmenu = entry->second; + + *slash = '/'; + start = slash + 1; + } + + const int numberOfItems = GetMenuItemCount(lastSubmenu); + int insertLocation = 0; + for (insertLocation = 0; insertLocation < numberOfItems && GetSubMenu(lastSubmenu, insertLocation); ++insertLocation) + ; + + HMENU newMenu = CreatePopupMenu(); + static_cast(InsertMenu(lastSubmenu, insertLocation, MF_BYPOSITION | MF_POPUP, reinterpret_cast(newMenu), start)); + lastSubmenu = newMenu; + map.insert(Map::value_type(DuplicateString(buffer), lastSubmenu)); + } + + // add the current flag to the current menu + static_cast(AppendMenu(lastSubmenu, MF_ENABLED | MF_STRING | (*flag.variable ? MF_CHECKED : MF_UNCHECKED), index, flag.name)); + } + + { + ms_debugKeyIndex = index; + + Map::iterator entry = map.find("SharedDebug"); + DEBUG_FATAL(entry == map.end(), ("Could not find SharedDebug section")); + + HMENU newMenu = CreatePopupMenu(); + static_cast(AppendMenu(entry->second, MF_POPUP, reinterpret_cast(newMenu), "DebugKey")); + lastSubmenu = newMenu; + + DebugKey::FlagVector::const_iterator end = DebugKey::ms_flags.end(); + for (DebugKey::FlagVector::const_iterator i = DebugKey::ms_flags.begin(); i != end; ++i, ++index) + { + // add the current flag to the current menu + const DebugKey::Flag &flag = *i; + static_cast(AppendMenu(lastSubmenu, MF_ENABLED | MF_STRING | (*flag.variable ? MF_CHECKED : MF_UNCHECKED), index, flag.name)); + } + } + + // free the map memory + while (!map.empty()) + { + Map::iterator i = map.begin(); + char *value = i->first; + map.erase(i); + delete [] value; + } + + // pop up the menu at the top corner of the client space + index = TrackPopupMenuEx(menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_RIGHTBUTTON, p.x, p.y, ms_window, NULL); + if (index) + { + if (index < ms_debugKeyIndex) + { + bool &value = *DebugFlags::ms_flagsSortedByName[index-1].variable; + value = !value; + } + else + { +#if PRODUCTION == 0 + DebugKey::setCurrentFlag(DebugKey::ms_flags[index - ms_debugKeyIndex].variable); +#endif + } + } + + DestroyMenu(menu); + + // don't want the menu anymore + ms_wantPopupDebugMenu = false; + ms_wasFocusLost = true; + ms_focused = true; + if (ms_acquiredFocusHookFunction2) + ms_acquiredFocusHookFunction2(); + + return true; + } + +#endif + + return false; +} + +// ---------------------------------------------------------------------- + +void Os::enablePopupDebugMenu() +{ +#if PRODUCTION == 0 + ms_allowPopupDebugMenu = true; +#endif +} + +// ---------------------------------------------------------------------- +/** + * Request that the popup debug menu be displayed. + * + * The popup debug menu will only be displayed if the proper config file + * switch has been set. + */ + +void Os::requestPopupDebugMenu() +{ +#if PRODUCTION == 0 + ms_wantPopupDebugMenu = ms_allowPopupDebugMenu; +#endif +} + +bool Os::isNumPadValue(unsigned char asciiChar) +{ + return (asciiChar >= '0' && asciiChar <= '9') || + (asciiChar == '/') || + (asciiChar == '*') || + (asciiChar == '-') || + (asciiChar == '+') || + (asciiChar == '.'); +} + + +// ---------------------------------------------------------------------- +/** + * Check to see if this is a NumPad keypress to be consumed. Enter is the only one not consumed. + */ +bool Os::isNumPadChar(unsigned char asciiChar) +{ + BYTE keyboardstate[256]; + GetKeyboardState( keyboardstate ); + + if (isNumPadValue(asciiChar)) + { + return ( (keyboardstate[VK_NUMPAD1] > 1) || + (keyboardstate[VK_NUMPAD2] > 1) || + (keyboardstate[VK_NUMPAD3] > 1) || + (keyboardstate[VK_NUMPAD4] > 1) || + (keyboardstate[VK_NUMPAD5] > 1) || + (keyboardstate[VK_NUMPAD6] > 1) || + (keyboardstate[VK_NUMPAD7] > 1) || + (keyboardstate[VK_NUMPAD8] > 1) || + (keyboardstate[VK_NUMPAD9] > 1) || + (keyboardstate[VK_NUMPAD0] > 1) || + (keyboardstate[VK_DIVIDE] > 1) || + (keyboardstate[VK_ADD] > 1) || + (keyboardstate[VK_SUBTRACT] > 1) || + (keyboardstate[VK_MULTIPLY] > 1) || + (keyboardstate[VK_DECIMAL] > 1)); + } + return false; +} + +// ---------------------------------------------------------------------- +/** + * Handle window messages. + * + * This routine will process window messages that are passed into the application from + * Windows, likely though the Os::update() routine, but may be from other locations as well. + * + * @param hwnd Handle of window + * @param uMsg Message identifier + * @param wParam First message parameter + * @param lParam Second message parameter + * @see Os::update() + */ + +LRESULT CALLBACK Os::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ +#if 0 + DEBUG_REPORT_LOG_PRINT(true, ("%08d %08x %08x %08x\n", ms_numberOfUpdates, uMsg, wParam, lParam)); +#endif + + if (ms_IMEHookFunction) + { + // Let the IME Manager see and possibly consume message + if (ms_IMEHookFunction(hwnd, uMsg, wParam, lParam) == 0) + { + return 0; + } + } + + switch (uMsg) + { + case WM_ERASEBKGND: + // won't let windows erase the background + return 0; + + case WM_IME_CHAR: + if (ms_queueCharacterHookFunction) + { + const char ansiChars [2] = + { + static_cast(HIBYTE( wParam )), //lint !e1924 // c-style case msvc bug + static_cast(LOBYTE( wParam )) //lint !e1924 // c-style case msvc bug + }; + + wchar_t u; + if (MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, reinterpret_cast(ansiChars), 2, &u, 1)) + ms_queueCharacterHookFunction(0, static_cast(u)); + } + return 0; + + case WM_HOTKEY: + { + if (ms_queueKeyDownHookFunction) + { + ms_queueKeyDownHookFunction(0, MapVirtualKey(HIWORD(lParam), 0)); + } + return 0; + } + case WM_CHAR: + // handle typed string characters + if (ms_queueCharacterHookFunction) + { + //-- the extended bit is bit 24 + const int extended = (lParam & (1 << 24)) != 0; + + if (!extended) + { + int keyCode = (lParam << 8) >> 24; // key code is in bits 16-23 + // cp* == ASCII until 0x80, for which you then need to call the following to get the Unicode value + // from the cp* value. WM_CHAR always returns the values from the windows codepage (cp) used. For US/Europe + // it is cp1252 and for Japan it is cp932. + if (wParam >= 0x80) + { + char cpChar[2]; + wchar_t unicodeChar[2]; + + cpChar[0] = static_cast(wParam); + cpChar[1] = '\0'; + + int result = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cpChar, sizeof(cpChar), unicodeChar, sizeof(unicodeChar)); + + + if (result > 0) + { + ms_queueCharacterHookFunction(keyCode, static_cast(unicodeChar[0])); + } + } + else + { + ms_queueCharacterHookFunction(keyCode, static_cast(wParam)); + } + } + } + return 0; + + case WM_INPUTLANGCHANGE: + { + if (ms_inputLanguageChangedHookFunction) + { + ms_inputLanguageChangedHookFunction(); + } + } + return 0; + + case WM_DESTROY: + // if the main window gets destroyed, it's time to quit + PostQuitMessage(0); + return 0; + + case WM_SYSCOMMAND: + switch (wParam & 0xFFF0) + { + // hack hack hack hack hack + // don't let alt-f4 close the window, but allow clicking on the close X button to close the window + case SC_CLOSE: + if (GetKeyState(VK_F4) && (GetKeyState(VK_MENU) || GetKeyState(VK_RMENU))) + return 0; + break; + + // don't let the monitor get turned off + case SC_MONITORPOWER: + return 0; + + // don't allow the screen saver to come on + case SC_SCREENSAVE: + return 0; + + // don't allow alt-space to open up the window menu + case SC_KEYMENU: + return 0; + + case SC_MOVE: + ClipCursor(NULL); + ms_focused = false; + if (ms_lostFocusHookFunction) + ms_lostFocusHookFunction(); + ms_wasFocusLost = true; + break; + default: + break; + } + break; + + case WM_ENTERSIZEMOVE: + if (ms_getOtherAdapterRectsHookFunction) + { + ms_otherAdapterRects.clear(); + (*ms_getOtherAdapterRectsHookFunction)(ms_otherAdapterRects); + } + break; + + case WM_EXITSIZEMOVE: + ms_focused = true; + if (ms_acquiredFocusHookFunction) + ms_acquiredFocusHookFunction(); + if (ms_acquiredFocusHookFunction2) + ms_acquiredFocusHookFunction2(); + ms_wasFocusLost = true; + if (ms_windowPositionChangedHookFunction) + (*ms_windowPositionChangedHookFunction)(); +#if PRODUCTION == 0 + DebugMonitor::setBehindWindow(ms_window); +#endif + break; + + case WM_MOUSEACTIVATE: + if (hwnd == ms_window) + { + if (LOWORD(lParam) == HTCAPTION) + ms_clickToMove = true; + else if (LOWORD(lParam) == HTCLIENT) + { + ms_focused = true; + if (ms_acquiredFocusHookFunction) + ms_acquiredFocusHookFunction(); + if (ms_acquiredFocusHookFunction2) + ms_acquiredFocusHookFunction2(); + } + } + + break; + + case WM_MOUSEMOVE: + if (ms_focused && hwnd == ms_window) + { + ms_mouseMoveInClient = true; + updateMousePosition(LOWORD(lParam), HIWORD(lParam)); + } + break; + + case WM_NCMOUSEMOVE: + ms_mouseMoveInClient = false; + break; + + case WM_SETCURSOR: + if (!ms_mouseMoveInClient || hwnd != ms_window) + SetCursor(ms_cursorArrow); + else + if (!ms_getHardwareMouseCursorEnabled || !ms_getHardwareMouseCursorEnabled()) + SetCursor(NULL); + break; + + case WM_NCACTIVATE: +#if PRODUCTION == 0 + // hack to handle coming back from the debugger cleanly + if (wParam) + { + //allow game-specific systems a chance to respond to focus changes + DebugMonitor::setBehindWindow(ms_window); + if (ms_lostFocusHookFunction) + ms_lostFocusHookFunction(); + if (ms_acquiredFocusHookFunction) + ms_acquiredFocusHookFunction(); + if (ms_acquiredFocusHookFunction2) + ms_acquiredFocusHookFunction2(); + ms_wasFocusLost = true; + ms_focused = true; + } +#endif + break; + + case WM_ACTIVATE: + if (hwnd == ms_window) + { + if (wParam != WA_INACTIVE) + { + if (ms_clickToMove) + ms_clickToMove = false; + ms_mouseMoveInClient = true; + ms_focused = true; + ms_wasFocusLost = true; + + if (ms_acquiredFocusHookFunction) + ms_acquiredFocusHookFunction(); + if (ms_acquiredFocusHookFunction2) + ms_acquiredFocusHookFunction2(); + } + else + { + ClipCursor(NULL); + ms_focused = false; + if (ms_lostFocusHookFunction) + ms_lostFocusHookFunction(); + } + } + break; + + case WM_ACTIVATEAPP: + if (wParam == FALSE) + { + ClipCursor(NULL); + ms_focused = false; + if (ms_lostFocusHookFunction) + ms_lostFocusHookFunction(); + } + break; + + case WM_DISPLAYCHANGE: + if (ms_displayModeChangedHookFunction) + ms_displayModeChangedHookFunction(); + break; + + default: + break; + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +// ---------------------------------------------------------------------- + +void OsNamespace::updateMousePosition(int x, int y) +{ + if (ms_setSystemMouseCursorPositionHookFunction) + ms_setSystemMouseCursorPositionHookFunction(x, y); + + if (ms_setSystemMouseCursorPositionHookFunction2) + ms_setSystemMouseCursorPositionHookFunction2(x, y); +} + +// ---------------------------------------------------------------------- +/** + * Get an identifier indicating which thread called this function. + */ + +Os::ThreadId Os::getThreadId() +{ + return GetCurrentThreadId(); +} + +// ---------------------------------------------------------------------- +/** + * Get the actual system time, in seconds since the epoch. + * + * Do not use this for most game systems, since it does not take into account + * clock sku, game loop times, etc. + */ +time_t Os::getRealSystemTime() +{ + return time(0); +} + +// ---------------------------------------------------------------------- +/** + * Convert a time in seconds since the epoch to GMT. + * + */ + +void Os::convertTimeToGMT(const time_t &convertTime, tm &zulu) +{ + zulu=*gmtime(&convertTime); // gmtime uses a single static tm structure. Yuck! +} + +// ---------------------------------------------------------------------- +/** + * Convert a tm structure to the time in seconds since the epoch. + * + */ + +time_t Os::convertGMTToTime(const tm &zulu) +{ + return mktime(const_cast(&zulu)); +} + +// ---------------------------------------------------------------------- +/** + * Cause the current thread to suspend for a period of time. Zero delay indicates + * to yield the current time slice. + */ + +void Os::sleep(int ms) +{ + ::Sleep(static_cast(ms)); +} + +// ---------------------------------------------------------------------- +/** + * Assign the given thread a reasonable name (only works for MSDev 6.0 debugger) + * Max 9 characters + * + */ + +void Os::setThreadName(ThreadId threadID, const char* threadName) +{ + //used to give threads reasonable names in the MSDev debugger, + //see http://www.vcdj.com/upload/free/features/vcdj/2001/03mar01/et0103/et0103.asp for more info + struct ThreadNameInfo + { + DWORD dwType; + LPCSTR szName; + DWORD dwThreadID; + DWORD dwFlags; + }; + + ThreadNameInfo info; + info.dwType = 0x1000; //must be this value + info.szName = threadName; + info.dwThreadID = threadID; + info.dwFlags = 0; //unused, reserved for future use + + __try + { + // use the magic exception number MS picked for this purpose + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), reinterpret_cast(&info)); + } + __except (EXCEPTION_CONTINUE_EXECUTION) + { + } +} + +// ---------------------------------------------------------------------- +/** + * Given a base directory and a full file pathname, find the relative path + * needed to get from the source directory to the target. + * + * This command is case sensitive. It does not care whether baseDirectory contains + * a trailing backslash or not. + * + * @param baseDirectory the base directory from which a relative path will be constructed. + * @param targetPathname the full pathname for the file for which we want to generate a relative path + * @param relativePath the string into which the constructed relative path will be returned + */ + +void Os::buildRelativePath(const char *baseDirectory, const char *targetPathname, std::string &relativePath) +{ + NOT_NULL(baseDirectory); + DEBUG_FATAL(!targetPathname || !*targetPathname, ("bad targetPathname, must be non-zero length")); + + const char directorySeparator = '\\'; + const char *const backupDirectoryString = "..\\"; + + std::string workingBaseDirectory(baseDirectory); + + //-- ensure base directory ends in directory separator + if (workingBaseDirectory[workingBaseDirectory.length()-1] != directorySeparator) + workingBaseDirectory += directorySeparator; + + //-- grab the target directory + std::string workingTargetDirectory; + + const char *endOfDirectory = strrchr(targetPathname, static_cast(directorySeparator)); + if (endOfDirectory) + IGNORE_RETURN(workingTargetDirectory.append(targetPathname, static_cast(endOfDirectory - targetPathname + 1))); + + //-- find count of character of match between directory strings + const size_t workingBaseDirectoryLength = workingBaseDirectory.length(); + const size_t workingTargetDirectoryLength = workingTargetDirectory.length(); + + size_t searchIndex = 0; + while ((searchIndex < workingBaseDirectoryLength) && (searchIndex < workingTargetDirectoryLength) && (workingBaseDirectory[searchIndex] == workingTargetDirectory[searchIndex])) + ++searchIndex; + + size_t matchCount = searchIndex; + + //-- if we match into the middle of a directory, back up until the previous directory + if ((matchCount > 0) && (workingBaseDirectory[matchCount - 1] != directorySeparator)) + { + do + { + --matchCount; + } while ((matchCount > 0) && (workingBaseDirectory[matchCount - 1] != directorySeparator)); + } + + //-- if we have no match between directories, the best path is the full path. + if (matchCount < 1) + { + relativePath = targetPathname; + return; + } + + //-- for each directory in base directory not matched, insert a "backup directory" string + relativePath = ""; + { + for (size_t i = matchCount; i < workingBaseDirectoryLength; ++i) + if (workingBaseDirectory[i] == directorySeparator) + IGNORE_RETURN(relativePath.append(backupDirectoryString)); + } + + //-- for each directory in the target directory not matched, append to result. + // this works out to copying from the match point forward in the target path. + IGNORE_RETURN(relativePath.append(targetPathname + matchCount)); +} + +// ---------------------------------------------------------------------- +/** + * Convert a relative path to an absolute path. + */ +bool Os::getAbsolutePath(const char *relativePath, char *absolutePath, int absolutePathBufferSize) +{ + if (_fullpath(absolutePath, relativePath, static_cast(absolutePathBufferSize)) == NULL) + return false; + + // convert the slashes to be forwards + for (char *convert = absolutePath; *convert; ++convert) + if (*convert == '\\') + *convert = '/'; + + return true; +} + +// ---------------------------------------------------------------------- +/** + * Copy text to the system clipboard. + * + * This routine can be used if the application wants to make some data easily available for pasting (like crash call stacks). + */ + +bool Os::copyTextToClipboard(const char *text) +{ + if (!OpenClipboard(ms_window)) + return false; + + if (!EmptyClipboard()) + return false; + + // need to convert to cr/lf sequences. yuck. + int length = 1; + for (const char *t2 = text; *t2; ++t2, ++length) + { + if (*t2 == '\n') + ++length; + } + + HANDLE memoryHandle = GlobalAlloc(GMEM_MOVEABLE, length); + if (memoryHandle == NULL) + { + CloseClipboard(); + return FALSE; + } + + // lock the handle and copy the text to the buffer. + char *destination = reinterpret_cast(GlobalLock(memoryHandle)); + while (*text) + { + if (*text == '\n') + *(destination++) = '\r'; + *destination++ = *text++; + } + + if (GlobalUnlock(memoryHandle) != 0 || GetLastError() != NO_ERROR) + { + IGNORE_RETURN(GlobalFree(memoryHandle)); + return false; + } + + if (!SetClipboardData(CF_TEXT, memoryHandle)) + return false; + + if (!CloseClipboard()) + return false; + + return true; +} + +// ---------------------------------------------------------------------- + +bool Os::getUserName(char *buffer, int &bufferSize) +{ + NOT_NULL(buffer); + DWORD windowsBufferSize = static_cast(bufferSize); + buffer[0] = '\0'; + bool result = GetUserName(buffer, &windowsBufferSize) == TRUE; + bufferSize = static_cast(bufferSize); + return result; +} + +//----------------------------------------------------------------------- + +Os::OsPID_t Os::getProcessId() +{ + return static_cast(GetCurrentProcessId()); +} + +//---------------------------------------------------------------------- + +bool Os::isFocused() +{ + return ms_focused; +} + +//---------------------------------------------------------------------- + +bool Os::launchBrowser(std::string const & website) +{ + std::string URL("http://"); + if (strncmp(URL.c_str(), website.c_str(),7)!=0) + URL+=website; + else + URL=website; + int result = reinterpret_cast(ShellExecute(NULL, "open", URL.c_str(), NULL, NULL, SW_SHOWNORMAL)); + return (result > 32); +} + + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/win32/Os.h b/engine/shared/library/sharedFoundation/src/win32/Os.h new file mode 100644 index 00000000..afb3be40 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/Os.h @@ -0,0 +1,152 @@ +// ====================================================================== +// +// Os.h +// +// Portions copyright 1998 Bootprint Entertainment +// Portions copyright 2000-2002 Sony Online Entertainment +// All Rights Reserved +// +// ====================================================================== + +#ifndef INCLUDED_Os_H +#define INCLUDED_Os_H + +// ====================================================================== + +#include + +// ====================================================================== + +class Os +{ +public: + + typedef bool (*IsGdiVisibleHookFunction)(); + typedef void (*LostFocusHookFunction)(); + typedef void (*AcquiredFocusHookFunction)(); + typedef void (*QueueCharacterHookFunction)(int keyboard, int character); + typedef void (*SetSystemMouseCursorPositionHookFunction)(int x, int y); + typedef bool (*GetHardwareMouseCursorEnabled)(); + typedef void (*GetOtherAdapterRectsHookFunction)(stdvector::fwd &); + typedef void (*WindowPositionChangedHookFunction)(); + typedef void (*DisplayModeChangedHookFunction)(); + typedef void (*InputLanguageChangedHookFunction)(); + typedef int (*IMEHookFunction)(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + typedef void (*QueueKeyDownHookFunction)(int keyboard, int character); + + typedef uint ThreadId; + typedef DWORD OsPID_t; + + enum Priority + { + P_high, + P_normal, + P_low + }; + + enum + { + MAX_PATH_LENGTH = 512 + }; + +public: + + static void install(HINSTANCE newInstance, const char *windowName, HICON normalIcon, HICON smallIcon); + static void install(HWND newWindow, bool processMessagePump); + static void install(); + + static bool isGameOver(); + static DLLEXPORT bool isMainThread(); + static bool wasFocusLost(); + static void checkChildThreads(); + + static void setProcessPriority(Priority priority); + + static bool update(); + + static void returnFromAbort(); + static void abort(); + + static void enablePopupDebugMenu(); + static void requestPopupDebugMenu(); + + static bool createDirectories (const char *dirname); + + static bool writeFile(const char *fileName, const void *data, int length); + + static HWND getWindow(); + static bool engineOwnsWindow(); + + static int getNumberOfUpdates(); + + static char *getLastError(); + + static const char *getProgramName(); + static const char *getShortProgramName(); + static const char *getProgramStartupDirectory(); + + static void setIsGdiVisibleHookFunction(IsGdiVisibleHookFunction newGlIsGdiVisible); + static void setLostFocusHookFunction(LostFocusHookFunction lostFocusHookFunction); + static void setQueueCharacterHookFunction(QueueCharacterHookFunction queueCharacterHookFunction); + static void setSetSystemMouseCursorPositionHookFunction(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction); + static void setSetSystemMouseCursorPositionHookFunction2(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction); + static void setAcquiredFocusHookFunction(AcquiredFocusHookFunction acquiredFocusHookFunction); + static void setAcquiredFocusHookFunction2(AcquiredFocusHookFunction acquiredFocusHookFunction); + static void setGetHardwareMouseCursorEnabled(GetHardwareMouseCursorEnabled getHardwareMouseCursorEnabled); + static void setGetOtherAdapterRectsHookFunction(GetOtherAdapterRectsHookFunction getOtherAdapterRectsHookFunction); + static void setWindowPositionChangedHookFunction(WindowPositionChangedHookFunction windowPositionChangedHookFunction); + static void setDisplayModeChangedHookFunction(DisplayModeChangedHookFunction displayModeChangedHookFunction); + static void setInputLanguageChangedHookFunction(InputLanguageChangedHookFunction inputLanguageChangedHookFunction); + static void setIMEHookFunction(IMEHookFunction imeHookFunction); + static void setQueueKeyDownHookFunction(QueueKeyDownHookFunction queueKeyDownHookFunction); + + static DLLEXPORT ThreadId getThreadId(); + static void setThreadName(ThreadId threadID, const char* name); + + static void sleep(int ms); + + static time_t getRealSystemTime(); + static void convertTimeToGMT(const time_t &time, tm &zulu); + static time_t convertGMTToTime(const tm &zulu); + + static bool isMultiprocessor(); + static int getProcessorCount(); + + static void buildRelativePath(const char *baseDirectory, const char *targetPathname, std::string &relativePath); + static bool getAbsolutePath(const char *relativePath, char *absolutePath, int absolutePathBufferSize); + + static bool copyTextToClipboard(const char *text); + + static bool getUserName(char *buffer, int &bufferSize); + + static OsPID_t getProcessId(); + + static bool isFocused(); + + static bool launchBrowser(std::string const & website); + static bool isNumPadValue(unsigned char asciiChar); + static bool isNumPadChar(unsigned char asciiChar); + +private: + + Os(); + Os(const Os &); + Os &operator =(const Os &); + +private: + + static void remove(); + static void installCommon(); + + static LRESULT CALLBACK Os::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +private: + +private: + + static bool handleDebugMenu(); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/win32/PerThreadData.cpp b/engine/shared/library/sharedFoundation/src/win32/PerThreadData.cpp new file mode 100644 index 00000000..7b2d0b58 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/PerThreadData.cpp @@ -0,0 +1,465 @@ +// ====================================================================== +// +// PerThreadData.cpp +// +// Portions copyright 1998 Bootprint Entertainment +// Portions Copyright 2002 Sony Online Entertainment +// All Rights Reserved +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/PerThreadData.h" + +#include "sharedSynchronization/RecursiveMutex.h" +#include "sharedSynchronization/Gate.h" + +#include "sharedFoundation/Os.h" + +#include +#include + +// ====================================================================== + +// ====================================================================== +namespace PerThreadDataNamespace +{ + struct Data + { + bool exitChainRunning; + bool exitChainFataling; + ExitChain::Entry *exitChainFirstEntry; + + int debugPrintFlags; + + Gate *fileStreamerReadGate; + + HANDLE watchHandle; + }; + + typedef std::vector DataAllocations; + + // ------------------------------------------------------ + + static char buffer1[sizeof(RecursiveMutex)]; + static char buffer2[sizeof(DataAllocations)]; + + static const DWORD BadSlot = 0xffffffff; + + static DWORD slot = BadSlot; + static RecursiveMutex *criticalSection; + static DataAllocations *dataAllocations; + + // ------------------------------------------------------ + + static void _threadRemove(Data *data); + static void _removeFromList(Data *data); + static void _watchThreads(); + + /*---------------------------------------------------------------------- + * Get access to the per-thread-data. + * + * This routine will verify the per-thread-data subsystem has been installed and the + * threadInstall() function has been called for the current thread. + * + * @return A pointer to the per-thread-data. + */ + inline static Data *_getData(bool allowReturnNull=false) + { + UNREF(allowReturnNull); + + if (slot == BadSlot) + { + DEBUG_FATAL(true && !allowReturnNull, ("not installed")); + return NULL; + } + + Data * const data = reinterpret_cast(TlsGetValue(slot)); + DEBUG_FATAL(!data && !allowReturnNull, ("not installed for this thread")); + return data; + } + + // ------------------------------------------------------ + + inline static void _closeData(Data *data) + { + if (data->fileStreamerReadGate) + { + delete data->fileStreamerReadGate; + data->fileStreamerReadGate=0; + } + if (data->watchHandle) + { + CloseHandle(data->watchHandle); + data->watchHandle=0; + } + } + + // ------------------------------------------------------ + + inline static void _freeData(Data *data) + { + delete data; + } + + // ------------------------------------------------------ +} +using namespace PerThreadDataNamespace; + +// ====================================================================== + +// ====================================================================== +// Install the per-thread-data subsystem +// +// Remarks: +// +// This routine will install the per-thread-data subsystem that is required for several +// other subsystems in the engine. It should be called from the primary thread before +// any other threads have been created. It will also call threadInstall() for the +// primary thread. +// +// See Also: +// +// PerThreadData::remove() + +void PerThreadData::install() +{ + slot = TlsAlloc(); + FATAL(slot == BadSlot, ("TlsAlloc failed")); + + criticalSection = new(buffer1) RecursiveMutex; + dataAllocations = new(buffer2) DataAllocations; + dataAllocations->reserve(8); + threadInstall(); +} + +// ---------------------------------------------------------------------- +/** + * Remove the per-thread-subsystem. + * + * This routine should be called by the primary thread after all other threads have + * terminated, and no other uses of per-thread-data will occur. + * + * @see PerThreadData::install() + */ +void PerThreadData::remove() +{ + criticalSection->enter(); + { + // remove this thread. + threadRemove(); + + // clean up after any threads which didn't clean up after themselves (like the miles sound system) + const DataAllocations::iterator iEnd = dataAllocations->end(); + for (DataAllocations::iterator i = dataAllocations->begin(); i != iEnd; ++i) + { + _closeData(*i); + _freeData(*i); + } + + dataAllocations->clear(); + } + criticalSection->leave(); + + criticalSection->~RecursiveMutex(); + dataAllocations->~vector(); + + memset(buffer1, 0, sizeof(buffer1)); + memset(buffer2, 0, sizeof(buffer2)); + + const BOOL result = TlsFree(slot); + FATAL(!result, ("TlsFree failed")); +} + +// ---------------------------------------------------------------------- +/** + * Create the per-thread-data for a new thread. + * + * This routine should be called in a thread before the first usage of per-thread-data. + * + * If the client is calling this function on a thread that existed before the engine was + * installed, the client should set isNewThread to false. Setting isNewThread to false + * prevents the function from validating that the thread's TLS is NULL. For threads existing + * before the engine is installed, the TLS data for the thread is undefined. + * + * @param isNewThread [IN] true if the thread was created after the engine was installed, false otherwise + * @see PerThreadData::threadRemove() + */ + +void PerThreadData::threadInstall(bool isNewThread) +{ + UNREF(isNewThread); + + DEBUG_FATAL(slot == BadSlot, ("not installed")); + + // only check for already-set data if this is supposed to be a new thread + DEBUG_FATAL(isNewThread && TlsGetValue(slot), ("already installed for this thread")); + + // create the data + Data * const data = new Data; + + // initialize the data + memset(data, 0, sizeof(*data)); + + //create the event for file streaming reads + data->fileStreamerReadGate = new Gate(false); + + // set the data into the thread slot + const BOOL result = TlsSetValue(slot, data); + UNREF(result); + DEBUG_FATAL(!result, ("TlsSetValue failed")); + + criticalSection->enter(); + { + _watchThreads(); + + dataAllocations->push_back(data); + + // This is most likely a thread created by a 3rd party library such as Miles or Bink. + // Add a watch handle to it so we can clean it up. + if (!isNewThread) + { + const HANDLE processHandle = GetCurrentProcess(); + DuplicateHandle(processHandle, GetCurrentThread(), processHandle, &data->watchHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); + } + } + criticalSection->leave(); +} + +// ---------------------------------------------------------------------- + +void PerThreadDataNamespace::_removeFromList(Data *data) +{ + const DataAllocations::iterator iEnd = dataAllocations->end(); + const DataAllocations::iterator i = std::find(dataAllocations->begin(), iEnd, data); + if (i!=iEnd) + { + dataAllocations->erase(i); + } +} + +// ---------------------------------------------------------------------- +// Synchronization is left up to the user +// Unless this is called during shutdown, the critical section +// needs to be entered. +void PerThreadDataNamespace::_watchThreads() +{ + DataAllocations::iterator tiDest = dataAllocations->begin(); + DataAllocations::iterator tiSrc = tiDest; + DataAllocations::iterator tiEnd = dataAllocations->end(); + + while (tiSrc!=tiEnd) + { + Data *const data = *tiSrc; + const HANDLE h = data->watchHandle; + + if (h!=0 && WaitForSingleObject(h, 0)==WAIT_OBJECT_0) + { + _closeData(data); + _freeData(data); + } + else + { + *tiDest++=data; + } + ++tiSrc; + } + + if (tiSrc!=tiDest) + { + const int newSize = tiDest - dataAllocations->begin(); + dataAllocations->resize(newSize); + } +} + +// ---------------------------------------------------------------------- + +void PerThreadDataNamespace::_threadRemove(Data *data) +{ + //close the event used for file streaming reads + _closeData(data); + + _removeFromList(data); + + // free the memory + _freeData(data); +} + +// ---------------------------------------------------------------------- +/** + * Destroy the per-thread-data for a terminating thread. + * + * This routine should be called in a thread after the last usage of per-thread-data. + * + * @see PerThreadData::threadInstall() + */ + +void PerThreadData::threadRemove() +{ + DEBUG_FATAL(slot == BadSlot, ("not installed")); + DEBUG_FATAL(!TlsGetValue(slot), ("thread not installed")); + + // find our thread record and free the memory + criticalSection->enter(); + + _threadRemove(_getData()); + + // wipe the data in the thread slot + const BOOL result = TlsSetValue(slot, NULL); + UNREF(result); + DEBUG_FATAL(!result, ("TlsSetValue failed")); + + criticalSection->leave(); +} + +// ====================================================================== + +// ====================================================================== +// Determine if the per-thread-data is available for this thread +// +// Return value: +// +// True if the per-thread-data is installed correctly, false otherwise +// +// Remarks: +// +// This routine is not intended for general use; it should only be used by the ExitChain class. +// +// -TRF- looks like Win98 does not zero out a new TLS slot for +// threads existing at the time of slot creation. Thus, if you build a +// plugin that only initializes the engine the first time it is +// used, and other threads already exist in the app, those threads +// will contain bogus non-null data in the TLS slot. If the plugin really +// wants to do lazy initialization of the engine, it will need +// to handle calling PerThreadData::threadInstall() for all existing threads +// (except the thread that initialized the engine, which already +// has its PerThreadData::threadInstall() called). + +bool PerThreadData::isThreadInstalled() +{ + return (_getData(true) != NULL); +} + +// ---------------------------------------------------------------------- +/** + * Get the exit chain running flag value. + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * + * @return True if the exit chain is running, false otherwise. + * @see ExitChain::isRunning() + */ + +bool PerThreadData::getExitChainRunning() +{ + return _getData()->exitChainRunning; +} + +// ---------------------------------------------------------------------- +/** + * Set the exit chain running flag value. + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * + * @param newValue New value for the exit chain running flag + */ + +void PerThreadData::setExitChainRunning(bool newValue) +{ + _getData()->exitChainRunning = newValue; +} + +// ---------------------------------------------------------------------- +/** + * Get the exit chain fataling flag value. + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * + * @return True if the exit chain is fataling, false otherwise. + * @see ExitChain::isFataling() + */ + +bool PerThreadData::getExitChainFataling() +{ + return _getData()->exitChainFataling; +} + +// ---------------------------------------------------------------------- +/** + * Set the exit chain fataling flag value. + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * + * @param newValue New value for the exit chain fataling flag + */ + +void PerThreadData::setExitChainFataling(bool newValue) +{ + _getData()->exitChainFataling = newValue; +} + +// ---------------------------------------------------------------------- +/** + * Get the first entry for the exit chain. + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * This routine may return NULL. + * + * @return Pointer to the first entry on the exit chain + * @see ExitChain::isFataling() + */ + +ExitChain::Entry *PerThreadData::getExitChainFirstEntry() +{ + return _getData()->exitChainFirstEntry; +} + +// ---------------------------------------------------------------------- +/** + * Set the exit chain fataling flag value. + * + * This routine is not intended for general use; it should only be used by the ExitChain class. + * The parameter to this routine may be NULL. + * + * @param newValue New value for the exit chain first entry + */ + +void PerThreadData::setExitChainFirstEntry(ExitChain::Entry *newValue) +{ + _getData()->exitChainFirstEntry = newValue; +} + +// ---------------------------------------------------------------------- +/** + * Get the debug print flags. + * + * This routine is not intended for general use; it should only be used by the DebugPrint functions. + * + * @return Current value of the debug print flags + */ + +int PerThreadData::getDebugPrintFlags() +{ + return _getData()->debugPrintFlags; +} + +// ---------------------------------------------------------------------- +/** + * Set the debug print flags value. + * + * This routine is not intended for general use; it should only be used by the DebugPrint functions. + */ + +void PerThreadData::setDebugPrintFlags(int newValue) +{ + _getData()->debugPrintFlags = newValue; +} + +// ---------------------------------------------------------------------- + +Gate *PerThreadData::getFileStreamerReadGate() +{ + return _getData()->fileStreamerReadGate; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/win32/PerThreadData.h b/engine/shared/library/sharedFoundation/src/win32/PerThreadData.h new file mode 100644 index 00000000..e45a4170 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/PerThreadData.h @@ -0,0 +1,57 @@ +// ====================================================================== +// +// PerThreadData.h +// +// Portions copyright 1998 Bootprint Entertainment +// Portions Copyright 2002 Sony Online Entertainment +// All Rights Reserved +// +// ====================================================================== + +#ifndef INCLUDED_PerThreadData_H +#define INCLUDED_PerThreadData_H + +// ====================================================================== + +class Gate; + +#include "sharedFoundation/ExitChain.h" + +// ====================================================================== + +// Provide thread local storage functionality. +// +// This class' purpose is to allow each thread to maintain some storage that is local and private to each thread. +// The system must be installed before use. Each thread that may use per-thread-data will also need to call the +// threadInstall() routine after creation and threadRemove() just before termination of the thread. + +class PerThreadData +{ +public: + + static void install(void); + static void remove(void); + + static void threadInstall(bool isNewThread = true); + static void threadRemove(void); + + static bool isThreadInstalled(void); + + static bool getExitChainRunning(void); + static void setExitChainRunning(bool newValue); + + static bool getExitChainFataling(void); + static void setExitChainFataling(bool newValue); + + static ExitChain::Entry *getExitChainFirstEntry(void); + static void setExitChainFirstEntry(ExitChain::Entry *newValue); + + static int getDebugPrintFlags(void); + static void setDebugPrintFlags(int newValue); + + static Gate *getFileStreamerReadGate(void); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/win32/PlatformGlue.cpp b/engine/shared/library/sharedFoundation/src/win32/PlatformGlue.cpp new file mode 100644 index 00000000..cf562e00 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/PlatformGlue.cpp @@ -0,0 +1,124 @@ +// ====================================================================== +// +// PlatformGlue.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/PlatformGlue.h" + +#include +#include + +// ====================================================================== + +namespace +{ + +// ---------------------------------------------------------------------- + +class GmTimeSection +{ +public: + + GmTimeSection() + { + InitializeCriticalSection(&m_section); + } + + ~GmTimeSection() + { + DeleteCriticalSection(&m_section); + } + + void enter() + { + EnterCriticalSection(&m_section); + } + + void leave() + { + LeaveCriticalSection(&m_section); + } + +private: + CRITICAL_SECTION m_section; +}; + +// ---------------------------------------------------------------------- + +static GmTimeSection s_gmTimeSection; + +// ---------------------------------------------------------------------- + +} + +// ====================================================================== +// Tokenizing a string. +// Like strtok, except re-entrant. + +char *strsep(char **string, const char *delim) +{ + char *result = *string; + + // handle no string specified, or the end of the string + if (result == 0) + return 0; + + // skip leading delimiters + result = result + strspn(result, delim); + + // handle trailing delimiters + if (*result == '\0') + return 0; + + // look for the first delimiter + const int len = strcspn(result, delim); + if (result[len] == '\0') + { + // hit the end of the string + *string = 0; + } + else + { + // terminate the string and return the substring + result[len] = '\0'; + *string = result + len + 1; + } + + return result; +} + +// ---------------------------------------------------------------------- + +int snprintf(char *buffer, size_t count, const char *format, ...) +{ + va_list va; + + va_start(va, format); + const int result = _vsnprintf(buffer, count, format, va); + va_end(va); + + return result; +} + +// ---------------------------------------------------------------------- + +struct tm *gmtime_r(const time_t *timep, struct tm *result) +{ + s_gmTimeSection.enter(); + tm *t = gmtime(timep); + *result = *t; + s_gmTimeSection.leave(); + return result; +} + +// ---------------------------------------------------------------------- + +int finite(double value) +{ + return _finite(value); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/win32/PlatformGlue.h b/engine/shared/library/sharedFoundation/src/win32/PlatformGlue.h new file mode 100644 index 00000000..7eec7bb5 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/PlatformGlue.h @@ -0,0 +1,32 @@ +// ====================================================================== +// +// PlatformGlue.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_PlatformGlue_H +#define INCLUDED_PlatformGlue_H + +// ====================================================================== + +#include + +// ====================================================================== + +char * strsep(char **string, const char *delim); +int snprintf(char *buffer, size_t count, const char *format, ...); +struct tm * gmtime_r(const time_t *timep, struct tm *result); +int finite(double value); + +//Format specifier for non-portable printf +#define UINT64_FORMAT_SPECIFIER "%I64u" +#define INT64_FORMAT_SPECIFIER "%I64i" + +//Constant definition macro for 64 bit values +#define UINT64_LITERAL(a) a ## ui64 +#define INT64_LITERAL(a) a ## i64 + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/win32/ProcessSpawner.cpp b/engine/shared/library/sharedFoundation/src/win32/ProcessSpawner.cpp new file mode 100644 index 00000000..987e9b64 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/ProcessSpawner.cpp @@ -0,0 +1,310 @@ +// +// ProcessSpawner.cpp +// +//------------------------------------------------------------------- + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/ProcessSpawner.h" + +#include "sharedFoundation/Os.h" + +#include + +ProcessSpawner::ProcessSpawner() +{ + m_asConsole=false; + hProcess=0; + hOutputRead=0; + hInputWrite=0; + currentLine=currentRead=readBuffer; +} + + +ProcessSpawner::~ProcessSpawner() +{ + if (hProcess) + { + CloseHandle(hProcess); + hProcess=0; + } + if (hOutputRead) + { + CloseHandle(hOutputRead); + hOutputRead=0; + } + if (hInputWrite) + { + CloseHandle(hInputWrite); + hInputWrite=0; + } +} + +bool ProcessSpawner::terminate(unsigned exitCode) +{ + if (!hProcess) + { + return false; + } + return TerminateProcess(hProcess, exitCode)!=0; +} + +bool ProcessSpawner::create(const char *commandLine, const char *startupFolder, bool asConsole) +{ + if (hProcess) + { + return false; + } + + if (!commandLine) + { + return false; + } + + if (!startupFolder) + { + startupFolder=Os::getProgramStartupDirectory(); + } + + m_asConsole=asConsole; + + STARTUPINFO sinfo; + memset(&sinfo, 0, sizeof(sinfo)); + sinfo.cb=sizeof(sinfo); + + HANDLE hOutputWrite=0; + HANDLE hErrorWrite=0; + HANDLE hInputRead=0; + + if (asConsole) + { + SECURITY_ATTRIBUTES sa; + sa.nLength=sizeof(sa); + sa.lpSecurityDescriptor=0; + sa.bInheritHandle=true; + + // ----------------------------------------------------- + + // Create the child output pipe. + HANDLE hOutputReadTmp; + CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0); + + // Create a duplicate of the output write handle for the std error + // write handle. This is necessary in case the child application + // closes one of its std output handles. + DuplicateHandle( + GetCurrentProcess(), hOutputWrite, + GetCurrentProcess(),&hErrorWrite, + 0, + TRUE,DUPLICATE_SAME_ACCESS + ); + + + // Create the child input pipe. + HANDLE hInputWriteTmp; + CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0); + + // Create new output read handle and the input write handles. Set + // the Properties to FALSE. Otherwise, the child inherits the + // properties and, as a result, non-closeable handles to the pipes + // are created. + DuplicateHandle( + GetCurrentProcess(), hOutputReadTmp, + GetCurrentProcess(), &hOutputRead, // Address of new handle. + 0, FALSE, // Make it uninheritable. + DUPLICATE_SAME_ACCESS + ); + + DuplicateHandle( + GetCurrentProcess(), hInputWriteTmp, + GetCurrentProcess(), &hInputWrite, // Address of new handle. + 0,FALSE, // Make it uninheritable. + DUPLICATE_SAME_ACCESS + ); + + + // Close inheritable copies of the handles you do not want to be + // inherited. + CloseHandle(hOutputReadTmp); hOutputReadTmp=0; + CloseHandle(hInputWriteTmp); hInputWriteTmp=0; + + sinfo.dwFlags|=(STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW); + sinfo.hStdError=hErrorWrite; + sinfo.hStdInput=hInputRead; + sinfo.hStdOutput=hOutputWrite; + sinfo.wShowWindow = SW_HIDE; + } + + PROCESS_INFORMATION pinfo; + BOOL result = CreateProcess( + 0, + (char *)commandLine, + 0, + 0, + TRUE, + CREATE_NEW_CONSOLE, + 0, + startupFolder, + &sinfo, + &pinfo + ); + + if (asConsole) + { + // Close pipe handles (do not continue to modify the parent). + // You need to make sure that no handles to the write end of the + // output pipe are maintained in this process or else the pipe will + // not close when the child process exits and the ReadFile will hang. + CloseHandle(hOutputWrite); hOutputWrite=0; + CloseHandle(hErrorWrite); hErrorWrite=0; + CloseHandle(hInputRead); hInputRead=0; + } + + if (result) + { + CloseHandle(pinfo.hThread); + hProcess=pinfo.hProcess; + return true; + } + else + { + // Failed to launch turf + hProcess=0; + return false; + } +} + +bool ProcessSpawner::isFinished(unsigned waitTime) +{ + if (!hProcess) + { + return true; + } + + DWORD waitResult = WaitForSingleObject(hProcess, waitTime); + + return waitResult==WAIT_OBJECT_0; +} + +bool ProcessSpawner::getExitCode(unsigned &o_code) +{ + if (!hProcess) + { + return false; + } + + DWORD exitCode; + BOOL result = GetExitCodeProcess(hProcess, &exitCode); + if (result) + { + o_code=exitCode; + return true; + } + else + { + return false; + } +} + +bool ProcessSpawner::_returnExistingLine(char *buffer, const int bufferSize) +{ + const char *const bufferStop = buffer + bufferSize; + char *iter = currentLine; + while (iter!=currentRead) + { + if (buffer==bufferStop) + { + currentLine=iter; + return true; + } + + if (*iter=='\n') + { + *buffer++=0; + _stepIter(iter); + currentLine=iter; + return true; + } + else + { + *buffer++=*iter; + _stepIter(iter); + } + } + + return false; +} + +bool ProcessSpawner::getOutputString(char *buffer, int bufferSize) +{ + if (_returnExistingLine(buffer, bufferSize)) + { + return true; + } + + // ---------------------------------------------- + + if (!hOutputRead) + { + return false; + } + + DWORD dwAvail = 0; + if (!::PeekNamedPipe(hOutputRead, NULL, 0, NULL, &dwAvail, NULL)) + { + // ERROR + return false; + } + + if (!dwAvail) + { + return false; + } + + DWORD dwRead; + + if (currentRead >= currentLine) + { + const unsigned bufferAvailable = sizeof(readBuffer) - (currentRead - readBuffer); + unsigned toRead = dwAvail; + if (toRead > bufferAvailable) + { + toRead=bufferAvailable; + } + + dwRead=0; + if (!::ReadFile(hOutputRead, currentRead, min(bufferAvailable, dwAvail), &dwRead, NULL) || !dwRead) + { + return false; + } + dwAvail-=dwRead; + currentRead+=dwRead; + if (currentRead==readBuffer+sizeof(readBuffer)) + { + currentRead=readBuffer; + } + } + + if (dwAvail>0) + { + const unsigned bufferAvailable = currentLine - currentRead - 1; + if (bufferAvailable) + { + unsigned toRead = dwAvail; + if (toRead > bufferAvailable) + { + toRead=bufferAvailable; + } + + dwRead=0; + if (!::ReadFile(hOutputRead, currentRead, min(bufferAvailable, dwAvail), &dwRead, NULL) || !dwRead) + { + return false; + } + currentRead+=dwRead; + + DEBUG_FATAL(currentRead>=currentLine, ("")); + } + } + + return _returnExistingLine(buffer, bufferSize); +} diff --git a/engine/shared/library/sharedFoundation/src/win32/ProcessSpawner.h b/engine/shared/library/sharedFoundation/src/win32/ProcessSpawner.h new file mode 100644 index 00000000..ed64750f --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/ProcessSpawner.h @@ -0,0 +1,43 @@ +#ifndef INCLUDED_ProcessSpawner_H +#define INCLUDED_ProcessSpawner_H + +class ProcessSpawner +{ +public: + + ProcessSpawner(); + ~ProcessSpawner(); + + bool create(const char *commandLine, const char *startupFolder=0, bool asConsole=true); + + bool terminate(unsigned exitCode=0); + bool isFinished(unsigned waitTime=0); + bool getExitCode(unsigned &o_code); + + bool getOutputString(char *buffer, int bufferSize); + +protected: + + bool _returnExistingLine(char *buffer, int bufferSize); + + void _stepIter(char *&i) + { + if (i==readBuffer+sizeof(readBuffer)-1) + { + i=readBuffer; + } + else + { + i++; + } + } + + HANDLE hProcess; + HANDLE hOutputRead, hInputWrite; + bool m_asConsole; + char *currentLine, *currentRead, readBuffer[4096]; +}; + +#endif + + diff --git a/engine/shared/library/sharedFoundation/src/win32/RegistryKey.cpp b/engine/shared/library/sharedFoundation/src/win32/RegistryKey.cpp new file mode 100644 index 00000000..a29d0db5 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/RegistryKey.cpp @@ -0,0 +1,918 @@ +// ====================================================================== +// +// RegistryKey.cpp +// Todd Fiala +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/RegistryKey.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/ConfigFile.h" + +#if USE_REGISTRY_EXECUTION_STATISTICS +#include +#include +#endif + +// ====================================================================== + +// keyname for config file parameter containing relative registry path +// for the product + +const char * const RegistryKey::PRODUCT_REGISTRY_PATH_KEYNAME = "ProductRegistryPath"; +const char * const RegistryKey::DEFAULT_PRODUCT_REGISTRY_PATH = "Software\\Sony Online Entertainment\\Default"; + +#if USE_REGISTRY_EXECUTION_STATISTICS +const char * const RegistryKey::STATISTICS_KEYNAME = "Statistics"; +const char * const RegistryKey::STAT_EXEC_STARTED_COUNT_VALUENAME = "StartedExecutions"; +const char * const RegistryKey::STAT_EXEC_INCOMPLETE_COUNT_VALUENAME = "IncompleteExecutions"; +const char * const RegistryKey::STAT_TIME_AVERAGE_VALUENAME = "AverageClockTime"; +const char * const RegistryKey::STAT_TIME_MIN_VALUENAME = "MinimumClockTime"; +const char * const RegistryKey::STAT_TIME_MAX_VALUENAME = "MaximumClockTime"; +const char * const RegistryKey::STAT_TIME_START_VALUENAME = "StartClockTime"; + +#endif + +bool RegistryKey::installed; +bool RegistryKey::setProductKeyPathFromConfig; + +RegistryKey *RegistryKey::usersKey; +RegistryKey *RegistryKey::currentUserKey; +RegistryKey *RegistryKey::classRootKey; +RegistryKey *RegistryKey::localMachineKey; +RegistryKey *RegistryKey::productUserKey; +RegistryKey *RegistryKey::productMachineKey; + +// ====================================================================== +// construct a RegistryKey instance +// +// Remarks: +// This function does not create the underlying registry object. It +// solely attaches such a registry object with a RegistryKey class +// instance. + +RegistryKey::RegistryKey( + HKEY newKeyHandle, // [IN] handle of existing registry key + bool newCloseKeyOnDestroy // [IN] true if RegCloseKey() should be called on key at destruction time + ) : + keyHandle(newKeyHandle), + closeKeyOnDestroy(newCloseKeyOnDestroy) +{ + // -qq- don't know which of these indicates an invalid handle, so check for both + DEBUG_FATAL(!newKeyHandle, ("null newKeyHandle arg")); + DEBUG_FATAL(newKeyHandle == INVALID_HANDLE_VALUE, ("newKeyHandle arg is an invalid handle")); +} + +// ---------------------------------------------------------------------- +/** + * destroy a RegistryKey instance. + */ + +RegistryKey::~RegistryKey(void) +{ + DEBUG_FATAL(!keyHandle, ("null keyHandle")); + + if (closeKeyOnDestroy) + { + const LONG result = RegCloseKey(keyHandle); + UNREF(result); + DEBUG_FATAL(result != ERROR_SUCCESS, ("failed to close registry key, error = %ld\n", result)); + } + keyHandle = 0; +} + +// ---------------------------------------------------------------------- +/** + * enumerate all child subkeys of the current key. + * + * @param context [IN] user-specified context variable passed to callback + * @param callback [IN] function to call for each subkey enumerated + * @see EnumerateKeyCallback, enumerateValues() + */ + +void RegistryKey::enumerateSubkeys(void *context, EnumerateKeyCallback callback) const +{ + const size_t MAX_NAME_LENGTH = 256; + + LONG result; + FILETIME lastModifiedFileTime; + char subkeyName[MAX_NAME_LENGTH]; + DWORD subkeyNameLength; + DWORD index; + + DEBUG_FATAL(!callback, ("null callback arg\n")); + + for ( + index = 0, subkeyNameLength = MAX_NAME_LENGTH; + ERROR_SUCCESS == (result = RegEnumKeyEx(keyHandle, index, subkeyName, &subkeyNameLength, 0, 0, 0, &lastModifiedFileTime)); + ++index, subkeyNameLength = MAX_NAME_LENGTH + ) + { + bool continueEnum = callback(context, subkeyName, &lastModifiedFileTime); + if (!continueEnum) break; + } + + // ensure we finished enumeration cleanly + FATAL( + (result != ERROR_SUCCESS) && (result != ERROR_NO_MORE_ITEMS), + ("failed to enumerate registry subkeys, error = %ld\n", result)); +} + +// ---------------------------------------------------------------------- +/** + * open and return a subkey under this RegistryKey instance. + * + * The function will fail if the specified subkey does not exist. + * + * @param subkeyName [IN] registry path for subkey to open, relative to this RegistryKey instance + * @param accessFlags [IN] flags indicating access granted to the returned RegistryKey + * @return This function returns a RegistryKey instance for the specified + * subkey. + */ + +RegistryKey *RegistryKey::openSubkey(const char *subkeyName, uint32 accessFlags) const +{ + REGSAM samDesired = 0; + LONG result; + HKEY newKey = 0; + + DEBUG_FATAL(!keyHandle, ("null keyHandle")); + DEBUG_FATAL(!subkeyName, ("null subkeyName arg")); + DEBUG_FATAL(!strlen(subkeyName), ("zero-length subkeyName arg")); + + // configure security access desired + if (accessFlags & AF_READ) + samDesired |= KEY_READ; + if (accessFlags & AF_WRITE) + samDesired |= KEY_WRITE; + + // open the key + result = RegOpenKeyEx(keyHandle, subkeyName, 0, samDesired, &newKey); + FATAL(result != ERROR_SUCCESS, ("failed to open registry subkey \"%s\", error = %ld\n", subkeyName, result)); + + // Create the RegistryKey object. Assume the key must be closed upon + // destruction. + return new RegistryKey(newKey, true); +} + +// ---------------------------------------------------------------------- +/** + * create and return a subkey under this RegistryKey instance. + * + * The function will succeed even if the specified subkey + * already exists. + * + * @return This function returns a RegistryKey instance for the specified + * subkey. + */ + +RegistryKey *RegistryKey::createSubkey(const char *subkeyName, uint32 accessFlags) const +{ + REGSAM samDesired = 0; + LONG result; + HKEY newKey = 0; + DWORD disposition; + + DEBUG_FATAL(!keyHandle, ("null keyHandle")); + DEBUG_FATAL(!subkeyName, ("null subkeyName arg")); + DEBUG_FATAL(!strlen(subkeyName), ("zero-length subkeyName arg")); + + // configure security access desired + if (accessFlags & AF_READ) + samDesired |= KEY_READ; + if (accessFlags & AF_WRITE) + samDesired |= KEY_WRITE; + + // open the key + result = RegCreateKeyEx( + keyHandle, + subkeyName, + 0, // reserved + const_cast(""), // class + REG_OPTION_NON_VOLATILE, // options + samDesired, + NULL, // security + &newKey, + &disposition); + FATAL(result != ERROR_SUCCESS, ("failed to create registry subkey \"%s\", error = %ld\n", subkeyName, result)); + + // Create the RegistryKey object. Assume the key must be closed upon + // destruction. + return new RegistryKey(newKey, true); +} + +// ---------------------------------------------------------------------- +/** + * delete a subkey relative to this RegistryKey instance. + * + * Under Windows NT, deleting a key that has subkeys is considered an + * error. Therefore, the client should ensure the target key for + * deletion does not have any subkeys. (Under Windows 9X, deletion of + * the target registry key will automatically delete all subkeys + * underneath the target key.) + */ + +void RegistryKey::deleteSubkey(const char *subkeyName) +{ + DEBUG_FATAL(!keyHandle, ("null keyHandle")); + DEBUG_FATAL(!subkeyName, ("null subkeyName arg")); + DEBUG_FATAL(!strlen(subkeyName), ("zero-length subkeyName arg")); + + IGNORE_RETURN(RegDeleteKey(keyHandle, subkeyName)); +} + +// ---------------------------------------------------------------------- +/** + * test for the existence of a subkey under this RegistryKey instance. + * + * @param subkeyName [IN] registry path for subkey to open, relative to this RegistryKey instance + */ + +bool RegistryKey::subKeyExists(const char *subkeyName) +{ + REGSAM samDesired = KEY_READ; + LONG result; + HKEY newKey = 0; + + DEBUG_FATAL(!keyHandle, ("null keyHandle")); + DEBUG_FATAL(!subkeyName, ("null subkeyName arg")); + DEBUG_FATAL(!strlen(subkeyName), ("zero-length subkeyName arg")); + + // open the key + result = RegOpenKeyEx(keyHandle, subkeyName, 0, samDesired, &newKey); + return (result == ERROR_SUCCESS); +} + +// ---------------------------------------------------------------------- +/** + * enumerate all values under the current key. + * + * @param context [IN] user-specified context variable passed to callback + * @param callback [IN] function to call for each value enumerated + * @see EnumerateValueCallback, enumerateSubkeys() + */ + +void RegistryKey::enumerateValues(void *context, EnumerateValueCallback callback) const +{ + const size_t MAX_NAME_LENGTH = 256; + + LONG result; + char valueName[MAX_NAME_LENGTH]; + DWORD valueNameLength; + DWORD index; + DWORD dataSize; + DWORD valueType; + + DEBUG_FATAL(!callback, ("null callback arg\n")); + + for ( + index = 0, valueNameLength = MAX_NAME_LENGTH, dataSize = 0; + ERROR_SUCCESS == (result = RegEnumValue(keyHandle, index, valueName, &valueNameLength, 0, &valueType, 0, &dataSize)); + ++index, valueNameLength = MAX_NAME_LENGTH, dataSize = 0 + ) + { + bool continueEnum = callback(context, valueName, static_cast(dataSize), valueType); + if (!continueEnum) break; + } + + // ensure we finished enumeration cleanly + FATAL( + (result != ERROR_SUCCESS) && (result != ERROR_NO_MORE_ITEMS), + ("failed to enumerate registry values, error = %ld\n", result)); +} + +// ---------------------------------------------------------------------- +/** + * query if a value exists and how many bytes that value occupies. + * + * The client does can pass null for the valueSize and/or valueType + * parameter if that information is not desired. The value returned + * within the valueSize and valueType parameter is only valid + * if the doesExist parameter is set to true upon function return. + * The value of the valueType parameter is one of the Windows-defined + * REG_* constants provided for use with the Win32 Reg* registry + * API. Common values are REG_BINARY (binary data), REG_DWORD + * (unsigned integral type data) and REG_SZ (C-style zero-terminated + * strings). Consult the Win32 documentation for RegGetValueEx() + * for a description of all the type constants. + * + * @param valueName [IN] name of the value to query + * @param doesExist [OUT] true if value exists under this key, false otherwise + * @param valueSize [OUT] number of bytes occupied by value's data + * @param valueType [OUT] type flag for registry value (see REG_* in RegSetValueEx()) + */ + +void RegistryKey::getValueInfo(const char *valueName, bool *doesExist, uint32 *valueSize, DWORD *valueType) const +{ + LONG result; + DWORD dwSize = 0; + + DEBUG_FATAL(!keyHandle, ("null keyHandle")); + DEBUG_FATAL(!valueName, ("null valueName arg")); + DEBUG_FATAL(!doesExist, ("null doesExist arg")); + DEBUG_FATAL(!strlen(valueName), ("zero-length valueName arg")); + + // get information on the value + result = RegQueryValueEx(keyHandle, valueName, 0, valueType, 0, &dwSize); + + // assume a query failure indicates the value was not found + *doesExist = (result == ERROR_SUCCESS); + if (valueSize) + *valueSize = static_cast(dwSize); +} + +// ---------------------------------------------------------------------- +/** + * set the data for this key's value. + * + * The value of the valueType parameter is one of the Windows-defined + * REG_* constants provided for use with the Win32 Reg* registry + * API. Common values are REG_BINARY (binary data), REG_DWORD + * (unsigned integral type data) and REG_SZ (C-style zero-terminated + * strings). Consult the Win32 documentation for RegGetValueEx() + * for a description of all the type constants. + * + * @param valueName [IN] name of value under which data will be stored + * @param dataPtr [IN] pointer to buffer containing value's data + * @param dataSize [IN] # bytes to store + * @param valueType [IN] type field for value (indicates nature of data stored with value) + */ + +void RegistryKey::setValue(const char *valueName, const void *dataPtr, uint32 dataSize, DWORD valueType) +{ + LONG result; + + DEBUG_FATAL(!keyHandle, ("null keyHandle")); + DEBUG_FATAL(!valueName, ("null valueName arg")); + DEBUG_FATAL(!strlen(valueName), ("zero-length valueName arg")); + DEBUG_FATAL(!dataPtr, ("null dataPtr arg")); + + // get information on the value + result = RegSetValueEx(keyHandle, valueName, 0, valueType, static_cast(dataPtr), static_cast(dataSize)); + FATAL(result != ERROR_SUCCESS, ("failed to set registry value \"%s\", error = %ld\n", valueName, result)); +} + +// ---------------------------------------------------------------------- +/** + * retrieve the data for the this key's value. + * + * The valueType and/or the valueDataSize parameter may be set + * to null if the client doesn't need this information. + * The value of the valueType parameter is one of the Windows-defined + * REG_* constants provided for use with the Win32 Reg* registry + * API. Common values are REG_BINARY (binary data), REG_DWORD + * (unsigned integral type data) and REG_SZ (C-style zero-terminated + * strings). Consult the Win32 documentation for RegGetValueEx() + * for a description of all the type constants. + * + * @param valueName [IN] the name of the value to retrieve + * @param dataPtr [OUT] the buffer where the value's data will be stored + * @param maxDataSize [IN] size of the data buffer in bytes + * @param valueDataSize [OUT] number of bytes retrieved from the named value + * @param valueType [OUT] type field for value's data (see REG_* codes in RegSetValueEx) + */ + +void RegistryKey::getValue(const char *valueName, void *dataPtr, uint32 maxDataSize, uint32 *valueDataSize, DWORD *valueType) const +{ + LONG result; + DWORD dwSize = maxDataSize; + + DEBUG_FATAL(!keyHandle, ("null keyHandle")); + DEBUG_FATAL(!valueName, ("null valueName arg")); + DEBUG_FATAL(!strlen(valueName), ("zero-length valueName arg")); + + // get information on the value + result = RegQueryValueEx(keyHandle, valueName, 0, valueType, static_cast(dataPtr), &dwSize); + FATAL(result != ERROR_SUCCESS, ("failed to read registry value \"%s\", error = %ld\n", valueName, result)); + + // assume a query failure indicates the value was not found + if (valueDataSize) + *valueDataSize = static_cast(dwSize); +} + +// ---------------------------------------------------------------------- +/** + * retrieve a string from of this key's values, returning a default string + * if the value doesn't exist. + * + * The defaultValue arg is required, must be non-null. + * + * If the specified value exists but is not of type REG_SZ, the default + * string will be returned. + * + * This routine will DEBUG_FATAL on null args, even if optional is set. + * Optional only controls whether a FATAL occurs if there is an issue + * retrieving the value. + * + * @param valueName [IN] name of the string value to retrieve + * @param defaultValue [IN] string to return if registry key does not contain thev value + * @param dest [OUT] buffer for returned string + * @param destSize [IN] max number of bytes (including terminating null) that can be placed in dest + * @param optional [IN] if set, the function will return false if there is a problem retrieving the value. otherwise, a DEBUG_FATAL will occur + */ + +bool RegistryKey::getStringValue(const char *valueName, const char *defaultValue, char *dest, DWORD destSize, bool optional) +{ + DEBUG_FATAL(!defaultValue, ("null defaultValue arg")); + DEBUG_FATAL(!dest, ("null dest arg")); + + bool doesExist; + DWORD valueType; + DWORD valueSize; + + // clear out string + memset(dest, 0, static_cast(destSize)); + + // get info on the value + getValueInfo (valueName, &doesExist, &valueSize, &valueType); + if (!doesExist || (valueType != REG_SZ)) + strncpy(dest, defaultValue, destSize-1); + else + { + // value exists and is a string, retrieve it + getValue (valueName, dest, destSize, &valueSize); + if (!valueSize) + { + FATAL(!optional, ("failed to get registry data for key %s\n", valueName)); + return false; + } + + // terminate the string + dest [valueSize] = 0; + } + return true; +} + + +// ---------------------------------------------------------------------- +/** + * delete a value from this registry key. + */ + +void RegistryKey::deleteValue(const char *valueName) +{ + LONG result; + + DEBUG_FATAL(!keyHandle, ("null keyHandle")); + DEBUG_FATAL(!valueName, ("null valueName arg")); + DEBUG_FATAL(!strlen(valueName), ("zero-length valueName arg")); + + result = RegDeleteValue(keyHandle, valueName); + FATAL(result != ERROR_SUCCESS, ("failed to delete registry value \"%s\", error = %ld\n", valueName, result)); +} + +#if USE_REGISTRY_EXECUTION_STATISTICS + +// ---------------------------------------------------------------------- +/** + * updates beginning-of-execution statistics using the values under a + * given key. + * + * Call this function at the beginning of execution of the code + * for which statistics are desired. At the end of execution, + * call updateShutdownKey() to finish generating statistics. + * This function should only be called once per execution, + * and should be followed by a call to updateShutdownKey(). + * If the latter is not called, the next call to updateStartupKey() + * will assume the application terminated abnormally before + * proper shutdown could occur. + */ + +void RegistryKey::updateStartupKey(RegistryKey *key) +{ + bool valueExist; + uint32 valueSize; + DWORD valueType; + DWORD execStartedCount = 0; + clock_t startTime = clock(); + + DEBUG_FATAL(!key, ("null key arg\n")); + + // handle improper shutdown of last run + key->getValueInfo(STAT_TIME_START_VALUENAME, &valueExist); + if (valueExist) + { + // appears the product did not run to completion on last run. + // increment the incomplete run counts + + DWORD execIncompleteCount = 0; + + key->getValueInfo(STAT_EXEC_INCOMPLETE_COUNT_VALUENAME, &valueExist); + if (valueExist) + { + key->getValue(STAT_EXEC_INCOMPLETE_COUNT_VALUENAME, &execIncompleteCount, sizeof(DWORD), &valueSize, &valueType); + DEBUG_FATAL((valueType != REG_DWORD) || (valueSize != sizeof(DWORD)), ("%s key not DWORD type as expected\n", STAT_EXEC_INCOMPLETE_COUNT_VALUENAME)); + } + ++execIncompleteCount; + key->setValue(STAT_EXEC_INCOMPLETE_COUNT_VALUENAME, &execIncompleteCount, sizeof(DWORD), REG_DWORD); + } + + // get the start count + key->getValueInfo(STAT_EXEC_STARTED_COUNT_VALUENAME, &valueExist); + if (valueExist) + { + key->getValue(STAT_EXEC_STARTED_COUNT_VALUENAME, &execStartedCount, sizeof(DWORD), &valueSize, &valueType); + DEBUG_FATAL((valueType != REG_DWORD) || (valueSize != sizeof(DWORD)), ("%s key not DWORD type as expected\n", STAT_EXEC_STARTED_COUNT_VALUENAME)); + } + ++execStartedCount; + + // save the data + key->setValue(STAT_EXEC_STARTED_COUNT_VALUENAME, &execStartedCount, sizeof(DWORD), REG_DWORD); + key->setValue(STAT_TIME_START_VALUENAME, &startTime, sizeof(clock_t)); +} + +#endif + + +#if USE_REGISTRY_EXECUTION_STATISTICS + +// ---------------------------------------------------------------------- +/** + * updates end-of-execution statistics using the values under a given key. + * + * This function should only be called after updateStartupKey() + * has been called on the same key. After this call returns, + * this function should not be called again until another + * call to updateStartupKey() is made. + */ + +void RegistryKey::updateShutdownKey(RegistryKey *key) +{ + bool valueExist; + uint32 valueSize; + DWORD valueType; + clock_t minTime; + clock_t maxTime; + clock_t averageTime = 0; + clock_t startTime; + clock_t stopTime = clock(); + clock_t runTime; + DWORD startExecCount; + DWORD incompleteExecCount = 0; + DWORD completeExecCount; + real averageFraction; + + DEBUG_FATAL(!key, ("null key arg\n")); + + // find the number of complete execution runs of the product + key->getValue(STAT_EXEC_STARTED_COUNT_VALUENAME, &startExecCount, sizeof(DWORD), &valueSize, &valueType); + DEBUG_FATAL((valueSize != sizeof(DWORD)) || (valueType != REG_DWORD), ("invalid start count statistic registry value\n")); + + key->getValueInfo(STAT_EXEC_INCOMPLETE_COUNT_VALUENAME, &valueExist); + if (valueExist) + { + key->getValue(STAT_EXEC_INCOMPLETE_COUNT_VALUENAME, &incompleteExecCount, sizeof(DWORD), &valueSize, &valueType); + DEBUG_FATAL((valueType != REG_DWORD) || (valueSize != sizeof(DWORD)), ("%s expected to be DWORD type, was %lu instead\n", STAT_EXEC_INCOMPLETE_COUNT_VALUENAME, valueType)); + } + completeExecCount = startExecCount - incompleteExecCount; + + // retrieve the start time + key->getValue(STAT_TIME_START_VALUENAME, &startTime, sizeof(clock_t), &valueSize, &valueType); + DEBUG_FATAL((valueSize != sizeof(clock_t)) || (valueType != REG_BINARY), ("invalid start time statistic registry value\n")); + + // -qq- we don't handle clock wraparound + runTime = stopTime - startTime; + minTime = runTime; + maxTime = runTime; + + // calculate average time + key->getValueInfo(STAT_TIME_AVERAGE_VALUENAME, &valueExist); + if (valueExist) + { + key->getValue(STAT_TIME_AVERAGE_VALUENAME, &averageTime, sizeof(clock_t), &valueSize, &valueType); + DEBUG_FATAL((valueSize != sizeof(clock_t)) || (valueType != REG_BINARY), ("invalid average exec time statistic registry value\n")); + } + averageFraction = CONST_REAL(1.0 / completeExecCount); + averageTime = static_cast(( CONST_REAL(averageTime) * (completeExecCount-1) + runTime) * averageFraction); + if (averageTime < 1) + averageTime = 1; + + // check min exec time + key->getValueInfo(STAT_TIME_MIN_VALUENAME, &valueExist); + if (valueExist) + { + clock_t testValue; + key->getValue(STAT_TIME_MIN_VALUENAME, &testValue, sizeof(clock_t), &valueSize, &valueType); + DEBUG_FATAL((valueSize != sizeof(clock_t)) || (valueType != REG_BINARY), ("invalid min exec time statistic registry value\n")); + if (testValue < minTime) + minTime = testValue; + } + + // check for max exec time + key->getValueInfo(STAT_TIME_MAX_VALUENAME, &valueExist); + if (valueExist) + { + clock_t testValue; + key->getValue(STAT_TIME_MAX_VALUENAME, &testValue, sizeof(clock_t), &valueSize, &valueType); + DEBUG_FATAL((valueSize != sizeof(clock_t)) || (valueType != REG_BINARY), ("invalid max exec time statistic registry value\n")); + if (testValue > maxTime) + maxTime = testValue; + } + + // save the data + key->setValue(STAT_TIME_AVERAGE_VALUENAME, &averageTime, sizeof(clock_t)); + key->setValue(STAT_TIME_MIN_VALUENAME, &minTime, sizeof(clock_t)); + key->setValue(STAT_TIME_MAX_VALUENAME, &maxTime, sizeof(clock_t)); + + // delete the start time value + key->deleteValue(STAT_TIME_START_VALUENAME); +} + +#endif + + +#if USE_REGISTRY_EXECUTION_STATISTICS + +// ---------------------------------------------------------------------- +/** + * An EnumValueCallback that prints each value name, type and size + * + * @param valueName name of value + * @param valueSize size of value in bytes + * @param valueTye type of value + */ + +bool RegistryKey::enumValueInfoPrint( + void*, // unused user context + const char *valueName, + uint32 valueSize, + DWORD valueType + ) +{ + char *valueTypeStr; + char buffer[64]; + + switch (valueType) + { + case REG_BINARY: + valueTypeStr = "REG_BINARY"; + break; + case REG_DWORD: + valueTypeStr = "REG_DWORD [little endian]"; + break; + case REG_DWORD_BIG_ENDIAN: + valueTypeStr = "REG_DWORD_BIG_ENDIAN"; + break; + case REG_EXPAND_SZ: + valueTypeStr = "REG_EXPAND_SZ"; + break; + case REG_NONE: + valueTypeStr = "REG_NONE"; + break; + case REG_SZ: + valueTypeStr = "REG_SZ"; + break; + default: + valueTypeStr = buffer; + sprintf(buffer, "", valueType); + break; + } + + DEBUG_PRINT_LOG(true, (" Key: \"%s\", %s, %u bytes\n", valueName, valueTypeStr, valueSize)); + + // continue enumerating + return true; +} + +#endif + + +#if USE_REGISTRY_EXECUTION_STATISTICS + +// ---------------------------------------------------------------------- +/** + * Update per-startup registry values. + * + * This routine is used primarily to test registry read/write + * functionality; however, it does provide statistics related + * to game usage. These include the following statistics on + * a per-game and per-machine basis: + * # times product was executed + * average real-time duration of execution + * minimum execution time + * maximum execution time + * # times product failed to execute to completion + * (i.e. updateRegistryShutdown() never executed---hard crash, stop debugging) + */ + +void RegistryKey::updateStartupStatistics(void) +{ + DEBUG_FATAL(!productUserKey, ("null productUserKey\n")); + DEBUG_FATAL(!productMachineKey, ("null productMachineKey\n")); + + // create required keys + RegistryKey *userStatKey = productUserKey->createSubkey(STATISTICS_KEYNAME); + RegistryKey *machineStatKey = productMachineKey->createSubkey(STATISTICS_KEYNAME); + + FATAL(!userStatKey, ("failed to create user statistics key")); + FATAL(!machineStatKey, ("failed to create machine statistics key")); + + // handle machine stat key + +#if 1 + // print existing machine stat keys + DEBUG_PRINT_LOG(true, ("BEGIN machine stat key enumeration:\n")); + machineStatKey->enumerateValues(0, enumValueInfoPrint); + DEBUG_PRINT_LOG(true, ("END machine stat key enumeration:\n")); +#endif + + updateStartupKey(machineStatKey); + + + // handle user stat key + +#if 1 + // print existing user stat keys + DEBUG_PRINT_LOG(true, ("BEGIN user stat key enumeration:\n")); + userStatKey->enumerateValues(0, enumValueInfoPrint); + DEBUG_PRINT_LOG(true, ("END user stat key enumeration:\n")); +#endif + + updateStartupKey(userStatKey); + + // cleanup + delete machineStatKey; + delete userStatKey; +} + +#endif + + +#if USE_REGISTRY_EXECUTION_STATISTICS + +// ---------------------------------------------------------------------- +/** + * Update per-shutdown registry values. + * + * @see updateRegistryStartup() + */ + +void RegistryKey::updateShutdownStatistics(void) +{ + DEBUG_FATAL(!productUserKey, ("null productUserKey\n")); + DEBUG_FATAL(!productMachineKey, ("null productMachineKey\n")); + + // create required keys + RegistryKey *userStatKey = productUserKey->createSubkey(STATISTICS_KEYNAME); + RegistryKey *machineStatKey = productMachineKey->createSubkey(STATISTICS_KEYNAME); + + FATAL(!userStatKey, ("failed to create user statistics key")); + FATAL(!machineStatKey, ("failed to create machine statistics key")); + + // handle machine stat key + updateShutdownKey(machineStatKey); + + // handle user stat key + updateShutdownKey(userStatKey); + + // cleanup + delete machineStatKey; + delete userStatKey; +} + +#endif + +// ---------------------------------------------------------------------- +/** + * install the RegistryKey class. + * + * After installation, the following predefined keys are available: + * + * usersKey: HKEY_USERS + * currentUserKey: HKEY_CURRENT_USER + * classRootKey: HKEY_CLASSES_ROOT + * localMachineKey: HKEY_LOCAL_MACHINE + * productUserKey: HKEY_CURENT_USER\ + * productMachineKey: HKEY_LOCAL_MACHINE\ + * + * The client is free to create any other keys required. + * + * The product relative registry path is determined by the first of the + * following methods that succeed: + * 1. If the config file key "ProductRegistryPath" is set, that value is + * used for the relative path. If the product relative path is set + * in this manner, the client's attempt to change the product relative + * path via the setProductKey() function will silently fail. + * 2. If the productKeyRelativePath parameter is a non-null positive length + * string, that value is used as the product keys' relative path. + * 3. The default value DEFAULT_PRODUCT_REGISTRY_PATH ("Software\\Bootprint\\Default") + * is used. + * + * RegistryKey::remove() is added to the exit chain. + * + * Do not delete any of the predefined registry keys. + * + * @param productKeyRelativePath [IN] relative registry path for the product keys + * @see setProductKeyPath() + */ + +void RegistryKey::install(const char *productKeyRelativePath) +{ + UNREF(productKeyRelativePath); + char *useRegistryPath = 0; + + DEBUG_FATAL(installed, ("attempted to install RegistryKey when already installed\n")); + installed = true; + + // add to exit chain + ExitChain::add(remove, "RegistryKey::remove", 0, true); + + // if no passed in value, use the default + setProductKeyPathFromConfig = false; + useRegistryPath = DuplicateString(DEFAULT_PRODUCT_REGISTRY_PATH); + + // create the Windows-defined RegistryKeys (these keys don't get closed at object destruction time) + usersKey = new RegistryKey(HKEY_USERS, false); //lint !e1924 // Note -- C-style cast + currentUserKey = new RegistryKey(HKEY_CURRENT_USER, false); //lint !e1924 // Note -- C-style cast + classRootKey = new RegistryKey(HKEY_CLASSES_ROOT, false); //lint !e1924 // Note -- C-style cast + localMachineKey = new RegistryKey(HKEY_LOCAL_MACHINE, false); //lint !e1924 // Note -- C-style cast + + // check for errors --- unnecessary if new cannot return NULL + FATAL( + !usersKey || !currentUserKey || !classRootKey || !localMachineKey, + ("failed to create standard RegistryKey objects")); + + // create/open the product user key + productUserKey = currentUserKey->createSubkey(useRegistryPath, AF_READ | AF_WRITE); + + // create/open the product machine key + productMachineKey = localMachineKey->createSubkey(useRegistryPath, AF_READ); + + delete [] useRegistryPath; + +#if USE_REGISTRY_EXECUTION_STATISTICS + updateStartupStatistics(); +#endif +} + +// ---------------------------------------------------------------------- +/** + * release all resources and state associated with the RegistryKey system. + * + * It is invalid to call any RegistryKey functions other than install() + * after calling remove(). + */ + +void RegistryKey::remove(void) +{ +#if USE_REGISTRY_EXECUTION_STATISTICS + updateShutdownStatistics(); +#endif + + DEBUG_FATAL(!installed, ("attempted to remove RegistryKey when not installed\n")); + installed = false; + + delete productMachineKey; + delete productUserKey; + delete localMachineKey; + delete classRootKey; + delete currentUserKey; + delete usersKey; + + productMachineKey = 0; + productUserKey = 0; + localMachineKey = 0; + classRootKey = 0; + currentUserKey = 0; + usersKey = 0; + +} + +// ---------------------------------------------------------------------- +/** + * reset the path to the product's machine and user keys. + * + * This routine will redefine the following keys: + * productUserKey: HKEY_CURENT_USER\ + * productMachineKey: HKEY_LOCAL_MACHINE\ + * + * If the product key relative paths were specified in the config + * file, this routine will essentially do nothing --- the client + * is not able to ovveride the config file settings. + */ + +void RegistryKey::setProductKeyPath(const char *productKeyRelativePath) +{ + DEBUG_FATAL( + !productKeyRelativePath || !productKeyRelativePath[0], + ("invalid productKeyRelativePath arg\n")); + + // don't allow client to overwrite if path set by config file + if (setProductKeyPathFromConfig) + { + DEBUG_REPORT_LOG_PRINT(true, ("attempted to set product registry key path to '%s' but config file setting will override\n", productKeyRelativePath)); + return; + } + + delete productUserKey; + delete productMachineKey; + + productUserKey = currentUserKey->createSubkey(productKeyRelativePath, AF_READ | AF_WRITE); + productMachineKey = localMachineKey->createSubkey(productKeyRelativePath, AF_READ | AF_WRITE); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/win32/RegistryKey.h b/engine/shared/library/sharedFoundation/src/win32/RegistryKey.h new file mode 100644 index 00000000..9c885194 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/RegistryKey.h @@ -0,0 +1,270 @@ +#ifndef REGISTRY_KEY_H +#define REGISTRY_KEY_H + +// ====================================================================== +// +// RegistryKey.h +// Todd Fiala +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +// provide read and write access to the Windows Registry +// +// Remarks: +// +// Each RegistryKey can create or open a subkey relative to that +// key. This process produces another RegistryKey. RegistryKeys +// provide a mechanism to enumerate all the child subkeys and values +// associated with the key. In addition, clients may query for +// the presence, type and size of a specific value, get a specific +// value's data, and set a named value's data and type. +// +// The RegistryKey class provides the client with six RegistryKey +// objects as starting points into the registry. See documentation +// for install() for more info on these starting points. +// +// The client must install() the RegistryKey class before using it. + +class RegistryKey +{ +public: + // ---------------------------------------------------------------------- + // flags used to indicate what type of access (e.g. read, write) should + // be granted when creating or opening a key. + // + // See Also: + // + // createSubkey(), openSubkey() + + enum // AccessFlags + { + AF_READ = BINARY1(0001), // query values, enumerate subkeys + AF_WRITE = BINARY1(0010) // set values, create subkeys + }; + + // ---------------------------------------------------------------------- + // callback prototype for subkey enumeration + // + // Return Value: + // + // A return value of true indicates the enumeration of subkeys should + // continue. A return value of false stops further enumeration of + // subkeys. + // + // Remarks: + // + // The context parameter is specified in the call to + // enumerateSubkeys(). One use for this could be to pass a class + // instance, with the callack defined as a static member function. + // The function can then cast the context to a pointer to class + // instance, allowing the static function to access per-instance + // data explicitly in place of an assumed this pointer. + // + // See Also: + // + // enumerateSubkeys() + + typedef bool (*EnumerateKeyCallback)( + void *context, // [IN] user-specified context variable + const char *keyName, // [IN] name of the key being enumerated + const FILETIME *lastWriteTime // [IN] last time this key was modified + ); + + // ---------------------------------------------------------------------- + // callback prototype for value enumeration + // + // Return Value: + // + // A return value of true indicates the enumeration of values should + // continue. A return value of false stops further enumeration of + // values . + // + // Remarks: + // + // The context parameter is specified in the call to + // enumerateValues(). One use for this could be to pass a class + // instance, with the callack defined as a static member function. + // The function can then cast the context to a pointer to class + // instance, allowing the static function to access per-instance + // data explicitly in place of an assumed this pointer. + // + // See Also: + // + // enumerateValues() + + typedef bool (*EnumerateValueCallback)( + void *context, // [IN] user-specified context variable + const char *valueName, // [IN] name of the value being enumerated + uint32 valueSize, // [IN] number of bytes occupied by this value's data + DWORD valueType // [IN] type of value (one of REG_* as in RegSetValueEx documentation) + ); + +private: + static const char * const PRODUCT_REGISTRY_PATH_KEYNAME; + static const char * const DEFAULT_PRODUCT_REGISTRY_PATH; + +#if USE_REGISTRY_EXECUTION_STATISTICS + static const char * const STATISTICS_KEYNAME; + static const char * const STAT_EXEC_STARTED_COUNT_VALUENAME; + static const char * const STAT_EXEC_INCOMPLETE_COUNT_VALUENAME; + static const char * const STAT_TIME_AVERAGE_VALUENAME; + static const char * const STAT_TIME_MIN_VALUENAME; + static const char * const STAT_TIME_MAX_VALUENAME; + static const char * const STAT_TIME_START_VALUENAME; +#endif + + static bool installed; + static bool setProductKeyPathFromConfig; + + // private instance member variables + HKEY keyHandle; + bool closeKeyOnDestroy; + +private: + // public member variables + static RegistryKey *usersKey; + static RegistryKey *currentUserKey; + static RegistryKey *classRootKey; + static RegistryKey *localMachineKey; + static RegistryKey *productUserKey; + static RegistryKey *productMachineKey; + +private: + // private member functions + static void remove(void); + RegistryKey(HKEY newKeyHandle, bool newCloseKeyOnDestroy); + +#if USE_REGISTRY_EXECUTION_STATISTICS + static void updateStartupKey(RegistryKey *key); + static void updateShutdownKey(RegistryKey *key); + static bool enumValueInfoPrint(void *context, const char *valueName, uint32 valueSize, DWORD valueType); + + static void updateStartupStatistics(void); + static void updateShutdownStatistics(void); +#endif + +private: + // disable: default constructor, copy constructor, assignment operator + // NOTE: last two can be implemented, but must be specially handled + RegistryKey(void); + RegistryKey(const RegistryKey&); + RegistryKey &operator =(const RegistryKey&); + +public: + // public member functions + + static void install(const char *productKeyRelativePath = 0); + static void setProductKeyPath(const char *productKeyRelativePath); + + // pre-defined RegistryKey retrieval + static RegistryKey *getUsersKey(void); + static RegistryKey *getCurrentUserKey(void); + static RegistryKey *getClassRootKey(void); + static RegistryKey *getLocalMachineKey(void); + static RegistryKey *getProductUserKey(void); + static RegistryKey *getProductMachineKey(void); + + ~RegistryKey(void); + + // subkey interface + void enumerateSubkeys(void *context, EnumerateKeyCallback callback) const; + RegistryKey *openSubkey(const char *subkeyName, uint32 accessFlags = AF_READ) const; + RegistryKey *createSubkey(const char *subkeyName, uint32 accessFlags = AF_READ | AF_WRITE) const; + void deleteSubkey(const char *subkeyName); + bool subKeyExists(const char *subkeyName); + + // value interface + void enumerateValues(void *context, EnumerateValueCallback callback) const; + void setValue(const char *valueName, const void *dataPtr, uint32 dataSize, DWORD valueType = REG_BINARY); + void deleteValue(const char *valueName); + + void getValueInfo(const char *valueName, bool *doesExist, uint32 *valueSize = 0, DWORD *valueType = 0) const; + void getValue(const char *valueName, void *dataPtr, uint32 maxDataSize, uint32 *valueDataSize, DWORD *valueType = 0) const; + bool getStringValue(const char *valueName, const char *defaultValue, char *dest, DWORD destSize, bool optional = false); + +}; + +// ====================================================================== +// retrieve a key to the HKEY_USERS registry key with read access + +inline RegistryKey *RegistryKey::getUsersKey(void) +{ + DEBUG_FATAL(!installed, ("Attempted to use RegistryKey when not installed\n")); + return usersKey; +} + +// ---------------------------------------------------------------------- +/** + * retrieve a key to the HKEY_CURRENT_USER registry key with read/write + * access. + */ + +inline RegistryKey *RegistryKey::getCurrentUserKey(void) +{ + DEBUG_FATAL(!installed, ("Attempted to use RegistryKey when not installed\n")); + return currentUserKey; +} + +// ---------------------------------------------------------------------- +/** + * retrieve a key to the HKEY_CLASSES_ROOT registry key with read/write + * access. + */ + +inline RegistryKey *RegistryKey::getClassRootKey(void) +{ + DEBUG_FATAL(!installed, ("Attempted to use RegistryKey when not installed\n")); + return classRootKey; +} + +// ---------------------------------------------------------------------- +/** + * retrieve a key to the HKEY_LOCAL_MACHINE registry key with read/write + * access. + */ + +inline RegistryKey *RegistryKey::getLocalMachineKey(void) +{ + DEBUG_FATAL(!installed, ("Attempted to use RegistryKey when not installed\n")); + return localMachineKey; +} + +// ---------------------------------------------------------------------- +/** + * retrieve a key to the product's user key with read/write access. + * + * The product user key is the root key for storing user-specific + * product-related information. install() describes where this + * information exists in the registry. + * + * @see install(), getProductMachineKey() + */ + +inline RegistryKey *RegistryKey::getProductUserKey(void) +{ + DEBUG_FATAL(!installed, ("Attempted to use RegistryKey when not installed\n")); + return productUserKey; +} + +// ---------------------------------------------------------------------- +/** + * retrieve a key to the product's machine key with read/write access. + * + * The product machine key is the root key for storing machine-specific + * product-related information. install() describes where this + * information exists in the registry. + * + * @see install(), getProductUserKey() + */ + +inline RegistryKey *RegistryKey::getProductMachineKey(void) +{ + DEBUG_FATAL(!installed, ("Attempted to use RegistryKey when not installed\n")); + return productMachineKey; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/win32/SetupSharedFoundation.cpp b/engine/shared/library/sharedFoundation/src/win32/SetupSharedFoundation.cpp new file mode 100644 index 00000000..98889b52 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/SetupSharedFoundation.cpp @@ -0,0 +1,410 @@ +// ====================================================================== +// +// SetupSharedFoundation.cpp +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/SetupSharedFoundation.h" + +#include "sharedDebug/DebugMonitor.h" +#include "sharedDebug/InstallTimer.h" +#include "sharedDebug/Profiler.h" + +#include "sharedFoundation/ApplicationVersion.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/CommandLine.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedFoundation/CrashReportInformation.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/Os.h" +#include "sharedFoundation/Production.h" +#include "sharedFoundation/RegistryKey.h" +#include "sharedFoundation/StaticCallbackEntry.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedFoundation/Watcher.h" +#include "sharedLog/TailFileLogObserver.h" + +#include +#include + +// ====================================================================== + +namespace FatalNamespace +{ + extern char ms_buffer[32 * 1024]; +} + +namespace SetupSharedFoundationNamespace +{ + LONG __stdcall MyUnhandledExceptionFilter(LPEXCEPTION_POINTERS exceptionPointers); + + bool ms_writeMiniDumps; +} + +using namespace SetupSharedFoundationNamespace; + +// ====================================================================== + +LONG __stdcall SetupSharedFoundationNamespace::MyUnhandledExceptionFilter(LPEXCEPTION_POINTERS exceptionPointers) +{ + // make the routine somewhat safe from re-entrance + static bool entered = false; + if (entered) + return EXCEPTION_CONTINUE_SEARCH; + entered = true; + + // log some important information + static char buffer[128]; + sprintf(buffer, "Exception %08x(%d)=code %08x=addr\n", exceptionPointers->ExceptionRecord->ExceptionCode, exceptionPointers->ExceptionRecord->ExceptionCode, exceptionPointers->ExceptionRecord->ExceptionAddress); + OutputDebugString(buffer); + + // write the minidump if we're in here for the first time + static bool ms_alreadyWroteMiniDump = false; + if (ms_writeMiniDumps && !ms_alreadyWroteMiniDump) + { + ms_alreadyWroteMiniDump = true; + + uint64 timestamp; + time_t now; + tm t; + + IGNORE_RETURN(time(&now)); + IGNORE_RETURN(gmtime_r(&now, &t)); + timestamp = t.tm_year+1900; //lint !e732 !e737 !e776 + timestamp *= 100; + timestamp += t.tm_mon+1; //lint !e737 !e776 + timestamp *= 100; + timestamp += static_cast(t.tm_mday); + timestamp *= 100; + timestamp += static_cast(t.tm_hour); + timestamp *= 100; + timestamp += static_cast(t.tm_min); + timestamp *= 100; + timestamp += static_cast(t.tm_sec); + + static char fileName[512]; + + sprintf(fileName, "%s-%s-%I64d.txt", Os::getShortProgramName(), ApplicationVersion::getInternalVersion(), timestamp); + HANDLE const file = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL); + if (file != INVALID_HANDLE_VALUE) + { + char text1[] = "automated crash dump from "; + DWORD bytesWritten; + WriteFile(file, text1, strlen(text1), &bytesWritten, NULL); + + char const * text2 = Os::getShortProgramName(); + WriteFile(file, text2, strlen(text2), &bytesWritten, NULL); + + char text3[] = " "; + WriteFile(file, text3, strlen(text3), &bytesWritten, NULL); + + char const * text4 = ApplicationVersion::getInternalVersion(); + WriteFile(file, text4, strlen(text4), &bytesWritten, NULL); + + char text5[] = "\n\n\n"; + WriteFile(file, text5, strlen(text5), &bytesWritten, NULL); + + if (exceptionPointers->ExceptionRecord->ExceptionCode == 0x80000003) + { + // write out the fatal buffer + char const * text6 = FatalNamespace::ms_buffer; + WriteFile(file, text6, strlen(text6), &bytesWritten, NULL); + } + else + { + char const * text6 = buffer; + WriteFile(file, text6, strlen(text6), &bytesWritten, NULL); + } + + char text7[] = "\n\n"; + WriteFile(file, text7, strlen(text7), &bytesWritten, NULL); + + char const * text8 = ""; + for (int i = 0; text8; ++i) + { + text8 = CrashReportInformation::getEntry(i); + if (text8) + { + int const text8Length = strlen(text8); + if (text8Length) + WriteFile(file, text8, text8Length, &bytesWritten, NULL); + } + } + + CloseHandle(file); + } + + sprintf(fileName, "%s-%s-%I64d.mdmp", Os::getShortProgramName(), ApplicationVersion::getInternalVersion(), timestamp); + OutputDebugString("Generating minidump "); + OutputDebugString(fileName); + OutputDebugString("\n"); + DebugHelp::writeMiniDump(fileName, exceptionPointers); + + sprintf(fileName, "%s-%s-%I64d.log", Os::getShortProgramName(), ApplicationVersion::getInternalVersion(), timestamp); + TailFileLogObserver::flushAllTailFileLogObservers(fileName); + } + + // tell the Os not to abort so we can rethrow the exception + Os::returnFromAbort(); + + // Let the ExitChain do its job + Fatal("ExceptionHandler invoked"); + + // rethrow the exception so that the debugger can catch it + entered = false; + return EXCEPTION_CONTINUE_SEARCH; //lint !e527 // Unreachable +} + +// ---------------------------------------------------------------------- + +static void setFatalVersionString() +{ + char buffer[256]; + sprintf(buffer, "%s: %s\n", Os::getShortProgramName(), ApplicationVersion::getInternalVersion()); + FatalSetVersionString(buffer); +} + +// ====================================================================== +// Install the engine +// +// Remarks: +// +// The settings in the Data structure will determine which subsystems +// get initialized. + +void SetupSharedFoundation::install(const Data &data) +{ + InstallTimer const installTimer("SetupSharedFoundation::install"); + + DEBUG_REPORT_LOG(true, ("SetupSharedFoundation::install: version %s\n", ApplicationVersion::getInternalVersion())); + + ms_writeMiniDumps = data.writeMiniDumps; + SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); + + // and get the command line stuff in quick so we can make decisions based on the command line settings + CommandLine::install(); + + // feed CommandLine with appropriate strings + if (data.commandLine) + CommandLine::absorbString(data.commandLine); + if (data.argc) + CommandLine::absorbStrings(const_cast(data.argv+1), data.argc-1); + + // load the config file + ConfigFile::install(); + if (data.configFile) + IGNORE_RETURN(ConfigFile::loadFile(data.configFile)); + + // get the post command-line text for the ConfigFile (key-value pairs) + const char *configString = CommandLine::getPostCommandLineString(); + if (configString) + { + IGNORE_RETURN(ConfigFile::loadFromCommandLine(configString)); + } + + // @todo codereorg should this be here? + MemoryManager::registerDebugFlags(); +#if PRODUCTION == 0 + Profiler::registerDebugFlags(); +#endif + FatalInstall(); + + // @todo move these, it's part of sharedDebug. However, sharedDebug is installed before sharedFoundation, but these need the ConfigFile. ugh. +#if PRODUCTION == 0 + DebugMonitor::install(); +#endif + SetWarningStrictFatal(ConfigFile::getKeyBool("SharedDebug", "strict", false)); + + { + ConfigSharedFoundation::Defaults defaults; + defaults.frameRateLimit = data.frameRateLimit; + defaults.demoMode = data.demoMode; + defaults.verboseWarnings = data.verboseWarnings; + ConfigSharedFoundation::install(defaults); + + if (ConfigSharedFoundation::getCauseAccessViolation()) + static_cast(0)[0] = 0; + } + + // @todo codereorg should this be here? +#ifdef _DEBUG + MemoryManager::setReportAllocations (ConfigSharedFoundation::getMemoryManagerReportAllocations ()); +#endif + + MemoryBlockManager::install (ConfigSharedFoundation::getMemoryBlockManagerDebugDumpOnRemove ()); + + ExitChain::install(); + Report::install(); + Clock::install(data.clockUsesSleep, data.clockUsesRecalibrationThread); + CrashReportInformation::install(); + RegistryKey::install(data.productRegistryKey); + + PersistentCrcString::install(); + CrcLowerString::install(); + + WatchedByList::install(); + + if (data.createWindow) + { + DEBUG_FATAL(data.useWindowHandle, ("exactly one of createWindow and useWindowHandle must be true")); + Os::install(data.hInstance, data.windowName, data.windowNormalIcon, data.windowSmallIcon); + } + else + { + if (data.useWindowHandle) + Os::install(data.windowHandle, data.processMessagePump); + else + Os::install(); + } + + StaticCallbackEntry::install(); + + setFatalVersionString(); +} + +// ---------------------------------------------------------------------- +// Call a function with appropriate exception handling +// +// Remarks: +// +// If exception handling has been disabled in the config file, this routine +// will call the callback without exception handling. + +void SetupSharedFoundation::callbackWithExceptionHandling( + void (*callback)(void) // Routine to call with exception handling + ) +{ + callback(); +} + +// ---------------------------------------------------------------------- +// Uninstall the engine +// +// Remarks: +// +// This routine will properly uninstall the engine componenets that were +// installed by SetupSharedFoundation::install(). + +void SetupSharedFoundation::remove(void) +{ + ExitChain::quit(); + + if (!ConfigSharedFoundation::getDemoMode() && GetNumberOfWarnings()) + REPORT(true, Report::RF_print | Report::RF_log | Report::RF_dialog, ("%d warnings logged", GetNumberOfWarnings())); +} + +// ====================================================================== + +SetupSharedFoundation::Data::Data(Defaults defaults) +{ + Zero(*this); + + switch (defaults) + { + case D_console: setupConsoleDefaults(); break; + case D_game: setupGameDefaults(); break; + case D_mfc: setupMfcDefaults(); break; + default: DEBUG_FATAL(true, ("invalid enum value")); + } +} + +// ---------------------------------------------------------------------- + +void SetupSharedFoundation::Data::setupGameDefaults() +{ + createWindow = true; + windowName = NULL; + windowNormalIcon = NULL; + windowSmallIcon = NULL; + hInstance = NULL; + useWindowHandle = false; + processMessagePump = true; + windowHandle = NULL; + clockUsesSleep = false; + clockUsesRecalibrationThread = true; + writeMiniDumps = false; + + commandLine = NULL; + argc = 0; + argv = NULL; + + configFile = NULL; + + productRegistryKey = NULL; + + frameRateLimit = CONST_REAL(0); + + lostFocusCallback = NULL; + + demoMode = false; + verboseWarnings = false; +} + +// ---------------------------------------------------------------------- + +void SetupSharedFoundation::Data::setupConsoleDefaults() +{ + createWindow = false; + windowName = NULL; + windowNormalIcon = NULL; + windowSmallIcon = NULL; + hInstance = NULL; + useWindowHandle = false; + processMessagePump = true; + windowHandle = NULL; + clockUsesSleep = false; + clockUsesRecalibrationThread = false; + writeMiniDumps = false; + + commandLine = NULL; + argc = NULL; + argv = NULL; + + configFile = NULL; + + productRegistryKey = NULL; + + frameRateLimit = CONST_REAL(0); + + lostFocusCallback = NULL; + + demoMode = false; + verboseWarnings = false; +} + +// ---------------------------------------------------------------------- + +void SetupSharedFoundation::Data::setupMfcDefaults() +{ + createWindow = false; + windowName = NULL; + windowNormalIcon = NULL; + windowSmallIcon = NULL; + hInstance = NULL; + useWindowHandle = false; + processMessagePump = true; + windowHandle = NULL; + clockUsesSleep = false; + clockUsesRecalibrationThread = false; + writeMiniDumps = false; + + commandLine = NULL; + argc = 0; + argv = NULL; + + configFile = NULL; + + productRegistryKey = NULL; + + frameRateLimit = CONST_REAL(0); + + demoMode = false; + verboseWarnings = false; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedFoundation/src/win32/SetupSharedFoundation.h b/engine/shared/library/sharedFoundation/src/win32/SetupSharedFoundation.h new file mode 100644 index 00000000..b0675d8f --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/SetupSharedFoundation.h @@ -0,0 +1,99 @@ +// ====================================================================== +// +// SetupSharedFoundation.h +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_SetupSharedFoundation_H +#define INCLUDED_SetupSharedFoundation_H + +// ====================================================================== + +class SetupSharedFoundation +{ +public: + + struct Data + { + typedef void (*LostFocusCallbackFuction)(); + + // window creation stuff + bool createWindow; + const char *windowName; + HICON windowNormalIcon; + HICON windowSmallIcon; + HINSTANCE hInstance; + + // window use stuff + bool useWindowHandle; + bool processMessagePump; + HWND windowHandle; + + bool writeMiniDumps; + + bool clockUsesSleep; + bool clockUsesRecalibrationThread; + + // pointer to command line + const char *commandLine; + int argc; + char **argv; + + // name of the config file to lead + const char *configFile; + + // registry stuff + const char *productRegistryKey; + + real frameRateLimit; + + + bool demoMode; + + bool verboseWarnings; + + LostFocusCallbackFuction lostFocusCallback; + + public: + + enum Defaults + { + D_console, + D_game, + D_mfc + }; + + Data(Defaults defaults); + + private: + + Data(); + + void setupGameDefaults(); + void setupConsoleDefaults(); + void setupMfcDefaults(); + }; + +public: + + typedef void (*MainFunction)(); + +public: + + static void install(const Data &data); + static void remove(void); + + static void callbackWithExceptionHandling(MainFunction mainFunction); + +private: + + SetupSharedFoundation(); + SetupSharedFoundation(const SetupSharedFoundation &); + SetupSharedFoundation &operator =(const SetupSharedFoundation &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedFoundation/src/win32/WindowsWrapper.h b/engine/shared/library/sharedFoundation/src/win32/WindowsWrapper.h new file mode 100644 index 00000000..88b64ed5 --- /dev/null +++ b/engine/shared/library/sharedFoundation/src/win32/WindowsWrapper.h @@ -0,0 +1,51 @@ +// ====================================================================== +// +// WindowsWrapper.h +// copyright (c) 1998 Bootprint Entertainment +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_WindowsWrapper_H +#define INCLUDED_WindowsWrapper_H + +// ====================================================================== + +// C4201 nonstandard extension used : nameless struct/union +#pragma warning(disable: 4201) + +// make windows.h more strict in the types of handles +#ifndef STRICT +#define STRICT 1 +#endif + +// trim down the amount of stuff windows.h includes +#define NOGDICAPMASKS +#define NOVIRTUALKEYCODE +#define NOKEYSTATES +#define NORASTEROPS +#define NOATOM +#define NOCOLOR +#define NODRAWTEXT +#define NOMEMMGR +#define NOMETAFILE +#define NOMINMAX +#define NOOPENFILE +#define NOSERVICE +#define NOSOUND +#define NOCOMM +#define NOHELP +#define NOPROFILER +#define NODEFERWINDOWPOS +#define NOMCX +#define WIN32_LEAN_AND_MEAN + +#include +#include + +// reenable warnings disables for windows.h +#pragma warning(default: 4201) + +// ====================================================================== + +#endif