diff --git a/README.md b/README.md index 1a59ba1..46e2940 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ cmake --build .. // -u 卸载程序名 -d 卸载dll名称 // -m pid 关闭微信互斥体,多开微信 // -P port 指定http端口,需要使用 specify-port 分支的生成的dll + // -I 注入程序的pid //注入 ConsoleInject.exe -i demo.exe -p E:\testInject.dll //卸载 @@ -130,7 +131,17 @@ cmake --build .. //多开 ConsoleInject.exe -m 1222 // 注入并指定http端口 - ConsoleInject.exe -i demo.exe -p E:\testInject.dll -P 18888 + ConsoleInject.exe -i demo.exe -p E:\testInject.dll -P 18888 + // 注入指定pid并关闭多开限制 + ConsoleInject.exe -I 15048 -p E:\testInject.dll -m 15048 + +``` + +6.如果想改变端口,可以在微信目录下创建config.ini配置文件,修改端口即可。不创建则默认端口19088。 +``` shell +[config] +port=19099 + ``` #### 更新说明 diff --git a/source/ConsoleApplication.cpp b/source/ConsoleApplication.cpp deleted file mode 100644 index d06f638..0000000 --- a/source/ConsoleApplication.cpp +++ /dev/null @@ -1,956 +0,0 @@ -// ConsoleApplication.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 -// https://github.com/yihleego/handle-tools - -#include -#include -#include -#include "getopt.h" -#include - -#include "ntstatus.h" - - -#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) - -bool endsWith(const std::string& str, const std::string suffix) { - if (suffix.length() > str.length()) { return false; } - return (str.rfind(suffix) == (str.length() - suffix.length())); -} - -typedef struct _UNICODE_STRING { - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; -} UNICODE_STRING, * PUNICODE_STRING; - -typedef struct _SYSTEM_HANDLE { - PVOID Object; - HANDLE UniqueProcessId; - HANDLE HandleValue; - ULONG GrantedAccess; - USHORT CreatorBackTraceIndex; - USHORT ObjectTypeIndex; - ULONG HandleAttributes; - ULONG Reserved; -} SYSTEM_HANDLE, * PSYSTEM_HANDLE; - -typedef struct _SYSTEM_HANDLE_INFORMATION_EX { - ULONG_PTR HandleCount; - ULONG_PTR Reserved; - SYSTEM_HANDLE Handles[1]; -} SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX; - -typedef struct _OBJECT_BASIC_INFORMATION { - ULONG Attributes; - ACCESS_MASK GrantedAccess; - ULONG HandleCount; - ULONG PointerCount; - ULONG PagedPoolCharge; - ULONG NonPagedPoolCharge; - ULONG Reserved[3]; - ULONG NameInfoSize; - ULONG TypeInfoSize; - ULONG SecurityDescriptorSize; - LARGE_INTEGER CreationTime; -} OBJECT_BASIC_INFORMATION, * POBJECT_BASIC_INFORMATION; - -typedef struct _OBJECT_NAME_INFORMATION { - UNICODE_STRING Name; -} OBJECT_NAME_INFORMATION, * POBJECT_NAME_INFORMATION; - -typedef struct _OBJECT_TYPE_INFORMATION { - UNICODE_STRING TypeName; - ULONG Reserved[22]; // reserved for internal use -} OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION; - -typedef enum _SYSTEM_INFORMATION_CLASS { - SystemBasicInformation, // q: SYSTEM_BASIC_INFORMATION - SystemProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION - SystemPerformanceInformation, // q: SYSTEM_PERFORMANCE_INFORMATION - SystemTimeOfDayInformation, // q: SYSTEM_TIMEOFDAY_INFORMATION - SystemPathInformation, // not implemented - SystemProcessInformation, // q: SYSTEM_PROCESS_INFORMATION - SystemCallCountInformation, // q: SYSTEM_CALL_COUNT_INFORMATION - SystemDeviceInformation, // q: SYSTEM_DEVICE_INFORMATION - SystemProcessorPerformanceInformation, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION - SystemFlagsInformation, // q: SYSTEM_FLAGS_INFORMATION - SystemCallTimeInformation, // not implemented // SYSTEM_CALL_TIME_INFORMATION // 10 - SystemModuleInformation, // q: RTL_PROCESS_MODULES - SystemLocksInformation, // q: RTL_PROCESS_LOCKS - SystemStackTraceInformation, // q: RTL_PROCESS_BACKTRACES - SystemPagedPoolInformation, // not implemented - SystemNonPagedPoolInformation, // not implemented - SystemHandleInformation, // q: SYSTEM_HANDLE_INFORMATION - SystemObjectInformation, // q: SYSTEM_OBJECTTYPE_INFORMATION mixed with SYSTEM_OBJECT_INFORMATION - SystemPageFileInformation, // q: SYSTEM_PAGEFILE_INFORMATION - SystemVdmInstemulInformation, // q: SYSTEM_VDM_INSTEMUL_INFO - SystemVdmBopInformation, // not implemented // 20 - SystemFileCacheInformation, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemCache) - SystemPoolTagInformation, // q: SYSTEM_POOLTAG_INFORMATION - SystemInterruptInformation, // q: SYSTEM_INTERRUPT_INFORMATION - SystemDpcBehaviorInformation, // q: SYSTEM_DPC_BEHAVIOR_INFORMATION; s: SYSTEM_DPC_BEHAVIOR_INFORMATION (requires SeLoadDriverPrivilege) - SystemFullMemoryInformation, // not implemented // SYSTEM_MEMORY_USAGE_INFORMATION - SystemLoadGdiDriverInformation, // s (kernel-mode only) - SystemUnloadGdiDriverInformation, // s (kernel-mode only) - SystemTimeAdjustmentInformation, // q: SYSTEM_QUERY_TIME_ADJUST_INFORMATION; s: SYSTEM_SET_TIME_ADJUST_INFORMATION (requires SeSystemtimePrivilege) - SystemSummaryMemoryInformation, // not implemented // SYSTEM_MEMORY_USAGE_INFORMATION - SystemMirrorMemoryInformation, // s (requires license value "Kernel-MemoryMirroringSupported") (requires SeShutdownPrivilege) // 30 - SystemPerformanceTraceInformation, // q; s: (type depends on EVENT_TRACE_INFORMATION_CLASS) - SystemObsolete0, // not implemented - SystemExceptionInformation, // q: SYSTEM_EXCEPTION_INFORMATION - SystemCrashDumpStateInformation, // s: SYSTEM_CRASH_DUMP_STATE_INFORMATION (requires SeDebugPrivilege) - SystemKernelDebuggerInformation, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION - SystemContextSwitchInformation, // q: SYSTEM_CONTEXT_SWITCH_INFORMATION - SystemRegistryQuotaInformation, // q: SYSTEM_REGISTRY_QUOTA_INFORMATION; s (requires SeIncreaseQuotaPrivilege) - SystemExtendServiceTableInformation, // s (requires SeLoadDriverPrivilege) // loads win32k only - SystemPrioritySeperation, // s (requires SeTcbPrivilege) - SystemVerifierAddDriverInformation, // s (requires SeDebugPrivilege) // 40 - SystemVerifierRemoveDriverInformation, // s (requires SeDebugPrivilege) - SystemProcessorIdleInformation, // q: SYSTEM_PROCESSOR_IDLE_INFORMATION - SystemLegacyDriverInformation, // q: SYSTEM_LEGACY_DRIVER_INFORMATION - SystemCurrentTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION - SystemLookasideInformation, // q: SYSTEM_LOOKASIDE_INFORMATION - SystemTimeSlipNotification, // s: HANDLE (NtCreateEvent) (requires SeSystemtimePrivilege) - SystemSessionCreate, // not implemented - SystemSessionDetach, // not implemented - SystemSessionInformation, // not implemented (SYSTEM_SESSION_INFORMATION) - SystemRangeStartInformation, // q: SYSTEM_RANGE_START_INFORMATION // 50 - SystemVerifierInformation, // q: SYSTEM_VERIFIER_INFORMATION; s (requires SeDebugPrivilege) - SystemVerifierThunkExtend, // s (kernel-mode only) - SystemSessionProcessInformation, // q: SYSTEM_SESSION_PROCESS_INFORMATION - SystemLoadGdiDriverInSystemSpace, // s: SYSTEM_GDI_DRIVER_INFORMATION (kernel-mode only) (same as SystemLoadGdiDriverInformation) - SystemNumaProcessorMap, // q: SYSTEM_NUMA_INFORMATION - SystemPrefetcherInformation, // q; s: PREFETCHER_INFORMATION // PfSnQueryPrefetcherInformation - SystemExtendedProcessInformation, // q: SYSTEM_PROCESS_INFORMATION - SystemRecommendedSharedDataAlignment, // q: ULONG // KeGetRecommendedSharedDataAlignment - SystemComPlusPackage, // q; s: ULONG - SystemNumaAvailableMemory, // q: SYSTEM_NUMA_INFORMATION // 60 - SystemProcessorPowerInformation, // q: SYSTEM_PROCESSOR_POWER_INFORMATION - SystemEmulationBasicInformation, // q: SYSTEM_BASIC_INFORMATION - SystemEmulationProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION - SystemExtendedHandleInformation, // q: SYSTEM_HANDLE_INFORMATION_EX - SystemLostDelayedWriteInformation, // q: ULONG - SystemBigPoolInformation, // q: SYSTEM_BIGPOOL_INFORMATION - SystemSessionPoolTagInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION - SystemSessionMappedViewInformation, // q: SYSTEM_SESSION_MAPPED_VIEW_INFORMATION - SystemHotpatchInformation, // q; s: SYSTEM_HOTPATCH_CODE_INFORMATION - SystemObjectSecurityMode, // q: ULONG // 70 - SystemWatchdogTimerHandler, // s: SYSTEM_WATCHDOG_HANDLER_INFORMATION // (kernel-mode only) - SystemWatchdogTimerInformation, // q: SYSTEM_WATCHDOG_TIMER_INFORMATION // (kernel-mode only) - SystemLogicalProcessorInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION - SystemWow64SharedInformationObsolete, // not implemented - SystemRegisterFirmwareTableInformationHandler, // s: SYSTEM_FIRMWARE_TABLE_HANDLER // (kernel-mode only) - SystemFirmwareTableInformation, // SYSTEM_FIRMWARE_TABLE_INFORMATION - SystemModuleInformationEx, // q: RTL_PROCESS_MODULE_INFORMATION_EX - SystemVerifierTriageInformation, // not implemented - SystemSuperfetchInformation, // q; s: SUPERFETCH_INFORMATION // PfQuerySuperfetchInformation - SystemMemoryListInformation, // q: SYSTEM_MEMORY_LIST_INFORMATION; s: SYSTEM_MEMORY_LIST_COMMAND (requires SeProfileSingleProcessPrivilege) // 80 - SystemFileCacheInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (same as SystemFileCacheInformation) - SystemThreadPriorityClientIdInformation, // s: SYSTEM_THREAD_CID_PRIORITY_INFORMATION (requires SeIncreaseBasePriorityPrivilege) - SystemProcessorIdleCycleTimeInformation, // q: SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION[] - SystemVerifierCancellationInformation, // SYSTEM_VERIFIER_CANCELLATION_INFORMATION // name:wow64:whNT32QuerySystemVerifierCancellationInformation - SystemProcessorPowerInformationEx, // not implemented - SystemRefTraceInformation, // q; s: SYSTEM_REF_TRACE_INFORMATION // ObQueryRefTraceInformation - SystemSpecialPoolInformation, // q; s: SYSTEM_SPECIAL_POOL_INFORMATION (requires SeDebugPrivilege) // MmSpecialPoolTag, then MmSpecialPoolCatchOverruns != 0 - SystemProcessIdInformation, // q: SYSTEM_PROCESS_ID_INFORMATION - SystemErrorPortInformation, // s (requires SeTcbPrivilege) - SystemBootEnvironmentInformation, // q: SYSTEM_BOOT_ENVIRONMENT_INFORMATION // 90 - SystemHypervisorInformation, // q: SYSTEM_HYPERVISOR_QUERY_INFORMATION - SystemVerifierInformationEx, // q; s: SYSTEM_VERIFIER_INFORMATION_EX - SystemTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege) - SystemImageFileExecutionOptionsInformation, // s: SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION (requires SeTcbPrivilege) - SystemCoverageInformation, // q: COVERAGE_MODULES s: COVERAGE_MODULE_REQUEST // ExpCovQueryInformation (requires SeDebugPrivilege) - SystemPrefetchPatchInformation, // SYSTEM_PREFETCH_PATCH_INFORMATION - SystemVerifierFaultsInformation, // s: SYSTEM_VERIFIER_FAULTS_INFORMATION (requires SeDebugPrivilege) - SystemSystemPartitionInformation, // q: SYSTEM_SYSTEM_PARTITION_INFORMATION - SystemSystemDiskInformation, // q: SYSTEM_SYSTEM_DISK_INFORMATION - SystemProcessorPerformanceDistribution, // q: SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION // 100 - SystemNumaProximityNodeInformation, // q; s: SYSTEM_NUMA_PROXIMITY_MAP - SystemDynamicTimeZoneInformation, // q; s: RTL_DYNAMIC_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege) - SystemCodeIntegrityInformation, // q: SYSTEM_CODEINTEGRITY_INFORMATION // SeCodeIntegrityQueryInformation - SystemProcessorMicrocodeUpdateInformation, // s: SYSTEM_PROCESSOR_MICROCODE_UPDATE_INFORMATION - SystemProcessorBrandString, // q: CHAR[] // HaliQuerySystemInformation -> HalpGetProcessorBrandString, info class 23 - SystemVirtualAddressInformation, // q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // MmQuerySystemVaInformation - SystemLogicalProcessorAndGroupInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // since WIN7 // KeQueryLogicalProcessorRelationship - SystemProcessorCycleTimeInformation, // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[] - SystemStoreInformation, // q; s: SYSTEM_STORE_INFORMATION (requires SeProfileSingleProcessPrivilege) // SmQueryStoreInformation - SystemRegistryAppendString, // s: SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS // 110 - SystemAitSamplingValue, // s: ULONG (requires SeProfileSingleProcessPrivilege) - SystemVhdBootInformation, // q: SYSTEM_VHD_BOOT_INFORMATION - SystemCpuQuotaInformation, // q; s: PS_CPU_QUOTA_QUERY_INFORMATION - SystemNativeBasicInformation, // q: SYSTEM_BASIC_INFORMATION - SystemErrorPortTimeouts, // SYSTEM_ERROR_PORT_TIMEOUTS - SystemLowPriorityIoInformation, // q: SYSTEM_LOW_PRIORITY_IO_INFORMATION - SystemTpmBootEntropyInformation, // q: TPM_BOOT_ENTROPY_NT_RESULT // ExQueryTpmBootEntropyInformation - SystemVerifierCountersInformation, // q: SYSTEM_VERIFIER_COUNTERS_INFORMATION - SystemPagedPoolInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypePagedPool) - SystemSystemPtesInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemPtes) // 120 - SystemNodeDistanceInformation, - SystemAcpiAuditInformation, // q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26 - SystemBasicPerformanceInformation, // q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation - SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1 - SystemSessionBigPoolInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8 - SystemBootGraphicsInformation, // q; s: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only) - SystemScrubPhysicalMemoryInformation, // q; s: MEMORY_SCRUB_INFORMATION - SystemBadPageInformation, - SystemProcessorProfileControlArea, // q; s: SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA - SystemCombinePhysicalMemoryInformation, // s: MEMORY_COMBINE_INFORMATION, MEMORY_COMBINE_INFORMATION_EX, MEMORY_COMBINE_INFORMATION_EX2 // 130 - SystemEntropyInterruptTimingInformation, // q; s: SYSTEM_ENTROPY_TIMING_INFORMATION - SystemConsoleInformation, // q: SYSTEM_CONSOLE_INFORMATION - SystemPlatformBinaryInformation, // q: SYSTEM_PLATFORM_BINARY_INFORMATION (requires SeTcbPrivilege) - SystemPolicyInformation, // q: SYSTEM_POLICY_INFORMATION - SystemHypervisorProcessorCountInformation, // q: SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION - SystemDeviceDataInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION - SystemDeviceDataEnumerationInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION - SystemMemoryTopologyInformation, // q: SYSTEM_MEMORY_TOPOLOGY_INFORMATION - SystemMemoryChannelInformation, // q: SYSTEM_MEMORY_CHANNEL_INFORMATION - SystemBootLogoInformation, // q: SYSTEM_BOOT_LOGO_INFORMATION // 140 - SystemProcessorPerformanceInformationEx, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX // since WINBLUE - SystemCriticalProcessErrorLogInformation, - SystemSecureBootPolicyInformation, // q: SYSTEM_SECUREBOOT_POLICY_INFORMATION - SystemPageFileInformationEx, // q: SYSTEM_PAGEFILE_INFORMATION_EX - SystemSecureBootInformation, // q: SYSTEM_SECUREBOOT_INFORMATION - SystemEntropyInterruptTimingRawInformation, - SystemPortableWorkspaceEfiLauncherInformation, // q: SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION - SystemFullProcessInformation, // q: SYSTEM_PROCESS_INFORMATION with SYSTEM_PROCESS_INFORMATION_EXTENSION (requires admin) - SystemKernelDebuggerInformationEx, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX - SystemBootMetadataInformation, // 150 - SystemSoftRebootInformation, // q: ULONG - SystemElamCertificateInformation, // s: SYSTEM_ELAM_CERTIFICATE_INFORMATION - SystemOfflineDumpConfigInformation, // q: OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2 - SystemProcessorFeaturesInformation, // q: SYSTEM_PROCESSOR_FEATURES_INFORMATION - SystemRegistryReconciliationInformation, // s: NULL (requires admin) (flushes registry hives) - SystemEdidInformation, // q: SYSTEM_EDID_INFORMATION - SystemManufacturingInformation, // q: SYSTEM_MANUFACTURING_INFORMATION // since THRESHOLD - SystemEnergyEstimationConfigInformation, // q: SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION - SystemHypervisorDetailInformation, // q: SYSTEM_HYPERVISOR_DETAIL_INFORMATION - SystemProcessorCycleStatsInformation, // q: SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION // 160 - SystemVmGenerationCountInformation, - SystemTrustedPlatformModuleInformation, // q: SYSTEM_TPM_INFORMATION - SystemKernelDebuggerFlags, // SYSTEM_KERNEL_DEBUGGER_FLAGS - SystemCodeIntegrityPolicyInformation, // q: SYSTEM_CODEINTEGRITYPOLICY_INFORMATION - SystemIsolatedUserModeInformation, // q: SYSTEM_ISOLATED_USER_MODE_INFORMATION - SystemHardwareSecurityTestInterfaceResultsInformation, - SystemSingleModuleInformation, // q: SYSTEM_SINGLE_MODULE_INFORMATION - SystemAllowedCpuSetsInformation, - SystemVsmProtectionInformation, // q: SYSTEM_VSM_PROTECTION_INFORMATION (previously SystemDmaProtectionInformation) - SystemInterruptCpuSetsInformation, // q: SYSTEM_INTERRUPT_CPU_SET_INFORMATION // 170 - SystemSecureBootPolicyFullInformation, // q: SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION - SystemCodeIntegrityPolicyFullInformation, - SystemAffinitizedInterruptProcessorInformation, // (requires SeIncreaseBasePriorityPrivilege) - SystemRootSiloInformation, // q: SYSTEM_ROOT_SILO_INFORMATION - SystemCpuSetInformation, // q: SYSTEM_CPU_SET_INFORMATION // since THRESHOLD2 - SystemCpuSetTagInformation, // q: SYSTEM_CPU_SET_TAG_INFORMATION - SystemWin32WerStartCallout, - SystemSecureKernelProfileInformation, // q: SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION - SystemCodeIntegrityPlatformManifestInformation, // q: SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION // since REDSTONE - SystemInterruptSteeringInformation, // SYSTEM_INTERRUPT_STEERING_INFORMATION_INPUT // 180 - SystemSupportedProcessorArchitectures, // in: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] (Max 5 structs) // NtQuerySystemInformationEx - SystemMemoryUsageInformation, // q: SYSTEM_MEMORY_USAGE_INFORMATION - SystemCodeIntegrityCertificateInformation, // q: SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION - SystemPhysicalMemoryInformation, // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2 - SystemControlFlowTransition, - SystemKernelDebuggingAllowed, // s: ULONG - SystemActivityModerationExeState, // SYSTEM_ACTIVITY_MODERATION_EXE_STATE - SystemActivityModerationUserSettings, // SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS - SystemCodeIntegrityPoliciesFullInformation, - SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190 - SystemIntegrityQuotaInformation, - SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION - SystemProcessorIdleMaskInformation, // q: ULONG_PTR // since REDSTONE3 - SystemSecureDumpEncryptionInformation, - SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION - SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION - SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // since REDSTONE4 - SystemFirmwareBootPerformanceInformation, - SystemCodeIntegrityVerificationInformation, // SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION - SystemFirmwarePartitionInformation, // SYSTEM_FIRMWARE_PARTITION_INFORMATION // 200 - SystemSpeculationControlInformation, // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above. - SystemDmaGuardPolicyInformation, // SYSTEM_DMA_GUARD_POLICY_INFORMATION - SystemEnclaveLaunchControlInformation, // SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION - SystemWorkloadAllowedCpuSetsInformation, // SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION // since REDSTONE5 - SystemCodeIntegrityUnlockModeInformation, - SystemLeapSecondInformation, // SYSTEM_LEAP_SECOND_INFORMATION - SystemFlags2Information, // q: SYSTEM_FLAGS_INFORMATION - SystemSecurityModelInformation, // SYSTEM_SECURITY_MODEL_INFORMATION // since 19H1 - SystemCodeIntegritySyntheticCacheInformation, - SystemFeatureConfigurationInformation, // SYSTEM_FEATURE_CONFIGURATION_INFORMATION // since 20H1 // 210 - SystemFeatureConfigurationSectionInformation, // SYSTEM_FEATURE_CONFIGURATION_SECTIONS_INFORMATION - SystemFeatureUsageSubscriptionInformation, // SYSTEM_FEATURE_USAGE_SUBSCRIPTION_DETAILS - SystemSecureSpeculationControlInformation, // SECURE_SPECULATION_CONTROL_INFORMATION - SystemSpacesBootInformation, // since 20H2 - SystemFwRamdiskInformation, // SYSTEM_FIRMWARE_RAMDISK_INFORMATION - SystemWheaIpmiHardwareInformation, - SystemDifSetRuleClassInformation, - SystemDifClearRuleClassInformation, - SystemDifApplyPluginVerificationOnDriver, - SystemDifRemovePluginVerificationOnDriver, // 220 - SystemShadowStackInformation, // SYSTEM_SHADOW_STACK_INFORMATION - SystemBuildVersionInformation, // SYSTEM_BUILD_VERSION_INFORMATION - SystemPoolLimitInformation, // SYSTEM_POOL_LIMIT_INFORMATION - SystemCodeIntegrityAddDynamicStore, - SystemCodeIntegrityClearDynamicStores, - SystemDifPoolTrackingInformation, - SystemPoolZeroingInformation, // SYSTEM_POOL_ZEROING_INFORMATION - MaxSystemInfoClass -} SYSTEM_INFORMATION_CLASS; - -typedef enum _OBJECT_INFORMATION_CLASS { - ObjectBasicInformation = 0, // q: OBJECT_BASIC_INFORMATION - ObjectNameInformation = 1, // q: OBJECT_NAME_INFORMATION - ObjectTypeInformation = 2, // q: OBJECT_TYPE_INFORMATION - ObjectTypesInformation, // q: OBJECT_TYPES_INFORMATION - ObjectHandleFlagInformation, // qs: OBJECT_HANDLE_FLAG_INFORMATION - ObjectSessionInformation, // s: void // change object session // (requires SeTcbPrivilege) - ObjectSessionObjectInformation, // s: void // change object session // (requires SeTcbPrivilege) - MaxObjectInfoClass -} OBJECT_INFORMATION_CLASS; - -typedef NTSTATUS(WINAPI* PNtQuerySystemInformation)( - _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, - _Inout_ PVOID SystemInformation, - _In_ ULONG SystemInformationLength, - _Out_opt_ PULONG ReturnLength - ); - -typedef NTSTATUS(WINAPI* PNtQueryObject)( - _In_opt_ HANDLE Handle, - _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, - _Out_opt_ PVOID ObjectInformation, - _In_ ULONG ObjectInformationLength, - _Out_opt_ PULONG ReturnLength); - -typedef NTSTATUS(WINAPI* PNtDuplicateObject)( - _In_ HANDLE SourceProcessHandle, - _In_ HANDLE SourceHandle, - _In_opt_ HANDLE TargetProcessHandle, - _Out_opt_ PHANDLE TargetHandle, - _In_ ACCESS_MASK DesiredAccess, - _In_ ULONG HandleAttributes, - _In_ ULONG Options - ); - -int FindHandles(ULONG pid, LPSTR handleName, BOOL closeHandle, BOOL suffix) { - HMODULE ntdll = GetModuleHandle(TEXT("ntdll.dll")); - if (NULL == ntdll) { - printf("Failed to load 'ntdll.dll'\n"); - return 0; - } - PNtQuerySystemInformation pQuerySystemInformation = (PNtQuerySystemInformation)GetProcAddress(ntdll, "NtQuerySystemInformation"); - PNtQueryObject pQueryObject = (PNtQueryObject)GetProcAddress(ntdll, "NtQueryObject"); - PNtDuplicateObject pDuplicateObject = (PNtDuplicateObject)GetProcAddress(ntdll, "NtDuplicateObject"); - if (NULL == pQuerySystemInformation || NULL == pQueryObject || NULL == pDuplicateObject) { - printf("Failed to call 'GetProcAddress()'\n"); - return 0; - } - - ULONG len = 0x10000; - NTSTATUS status; - PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL; - do { - if (len > 0x4000000) { - return 0; - } - len *= 2; - pHandleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)GlobalAlloc(GMEM_ZEROINIT, len); - status = pQuerySystemInformation(SystemExtendedHandleInformation, pHandleInfo, len, &len); - } while (status == STATUS_INFO_LENGTH_MISMATCH); - - if (!NT_SUCCESS(status)) { - printf("Failed to call 'NtQuerySystemInformation()' with error code 0x%X\n", status); - return 0; - } - - HANDLE currentProcess = GetCurrentProcess(); - for (int i = 0; i < pHandleInfo->HandleCount; i++) { - SYSTEM_HANDLE handle = pHandleInfo->Handles[i]; - PVOID object = handle.Object; - HANDLE handleValue = handle.HandleValue; - HANDLE uniqueProcessId = handle.UniqueProcessId; - if (NULL != pid && HandleToLong(uniqueProcessId) != pid) { - continue; - } - LPSTR pName = NULL; - LPSTR pType = NULL; - HANDLE sourceProcess = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_DUP_HANDLE | PROCESS_SUSPEND_RESUME, FALSE, HandleToULong(uniqueProcessId)); - HANDLE targetHandle = NULL; - NTSTATUS status = pDuplicateObject(sourceProcess, handleValue, currentProcess, &targetHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); - if (NT_SUCCESS(status)) { - //printf("Failed to call 'NtDuplicateObject()' with error code 0x%X\n", status); - POBJECT_NAME_INFORMATION pNameInfo = (POBJECT_NAME_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len); - POBJECT_TYPE_INFORMATION pTypeInfo = (POBJECT_TYPE_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len); - if (NT_SUCCESS(pQueryObject(targetHandle, ObjectNameInformation, pNameInfo, len, NULL))) { - pName = (LPSTR)GlobalAlloc(GMEM_ZEROINIT, pNameInfo->Name.Length); - WideCharToMultiByte(CP_ACP, 0, pNameInfo->Name.Buffer, -1, pName, pNameInfo->Name.Length, NULL, NULL); - } - if (NT_SUCCESS(pQueryObject(targetHandle, ObjectTypeInformation, pTypeInfo, len, NULL))) { - pType = (LPSTR)GlobalAlloc(GMEM_ZEROINIT, pTypeInfo->TypeName.Length); - WideCharToMultiByte(CP_ACP, 0, pTypeInfo->TypeName.Buffer, -1, pType, pTypeInfo->TypeName.Length, NULL, NULL); - } - } - if (NULL != handleName) { - if (suffix) { - if (NULL == pName || !endsWith(std::string(pName), std::string(handleName))) { - continue; - } - } - else { - if (NULL == pName || 0 != strcmp(pName, handleName)) { - continue; - } - } - - if (TRUE == closeHandle) { - HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, HandleToLong(uniqueProcessId)); - DuplicateHandle(hProcess, handleValue, 0, 0, 0, 0, DUPLICATE_CLOSE_SOURCE); - CloseHandle(hProcess); - } - } - printf("PID: %-6d\t", uniqueProcessId); - printf("Handle: 0x%-3x\t", handleValue); - printf("Object: 0x%-8X\t", object); - printf("Type: %-20s\t", NULL != pType ? pType : ""); - printf("Name: %-30s\t", NULL != pName ? pName : ""); - printf("\n"); - } - return 1; -} - -int DisplayHandles() { - return FindHandles(NULL, NULL, FALSE, FALSE); -} - -int DisplayHandles(ULONG pid) { - return FindHandles(pid, NULL, FALSE, FALSE); -} - -int FindHandle(ULONG pid, LPSTR handleName) { - return FindHandles(pid, handleName, FALSE, FALSE); -} - -int CloseHandle(ULONG pid, LPSTR handleName) { - return FindHandles(pid, handleName, TRUE, FALSE); -} - -HANDLE FindHandleByName(ULONG pid, LPSTR handleName) { - HMODULE ntdll = GetModuleHandle(TEXT("ntdll.dll")); - if (NULL == ntdll) { - printf("Failed to load 'ntdll.dll'\n"); - return 0; - } - PNtQuerySystemInformation pQuerySystemInformation = (PNtQuerySystemInformation)GetProcAddress(ntdll, "NtQuerySystemInformation"); - PNtQueryObject pQueryObject = (PNtQueryObject)GetProcAddress(ntdll, "NtQueryObject"); - PNtDuplicateObject pDuplicateObject = (PNtDuplicateObject)GetProcAddress(ntdll, "NtDuplicateObject"); - if (NULL == pQuerySystemInformation || NULL == pQueryObject || NULL == pDuplicateObject) { - printf("Failed to call 'GetProcAddress()'\n"); - return 0; - } - - ULONG len = 0x10000; - NTSTATUS status; - PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL; - do { - if (len > 0x4000000) { - return 0; - } - len *= 2; - pHandleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)GlobalAlloc(GMEM_ZEROINIT, len); - status = pQuerySystemInformation(SystemExtendedHandleInformation, pHandleInfo, len, &len); - } while (status == STATUS_INFO_LENGTH_MISMATCH); - - if (!NT_SUCCESS(status)) { - printf("Failed to call 'NtQuerySystemInformation()' with error code 0x%X\n", status); - return 0; - } - - HANDLE currentProcess = GetCurrentProcess(); - for (int i = 0; i < pHandleInfo->HandleCount; i++) { - SYSTEM_HANDLE handle = pHandleInfo->Handles[i]; - PVOID object = handle.Object; - HANDLE handleValue = handle.HandleValue; - HANDLE uniqueProcessId = handle.UniqueProcessId; - if (NULL != pid && HandleToLong(uniqueProcessId) != pid) { - continue; - } - LPSTR pName = NULL; - LPSTR pType = NULL; - HANDLE sourceProcess = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_DUP_HANDLE | PROCESS_SUSPEND_RESUME, FALSE, HandleToULong(uniqueProcessId)); - HANDLE targetHandle = NULL; - NTSTATUS status = pDuplicateObject(sourceProcess, handleValue, currentProcess, &targetHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); - if (NT_SUCCESS(status)) { - //printf("Failed to call 'NtDuplicateObject()' with error code 0x%X\n", status); - POBJECT_NAME_INFORMATION pNameInfo = (POBJECT_NAME_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len); - POBJECT_TYPE_INFORMATION pTypeInfo = (POBJECT_TYPE_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len); - if (NT_SUCCESS(pQueryObject(targetHandle, ObjectNameInformation, pNameInfo, len, NULL))) { - pName = (LPSTR)GlobalAlloc(GMEM_ZEROINIT, pNameInfo->Name.Length); - WideCharToMultiByte(CP_ACP, 0, pNameInfo->Name.Buffer, -1, pName, pNameInfo->Name.Length, NULL, NULL); - } - if (NT_SUCCESS(pQueryObject(targetHandle, ObjectTypeInformation, pTypeInfo, len, NULL))) { - pType = (LPSTR)GlobalAlloc(GMEM_ZEROINIT, pTypeInfo->TypeName.Length); - WideCharToMultiByte(CP_ACP, 0, pTypeInfo->TypeName.Buffer, -1, pType, pTypeInfo->TypeName.Length, NULL, NULL); - } - } - if (NULL != handleName) { - - if (NULL == pName || 0 != strcmp(pName, handleName)) { - continue; - } - return handleValue; - } - - } -} - - -std::wstring Utf8ToUnicode(const char* buffer) { - int c_size = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, NULL, 0); - if (c_size > 0) { - wchar_t* temp = new wchar_t[c_size + 1]; - MultiByteToWideChar(CP_UTF8, 0, buffer, -1, temp, c_size); - temp[c_size] = L'\0'; - std::wstring ret(temp); - delete[] temp; - temp = NULL; - return ret; - } - return std::wstring(); -} - -DWORD GetPIDForProcess(wchar_t* process) -{ - HANDLE hSnapshot; - DWORD dPid = 0; - PROCESSENTRY32W pe32; - int working; - hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (!hSnapshot) { - return 0; - } - pe32.dwSize = sizeof(PROCESSENTRY32); - for (working = Process32FirstW(hSnapshot, &pe32); working; working = Process32NextW(hSnapshot, &pe32)) - { - if (!wcscmp(pe32.szExeFile, process)) - { - dPid = pe32.th32ProcessID; - break; - } - } - CloseHandle(hSnapshot); - return dPid; -} - -HMODULE GetDLLHandle(wchar_t* wDllName, DWORD dPid) -{ - HMODULE result; - tagMODULEENTRY32W me32; - void* snapMod; - - if (!dPid) { - return 0; - } - - snapMod = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dPid); - me32.dwSize = sizeof(tagMODULEENTRY32W); - if (Module32FirstW(snapMod, &me32)) - { - while (wcscmp(wDllName, me32.szModule)) - { - if (!Module32NextW(snapMod, &me32)) - goto error; - } - CloseHandle(snapMod); - result = me32.hModule; - } - else - { - error: - CloseHandle(snapMod); - result = 0; - } - return result; -} - - -static unsigned char GetProcAddressAsmCode[] = { - 0x55, // push ebp; - 0x8B, 0xEC, // mov ebp, esp; - 0x83, 0xEC, 0x40, // sub esp, 0x40; - 0x57, // push edi; - 0x51, // push ecx; - 0x8B, 0x7D, 0x08, // mov edi, dword ptr[ebp + 0x8]; - 0x8B, 0x07, // mov eax,dword ptr[edi]; - 0x50, // push eax; - 0xE8, 0x00, 0x00, 0x00, 0x00, // call GetModuleHandleW; - 0x83, 0xC4, 0x04, // add esp,0x4; - 0x83, 0xC7, 0x04, // add edi,0x4; - 0x8B, 0x0F, // mov ecx, dword ptr[edi]; - 0x51, // push ecx; - 0x50, // push eax; - 0xE8, 0x00, 0x00, 0x00, 0x00, // call GetProcAddress; - 0x83, 0xC4, 0x08, // add esp, 0x8; - 0x59, // pop ecx; - 0x5F, // pop edi; - 0x8B, 0xE5, // mov esp, ebp; - 0x5D, // pop ebp; - 0xC3 // retn; -}; - -LPVOID FillAsmCode(HANDLE handle) { - DWORD pGetModuleHandleW = (DWORD)GetModuleHandleW; - DWORD pGetProcAddress = (DWORD)GetProcAddress; - PVOID fillCall1 = (PVOID)&GetProcAddressAsmCode[15]; - PVOID fillCall2 = (PVOID)&GetProcAddressAsmCode[30]; - LPVOID pAsmFuncAddr = VirtualAllocEx(handle, NULL, 1, MEM_COMMIT, PAGE_EXECUTE); - if (!pAsmFuncAddr) { - return 0; - } - *(DWORD*)fillCall1 = pGetModuleHandleW - (DWORD)pAsmFuncAddr - 14 - 5; - *(DWORD*)fillCall2 = pGetProcAddress - (DWORD)pAsmFuncAddr - 29 - 5; - //*(DWORD*)fillCall1 = pGetModuleHandleW ; - //*(DWORD*)fillCall2 = pGetProcAddress; - SIZE_T dwWriteSize; - WriteProcessMemory(handle, pAsmFuncAddr, GetProcAddressAsmCode, sizeof(GetProcAddressAsmCode), &dwWriteSize); - return pAsmFuncAddr; - -} - -BOOL RemoteLibraryFunction(HANDLE hProcess, LPCSTR lpModuleName, LPCSTR lpProcName, LPVOID lpParameters, SIZE_T dwParamSize, PVOID* ppReturn) -{ - LPVOID lpRemoteParams = NULL; - - LPVOID lpFunctionAddress = GetProcAddress(GetModuleHandleA(lpModuleName), lpProcName); - if (!lpFunctionAddress) lpFunctionAddress = GetProcAddress(LoadLibraryA(lpModuleName), lpProcName); - if (!lpFunctionAddress) goto ErrorHandler; - - if (lpParameters) - { - lpRemoteParams = VirtualAllocEx(hProcess, NULL, dwParamSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if (!lpRemoteParams) goto ErrorHandler; - - SIZE_T dwBytesWritten = 0; - BOOL result = WriteProcessMemory(hProcess, lpRemoteParams, lpParameters, dwParamSize, &dwBytesWritten); - if (!result || dwBytesWritten < 1) goto ErrorHandler; - } - - HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpFunctionAddress, lpRemoteParams, NULL, NULL); - if (!hThread) goto ErrorHandler; - - DWORD dwOut = 0; - while (GetExitCodeThread(hThread, &dwOut)) { - if (dwOut != STILL_ACTIVE) { - *ppReturn = (PVOID)dwOut; - break; - } - } - - return TRUE; - -ErrorHandler: - if (lpRemoteParams) VirtualFreeEx(hProcess, lpRemoteParams, dwParamSize, MEM_RELEASE); - return FALSE; -} - -int InjectDllAndStartHttp(wchar_t* szPName, wchar_t* szDllPath, DWORD port) -{ - int result = 0; - HANDLE hRemoteThread = NULL; - LPTHREAD_START_ROUTINE lpSysLibAddr = NULL; - HINSTANCE__* hKernelModule = NULL; - LPVOID lpRemoteDllBase = NULL; - HANDLE hProcess; - unsigned int dwPid; - size_t ulDllLength; - wchar_t* dllName = L"wxhelper.dll"; - size_t dllNameLen = wcslen(dllName) * 2 + 2; - char* funcName = "http_start"; - size_t funcNameLen = strlen(funcName) + 1; - - HANDLE hStartHttp = NULL; - LPVOID portAddr = NULL; - HANDLE getProcThread = NULL; - - LPVOID paramsAddr = NULL; - LPVOID param1Addr = NULL; - LPVOID param2Addr = NULL; - LPVOID GetProcFuncAddr = NULL; - - DWORD params[2] = { 0 }; - - dwPid = GetPIDForProcess(szPName); - ulDllLength = (wcslen(szDllPath) + 1) * sizeof(wchar_t); - hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwPid); - if (!hProcess) { - goto error; - } - - lpRemoteDllBase = VirtualAllocEx(hProcess, NULL, ulDllLength, MEM_COMMIT, PAGE_READWRITE); - if (lpRemoteDllBase) - { - if (WriteProcessMemory(hProcess, lpRemoteDllBase, szDllPath, ulDllLength, NULL) - && (hKernelModule = GetModuleHandleW(L"kernel32.dll")) != 0 - && (lpSysLibAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(hKernelModule, "LoadLibraryW")) != 0 - && (hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, lpSysLibAddr, lpRemoteDllBase, 0, NULL)) != 0) - { - WaitForSingleObject(hRemoteThread, INFINITE); - GetProcFuncAddr = FillAsmCode(hProcess); - param1Addr = VirtualAllocEx(hProcess, NULL, dllNameLen, MEM_COMMIT, PAGE_READWRITE); - if (param1Addr) { - SIZE_T dwWriteSize; - BOOL bRet = WriteProcessMemory(hProcess, (LPVOID)param1Addr, dllName, dllNameLen, &dwWriteSize); - if (!bRet) { - goto error; - } - } - param2Addr = VirtualAllocEx(hProcess, NULL, funcNameLen, MEM_COMMIT, PAGE_READWRITE); - if (param2Addr) { - SIZE_T dwWriteSize; - BOOL bRet = WriteProcessMemory(hProcess, (LPVOID)param2Addr, funcName, funcNameLen, &dwWriteSize); - if (!bRet) { - goto error; - } - } - - params[0] = (DWORD)param1Addr; - params[1] = (DWORD)param2Addr; - - paramsAddr = VirtualAllocEx(hProcess, NULL, sizeof(params), MEM_COMMIT, PAGE_READWRITE); - if (paramsAddr) { - SIZE_T dwWriteSize; - BOOL bRet = WriteProcessMemory(hProcess, (LPVOID)paramsAddr, ¶ms[0], sizeof(params), &dwWriteSize); - if (!bRet) { - goto error; - } - } - - DWORD dwRet = 0; - getProcThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcFuncAddr, paramsAddr, 0, NULL); - - if (getProcThread) - { - WaitForSingleObject(getProcThread, INFINITE); - GetExitCodeThread(getProcThread, &dwRet); - if (dwRet) { - hStartHttp = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)dwRet, (LPVOID)port, 0, NULL); - WaitForSingleObject(hStartHttp, INFINITE); - result = 1; - } - } - } - } -error: - if (hRemoteThread) { - CloseHandle(hRemoteThread); - } - if (getProcThread) { - CloseHandle(getProcThread); - } - if (hStartHttp) { - CloseHandle(hStartHttp); - } - - if (lpRemoteDllBase) { - VirtualFreeEx(hProcess, lpRemoteDllBase, ulDllLength, MEM_DECOMMIT | MEM_RELEASE); - } - if (param1Addr) { - VirtualFreeEx(hProcess, param1Addr, dllNameLen, MEM_DECOMMIT | MEM_RELEASE); - } - - if (param2Addr) { - VirtualFreeEx(hProcess, param1Addr, funcNameLen, MEM_DECOMMIT | MEM_RELEASE); - } - - if (paramsAddr) { - VirtualFreeEx(hProcess, param1Addr, sizeof(params), MEM_DECOMMIT | MEM_RELEASE); - } - - if (GetProcFuncAddr) { - VirtualFreeEx(hProcess, GetProcFuncAddr, sizeof(GetProcAddressAsmCode), MEM_DECOMMIT | MEM_RELEASE); - } - - CloseHandle(hProcess); - return result; -} - -int InjectDll(wchar_t* szPName, wchar_t* szDllPath) -{ - int result = 0; - HANDLE hRemoteThread; - LPTHREAD_START_ROUTINE lpSysLibAddr; - HINSTANCE__* hKernelModule; - LPVOID lpRemoteDllBase; - HANDLE hProcess; - unsigned int dwPid; - size_t ulDllLength; - - dwPid = GetPIDForProcess(szPName); - ulDllLength = (wcslen(szDllPath) + 1) * sizeof(wchar_t); - hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwPid); - if (!hProcess) { - return 0; - } - - lpRemoteDllBase = VirtualAllocEx(hProcess, NULL, ulDllLength, MEM_COMMIT, PAGE_READWRITE); - if (lpRemoteDllBase) - { - if (WriteProcessMemory(hProcess, lpRemoteDllBase, szDllPath, ulDllLength, NULL) - && (hKernelModule = GetModuleHandleW(L"kernel32.dll")) != 0 - && (lpSysLibAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(hKernelModule, "LoadLibraryW")) != 0 - && (hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, lpSysLibAddr, lpRemoteDllBase, 0, NULL)) != 0) - { - WaitForSingleObject(hRemoteThread, INFINITE); - VirtualFreeEx(hProcess, lpRemoteDllBase, ulDllLength, MEM_DECOMMIT | MEM_RELEASE); - CloseHandle(hRemoteThread); - CloseHandle(hProcess); - OutputDebugStringA("[DBG] dll inject success"); - result = 1; - } - else - { - VirtualFreeEx(hProcess, lpRemoteDllBase, ulDllLength, MEM_DECOMMIT | MEM_RELEASE); - CloseHandle(hProcess); - result = 0; - } - } - else - { - CloseHandle(hProcess); - result = 0; - } - return result; -} - -int UnInjectDll(wchar_t* szPName, wchar_t* szDName) -{ - HMODULE hDll; - HANDLE lpFreeLibAddr; - HINSTANCE__* hK32; - HANDLE hProcess; - unsigned int dwPID; - - dwPID = GetPIDForProcess(szPName); - hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwPID); - if (!hProcess) { - return 0; - } - - hK32 = GetModuleHandleW(L"Kernel32.dll"); - if (!hK32) { - return 0; - } - - lpFreeLibAddr = GetProcAddress(hK32, "FreeLibraryAndExitThread"); - //lpFreeLibAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(hK32, "FreeLibrary"); - hDll = GetDLLHandle(szDName, dwPID); - if (hDll) { - HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)lpFreeLibAddr, hDll, NULL, NULL); - if (hThread == NULL) { - int errorCode = GetLastError(); - return 0; - } - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - CloseHandle(hProcess); - return 1; - } - - CloseHandle(hProcess); - return 0; -} - -FARPROC ShellCode(DWORD param[]) { - return GetProcAddress(GetModuleHandleW((LPCWSTR)param[0]), (LPCSTR)param[1]); -} - - -int main(int argc, char** argv) -{ - int param; - char cInjectprogram[MAX_PATH] = { 0 }; - char cUnInjectprogram[MAX_PATH] = { 0 }; - char cDllPath[MAX_PATH] = { 0 }; - char cDllName[MAX_PATH] = { 0 }; - int port = 0; - - ULONG pid = 0; - - while ((param = getopt(argc, argv, "i:p:u:d:m:P:h")) != -1) - { - switch (param) - { - case 'i': - strcpy(cInjectprogram, optarg); - break; - case 'p': - strcpy(cDllPath, optarg); - break; - case 'u': - strcpy(cUnInjectprogram, optarg); - case 'd': - strcpy(cDllName, optarg); - break; - case 'h': - printf("Usage: %s [-i/u] [-p/d] [-m]\n", argv[0]); - printf("Options:\n"); - printf(" -h Print this help message.\n"); - printf(" -i Name of the running program to be injected.\n"); - printf(" -u Name of the running program to be uninstalled.\n"); - printf(" -p Full path of injection file.\n"); - printf(" -d Name of injection file.\n"); - printf(" -m WeChat.exe pid.\n"); - printf("\n"); - printf("Examples:\n"); - printf(" window> %s -i test.exe -p c:/inject.dll \n", argv[0]); - printf(" window> %s -u test.exe -d inject.dll \n", argv[0]); - printf(" window> %s -m 1988 \n", argv[0]); - exit(0); - break; - case 'm': - pid = std::stol(optarg); - break; - case 'P': - port = std::atoi(optarg); - break; - default: - abort(); - break; - } - } - - if (pid) { - FindHandles(pid, "_WeChat_App_Instance_Identity_Mutex_Name", TRUE, TRUE); - } - - if (cInjectprogram[0] != 0 && cDllPath[0] != 0) - { - if (cInjectprogram[0] != '\0' && cDllPath[0] != '\0') - { - if (port == 0) { - std::wstring wsProgram = Utf8ToUnicode(cInjectprogram); - std::wstring wsPath = Utf8ToUnicode(cDllPath); - int ret = InjectDll((wchar_t*)wsProgram.c_str(), (wchar_t*)wsPath.c_str()); - printf(" 注入结果:%i \n", ret); - } - else - { - std::wstring wsProgram = Utf8ToUnicode(cInjectprogram); - std::wstring wsPath = Utf8ToUnicode(cDllPath); - int ret = InjectDllAndStartHttp((wchar_t*)wsProgram.c_str(), (wchar_t*)wsPath.c_str(), port); - printf(" 注入结果:%i \n", ret); - } - } - } - - if (cUnInjectprogram[0] != 0 && cDllName[0] != 0) - { - if (cUnInjectprogram[0] != '\0' && cDllName[0] != '\0') - { - std::wstring wsUnInjectProgram = Utf8ToUnicode(cUnInjectprogram); - std::wstring wsName = Utf8ToUnicode(cDllName); - int ret = UnInjectDll((wchar_t*)wsUnInjectProgram.c_str(), (wchar_t*)wsName.c_str()); - printf(" 卸载结果:%i \n", ret); - } - - } - - return 0; -} diff --git a/src/account_mgr.cc b/src/account_mgr.cc deleted file mode 100644 index e8579ee..0000000 --- a/src/account_mgr.cc +++ /dev/null @@ -1,219 +0,0 @@ -#include "pch.h" -#include "account_mgr.h" -#include "easylogging++.h" - - -#include "wechat_function.h" - -using namespace std; -namespace wxhelper { - AccountMgr::AccountMgr(DWORD base):BaseMgr(base){ - - } - AccountMgr::~AccountMgr(){ - - } -int AccountMgr::GetSelfInfo(SelfInfoInner &out) { - DWORD accout_service_addr = base_addr_ + WX_ACCOUNT_SERVICE_OFFSET; - DWORD get_app_save_addr = base_addr_ + WX_GET_APP_DATA_SAVE_PATH_OFFSET; - DWORD get_current_data_path_addr = base_addr_ + WX_GET_CURRENT_DATA_PATH_OFFSET; - DWORD service_addr = NULL; - __asm { - PUSHAD - CALL accout_service_addr - MOV service_addr,EAX - POPAD - } - if (service_addr) { - if (*(DWORD *)(service_addr + 0x44) == 0 || - *(DWORD *)(service_addr + 0x44 + 0x10) == 0) { - out.wxid = string(); - } else { - if (*(DWORD *)(service_addr + 0x44 + 0x14) == 0xF) { - out.wxid = string((char *)(service_addr + 0x44), - *(DWORD *)(service_addr + 0x44 + 0x10)); - } else { - out.wxid = string(*(char **)(service_addr + 0x44), - *(DWORD *)(service_addr + 0x44 + 0x10)); - } - } - - if (*(DWORD *)(service_addr + 0xA8) == 0 || - *(DWORD *)(service_addr + 0xA8 + 0x10) == 0) { - out.account = string(); - } else { - if (*(DWORD *)(service_addr + 0xA8 + 0x14) == 0xF) { - out.account = string((char *)(service_addr + 0xA8), - *(DWORD *)(service_addr + 0xA8 + 0x10)); - } else { - out.account = string(*(char **)(service_addr + 0xA8), - *(DWORD *)(service_addr + 0xA8 + 0x10)); - } - } - - if (*(DWORD *)(service_addr + 0xC0) == 0 || - *(DWORD *)(service_addr + 0xC0 + 0x10) == 0) { - out.mobile = string(); - } else { - if (*(DWORD *)(service_addr + 0xC0 + 0x14) == 0xF) { - out.mobile = string((char *)(service_addr + 0xC0), - *(DWORD *)(service_addr + 0xC0 + 0x10)); - } else { - out.mobile = string(*(char **)(service_addr + 0xC0), - *(DWORD *)(service_addr + 0xC0 + 0x10)); - } - } - - if (*(DWORD *)(service_addr + 0xD8) == 0 || - *(DWORD *)(service_addr + 0xD8 + 0x10) == 0) { - out.signature = string(); - } else { - if (*(DWORD *)(service_addr + 0xD8 + 0x14) == 0xF) { - out.signature = string((char *)(service_addr + 0xD8), - *(DWORD *)(service_addr + 0xD8 + 0x10)); - } else { - out.signature = string(*(char **)(service_addr + 0xD8), - *(DWORD *)(service_addr + 0xD8 + 0x10)); - } - } - - if (*(DWORD *)(service_addr + 0xF0) == 0 || - *(DWORD *)(service_addr + 0xF0 + 0x10) == 0) { - out.country = string(); - } else { - if (*(DWORD *)(service_addr + 0xF0 + 0x14) == 0xF) { - out.country = string((char *)(service_addr + 0xF0), - *(DWORD *)(service_addr + 0xF0 + 0x10)); - } else { - out.country = string(*(char **)(service_addr + 0xF0), - *(DWORD *)(service_addr + 0xF0 + 0x10)); - } - } - - if (*(DWORD *)(service_addr + 0x108) == 0 || - *(DWORD *)(service_addr + 0x108 + 0x10) == 0) { - out.province = string(); - } else { - if (*(DWORD *)(service_addr + 0x108 + 0x14) == 0xF) { - out.province = string((char *)(service_addr + 0x108), - *(DWORD *)(service_addr + 0x108 + 0x10)); - } else { - out.province = string(*(char **)(service_addr + 0x108), - *(DWORD *)(service_addr + 0x108 + 0x10)); - } - } - - if (*(DWORD *)(service_addr + 0x120) == 0 || - *(DWORD *)(service_addr + 0x120 + 0x10) == 0) { - out.city = string(); - } else { - if (*(DWORD *)(service_addr + 0x120 + 0x14) == 0xF) { - out.city = string((char *)(service_addr + 0x120), - *(DWORD *)(service_addr + 0x120 + 0x10)); - } else { - out.city = string(*(char **)(service_addr + 0x120), - *(DWORD *)(service_addr + 0x120 + 0x10)); - } - } - - if (*(DWORD *)(service_addr + 0x150) == 0 || - *(DWORD *)(service_addr + 0x150 + 0x10) == 0) { - out.name = string(); - } else { - if (*(DWORD *)(service_addr + 0x150 + 0x14) == 0xF) { - out.name = string((char *)(service_addr + 0x150), - *(DWORD *)(service_addr + 0x150 + 0x10)); - } else { - out.name = string(*(char **)(service_addr + 0x150), - *(DWORD *)(service_addr + 0x150 + 0x10)); - } - } - - if (*(DWORD *)(service_addr + 0x304) == 0 || - *(DWORD *)(service_addr + 0x304 + 0x10) == 0) { - out.head_img = string(); - } else { - if (*(DWORD *)(service_addr + 0x304 + 0x14) == 0xF) { - out.head_img = string((char *)(service_addr + 0x304), - *(DWORD *)(service_addr + 0x304 + 0x10)); - } else { - out.head_img = string(*(char **)(service_addr + 0x304), - *(DWORD *)(service_addr + 0x304 + 0x10)); - } - } - - if (*(DWORD *)(service_addr + 0x4CC) == 0 || - *(DWORD *)(service_addr + 0x4D0) == 0) { - out.db_key = string(); - } else { - DWORD byte_addr = *(DWORD *)(service_addr + 0x4CC); - DWORD len = *(DWORD *)(service_addr + 0x4D0); - out.db_key = Utils::Bytes2Hex((BYTE *)byte_addr, len); - } - } - - WeChatString data_save_path; - WeChatString current_data_path; - - __asm { - PUSHAD - LEA ECX,data_save_path - CALL get_app_save_addr - LEA ECX,current_data_path - CALL get_current_data_path_addr - POPAD - } - - if (data_save_path.ptr) { - out.data_save_path = Utils::WstringToUTF8( - wstring(data_save_path.ptr, data_save_path.length)); - } - else { - out.data_save_path = string(); - } - - if (current_data_path.ptr) { - out.current_data_path = Utils::WstringToUTF8( - wstring(current_data_path.ptr, current_data_path.length)); - } else { - out.current_data_path = string(); - } - return 1; -} - -int AccountMgr::CheckLogin() { - int success = -1; - DWORD accout_service_addr = base_addr_ + WX_ACCOUNT_SERVICE_OFFSET; - DWORD service_addr = NULL; - __asm { - PUSHAD - CALL accout_service_addr - MOV service_addr,EAX - POPAD - } - if (service_addr) { - success = *(DWORD *)(service_addr + 0x4C8); - } - return success; -} - -int AccountMgr::Logout() { - int success = -1; - if (!CheckLogin()) { - return success; - } - DWORD account_service_addr = base_addr_ + WX_ACCOUNT_SERVICE_OFFSET; - DWORD logout_addr = base_addr_ + WX_LOGOUT_OFFSET; - __asm { - PUSHAD - CALL account_service_addr - PUSH 0x0 - MOV ECX,EAX - CALL logout_addr - MOV success,EAX - POPAD - } - return success; -} - -} // namespace wxhelper \ No newline at end of file diff --git a/src/account_mgr.h b/src/account_mgr.h deleted file mode 100644 index 67da58d..0000000 --- a/src/account_mgr.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef WXHELPER_ACCOUNT_MGR_H_ -#define WXHELPER_ACCOUNT_MGR_H_ -#include "wechat_function.h" -#include"base_mgr.h" -namespace wxhelper{ - class AccountMgr: public BaseMgr - { - public: - explicit AccountMgr(DWORD base); - ~AccountMgr(); - int GetSelfInfo(SelfInfoInner& out); - - int CheckLogin(); - - int Logout(); - }; - -} -#endif \ No newline at end of file diff --git a/src/api_route.h b/src/api_route.h deleted file mode 100644 index 224b7fe..0000000 --- a/src/api_route.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef WXHELPER_API_ROUTINES_H_ -#define WXHELPER_API_ROUTINES_H_ -namespace wxhelper { - -typedef enum HTTP_API_ROUTE { - // login check - WECHAT_IS_LOGIN = 0, - // self info - WECHAT_GET_SELF_INFO, - // send message - WECHAT_MSG_SEND_TEXT, - WECHAT_MSG_SEND_AT, - WECHAT_MSG_SEND_CARD, - WECHAT_MSG_SEND_IMAGE, - WECHAT_MSG_SEND_FILE, - WECHAT_MSG_SEND_ARTICLE, - WECHAT_MSG_SEND_APP, - // receive message - WECHAT_MSG_START_HOOK, - WECHAT_MSG_STOP_HOOK, - WECHAT_MSG_START_IMAGE_HOOK, - WECHAT_MSG_STOP_IMAGE_HOOK, - WECHAT_MSG_START_VOICE_HOOK, - WECHAT_MSG_STOP_VOICE_HOOK, - // contact - WECHAT_CONTACT_GET_LIST, - WECHAT_CONTACT_CHECK_STATUS, - WECHAT_CONTACT_DEL, - WECHAT_CONTACT_SEARCH_BY_CACHE, - WECHAT_CONTACT_SEARCH_BY_NET, - WECHAT_CONTACT_ADD_BY_WXID, - WECHAT_CONTACT_ADD_BY_V3, - WECHAT_CONTACT_ADD_BY_PUBLIC_ID, - WECHAT_CONTACT_VERIFY_APPLY, - WECHAT_CONTACT_EDIT_REMARK, - // chatroom - WECHAT_CHATROOM_GET_MEMBER_LIST, - WECHAT_CHATROOM_GET_MEMBER_NICKNAME, - WECHAT_CHATROOM_DEL_MEMBER, - WECHAT_CHATROOM_ADD_MEMBER, - WECHAT_CHATROOM_SET_ANNOUNCEMENT, - WECHAT_CHATROOM_SET_CHATROOM_NAME, - WECHAT_CHATROOM_SET_SELF_NICKNAME, - // database - WECHAT_DATABASE_GET_HANDLES, - WECHAT_DATABASE_BACKUP, - WECHAT_DATABASE_QUERY, - // version - WECHAT_SET_VERSION, - // log - WECHAT_LOG_START_HOOK, - WECHAT_LOG_STOP_HOOK, - // browser - WECHAT_BROWSER_OPEN_WITH_URL, - WECHAT_GET_PUBLIC_MSG, - WECHAT_MSG_FORWARD_MESSAGE, - WECHAT_GET_QRCODE_IMAGE, - WECHAT_GET_A8KEY, - WECHAT_MSG_SEND_XML, - WECHAT_LOGOUT, - WECHAT_GET_TRANSFER, - WECHAT_GET_CONTACT_ALL, - WECHAT_GET_CHATROOM_INFO, - WECHAT_GET_IMG_BY_NAME, - WECHAT_DO_OCR, - WECHAT_SEND_PAT_MSG, - WECHAT_SET_TOP_MSG, - WECHAT_REMOVE_TOP_MSG, - WECHAT_SNS_GET_FIRST_PAGE, - WECHAT_SNS_GET_NEXT_PAGE, - WECHAT_CONTACT_NAME, - WECHAT_ATTACH_DOWNLOAD, - WECHAT_GET_VOICE, -} WECHAT_HTTP_APIS, - *PWECHAT_HTTP_APIS; - -} -#endif \ No newline at end of file diff --git a/src/base_mgr.cc b/src/base_mgr.cc deleted file mode 100644 index 4131e0e..0000000 --- a/src/base_mgr.cc +++ /dev/null @@ -1,13 +0,0 @@ -#include "base_mgr.h" - -namespace wxhelper{ - - BaseMgr::BaseMgr(DWORD base):base_addr_(base) - { - } - - BaseMgr::~BaseMgr() - { - } - -} \ No newline at end of file diff --git a/src/base_mgr.h b/src/base_mgr.h deleted file mode 100644 index 86f4608..0000000 --- a/src/base_mgr.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef WXHELPER_BASE_MGR_H_ -#define WXHELPER_BASE_MGR_H_ -#include -namespace wxhelper{ - class BaseMgr{ - public: - explicit BaseMgr(DWORD base); - ~BaseMgr(); - protected: - DWORD base_addr_; - }; -} -#endif \ No newline at end of file diff --git a/src/chat_room_mgr.cc b/src/chat_room_mgr.cc deleted file mode 100644 index a0c6a12..0000000 --- a/src/chat_room_mgr.cc +++ /dev/null @@ -1,375 +0,0 @@ -#include "pch.h" -#include "chat_room_mgr.h" - -#include "db.h" - -using namespace std; - -namespace wxhelper { - -ChatRoomMgr::ChatRoomMgr(DWORD base) : BaseMgr(base) {} - -ChatRoomMgr::~ChatRoomMgr() {} - -int ChatRoomMgr::GetChatRoomDetailInfo(wchar_t* chat_room_id, - ChatRoomInfoInner& room_info) { - int success = -1; - WeChatString chat_room(chat_room_id); - DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET; - DWORD get_chat_room_detail_addr = - base_addr_ + WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET; - DWORD create_chat_room_info_addr = base_addr_ + WX_NEW_CHAT_ROOM_INFO_OFFSET; - DWORD free_chat_room_info_addr = base_addr_ + WX_FREE_CHAT_ROOM_INFO_OFFSET; - char chat_room_info[0xDC] = {0}; - __asm { - PUSHAD - LEA ECX,chat_room_info - CALL create_chat_room_info_addr - CALL get_chat_room_mgr_addr - PUSH 0x0 - LEA ECX,chat_room_info - PUSH ECX - LEA ECX,chat_room - PUSH ECX - MOV ECX,EAX - CALL get_chat_room_detail_addr - MOV success,EAX - POPAD - } - DWORD room_id_len = *(DWORD*)(chat_room_info + 0x8); - DWORD room_id_max_len = *(DWORD*)(chat_room_info + 0xC); - wchar_t* room_id = new wchar_t[room_id_len + 1]; - wmemcpy(room_id, *(wchar_t**)(chat_room_info + 0x4), room_id_len + 1); - room_info.chat_room_id.ptr = room_id; - room_info.chat_room_id.length = room_id_len; - room_info.chat_room_id.max_length = room_id_max_len; - - DWORD notice_len = *(DWORD*)(chat_room_info + 0x1C); - DWORD notice_max_len = *(DWORD*)(chat_room_info + 0x20); - wchar_t* notice_ptr = *(wchar_t**)(chat_room_info + 0x18); - if (notice_len <= 0) { - room_info.notice.ptr = nullptr; - } else { - wchar_t* notice = new wchar_t[notice_len + 1]; - wmemcpy(notice, notice_ptr, notice_len + 1); - room_info.notice.ptr = notice; - } - room_info.notice.length = notice_len; - room_info.notice.max_length = notice_max_len; - - DWORD admin_len = *(DWORD*)(chat_room_info + 0x30); - DWORD admin_max_len = *(DWORD*)(chat_room_info + 0x34); - wchar_t* admin_ptr = *(wchar_t**)(chat_room_info + 0x2C); - if (admin_len <= 0) { - room_info.admin.ptr = nullptr; - } else { - wchar_t* admin = new wchar_t[admin_len + 1]; - wmemcpy(admin, admin_ptr, admin_len + 1); - room_info.admin.ptr = admin; - } - room_info.admin.length = admin_len; - room_info.admin.max_length = admin_max_len; - - DWORD xml_len = *(DWORD*)(chat_room_info + 0x54); - DWORD xml_max_len = *(DWORD*)(chat_room_info + 0x58); - wchar_t* xml_ptr = *(wchar_t**)(chat_room_info + 0x50); - if (xml_len <= 0) { - room_info.xml.ptr = nullptr; - } else { - wchar_t* xml = new wchar_t[xml_len + 1]; - wmemcpy(xml, xml_ptr, xml_len + 1); - room_info.xml.ptr = xml; - } - room_info.xml.length = xml_len; - room_info.xml.max_length = xml_max_len; - - __asm { - PUSHAD - LEA ECX,chat_room_info - CALL free_chat_room_info_addr - POPAD - } - return success; -} - -int ChatRoomMgr::DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids, - int len) { - int success = 0; - WeChatString chat_room(chat_room_id); - vector members; - VectorInner* list = (VectorInner*)&members; - DWORD members_ptr = (DWORD)&list->start; - for (int i = 0; i < len; i++) { - WeChatString pwxid(wxids[i]); - members.push_back(pwxid); - } - DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET; - DWORD del_member_addr = base_addr_ + WX_DEL_CHAT_ROOM_MEMBER_OFFSET; - DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; - __asm { - PUSHAD - CALL get_chat_room_mgr_addr - SUB ESP,0x14 - MOV ESI,EAX - MOV ECX,ESP - LEA EDI,chat_room - PUSH EDI - CALL init_chat_msg_addr - MOV ECX,ESI - MOV EAX,dword ptr[members_ptr] - PUSH EAX - CALL del_member_addr - MOV success,EAX - POPAD - } - return success; -} - -int ChatRoomMgr::AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids, - int len) { - int success = -1; - WeChatString chat_room(chat_room_id); - vector members; - VectorInner* list = (VectorInner*)&members; - DWORD members_ptr = (DWORD)&list->start; - for (int i = 0; i < len; i++) { - WeChatString pwxid(wxids[i]); - members.push_back(pwxid); - } - DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET; - DWORD add_member_addr = base_addr_ + WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET; - DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; - DWORD temp = 0; - __asm { - PUSHAD - PUSHFD - CALL get_chat_room_mgr_addr - SUB ESP,0x8 - MOV temp,EAX - MOV ECX,ESP - MOV dword ptr [ECX],0x0 - MOV dword ptr [ECX + 4],0x0 - TEST ESI,ESI - SUB ESP,0x14 - MOV ECX,ESP - LEA EAX,chat_room - PUSH EAX - CALL init_chat_msg_addr - MOV ECX,temp - MOV EAX,dword ptr[members_ptr] - PUSH EAX - CALL add_member_addr - MOV success,EAX - POPFD - POPAD - } - return success; -} - -int ChatRoomMgr::GetMemberFromChatRoom(wchar_t* chat_room_id, - ChatRoomInner& out) { - int success = -1; - WeChatString chat_room(chat_room_id); - DWORD chat_room_ptr = (DWORD)&chat_room; - char buffer[0x1D4] = {0}; - DWORD get_member_addr = base_addr_ + WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET; - DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET; - DWORD create_chat_room_addr = base_addr_ + WX_INIT_CHAT_ROOM_OFFSET; - DWORD free_chat_room_addr = base_addr_ + WX_FREE_CHAT_ROOM_OFFSET; - __asm { - PUSHAD - LEA ECX,buffer - CALL create_chat_room_addr - CALL get_chat_room_mgr_addr - LEA EAX, buffer - PUSH EAX - PUSH chat_room_ptr - CALL get_member_addr - MOVZX EAX,AL - MOV success,EAX - POPAD - } - char* members = *(char**)(buffer + 0x1c); - wchar_t* room = *(wchar_t**)(buffer + 0x8); - wchar_t* admin = *(wchar_t**)(buffer + 0x4c); - - out.members = new char[strlen(members) + 1]; - memcpy(out.members, members, strlen(members) + 1); - - out.chat_room = new wchar_t[wcslen(room) + 1]; - wmemcpy(out.chat_room, room, wcslen(room) + 1); - - out.admin = new wchar_t[wcslen(admin) + 1]; - wmemcpy(out.admin, admin, wcslen(admin) + 1); - - __asm { - LEA ECX,buffer - CALL free_chat_room_addr - } - return success; -} - -int ChatRoomMgr::ModChatRoomMemberNickName(wchar_t* chat_room_id, wchar_t* wxid, - wchar_t* nick) { - int success = -1; - WeChatString chat_room(chat_room_id); - WeChatString self_wxid(wxid); - WeChatString new_nick(nick); - DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET; - DWORD mod_member_nick_name_addr = - base_addr_ + WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET; - DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; - __asm { - PUSHAD - CALL get_chat_room_mgr_addr - SUB ESP,0x14 - MOV ECX,ESP - LEA EDI,new_nick - PUSH EDI - CALL init_chat_msg_addr - SUB ESP,0x14 - LEA EAX,self_wxid - MOV ECX,ESP - PUSH EAX - CALL init_chat_msg_addr - SUB ESP,0x14 - LEA EAX,chat_room - MOV ECX,ESP - PUSH EAX - CALL init_chat_msg_addr - CALL mod_member_nick_name_addr - MOVZX EAX,AL - MOV success,EAX - POPAD - } - return success; -} - -int ChatRoomMgr::SetTopMsg(wchar_t* wxid, ULONG64 msg_id) { - int success = -1; - char chat_msg[0x2D8] = {0}; - DWORD new_chat_msg_addr = base_addr_ + WX_NEW_CHAT_MSG_OFFSET; - DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET; - DWORD handle_top_msg_addr = base_addr_ + WX_TOP_MSG_OFFSET; - DWORD free_addr = base_addr_ + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET; - DWORD get_chat_mgr_addr = base_addr_ + WX_CHAT_MGR_OFFSET; - DWORD get_by_local_Id_addr = base_addr_ + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET; - - - int db_index = 0; - int local_id = DB::GetInstance().GetLocalIdByMsgId(msg_id, db_index); - if (local_id < 1) { - return -2; - } - __asm{ - PUSHAD - PUSHFD - LEA ECX,chat_msg - CALL new_chat_msg_addr - CALL get_chat_mgr_addr - PUSH dword ptr [db_index] - LEA ECX,chat_msg - PUSH dword ptr [local_id] - CALL get_by_local_Id_addr - ADD ESP,0x8 - CALL get_chat_room_mgr_addr - PUSH 0x0 - LEA EAX,chat_msg - PUSH EAX - CALL handle_top_msg_addr - MOV success,EAX - LEA ECX,chat_msg - PUSH 0x0 - CALL free_addr - POPFD - POPAD - } - - return success; -} - -int ChatRoomMgr::RemoveTopMsg(wchar_t* chat_room_id, ULONG64 msg_id) { - int success = -1; - WeChatString chat_room(chat_room_id); - DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET; - DWORD new_chat_msg_addr = base_addr_ + WX_NEW_CHAT_MSG_OFFSET; - DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; - DWORD remove_top_msg_addr = base_addr_ + WX_REMOVE_TOP_MSG_OFFSET; - - __asm { - PUSHAD - CALL get_chat_room_mgr_addr - MOV EDI,dword ptr [msg_id] - LEA EAX,chat_room - MOV ESI,dword ptr [msg_id + 0x4] - SUB ESP,0x14 - MOV ECX,ESP - PUSH EAX - CALL init_chat_msg_addr - PUSH ESI - PUSH EDI - CALL remove_top_msg_addr - MOV success,EAX - POPAD - } - - return success; -} - -std::wstring ChatRoomMgr::GetChatRoomMemberNickname(wchar_t* chat_room_id, - wchar_t* wxid) { - WeChatString chat_room(chat_room_id); - WeChatString member_id(wxid); - WeChatString nickname(NULL); - DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET; - DWORD get_nickname_addr = base_addr_ + WX_GET_MEMBER_NICKNAME_OFFSET; - DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET; - DWORD get_contact_addr = base_addr_ + WX_GET_CONTACT_OFFSET; - DWORD free_contact_addr = base_addr_ + WX_FREE_CONTACT_OFFSET; - __asm { - PUSHAD - PUSHFD - CALL get_chat_room_mgr_addr - LEA ECX,nickname - PUSH ECX - LEA ECX,member_id - PUSH ECX - LEA ECX,chat_room - PUSH ECX - MOV ECX,EAX - CALL get_nickname_addr - POPFD - POPAD - } - wstring name = L""; - if (nickname.ptr) { - name += wstring(nickname.ptr); - } else { - char buff[0x440] = {0}; - __asm { - PUSHAD - PUSHFD - CALL contact_mgr_addr - LEA ECX,buff - PUSH ECX - LEA ECX,member_id - PUSH ECX - MOV ECX,EAX - CALL get_contact_addr - POPFD - POPAD - } - name += READ_WSTRING(buff, 0x6C); - - __asm { - PUSHAD - PUSHFD - LEA ECX,buff - CALL free_contact_addr - POPFD - POPAD - } - } - return name; -} -} // namespace wxhelper \ No newline at end of file diff --git a/src/chat_room_mgr.h b/src/chat_room_mgr.h deleted file mode 100644 index ce6ef19..0000000 --- a/src/chat_room_mgr.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef WXHELPER_CHAT_ROOM_MGR_H_ -#define WXHELPER_CHAT_ROOM_MGR_H_ -#include "wechat_function.h" -#include "base_mgr.h" -namespace wxhelper { -class ChatRoomMgr:public BaseMgr { - public: - explicit ChatRoomMgr(DWORD base); - ~ChatRoomMgr(); - int GetChatRoomDetailInfo(wchar_t* chat_room_id, - ChatRoomInfoInner& room_info); - int DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids, - int len); - int AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids, - int len); - - int GetMemberFromChatRoom(wchar_t* chat_room_id, ChatRoomInner& out); - int ModChatRoomMemberNickName(wchar_t* chat_room_id, wchar_t* wxid, - wchar_t* nick); - - int SetTopMsg(wchar_t* wxid, ULONG64 msg_id); - int RemoveTopMsg(wchar_t* chat_room_id, ULONG64 msg_id); - - std::wstring GetChatRoomMemberNickname(wchar_t* chat_room_id, - wchar_t* wxid); -}; -} // namespace wxhelper -#endif \ No newline at end of file diff --git a/src/config.cc b/src/config.cc deleted file mode 100644 index 171ff88..0000000 --- a/src/config.cc +++ /dev/null @@ -1,17 +0,0 @@ -#include "pch.h" -#include "config.h" - -namespace wxhelper { -Config::Config(/* args */) {} - -Config::~Config() {} - - -void Config::Initialize(){ - port_ = GetPrivateProfileInt("config", "Port", 19088, "./config.ini"); -} -int Config::GetPort(){ - return port_; -} - - } // namespace wxhelper \ No newline at end of file diff --git a/src/config.h b/src/config.h deleted file mode 100644 index ffde254..0000000 --- a/src/config.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef WXHELPER_CONFIG_H_ -#define WXHELPER_CONFIG_H_ - -namespace wxhelper { - -class Config { - public: - Config(/* args */); - ~Config(); - void Initialize(); - int GetPort(); - - private: - int port_; -}; -} // namespace wxhelper -#endif \ No newline at end of file diff --git a/src/contact_mgr.cc b/src/contact_mgr.cc deleted file mode 100644 index 9525e41..0000000 --- a/src/contact_mgr.cc +++ /dev/null @@ -1,219 +0,0 @@ -#include "pch.h" -#include "contact_mgr.h" - - -#include "wechat_function.h" - -using namespace std; -namespace wxhelper { -ContactMgr::ContactMgr(DWORD base) : BaseMgr(base) {} -ContactMgr::~ContactMgr() {} -int ContactMgr::GetAllContact(vector &vec) { - DWORD get_instance = base_addr_ + WX_CONTACT_MGR_OFFSET; - DWORD contact_get_list = base_addr_ + WX_CONTACT_GET_LIST_OFFSET; - DWORD *contact[3] = {0, 0, 0}; - int success = 0; - __asm { - PUSHAD - CALL get_instance - LEA ECX,contact - PUSH ECX - MOV ECX,EAX - CALL contact_get_list - MOVZX EAX,AL - MOV success,EAX - POPAD - } - DWORD start = (DWORD)contact[0]; - DWORD end = (DWORD)contact[2]; - while (start < end) { - Contact temp{0}; - - temp.wxid.ptr = *(wchar_t **)(start + 0x10); - temp.wxid.length = *(DWORD *)(start + 0x14); - temp.wxid.max_length = *(DWORD *)(start + 0x18); - - temp.custom_account.ptr = *(wchar_t **)(start + 0x24); - temp.custom_account.length = *(DWORD *)(start + 0x28); - temp.custom_account.max_length = *(DWORD *)(start + 0x2C); - - temp.encrypt_name.ptr = *(wchar_t **)(start + 0x6c); - temp.encrypt_name.length = *(DWORD *)(start + 0x70); - temp.encrypt_name.max_length = *(DWORD *)(start + 0x74); - - temp.pinyin.ptr = *(wchar_t **)(start + 0xAC); - temp.pinyin.length = *(DWORD *)(start + 0xB0); - temp.pinyin.max_length = *(DWORD *)(start + 0xB4); - - temp.pinyin_all.ptr = *(wchar_t **)(start + 0xC0); - temp.pinyin_all.length = *(DWORD *)(start + 0xC4); - temp.pinyin_all.max_length = *(DWORD *)(start + 0xC8); - - temp.del_flag = *(DWORD *)(start + 0x4c); - temp.type = *(DWORD *)(start + 0x50); - temp.verify_flag = *(DWORD *)(start + 0x54); - vec.push_back(temp); - start += 0x438; - } - return success; -} -int ContactMgr::DelContact(wchar_t *wxid) { - int success = -1; - WeChatString user_id(wxid); - DWORD id_ptr = (DWORD)&user_id; - DWORD sync_mgr_addr = base_addr_ + WX_SYNC_MGR_OFFSET; - DWORD set_id_addr = base_addr_ + WX_SET_VALUE_OFFSET; - DWORD del_contact_addr = base_addr_ + WX_DO_DEL_CONTACT_OFFSET; - int len = user_id.length; - wstring ws_wxid(wxid); - - string id_cstr = Utils::WstringToUTF8(ws_wxid); - char id_[0x20] = {0}; - memcpy(id_, id_cstr.c_str(), id_cstr.size() + 1); - char buff[0x10] = {0}; - __asm { - PUSHAD - PUSHFD - CALL sync_mgr_addr - MOV ECX,EAX - LEA EAX,buff - MOV [ECX + 4],EAX - LEA EAX,id_ - Mov dword ptr[buff +0x4],EAX - CALL del_contact_addr - MOV success,EAX - POPFD - POPAD - } - return success; -} -wstring ContactMgr::GetContactOrChatRoomNickname(wchar_t *id) { - int success = -1; - char buff[0x440] = {0}; - WeChatString pri(id); - DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET; - DWORD get_contact_addr = base_addr_ + WX_GET_CONTACT_OFFSET; - DWORD free_contact_addr = base_addr_ + WX_FREE_CONTACT_OFFSET; - wstring name = L""; - __asm { - PUSHAD - PUSHFD - CALL contact_mgr_addr - LEA ECX,buff - PUSH ECX - LEA ECX,pri - PUSH ECX - MOV ECX,EAX - CALL get_contact_addr - POPFD - POPAD - } - name += READ_WSTRING(buff, 0x6C); - __asm { - PUSHAD - PUSHFD - LEA ECX,buff - CALL free_contact_addr - POPFD - POPAD - } - return name; -} - -int ContactMgr::AddFriendByWxid(wchar_t *wxid,wchar_t* msg) { - int success = -1; - DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET; - DWORD verify_msg_addr = base_addr_ + WX_VERIFY_MSG_OFFSET; - DWORD set_value_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; - DWORD do_verify_user_addr = base_addr_ + WX_DO_VERIFY_USER_OFFSET; - DWORD fn1_addr = base_addr_ + 0x758720; - WeChatString user_id(wxid); - WeChatString w_msg(msg); - DWORD instance =0; - Unkown null_obj={0,0,0,0,0,0xF}; - __asm{ - PUSHAD - PUSHFD - CALL contact_mgr_addr - MOV dword ptr [instance],EAX - MOV EDI,0x6 - MOV ESI,0 - MOV EAX,0x2 - SUB ESP,0x18 - MOV EAX,ESP - MOV dword ptr ds:[EAX],0 - MOV dword ptr ds:[EAX+0x14],0xF - MOV dword ptr ds:[EAX+0x10],0 - MOV byte ptr ds:[EAX],0 - SUB ESP,0x18 - LEA EAX,null_obj - MOV ECX,ESP - PUSH EAX - CALL fn1_addr - PUSH 0x0 - PUSH 0x6 - MOV EAX,w_msg - - SUB ESP,0x14 - MOV ECX,ESP - PUSH -0x1 - PUSH EAX - CALL verify_msg_addr - PUSH 0x2 - LEA EAX,user_id - - SUB ESP,0x14 - MOV ECX,ESP - PUSH EAX - CALL set_value_addr - MOV ECX,dword ptr [instance] - CALL do_verify_user_addr - MOV success,EAX - POPFD - POPAD - } - return success; -} - - int ContactMgr::VerifyApply(wchar_t *v3, wchar_t *v4){ - int success = -1; - DWORD set_value_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; - DWORD verify_addr = base_addr_ + WX_VERIFY_OK_OFFSET; - DWORD new_helper_addr = base_addr_ + WX_NEW_ADD_FRIEND_HELPER_OFFSET; - DWORD free_helper_addr = base_addr_ + WX_FREE_ADD_FRIEND_HELPER_OFFSET; - - WeChatString v4_str(v4); - WeChatString v3_str(v3); - char helper_obj[0x40] = {0}; - char nullbuffer[0x3CC] = {0}; - __asm { - PUSHAD - PUSHFD - LEA ECX,helper_obj - CALL new_helper_addr - MOV ESI,0x0 - MOV EDI,0x6 - PUSH ESI - PUSH EDI - SUB ESP,0x14 - MOV ECX,ESP - LEA EAX,v4_str - PUSH EAX - CALL set_value_addr - SUB ESP,0x8 - PUSH 0x0 - LEA EAX, nullbuffer - PUSH EAX - LEA EAX,v3_str - PUSH EAX - LEA ECX,helper_obj - CALL verify_addr - MOV success,EAX - LEA ECX,helper_obj - CALL free_helper_addr - POPFD - POPAD - } - return success; - } -} // namespace wxhelper \ No newline at end of file diff --git a/src/contact_mgr.h b/src/contact_mgr.h deleted file mode 100644 index 677d564..0000000 --- a/src/contact_mgr.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef WXHELPER_CONTACT_MGR_H_ -#define WXHELPER_CONTACT_MGR_H_ -#include -#include - -#include "base_mgr.h" -#include "wechat_function.h" -namespace wxhelper { -class ContactMgr : public BaseMgr { - public: - explicit ContactMgr(DWORD base); - ~ContactMgr(); - int GetAllContact(std::vector& vec); - int DelContact(wchar_t* wxid); - std::wstring GetContactOrChatRoomNickname(wchar_t* id); - int AddFriendByWxid(wchar_t* wxid,wchar_t* msg); - int VerifyApply(wchar_t *v3, wchar_t *v4); -}; -} // namespace wxhelper - -#endif; \ No newline at end of file diff --git a/src/db.cc b/src/db.cc deleted file mode 100644 index 4c64ef7..0000000 --- a/src/db.cc +++ /dev/null @@ -1,549 +0,0 @@ -#include "pch.h" -#include "db.h" - -#include "base64.h" -#include "easylogging++.h" - -#include "wechat_function.h" -#include "utils.h" -using namespace std; - -namespace wxhelper { - -void DB::init(DWORD base) { - base_addr_ = base; - dbmap_ = {}; - dbs_ = {}; -} - -void FreeResult(vector> &data) { - if (data.size() == 0) { - return; - } - for (unsigned int i = 0; i < data.size(); i++) { - for (unsigned j = 0; j < data[i].size(); j++) { - SqlResult *sr = (SqlResult *)&data[i][j]; - if (sr->column_name) { - delete[] sr->column_name; - sr->column_name = NULL; - } - if (sr->content) { - delete[] sr->content; - sr->content = NULL; - } - } - data[i].clear(); - } - data.clear(); -} - -int DB::SelectDataInner(DWORD db, const char *sql, - vector> &data) { - Sqlite3_prepare p_Sqlite3_prepare = - (Sqlite3_prepare)(base_addr_ + SQLITE3_PREPARE_OFFSET); - Sqlite3_step p_Sqlite3_step = - (Sqlite3_step)(base_addr_ + SQLITE3_STEP_OFFSET); - Sqlite3_column_count p_Sqlite3_column_count = - (Sqlite3_column_count)(base_addr_ + SQLITE3_COLUMN_COUNT_OFFSET); - Sqlite3_column_name p_Sqlite3_column_name = - (Sqlite3_column_name)(base_addr_ + SQLITE3_COLUMN_NAME_OFFSET); - Sqlite3_column_type p_Sqlite3_column_type = - (Sqlite3_column_type)(base_addr_ + SQLITE3_COLUMN_TYPE_OFFSET); - Sqlite3_column_blob p_Sqlite3_column_blob = - (Sqlite3_column_blob)(base_addr_ + SQLITE3_COLUMN_BLOB_OFFSET); - Sqlite3_column_bytes p_Sqlite3_column_bytes = - (Sqlite3_column_bytes)(base_addr_ + SQLITE3_COLUMN_BYTES_OFFSET); - Sqlite3_finalize p_Sqlite3_finalize = - (Sqlite3_finalize)(base_addr_ + SQLITE3_FINALIZE_OFFSET); - DWORD *stmt; - int rc = p_Sqlite3_prepare(db, sql, -1, &stmt, 0); - if (rc != SQLITE_OK) return NULL; - while (p_Sqlite3_step(stmt) == SQLITE_ROW) { - int col_count = p_Sqlite3_column_count(stmt); - vector tempStruct; - for (int i = 0; i < col_count; i++) { - SqlResult temp = {0}; - const char *ColName = p_Sqlite3_column_name(stmt, i); - int nType = p_Sqlite3_column_type(stmt, i); - const void *pReadBlobData = p_Sqlite3_column_blob(stmt, i); - int nLength = p_Sqlite3_column_bytes(stmt, i); - temp.column_name = new char[strlen(ColName) + 1]; - memcpy(temp.column_name, ColName, strlen(ColName) + 1); - temp.column_name_len = strlen(ColName); - temp.content_len = nLength; - switch (nType) { - case SQLITE_BLOB: { - temp.content = new char[nLength]; - memcpy(temp.content, pReadBlobData, nLength); - temp.is_blob = true; - break; - } - default: { - if (nLength != 0) { - temp.content = new char[nLength + 1]; - memcpy(temp.content, pReadBlobData, nLength + 1); - } else { - temp.content = new char[2]; - ZeroMemory(temp.content, 2); - } - temp.is_blob = false; - break; - } - } - tempStruct.push_back(temp); - } - data.push_back(tempStruct); - } - p_Sqlite3_finalize(stmt); - return 1; -} - -int DB::Select(DWORD db_hanle, const char *sql, - vector> &query_result) { - vector> data; - int status = SelectDataInner(db_hanle, sql, data); - if (status == 0) { - return 0; - } - if (data.size() == 0) { - return 1; - } - vector index; - for (size_t i = 0; i < data[0].size(); i++) { - index.push_back(data[0][i].column_name); - } - query_result.push_back(index); - - for (auto it : data) { - vector item; - for (size_t i = 0; i < it.size(); i++) { - if (!it[i].is_blob) { - bool is_utf8 = Utils::IsTextUtf8(it[i].content, it[i].content_len); - if (is_utf8) { - string content(it[i].content); - item.push_back(content); - } else { - string base64_str = - base64_encode((BYTE *)it[i].content, it[i].content_len); - item.push_back(base64_str); - } - - } else { - string b64_str = - base64_encode((BYTE *)it[i].content, it[i].content_len); - item.push_back(b64_str); - } - } - query_result.push_back(item); - } - FreeResult(data); - return 1; -} - -int SelectDbInfo(void *data, int argc, char **argv, char **name) { - vector result; - for (int i = 0; i < argc; i++) { - SqlResult temp = {0}; - temp.column_name = new char[strlen(name[i]) + 1]; - memcpy(temp.column_name, name[i], strlen(name[i]) + 1); - temp.column_name_len = strlen(name[i]); - if (argv[i]) { - temp.content = new char[strlen(argv[i]) + 1]; - memcpy(temp.content, argv[i], strlen(argv[i]) + 1); - temp.content_len = strlen(argv[i]); - } else { - temp.content = new char[2]; - ZeroMemory(temp.content, 2); - temp.content_len = 0; - } - result.push_back(temp); - } - return 1; -} - -int DB::ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data) { - DWORD sqlite3_exec_addr = base_addr_ + SQLITE3_EXEC_OFFSET; - Sqlite3_exec fn_sqlite3_exec = (Sqlite3_exec)sqlite3_exec_addr; - int status = fn_sqlite3_exec(db, sql, (Sqlite3_callback)callback, data, 0); - return status; -} - -int GetDbInfo(void *data, int argc, char **argv, char **name) { - DatabaseInfo *pdata = (DatabaseInfo *)data; - TableInfo tb = {0}; - if (argv[1]) { - tb.name = new char[strlen(argv[1]) + 1]; - memcpy(tb.name, argv[1], strlen(argv[1]) + 1); - } else { - tb.name = (char *)"NULL"; - } - if (argv[2]) { - tb.table_name = new char[strlen(argv[2]) + 1]; - memcpy(tb.table_name, argv[2], strlen(argv[2]) + 1); - } else { - tb.table_name = (char *)"NULL"; - } - if (argv[3]) { - tb.rootpage = new char[strlen(argv[3]) + 1]; - memcpy(tb.rootpage, argv[3], strlen(argv[3]) + 1); - } else { - tb.rootpage = (char *)"NULL"; - } - if (argv[4]) { - tb.sql = new char[strlen(argv[4]) + 1]; - memcpy(tb.sql, argv[4], strlen(argv[4]) + 1); - } else { - tb.sql = (char *)"NULL"; - } - tb.name_len = strlen(tb.name); - tb.table_name_len = strlen(tb.table_name); - tb.sql_len = strlen(tb.sql); - tb.rootpage_len = strlen(tb.rootpage); - pdata->tables.push_back(tb); - pdata->count = pdata->tables.size(); - return 0; -} - -std::vector DB::GetDbHandles() { - dbs_.clear(); - dbmap_.clear(); - DWORD p_contact_addr = *(DWORD *)(base_addr_ + CONTACT_G_PINSTANCE_OFFSET); - DWORD micro_msg_db_addr = *(DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET); - DWORD chat_msg_db_addr = *(DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET); - DWORD misc_db_addr = *(DWORD *)(p_contact_addr + DB_MISC_OFFSET); - DWORD emotion_db_addr = *(DWORD *)(p_contact_addr + DB_EMOTION_OFFSET); - DWORD media_db_addr = *(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET); - DWORD bizchat_msg_db_addr = - *(DWORD *)(p_contact_addr + DB_BIZCHAT_MSG_OFFSET); - DWORD function_msg_db_addr = - *(DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET); - - // microMsg.db - DatabaseInfo micro_msg_db{0}; - micro_msg_db.db_name = (wchar_t *)(*( - DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET)); - micro_msg_db.db_name_len = - *(DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET + 0x4); - micro_msg_db.handle = micro_msg_db_addr; - ExecuteSQL(micro_msg_db_addr, - "select * from sqlite_master where type=\"table\";", - (DWORD)GetDbInfo, µ_msg_db); - dbs_.push_back(micro_msg_db); - wstring micro_msg_name = wstring((wchar_t *)(*( - DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET))); - dbmap_[micro_msg_name] = micro_msg_db; - - // chatMsg.db - DatabaseInfo chat_msg_db{0}; - chat_msg_db.db_name = (wchar_t *)(*( - DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET)); - chat_msg_db.db_name_len = - *(DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET + 0x4); - chat_msg_db.handle = chat_msg_db_addr; - ExecuteSQL(chat_msg_db_addr, - "select * from sqlite_master where type=\"table\";", - (DWORD)GetDbInfo, &chat_msg_db); - dbs_.push_back(chat_msg_db); - wstring chat_msg_name = wstring((wchar_t *)(*( - DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET))); - dbmap_[chat_msg_name] = chat_msg_db; - - // misc.db - DatabaseInfo misc_db{0}; - misc_db.db_name = - (wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET)); - misc_db.db_name_len = - *(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET + 0x4); - misc_db.handle = misc_db_addr; - ExecuteSQL(misc_db_addr, "select * from sqlite_master where type=\"table\";", - (DWORD)GetDbInfo, &misc_db); - dbs_.push_back(misc_db); - wstring misc_name = wstring(( - wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET))); - dbmap_[misc_name] = misc_db; - - // emotion.db - DatabaseInfo emotion_db{0}; - emotion_db.db_name = (wchar_t *)(*( - DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET)); - emotion_db.db_name_len = - *(DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET + 0x4); - emotion_db.handle = emotion_db_addr; - ExecuteSQL(emotion_db_addr, - "select * from sqlite_master where type=\"table\";", - (DWORD)GetDbInfo, &emotion_db); - dbs_.push_back(emotion_db); - wstring emotion_name = wstring((wchar_t *)(*( - DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET))); - dbmap_[emotion_name] = emotion_db; - - // media.db - DatabaseInfo media_db{0}; - media_db.db_name = (wchar_t *)(*(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + - DB_NAME_OFFSET)); - media_db.db_name_len = - *(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET + 0x4); - media_db.handle = media_db_addr; - ExecuteSQL(media_db_addr, "select * from sqlite_master where type=\"table\";", - (DWORD)GetDbInfo, &media_db); - dbs_.push_back(media_db); - wstring media_name = wstring((wchar_t *)(*( - DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET))); - dbmap_[media_name] = media_db; - - // functionMsg.db - DatabaseInfo function_msg_db{0}; - function_msg_db.db_name = (wchar_t *)(*( - DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET)); - function_msg_db.db_name_len = *( - DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET + 0x4); - function_msg_db.handle = function_msg_db_addr; - ExecuteSQL(function_msg_db_addr, - "select * from sqlite_master where type=\"table\";", - (DWORD)GetDbInfo, &function_msg_db); - dbs_.push_back(function_msg_db); - wstring function_msg_name = wstring((wchar_t *)(*( - DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET))); - dbmap_[function_msg_name] = function_msg_db; - - if (bizchat_msg_db_addr) { - // functionMsg.db maybe null - DatabaseInfo bizchat_msg_db{0}; - bizchat_msg_db.db_name = (wchar_t *)(*( - DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET)); - bizchat_msg_db.db_name_len = - *(DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET + - 0x4); - bizchat_msg_db.handle = bizchat_msg_db_addr; - ExecuteSQL(bizchat_msg_db_addr, - "select * from sqlite_master where type=\"table\";", - (DWORD)GetDbInfo, &bizchat_msg_db); - dbs_.push_back(bizchat_msg_db); - wstring bizchat_msg_name = wstring((wchar_t *)(*( - DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET))); - dbmap_[bizchat_msg_name] = bizchat_msg_db; - } - // Storage - DWORD storage_start = *(DWORD *)(p_contact_addr + STORAGE_START_OFFSET); - DWORD storage_end = *(DWORD *)(p_contact_addr + STORAGE_END_OFFSET); - - // do { - // DWORD vtable_ptr = *(DWORD *)(storage_start); - - // if(vtable_ptr == base + OP_LOG_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + CHAT_MSG_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + CHAT_CR_MSG_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + SESSION_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + APP_INFO_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + HEAD_IMG_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + HEAD_IMG_URL_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + BIZ_INFO_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + TICKET_INFO_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + CHAT_ROOM_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + CHAT_ROOM_INFO_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + MEDIA_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + NAME_2_ID_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + EMOTION_PACKAGE_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + EMOTION_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + BUFINFO_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + CUSTOM_EMOTION_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + DEL_SESSIONINFO_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + FUNCTION_MSG_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + FUNCTION_MSG_TASK_STORAGE_VFTABLE){ - - // }else if(vtable_ptr == base + REVOKE_MSG_STORAGE_VFTABLE){ - - // } - - // storage_start = storage_start + 0x4; - // } while (storage_start != storage_end); - - DWORD multi_db_mgr_addr = base_addr_ + MULTI_DB_MSG_MGR_OFFSET; - DWORD public_msg_mgr_addr = base_addr_ + PUBLIC_MSG_MGR_OFFSET; - DWORD favorite_storage_mgr_addr = base_addr_ + FAVORITE_STORAGE_MGR_OFFSET; - DWORD fts_favorite_mgr_addr = base_addr_ + FTS_FAVORITE_MGR_OFFSET; - - // MsgX.db - DWORD wrap_ptr = *(DWORD *)(multi_db_mgr_addr); - DWORD db_num = *(DWORD *)(wrap_ptr + 0x30); - DWORD current_db_num = *(DWORD *)(wrap_ptr + 0x38); - DWORD begin_ptr = *(DWORD *)(wrap_ptr + 0x2c); - - for (unsigned int i = 0; i < current_db_num; i++) { - DWORD next_addr = begin_ptr + i * 0x4; - DWORD db_addr = *(DWORD *)next_addr; - if (db_addr) { - DWORD msg0_db_addr = *(DWORD *)(db_addr + 0x60); - DatabaseInfo msg0_db{0}; - msg0_db.db_name = (wchar_t *)(*(DWORD *)(db_addr)); - msg0_db.db_name_len = *(DWORD *)(db_addr + 0x4); - msg0_db.handle = msg0_db_addr; - msg0_db.extrainfo = *(DWORD *)(*(DWORD *)(db_addr + 0x18) + 0x144); - ExecuteSQL(msg0_db_addr, - "select * from sqlite_master where type=\"table\";", - (DWORD)GetDbInfo, &msg0_db); - dbs_.push_back(msg0_db); - wstring msg_db_name = wstring((wchar_t *)(*(DWORD *)(db_addr))); - dbmap_[msg_db_name] = msg0_db; - - // BufInfoStorage - DWORD buf_info_addr = *(DWORD *)(db_addr + 0x14); - - DWORD buf_info_handle = *(DWORD *)(buf_info_addr + 0x38); - DatabaseInfo media_msg0_db{0}; - media_msg0_db.db_name = (wchar_t *)(*(DWORD *)(buf_info_addr + 0x4C)); - media_msg0_db.db_name_len = *(DWORD *)(buf_info_addr + 0x50); - media_msg0_db.handle = buf_info_handle; - ExecuteSQL(buf_info_handle, - "select * from sqlite_master where type=\"table\";", - (DWORD)GetDbInfo, &media_msg0_db); - dbs_.push_back(media_msg0_db); - wstring media_msg_db_name = - wstring((wchar_t *)(*(DWORD *)(buf_info_addr + 0x4C))); - dbmap_[media_msg_db_name] = media_msg0_db; - } - } - - // publicMsg.db - DWORD public_msg_ptr = *(DWORD *)(*(DWORD *)(public_msg_mgr_addr) + 0x8); - if (public_msg_ptr) { - DWORD public_msg_db_addr = *(DWORD *)(public_msg_ptr + 0x38); - DatabaseInfo public_msg_db{0}; - public_msg_db.db_name = (wchar_t *)(*(DWORD *)(public_msg_ptr + 0x4C)); - public_msg_db.db_name_len = *(DWORD *)(public_msg_ptr + 0x50); - public_msg_db.handle = public_msg_db_addr; - ExecuteSQL(public_msg_db_addr, - "select * from sqlite_master where type=\"table\";", - (DWORD)GetDbInfo, &public_msg_db); - dbs_.push_back(public_msg_db); - wstring public_msg_db_name = - wstring((wchar_t *)(*(DWORD *)(public_msg_ptr + 0x4C))); - dbmap_[public_msg_db_name] = public_msg_db; - } - - // Favorite.db - DWORD favItems_ptr = - *(DWORD *)(*(DWORD *)(*(DWORD *)(favorite_storage_mgr_addr) + 0x8) + 0x4); - if (favItems_ptr) { - DWORD favorite_db_addr = *(DWORD *)(favItems_ptr + 0x38); - DatabaseInfo favorite_db{0}; - favorite_db.db_name = (wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C)); - favorite_db.db_name_len = *(DWORD *)(favItems_ptr + 0x50); - favorite_db.handle = favorite_db_addr; - ExecuteSQL(favorite_db_addr, - "select * from sqlite_master where type=\"table\";", - (DWORD)GetDbInfo, &favorite_db); - dbs_.push_back(favorite_db); - wstring public_msg_db_name = - wstring((wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C))); - dbmap_[public_msg_db_name] = favorite_db; - } - - DatabaseInfo db_end = {0}; - dbs_.push_back(db_end); -#ifdef _DEBUG - for (unsigned int i = 0; i < dbs_.size() - 1; i++) { - LOG(INFO) << "dbname =" << dbs_[i].db_name; - LOG(INFO) << "handle =" << dbs_[i].handle; - LOG(INFO) << "table_count =" << dbs_[i].tables.size(); - } -#endif - vector ret_array; - for (unsigned int i = 0; i < dbs_.size() - 1; i++) - ret_array.push_back(&dbs_[i]); - return ret_array; -} - -DWORD DB::GetDbHandleByDbName(wchar_t *dbname) { - if (dbmap_.size() == 0) { - GetDbHandles(); - } - if (dbmap_.find(dbname) != dbmap_.end()) { - return dbmap_[dbname].handle; - } - - return 0; -} - -unsigned int DB::GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex) { - char sql[260] = {0}; - sprintf_s(sql, "select localId from MSG where MsgSvrID=%llu;", msgid); - wchar_t dbname[20] = {0}; - for (int i = 0;; i++) { - swprintf_s(dbname, L"MSG%d.db", i); - DWORD handle = GetDbHandleByDbName(dbname); - if (handle == 0) { - LOG(INFO) << "MSG db handle is null"; - return 0; - } - vector> result; - int ret = Select(handle, (const char *)sql, result); - if (result.size() == 0) continue; - dbIndex = dbmap_[dbname].extrainfo; - return stoi(result[1][0]); - } - return 0; -} - -vector DB::GetChatMsgByMsgId(ULONG64 msgid) { - char sql[260] = {0}; - sprintf_s(sql, - "select " - "localId,TalkerId,MsgSvrID,Type,SubType,IsSender,CreateTime," - "Sequence,StatusEx,FlagEx,Status,MsgServerSeq,MsgSequence," - "StrTalker,StrContent,BytesExtra from MSG where MsgSvrID=%llu;", - msgid); - wchar_t dbname[20] = {0}; - for (int i = 0;; i++) { - swprintf_s(dbname, L"MSG%d.db", i); - DWORD handle = GetDbHandleByDbName(dbname); - if (handle == 0) { - LOG(INFO) << "MSG db handle is null"; - return {}; - } - vector> result; - int ret = Select(handle, (const char *)sql, result); - if (result.size() == 0) continue; - return result[1]; - } - return {}; -} - -std::string DB::GetVoiceBuffByMsgId(ULONG64 msgid) { - char sql[260] = {0}; - sprintf_s(sql, "SELECT Buf from Media WHERE Reserved0=%llu;", msgid); - wchar_t dbname[20] = {0}; - for (int i = 0;; i++) { - swprintf_s(dbname, L"MediaMSG%d.db", i); - DWORD handle = GetDbHandleByDbName(dbname); - if (handle == 0) { - LOG(INFO) << "Media db handle is null"; - return ""; - } - vector> result; - int ret = Select(handle, (const char *)sql, result); - if (result.size() == 0) continue; - return result[1][0]; - } - return ""; -} -} // namespace wxhelper \ No newline at end of file diff --git a/src/db.h b/src/db.h deleted file mode 100644 index f8927fe..0000000 --- a/src/db.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef WXHELPER_DB_H_ -#define WXHELPER_DB_H_ -#include -#include - -#include "base_mgr.h" -#include "wechat_function.h" -#include "windows.h" -#include "singleton.h" -namespace wxhelper { -class DB :public Singleton{ - public: - void init(DWORD base); - int ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data); - - int Select(DWORD db_hanle, const char *sql, - std::vector> &query_result); - - std::vector GetDbHandles(); - DWORD GetDbHandleByDbName(wchar_t *dbname); - unsigned int GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex); - std::vector GetChatMsgByMsgId(ULONG64 msgid); - - std::string GetVoiceBuffByMsgId(ULONG64 msgid); - - private: - int SelectDataInner(DWORD db, const char *sql, - std::vector> &data); - - private: - std::map dbmap_; - std::vector dbs_; - DWORD base_addr_; -}; - -} // namespace wxhelper - -#endif \ No newline at end of file diff --git a/src/dllMain.cc b/src/dllMain.cc deleted file mode 100644 index 6a54435..0000000 --- a/src/dllMain.cc +++ /dev/null @@ -1,32 +0,0 @@ -#include "pch.h" -#include "hide_module.h" -#include "global_context.h" - - -using namespace wxhelper; - - - - - -BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, - LPVOID lpReserved) { - switch (ul_reason_for_call) { - case DLL_PROCESS_ATTACH: { - DisableThreadLibraryCalls(hModule); - GlobalContext::GetInstance().initialize(hModule); - break; - } - case DLL_THREAD_ATTACH: { - break; - } - case DLL_THREAD_DETACH: { - break; - } - case DLL_PROCESS_DETACH: { - GlobalContext::GetInstance().finally(); - break; - } - } - return TRUE; -} diff --git a/src/easylogging++.cc b/src/easylogging++.cc deleted file mode 100644 index 4a8d927..0000000 --- a/src/easylogging++.cc +++ /dev/null @@ -1,3120 +0,0 @@ -// -// Bismillah ar-Rahmaan ar-Raheem -// -// Easylogging++ v9.96.7 -// Cross-platform logging library for C++ applications -// -// Copyright (c) 2012-2018 Amrayn Web Services -// Copyright (c) 2012-2018 @abumusamq -// -// This library is released under the MIT Licence. -// https://github.com/amrayn/easyloggingpp/blob/master/LICENSE -// -// https://amrayn.com -// http://muflihun.com -// - -#include "easylogging++.h" - -#if defined(AUTO_INITIALIZE_EASYLOGGINGPP) -INITIALIZE_EASYLOGGINGPP -#endif - -namespace el { - -// el::base -namespace base { -// el::base::consts -namespace consts { - -// Level log values - These are values that are replaced in place of %level format specifier -// Extra spaces after format specifiers are only for readability purposes in log files -static const base::type::char_t* kInfoLevelLogValue = ELPP_LITERAL("INFO"); -static const base::type::char_t* kDebugLevelLogValue = ELPP_LITERAL("DEBUG"); -static const base::type::char_t* kWarningLevelLogValue = ELPP_LITERAL("WARNING"); -static const base::type::char_t* kErrorLevelLogValue = ELPP_LITERAL("ERROR"); -static const base::type::char_t* kFatalLevelLogValue = ELPP_LITERAL("FATAL"); -static const base::type::char_t* kVerboseLevelLogValue = - ELPP_LITERAL("VERBOSE"); // will become VERBOSE-x where x = verbose level -static const base::type::char_t* kTraceLevelLogValue = ELPP_LITERAL("TRACE"); -static const base::type::char_t* kInfoLevelShortLogValue = ELPP_LITERAL("I"); -static const base::type::char_t* kDebugLevelShortLogValue = ELPP_LITERAL("D"); -static const base::type::char_t* kWarningLevelShortLogValue = ELPP_LITERAL("W"); -static const base::type::char_t* kErrorLevelShortLogValue = ELPP_LITERAL("E"); -static const base::type::char_t* kFatalLevelShortLogValue = ELPP_LITERAL("F"); -static const base::type::char_t* kVerboseLevelShortLogValue = ELPP_LITERAL("V"); -static const base::type::char_t* kTraceLevelShortLogValue = ELPP_LITERAL("T"); -// Format specifiers - These are used to define log format -static const base::type::char_t* kAppNameFormatSpecifier = ELPP_LITERAL("%app"); -static const base::type::char_t* kLoggerIdFormatSpecifier = ELPP_LITERAL("%logger"); -static const base::type::char_t* kThreadIdFormatSpecifier = ELPP_LITERAL("%thread"); -static const base::type::char_t* kSeverityLevelFormatSpecifier = ELPP_LITERAL("%level"); -static const base::type::char_t* kSeverityLevelShortFormatSpecifier = ELPP_LITERAL("%levshort"); -static const base::type::char_t* kDateTimeFormatSpecifier = ELPP_LITERAL("%datetime"); -static const base::type::char_t* kLogFileFormatSpecifier = ELPP_LITERAL("%file"); -static const base::type::char_t* kLogFileBaseFormatSpecifier = ELPP_LITERAL("%fbase"); -static const base::type::char_t* kLogLineFormatSpecifier = ELPP_LITERAL("%line"); -static const base::type::char_t* kLogLocationFormatSpecifier = ELPP_LITERAL("%loc"); -static const base::type::char_t* kLogFunctionFormatSpecifier = ELPP_LITERAL("%func"); -static const base::type::char_t* kCurrentUserFormatSpecifier = ELPP_LITERAL("%user"); -static const base::type::char_t* kCurrentHostFormatSpecifier = ELPP_LITERAL("%host"); -static const base::type::char_t* kMessageFormatSpecifier = ELPP_LITERAL("%msg"); -static const base::type::char_t* kVerboseLevelFormatSpecifier = ELPP_LITERAL("%vlevel"); -static const char* kDateTimeFormatSpecifierForFilename = "%datetime"; -// Date/time -static const char* kDays[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; -static const char* kDaysAbbrev[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; -static const char* kMonths[12] = { "January", "February", "March", "April", "May", "June", "July", "August", - "September", "October", "November", "December" - }; -static const char* kMonthsAbbrev[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; -static const char* kDefaultDateTimeFormat = "%Y-%M-%d %H:%m:%s,%g"; -static const char* kDefaultDateTimeFormatInFilename = "%Y-%M-%d_%H-%m"; -static const int kYearBase = 1900; -static const char* kAm = "AM"; -static const char* kPm = "PM"; -// Miscellaneous constants - -static const char* kNullPointer = "nullptr"; -#if ELPP_VARIADIC_TEMPLATES_SUPPORTED -#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED -static const base::type::VerboseLevel kMaxVerboseLevel = 9; -static const char* kUnknownUser = "unknown-user"; -static const char* kUnknownHost = "unknown-host"; - - -//---------------- DEFAULT LOG FILE ----------------------- - -#if defined(ELPP_NO_DEFAULT_LOG_FILE) -# if ELPP_OS_UNIX -static const char* kDefaultLogFile = "/dev/null"; -# elif ELPP_OS_WINDOWS -static const char* kDefaultLogFile = "nul"; -# endif // ELPP_OS_UNIX -#elif defined(ELPP_DEFAULT_LOG_FILE) -static const char* kDefaultLogFile = ELPP_DEFAULT_LOG_FILE; -#else -static const char* kDefaultLogFile = "myeasylog.log"; -#endif // defined(ELPP_NO_DEFAULT_LOG_FILE) - - -#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) -static const char* kDefaultLogFileParam = "--default-log-file"; -#endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) -#if defined(ELPP_LOGGING_FLAGS_FROM_ARG) -static const char* kLoggingFlagsParam = "--logging-flags"; -#endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG) -static const char* kValidLoggerIdSymbols = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._"; -static const char* kConfigurationComment = "##"; -static const char* kConfigurationLevel = "*"; -static const char* kConfigurationLoggerId = "--"; -} -// el::base::utils -namespace utils { - -/// @brief Aborts application due with user-defined status -static void abort(int status, const std::string& reason) { - // Both status and reason params are there for debugging with tools like gdb etc - ELPP_UNUSED(status); - ELPP_UNUSED(reason); -#if defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG) - // Ignore msvc critical error dialog - break instead (on debug mode) - _asm int 3 -#else - ::abort(); -#endif // defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG) -} - -} // namespace utils -} // namespace base - -// el - -// LevelHelper - -const char* LevelHelper::convertToString(Level level) { - // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet. - if (level == Level::Global) return "GLOBAL"; - if (level == Level::Debug) return "DEBUG"; - if (level == Level::Info) return "INFO"; - if (level == Level::Warning) return "WARNING"; - if (level == Level::Error) return "ERROR"; - if (level == Level::Fatal) return "FATAL"; - if (level == Level::Verbose) return "VERBOSE"; - if (level == Level::Trace) return "TRACE"; - return "UNKNOWN"; -} - -struct StringToLevelItem { - const char* levelString; - Level level; -}; - -static struct StringToLevelItem stringToLevelMap[] = { - { "global", Level::Global }, - { "debug", Level::Debug }, - { "info", Level::Info }, - { "warning", Level::Warning }, - { "error", Level::Error }, - { "fatal", Level::Fatal }, - { "verbose", Level::Verbose }, - { "trace", Level::Trace } -}; - -Level LevelHelper::convertFromString(const char* levelStr) { - for (auto& item : stringToLevelMap) { - if (base::utils::Str::cStringCaseEq(levelStr, item.levelString)) { - return item.level; - } - } - return Level::Unknown; -} - -void LevelHelper::forEachLevel(base::type::EnumType* startIndex, const std::function& fn) { - base::type::EnumType lIndexMax = LevelHelper::kMaxValid; - do { - if (fn()) { - break; - } - *startIndex = static_cast(*startIndex << 1); - } while (*startIndex <= lIndexMax); -} - -// ConfigurationTypeHelper - -const char* ConfigurationTypeHelper::convertToString(ConfigurationType configurationType) { - // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet. - if (configurationType == ConfigurationType::Enabled) return "ENABLED"; - if (configurationType == ConfigurationType::Filename) return "FILENAME"; - if (configurationType == ConfigurationType::Format) return "FORMAT"; - if (configurationType == ConfigurationType::ToFile) return "TO_FILE"; - if (configurationType == ConfigurationType::ToStandardOutput) return "TO_STANDARD_OUTPUT"; - if (configurationType == ConfigurationType::SubsecondPrecision) return "SUBSECOND_PRECISION"; - if (configurationType == ConfigurationType::PerformanceTracking) return "PERFORMANCE_TRACKING"; - if (configurationType == ConfigurationType::MaxLogFileSize) return "MAX_LOG_FILE_SIZE"; - if (configurationType == ConfigurationType::LogFlushThreshold) return "LOG_FLUSH_THRESHOLD"; - return "UNKNOWN"; -} - -struct ConfigurationStringToTypeItem { - const char* configString; - ConfigurationType configType; -}; - -static struct ConfigurationStringToTypeItem configStringToTypeMap[] = { - { "enabled", ConfigurationType::Enabled }, - { "to_file", ConfigurationType::ToFile }, - { "to_standard_output", ConfigurationType::ToStandardOutput }, - { "format", ConfigurationType::Format }, - { "filename", ConfigurationType::Filename }, - { "subsecond_precision", ConfigurationType::SubsecondPrecision }, - { "milliseconds_width", ConfigurationType::MillisecondsWidth }, - { "performance_tracking", ConfigurationType::PerformanceTracking }, - { "max_log_file_size", ConfigurationType::MaxLogFileSize }, - { "log_flush_threshold", ConfigurationType::LogFlushThreshold }, -}; - -ConfigurationType ConfigurationTypeHelper::convertFromString(const char* configStr) { - for (auto& item : configStringToTypeMap) { - if (base::utils::Str::cStringCaseEq(configStr, item.configString)) { - return item.configType; - } - } - return ConfigurationType::Unknown; -} - -void ConfigurationTypeHelper::forEachConfigType(base::type::EnumType* startIndex, const std::function& fn) { - base::type::EnumType cIndexMax = ConfigurationTypeHelper::kMaxValid; - do { - if (fn()) { - break; - } - *startIndex = static_cast(*startIndex << 1); - } while (*startIndex <= cIndexMax); -} - -// Configuration - -Configuration::Configuration(const Configuration& c) : - m_level(c.m_level), - m_configurationType(c.m_configurationType), - m_value(c.m_value) { -} - -Configuration& Configuration::operator=(const Configuration& c) { - if (&c != this) { - m_level = c.m_level; - m_configurationType = c.m_configurationType; - m_value = c.m_value; - } - return *this; -} - -/// @brief Full constructor used to sets value of configuration -Configuration::Configuration(Level level, ConfigurationType configurationType, const std::string& value) : - m_level(level), - m_configurationType(configurationType), - m_value(value) { -} - -void Configuration::log(el::base::type::ostream_t& os) const { - os << LevelHelper::convertToString(m_level) - << ELPP_LITERAL(" ") << ConfigurationTypeHelper::convertToString(m_configurationType) - << ELPP_LITERAL(" = ") << m_value.c_str(); -} - -/// @brief Used to find configuration from configuration (pointers) repository. Avoid using it. -Configuration::Predicate::Predicate(Level level, ConfigurationType configurationType) : - m_level(level), - m_configurationType(configurationType) { -} - -bool Configuration::Predicate::operator()(const Configuration* conf) const { - return ((conf != nullptr) && (conf->level() == m_level) && (conf->configurationType() == m_configurationType)); -} - -// Configurations - -Configurations::Configurations(void) : - m_configurationFile(std::string()), - m_isFromFile(false) { -} - -Configurations::Configurations(const std::string& configurationFile, bool useDefaultsForRemaining, - Configurations* base) : - m_configurationFile(configurationFile), - m_isFromFile(false) { - parseFromFile(configurationFile, base); - if (useDefaultsForRemaining) { - setRemainingToDefault(); - } -} - -bool Configurations::parseFromFile(const std::string& configurationFile, Configurations* base) { - // We initial assertion with true because if we have assertion disabled, we want to pass this - // check and if assertion is enabled we will have values re-assigned any way. - bool assertionPassed = true; - ELPP_ASSERT((assertionPassed = base::utils::File::pathExists(configurationFile.c_str(), true)) == true, - "Configuration file [" << configurationFile << "] does not exist!"); - if (!assertionPassed) { - return false; - } - bool success = Parser::parseFromFile(configurationFile, this, base); - m_isFromFile = success; - return success; -} - -bool Configurations::parseFromText(const std::string& configurationsString, Configurations* base) { - bool success = Parser::parseFromText(configurationsString, this, base); - if (success) { - m_isFromFile = false; - } - return success; -} - -void Configurations::setFromBase(Configurations* base) { - if (base == nullptr || base == this) { - return; - } - base::threading::ScopedLock scopedLock(base->lock()); - for (Configuration*& conf : base->list()) { - set(conf); - } -} - -bool Configurations::hasConfiguration(ConfigurationType configurationType) { - base::type::EnumType lIndex = LevelHelper::kMinValid; - bool result = false; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - if (hasConfiguration(LevelHelper::castFromInt(lIndex), configurationType)) { - result = true; - } - return result; - }); - return result; -} - -bool Configurations::hasConfiguration(Level level, ConfigurationType configurationType) { - base::threading::ScopedLock scopedLock(lock()); -#if ELPP_COMPILER_INTEL - // We cant specify template types here, Intel C++ throws compilation error - // "error: type name is not allowed" - return RegistryWithPred::get(level, configurationType) != nullptr; -#else - return RegistryWithPred::get(level, configurationType) != nullptr; -#endif // ELPP_COMPILER_INTEL -} - -void Configurations::set(Level level, ConfigurationType configurationType, const std::string& value) { - base::threading::ScopedLock scopedLock(lock()); - unsafeSet(level, configurationType, value); // This is not unsafe anymore as we have locked mutex - if (level == Level::Global) { - unsafeSetGlobally(configurationType, value, false); // Again this is not unsafe either - } -} - -void Configurations::set(Configuration* conf) { - if (conf == nullptr) { - return; - } - set(conf->level(), conf->configurationType(), conf->value()); -} - -void Configurations::setToDefault(void) { - setGlobally(ConfigurationType::Enabled, std::string("true"), true); - setGlobally(ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile), true); -#if defined(ELPP_NO_LOG_TO_FILE) - setGlobally(ConfigurationType::ToFile, std::string("false"), true); -#else - setGlobally(ConfigurationType::ToFile, std::string("true"), true); -#endif // defined(ELPP_NO_LOG_TO_FILE) - setGlobally(ConfigurationType::ToStandardOutput, std::string("true"), true); - setGlobally(ConfigurationType::SubsecondPrecision, std::string("3"), true); - setGlobally(ConfigurationType::PerformanceTracking, std::string("true"), true); - setGlobally(ConfigurationType::MaxLogFileSize, std::string("0"), true); - setGlobally(ConfigurationType::LogFlushThreshold, std::string("0"), true); - - setGlobally(ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"), true); - set(Level::Debug, ConfigurationType::Format, - std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg")); - // INFO and WARNING are set to default by Level::Global - set(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - set(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - set(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg")); - set(Level::Trace, ConfigurationType::Format, std::string("%datetime %level [%logger] [%func] [%loc] %msg")); -} - -void Configurations::setRemainingToDefault(void) { - base::threading::ScopedLock scopedLock(lock()); -#if defined(ELPP_NO_LOG_TO_FILE) - unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, std::string("false")); -#else - unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, std::string("true")); -#endif // defined(ELPP_NO_LOG_TO_FILE) - unsafeSetIfNotExist(Level::Global, ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile)); - unsafeSetIfNotExist(Level::Global, ConfigurationType::ToStandardOutput, std::string("true")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::SubsecondPrecision, std::string("3")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::PerformanceTracking, std::string("true")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::MaxLogFileSize, std::string("0")); - unsafeSetIfNotExist(Level::Global, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - unsafeSetIfNotExist(Level::Debug, ConfigurationType::Format, - std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg")); - // INFO and WARNING are set to default by Level::Global - unsafeSetIfNotExist(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - unsafeSetIfNotExist(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); - unsafeSetIfNotExist(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg")); - unsafeSetIfNotExist(Level::Trace, ConfigurationType::Format, - std::string("%datetime %level [%logger] [%func] [%loc] %msg")); -} - -bool Configurations::Parser::parseFromFile(const std::string& configurationFile, Configurations* sender, - Configurations* base) { - sender->setFromBase(base); - std::ifstream fileStream_(configurationFile.c_str(), std::ifstream::in); - ELPP_ASSERT(fileStream_.is_open(), "Unable to open configuration file [" << configurationFile << "] for parsing."); - bool parsedSuccessfully = false; - std::string line = std::string(); - Level currLevel = Level::Unknown; - std::string currConfigStr = std::string(); - std::string currLevelStr = std::string(); - while (fileStream_.good()) { - std::getline(fileStream_, line); - parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender); - ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line); - } - return parsedSuccessfully; -} - -bool Configurations::Parser::parseFromText(const std::string& configurationsString, Configurations* sender, - Configurations* base) { - sender->setFromBase(base); - bool parsedSuccessfully = false; - std::stringstream ss(configurationsString); - std::string line = std::string(); - Level currLevel = Level::Unknown; - std::string currConfigStr = std::string(); - std::string currLevelStr = std::string(); - while (std::getline(ss, line)) { - parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender); - ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line); - } - return parsedSuccessfully; -} - -void Configurations::Parser::ignoreComments(std::string* line) { - std::size_t foundAt = 0; - std::size_t quotesStart = line->find("\""); - std::size_t quotesEnd = std::string::npos; - if (quotesStart != std::string::npos) { - quotesEnd = line->find("\"", quotesStart + 1); - while (quotesEnd != std::string::npos && line->at(quotesEnd - 1) == '\\') { - // Do not erase slash yet - we will erase it in parseLine(..) while loop - quotesEnd = line->find("\"", quotesEnd + 2); - } - } - if ((foundAt = line->find(base::consts::kConfigurationComment)) != std::string::npos) { - if (foundAt < quotesEnd) { - foundAt = line->find(base::consts::kConfigurationComment, quotesEnd + 1); - } - *line = line->substr(0, foundAt); - } -} - -bool Configurations::Parser::isLevel(const std::string& line) { - return base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationLevel)); -} - -bool Configurations::Parser::isComment(const std::string& line) { - return base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationComment)); -} - -bool Configurations::Parser::isConfig(const std::string& line) { - std::size_t assignment = line.find('='); - return line != "" && - ((line[0] >= 'A' && line[0] <= 'Z') || (line[0] >= 'a' && line[0] <= 'z')) && - (assignment != std::string::npos) && - (line.size() > assignment); -} - -bool Configurations::Parser::parseLine(std::string* line, std::string* currConfigStr, std::string* currLevelStr, - Level* currLevel, - Configurations* conf) { - ConfigurationType currConfig = ConfigurationType::Unknown; - std::string currValue = std::string(); - *line = base::utils::Str::trim(*line); - if (isComment(*line)) return true; - ignoreComments(line); - *line = base::utils::Str::trim(*line); - if (line->empty()) { - // Comment ignored - return true; - } - if (isLevel(*line)) { - if (line->size() <= 2) { - return true; - } - *currLevelStr = line->substr(1, line->size() - 2); - *currLevelStr = base::utils::Str::toUpper(*currLevelStr); - *currLevelStr = base::utils::Str::trim(*currLevelStr); - *currLevel = LevelHelper::convertFromString(currLevelStr->c_str()); - return true; - } - if (isConfig(*line)) { - std::size_t assignment = line->find('='); - *currConfigStr = line->substr(0, assignment); - *currConfigStr = base::utils::Str::toUpper(*currConfigStr); - *currConfigStr = base::utils::Str::trim(*currConfigStr); - currConfig = ConfigurationTypeHelper::convertFromString(currConfigStr->c_str()); - currValue = line->substr(assignment + 1); - currValue = base::utils::Str::trim(currValue); - std::size_t quotesStart = currValue.find("\"", 0); - std::size_t quotesEnd = std::string::npos; - if (quotesStart != std::string::npos) { - quotesEnd = currValue.find("\"", quotesStart + 1); - while (quotesEnd != std::string::npos && currValue.at(quotesEnd - 1) == '\\') { - currValue = currValue.erase(quotesEnd - 1, 1); - quotesEnd = currValue.find("\"", quotesEnd + 2); - } - } - if (quotesStart != std::string::npos && quotesEnd != std::string::npos) { - // Quote provided - check and strip if valid - ELPP_ASSERT((quotesStart < quotesEnd), "Configuration error - No ending quote found in [" - << currConfigStr << "]"); - ELPP_ASSERT((quotesStart + 1 != quotesEnd), "Empty configuration value for [" << currConfigStr << "]"); - if ((quotesStart != quotesEnd) && (quotesStart + 1 != quotesEnd)) { - // Explicit check in case if assertion is disabled - currValue = currValue.substr(quotesStart + 1, quotesEnd - 1); - } - } - } - ELPP_ASSERT(*currLevel != Level::Unknown, "Unrecognized severity level [" << *currLevelStr << "]"); - ELPP_ASSERT(currConfig != ConfigurationType::Unknown, "Unrecognized configuration [" << *currConfigStr << "]"); - if (*currLevel == Level::Unknown || currConfig == ConfigurationType::Unknown) { - return false; // unrecognizable level or config - } - conf->set(*currLevel, currConfig, currValue); - return true; -} - -void Configurations::unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value) { - Configuration* conf = RegistryWithPred::get(level, configurationType); - if (conf == nullptr) { - unsafeSet(level, configurationType, value); - } -} - -void Configurations::unsafeSet(Level level, ConfigurationType configurationType, const std::string& value) { - Configuration* conf = RegistryWithPred::get(level, configurationType); - if (conf == nullptr) { - registerNew(new Configuration(level, configurationType, value)); - } else { - conf->setValue(value); - } - if (level == Level::Global) { - unsafeSetGlobally(configurationType, value, false); - } -} - -void Configurations::setGlobally(ConfigurationType configurationType, const std::string& value, - bool includeGlobalLevel) { - if (includeGlobalLevel) { - set(Level::Global, configurationType, value); - } - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - set(LevelHelper::castFromInt(lIndex), configurationType, value); - return false; // Do not break lambda function yet as we need to set all levels regardless - }); -} - -void Configurations::unsafeSetGlobally(ConfigurationType configurationType, const std::string& value, - bool includeGlobalLevel) { - if (includeGlobalLevel) { - unsafeSet(Level::Global, configurationType, value); - } - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - unsafeSet(LevelHelper::castFromInt(lIndex), configurationType, value); - return false; // Do not break lambda function yet as we need to set all levels regardless - }); -} - -// LogBuilder - -void LogBuilder::convertToColoredOutput(base::type::string_t* logLine, Level level) { - if (!m_termSupportsColor) return; - const base::type::char_t* resetColor = ELPP_LITERAL("\x1b[0m"); - if (level == Level::Error || level == Level::Fatal) - *logLine = ELPP_LITERAL("\x1b[31m") + *logLine + resetColor; - else if (level == Level::Warning) - *logLine = ELPP_LITERAL("\x1b[33m") + *logLine + resetColor; - else if (level == Level::Debug) - *logLine = ELPP_LITERAL("\x1b[32m") + *logLine + resetColor; - else if (level == Level::Info) - *logLine = ELPP_LITERAL("\x1b[36m") + *logLine + resetColor; - else if (level == Level::Trace) - *logLine = ELPP_LITERAL("\x1b[35m") + *logLine + resetColor; -} - -// Logger - -Logger::Logger(const std::string& id, base::LogStreamsReferenceMapPtr logStreamsReference) : - m_id(id), - m_typedConfigurations(nullptr), - m_parentApplicationName(std::string()), - m_isConfigured(false), - m_logStreamsReference(logStreamsReference) { - initUnflushedCount(); -} - -Logger::Logger(const std::string& id, const Configurations& configurations, - base::LogStreamsReferenceMapPtr logStreamsReference) : - m_id(id), - m_typedConfigurations(nullptr), - m_parentApplicationName(std::string()), - m_isConfigured(false), - m_logStreamsReference(logStreamsReference) { - initUnflushedCount(); - configure(configurations); -} - -Logger::Logger(const Logger& logger) { - base::utils::safeDelete(m_typedConfigurations); - m_id = logger.m_id; - m_typedConfigurations = logger.m_typedConfigurations; - m_parentApplicationName = logger.m_parentApplicationName; - m_isConfigured = logger.m_isConfigured; - m_configurations = logger.m_configurations; - m_unflushedCount = logger.m_unflushedCount; - m_logStreamsReference = logger.m_logStreamsReference; -} - -Logger& Logger::operator=(const Logger& logger) { - if (&logger != this) { - base::utils::safeDelete(m_typedConfigurations); - m_id = logger.m_id; - m_typedConfigurations = logger.m_typedConfigurations; - m_parentApplicationName = logger.m_parentApplicationName; - m_isConfigured = logger.m_isConfigured; - m_configurations = logger.m_configurations; - m_unflushedCount = logger.m_unflushedCount; - m_logStreamsReference = logger.m_logStreamsReference; - } - return *this; -} - -void Logger::configure(const Configurations& configurations) { - m_isConfigured = false; // we set it to false in case if we fail - initUnflushedCount(); - if (m_typedConfigurations != nullptr) { - Configurations* c = const_cast(m_typedConfigurations->configurations()); - if (c->hasConfiguration(Level::Global, ConfigurationType::Filename)) { - flush(); - } - } - base::threading::ScopedLock scopedLock(lock()); - if (m_configurations != configurations) { - m_configurations.setFromBase(const_cast(&configurations)); - } - base::utils::safeDelete(m_typedConfigurations); - m_typedConfigurations = new base::TypedConfigurations(&m_configurations, m_logStreamsReference); - resolveLoggerFormatSpec(); - m_isConfigured = true; -} - -void Logger::reconfigure(void) { - ELPP_INTERNAL_INFO(1, "Reconfiguring logger [" << m_id << "]"); - configure(m_configurations); -} - -bool Logger::isValidId(const std::string& id) { - for (std::string::const_iterator it = id.begin(); it != id.end(); ++it) { - if (!base::utils::Str::contains(base::consts::kValidLoggerIdSymbols, *it)) { - return false; - } - } - return true; -} - -void Logger::flush(void) { - ELPP_INTERNAL_INFO(3, "Flushing logger [" << m_id << "] all levels"); - base::threading::ScopedLock scopedLock(lock()); - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - flush(LevelHelper::castFromInt(lIndex), nullptr); - return false; - }); -} - -void Logger::flush(Level level, base::type::fstream_t* fs) { - if (fs == nullptr && m_typedConfigurations->toFile(level)) { - fs = m_typedConfigurations->fileStream(level); - } - if (fs != nullptr) { - fs->flush(); - std::unordered_map::iterator iter = m_unflushedCount.find(level); - if (iter != m_unflushedCount.end()) { - iter->second = 0; - } - Helpers::validateFileRolling(this, level); - } -} - -void Logger::initUnflushedCount(void) { - m_unflushedCount.clear(); - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - m_unflushedCount.insert(std::make_pair(LevelHelper::castFromInt(lIndex), 0)); - return false; - }); -} - -void Logger::resolveLoggerFormatSpec(void) const { - base::type::EnumType lIndex = LevelHelper::kMinValid; - LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { - base::LogFormat* logFormat = - const_cast(&m_typedConfigurations->logFormat(LevelHelper::castFromInt(lIndex))); - base::utils::Str::replaceFirstWithEscape(logFormat->m_format, base::consts::kLoggerIdFormatSpecifier, m_id); - return false; - }); -} - -// el::base -namespace base { - -// el::base::utils -namespace utils { - -// File - -base::type::fstream_t* File::newFileStream(const std::string& filename) { - base::type::fstream_t *fs = new base::type::fstream_t(filename.c_str(), - base::type::fstream_t::out -#if !defined(ELPP_FRESH_LOG_FILE) - | base::type::fstream_t::app -#endif - ); -#if defined(ELPP_UNICODE) - std::locale elppUnicodeLocale(""); -# if ELPP_OS_WINDOWS - std::locale elppUnicodeLocaleWindows(elppUnicodeLocale, new std::codecvt_utf8_utf16); - elppUnicodeLocale = elppUnicodeLocaleWindows; -# endif // ELPP_OS_WINDOWS - fs->imbue(elppUnicodeLocale); -#endif // defined(ELPP_UNICODE) - if (fs->is_open()) { - fs->flush(); - } else { - base::utils::safeDelete(fs); - ELPP_INTERNAL_ERROR("Bad file [" << filename << "]", true); - } - return fs; -} - -std::size_t File::getSizeOfFile(base::type::fstream_t* fs) { - if (fs == nullptr) { - return 0; - } - // Since the file stream is appended to or truncated, the current - // offset is the file size. - std::size_t size = static_cast(fs->tellg()); - return size; -} - -bool File::pathExists(const char* path, bool considerFile) { - if (path == nullptr) { - return false; - } -#if ELPP_OS_UNIX - ELPP_UNUSED(considerFile); - struct stat st; - return (stat(path, &st) == 0); -#elif ELPP_OS_WINDOWS - DWORD fileType = GetFileAttributesA(path); - if (fileType == INVALID_FILE_ATTRIBUTES) { - return false; - } - return considerFile ? true : ((fileType & FILE_ATTRIBUTE_DIRECTORY) == 0 ? false : true); -#endif // ELPP_OS_UNIX -} - -bool File::createPath(const std::string& path) { - if (path.empty()) { - return false; - } - if (base::utils::File::pathExists(path.c_str())) { - return true; - } - int status = -1; - - char* currPath = const_cast(path.c_str()); - std::string builtPath = std::string(); -#if ELPP_OS_UNIX - if (path[0] == '/') { - builtPath = "/"; - } - currPath = STRTOK(currPath, base::consts::kFilePathSeparator, 0); -#elif ELPP_OS_WINDOWS - // Use secure functions API - char* nextTok_ = nullptr; - currPath = STRTOK(currPath, base::consts::kFilePathSeparator, &nextTok_); - ELPP_UNUSED(nextTok_); -#endif // ELPP_OS_UNIX - while (currPath != nullptr) { - builtPath.append(currPath); - builtPath.append(base::consts::kFilePathSeparator); -#if ELPP_OS_UNIX - status = mkdir(builtPath.c_str(), ELPP_LOG_PERMS); - currPath = STRTOK(nullptr, base::consts::kFilePathSeparator, 0); -#elif ELPP_OS_WINDOWS - status = _mkdir(builtPath.c_str()); - currPath = STRTOK(nullptr, base::consts::kFilePathSeparator, &nextTok_); -#endif // ELPP_OS_UNIX - } - if (status == -1) { - ELPP_INTERNAL_ERROR("Error while creating path [" << path << "]", true); - return false; - } - return true; -} - -std::string File::extractPathFromFilename(const std::string& fullPath, const char* separator) { - if ((fullPath == "") || (fullPath.find(separator) == std::string::npos)) { - return fullPath; - } - std::size_t lastSlashAt = fullPath.find_last_of(separator); - if (lastSlashAt == 0) { - return std::string(separator); - } - return fullPath.substr(0, lastSlashAt + 1); -} - -void File::buildStrippedFilename(const char* filename, char buff[], std::size_t limit) { - std::size_t sizeOfFilename = strlen(filename); - if (sizeOfFilename >= limit) { - filename += (sizeOfFilename - limit); - if (filename[0] != '.' && filename[1] != '.') { // prepend if not already - filename += 3; // 3 = '..' - STRCAT(buff, "..", limit); - } - } - STRCAT(buff, filename, limit); -} - -void File::buildBaseFilename(const std::string& fullPath, char buff[], std::size_t limit, const char* separator) { - const char *filename = fullPath.c_str(); - std::size_t lastSlashAt = fullPath.find_last_of(separator); - filename += lastSlashAt ? lastSlashAt+1 : 0; - std::size_t sizeOfFilename = strlen(filename); - if (sizeOfFilename >= limit) { - filename += (sizeOfFilename - limit); - if (filename[0] != '.' && filename[1] != '.') { // prepend if not already - filename += 3; // 3 = '..' - STRCAT(buff, "..", limit); - } - } - STRCAT(buff, filename, limit); -} - -// Str - -bool Str::wildCardMatch(const char* str, const char* pattern) { - while (*pattern) { - switch (*pattern) { - case '?': - if (!*str) - return false; - ++str; - ++pattern; - break; - case '*': - if (wildCardMatch(str, pattern + 1)) - return true; - if (*str && wildCardMatch(str + 1, pattern)) - return true; - return false; - default: - if (*str++ != *pattern++) - return false; - break; - } - } - return !*str && !*pattern; -} - -std::string& Str::ltrim(std::string& str) { - str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](char c) { - return !std::isspace(c); - } )); - return str; -} - -std::string& Str::rtrim(std::string& str) { - str.erase(std::find_if(str.rbegin(), str.rend(), [](char c) { - return !std::isspace(c); - }).base(), str.end()); - return str; -} - -std::string& Str::trim(std::string& str) { - return ltrim(rtrim(str)); -} - -bool Str::startsWith(const std::string& str, const std::string& start) { - return (str.length() >= start.length()) && (str.compare(0, start.length(), start) == 0); -} - -bool Str::endsWith(const std::string& str, const std::string& end) { - return (str.length() >= end.length()) && (str.compare(str.length() - end.length(), end.length(), end) == 0); -} - -std::string& Str::replaceAll(std::string& str, char replaceWhat, char replaceWith) { - std::replace(str.begin(), str.end(), replaceWhat, replaceWith); - return str; -} - -std::string& Str::replaceAll(std::string& str, const std::string& replaceWhat, - const std::string& replaceWith) { - if (replaceWhat == replaceWith) - return str; - std::size_t foundAt = std::string::npos; - while ((foundAt = str.find(replaceWhat, foundAt + 1)) != std::string::npos) { - str.replace(foundAt, replaceWhat.length(), replaceWith); - } - return str; -} - -void Str::replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, - const base::type::string_t& replaceWith) { - std::size_t foundAt = base::type::string_t::npos; - while ((foundAt = str.find(replaceWhat, foundAt + 1)) != base::type::string_t::npos) { - if (foundAt > 0 && str[foundAt - 1] == base::consts::kFormatSpecifierChar) { - str.erase(foundAt - 1, 1); - ++foundAt; - } else { - str.replace(foundAt, replaceWhat.length(), replaceWith); - return; - } - } -} -#if defined(ELPP_UNICODE) -void Str::replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, - const std::string& replaceWith) { - replaceFirstWithEscape(str, replaceWhat, base::type::string_t(replaceWith.begin(), replaceWith.end())); -} -#endif // defined(ELPP_UNICODE) - -std::string& Str::toUpper(std::string& str) { - std::transform(str.begin(), str.end(), str.begin(), - [](char c) { - return static_cast(::toupper(c)); - }); - return str; -} - -bool Str::cStringEq(const char* s1, const char* s2) { - if (s1 == nullptr && s2 == nullptr) return true; - if (s1 == nullptr || s2 == nullptr) return false; - return strcmp(s1, s2) == 0; -} - -bool Str::cStringCaseEq(const char* s1, const char* s2) { - if (s1 == nullptr && s2 == nullptr) return true; - if (s1 == nullptr || s2 == nullptr) return false; - - // With thanks to cygwin for this code - int d = 0; - - while (true) { - const int c1 = toupper(*s1++); - const int c2 = toupper(*s2++); - - if (((d = c1 - c2) != 0) || (c2 == '\0')) { - break; - } - } - - return d == 0; -} - -bool Str::contains(const char* str, char c) { - for (; *str; ++str) { - if (*str == c) - return true; - } - return false; -} - -char* Str::convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded) { - char localBuff[10] = ""; - char* p = localBuff + sizeof(localBuff) - 2; - if (n > 0) { - for (; n > 0 && p > localBuff && len > 0; n /= 10, --len) - *--p = static_cast(n % 10 + '0'); - } else { - *--p = '0'; - --len; - } - if (zeroPadded) - while (p > localBuff && len-- > 0) *--p = static_cast('0'); - return addToBuff(p, buf, bufLim); -} - -char* Str::addToBuff(const char* str, char* buf, const char* bufLim) { - while ((buf < bufLim) && ((*buf = *str++) != '\0')) - ++buf; - return buf; -} - -char* Str::clearBuff(char buff[], std::size_t lim) { - STRCPY(buff, "", lim); - ELPP_UNUSED(lim); // For *nix we dont have anything using lim in above STRCPY macro - return buff; -} - -/// @brief Converts wchar* to char* -/// NOTE: Need to free return value after use! -char* Str::wcharPtrToCharPtr(const wchar_t* line) { - std::size_t len_ = wcslen(line) + 1; - char* buff_ = static_cast(malloc(len_ + 1)); -# if ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS) - std::wcstombs(buff_, line, len_); -# elif ELPP_OS_WINDOWS - std::size_t convCount_ = 0; - mbstate_t mbState_; - ::memset(static_cast(&mbState_), 0, sizeof(mbState_)); - wcsrtombs_s(&convCount_, buff_, len_, &line, len_, &mbState_); -# endif // ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS) - return buff_; -} - -// OS - -#if ELPP_OS_WINDOWS -/// @brief Gets environment variables for Windows based OS. -/// We are not using getenv(const char*) because of CRT deprecation -/// @param varname Variable name to get environment variable value for -/// @return If variable exist the value of it otherwise nullptr -const char* OS::getWindowsEnvironmentVariable(const char* varname) { - const DWORD bufferLen = 50; - static char buffer[bufferLen]; - if (GetEnvironmentVariableA(varname, buffer, bufferLen)) { - return buffer; - } - return nullptr; -} -#endif // ELPP_OS_WINDOWS -#if ELPP_OS_ANDROID -std::string OS::getProperty(const char* prop) { - char propVal[PROP_VALUE_MAX + 1]; - int ret = __system_property_get(prop, propVal); - return ret == 0 ? std::string() : std::string(propVal); -} - -std::string OS::getDeviceName(void) { - std::stringstream ss; - std::string manufacturer = getProperty("ro.product.manufacturer"); - std::string model = getProperty("ro.product.model"); - if (manufacturer.empty() || model.empty()) { - return std::string(); - } - ss << manufacturer << "-" << model; - return ss.str(); -} -#endif // ELPP_OS_ANDROID - -const std::string OS::getBashOutput(const char* command) { -#if (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN) - if (command == nullptr) { - return std::string(); - } - FILE* proc = nullptr; - if ((proc = popen(command, "r")) == nullptr) { - ELPP_INTERNAL_ERROR("\nUnable to run command [" << command << "]", true); - return std::string(); - } - char hBuff[4096]; - if (fgets(hBuff, sizeof(hBuff), proc) != nullptr) { - pclose(proc); - const std::size_t buffLen = strlen(hBuff); - if (buffLen > 0 && hBuff[buffLen - 1] == '\n') { - hBuff[buffLen - 1] = '\0'; - } - return std::string(hBuff); - } else { - pclose(proc); - } - return std::string(); -#else - ELPP_UNUSED(command); - return std::string(); -#endif // (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN) -} - -std::string OS::getEnvironmentVariable(const char* variableName, const char* defaultVal, - const char* alternativeBashCommand) { -#if ELPP_OS_UNIX - const char* val = getenv(variableName); -#elif ELPP_OS_WINDOWS - const char* val = getWindowsEnvironmentVariable(variableName); -#endif // ELPP_OS_UNIX - if ((val == nullptr) || ((strcmp(val, "") == 0))) { -#if ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH) - // Try harder on unix-based systems - std::string valBash = base::utils::OS::getBashOutput(alternativeBashCommand); - if (valBash.empty()) { - return std::string(defaultVal); - } else { - return valBash; - } -#elif ELPP_OS_WINDOWS || ELPP_OS_UNIX - ELPP_UNUSED(alternativeBashCommand); - return std::string(defaultVal); -#endif // ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH) - } - return std::string(val); -} - -std::string OS::currentUser(void) { -#if ELPP_OS_UNIX && !ELPP_OS_ANDROID - return getEnvironmentVariable("USER", base::consts::kUnknownUser, "whoami"); -#elif ELPP_OS_WINDOWS - return getEnvironmentVariable("USERNAME", base::consts::kUnknownUser); -#elif ELPP_OS_ANDROID - ELPP_UNUSED(base::consts::kUnknownUser); - return std::string("android"); -#else - return std::string(); -#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID -} - -std::string OS::currentHost(void) { -#if ELPP_OS_UNIX && !ELPP_OS_ANDROID - return getEnvironmentVariable("HOSTNAME", base::consts::kUnknownHost, "hostname"); -#elif ELPP_OS_WINDOWS - return getEnvironmentVariable("COMPUTERNAME", base::consts::kUnknownHost); -#elif ELPP_OS_ANDROID - ELPP_UNUSED(base::consts::kUnknownHost); - return getDeviceName(); -#else - return std::string(); -#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID -} - -bool OS::termSupportsColor(void) { - std::string term = getEnvironmentVariable("TERM", ""); - return term == "xterm" || term == "xterm-color" || term == "xterm-256color" - || term == "screen" || term == "linux" || term == "cygwin" - || term == "screen-256color"; -} - -// DateTime - -void DateTime::gettimeofday(struct timeval* tv) { -#if ELPP_OS_WINDOWS - if (tv != nullptr) { -# if ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS) - const unsigned __int64 delta_ = 11644473600000000Ui64; -# else - const unsigned __int64 delta_ = 11644473600000000ULL; -# endif // ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS) - const double secOffSet = 0.000001; - const unsigned long usecOffSet = 1000000; - FILETIME fileTime; - GetSystemTimeAsFileTime(&fileTime); - unsigned __int64 present = 0; - present |= fileTime.dwHighDateTime; - present = present << 32; - present |= fileTime.dwLowDateTime; - present /= 10; // mic-sec - // Subtract the difference - present -= delta_; - tv->tv_sec = static_cast(present * secOffSet); - tv->tv_usec = static_cast(present % usecOffSet); - } -#else - ::gettimeofday(tv, nullptr); -#endif // ELPP_OS_WINDOWS -} - -std::string DateTime::getDateTime(const char* format, const base::SubsecondPrecision* ssPrec) { - struct timeval currTime; - gettimeofday(&currTime); - return timevalToString(currTime, format, ssPrec); -} - -std::string DateTime::timevalToString(struct timeval tval, const char* format, - const el::base::SubsecondPrecision* ssPrec) { - struct ::tm timeInfo; - buildTimeInfo(&tval, &timeInfo); - const int kBuffSize = 30; - char buff_[kBuffSize] = ""; - parseFormat(buff_, kBuffSize, format, &timeInfo, static_cast(tval.tv_usec / ssPrec->m_offset), - ssPrec); - return std::string(buff_); -} - -base::type::string_t DateTime::formatTime(unsigned long long time, base::TimestampUnit timestampUnit) { - base::type::EnumType start = static_cast(timestampUnit); - const base::type::char_t* unit = base::consts::kTimeFormats[start].unit; - for (base::type::EnumType i = start; i < base::consts::kTimeFormatsCount - 1; ++i) { - if (time <= base::consts::kTimeFormats[i].value) { - break; - } - if (base::consts::kTimeFormats[i].value == 1000.0f && time / 1000.0f < 1.9f) { - break; - } - time /= static_cast(base::consts::kTimeFormats[i].value); - unit = base::consts::kTimeFormats[i + 1].unit; - } - base::type::stringstream_t ss; - ss << time << " " << unit; - return ss.str(); -} - -unsigned long long DateTime::getTimeDifference(const struct timeval& endTime, const struct timeval& startTime, - base::TimestampUnit timestampUnit) { - if (timestampUnit == base::TimestampUnit::Microsecond) { - return static_cast(static_cast(1000000 * endTime.tv_sec + endTime.tv_usec) - - static_cast(1000000 * startTime.tv_sec + startTime.tv_usec)); - } - // milliseconds - auto conv = [](const struct timeval& tim) { - return static_cast((tim.tv_sec * 1000) + (tim.tv_usec / 1000)); - }; - return static_cast(conv(endTime) - conv(startTime)); -} - -struct ::tm* DateTime::buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo) { -#if ELPP_OS_UNIX - time_t rawTime = currTime->tv_sec; - ::elpptime_r(&rawTime, timeInfo); - return timeInfo; -#else -# if ELPP_COMPILER_MSVC - ELPP_UNUSED(currTime); - time_t t; -# if defined(_USE_32BIT_TIME_T) - _time32(&t); -# else - _time64(&t); -# endif - elpptime_s(timeInfo, &t); - return timeInfo; -# else - // For any other compilers that don't have CRT warnings issue e.g, MinGW or TDM GCC- we use different method - time_t rawTime = currTime->tv_sec; - struct tm* tmInf = elpptime(&rawTime); - *timeInfo = *tmInf; - return timeInfo; -# endif // ELPP_COMPILER_MSVC -#endif // ELPP_OS_UNIX -} - -char* DateTime::parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo, - std::size_t msec, const base::SubsecondPrecision* ssPrec) { - const char* bufLim = buf + bufSz; - for (; *format; ++format) { - if (*format == base::consts::kFormatSpecifierChar) { - switch (*++format) { - case base::consts::kFormatSpecifierChar: // Escape - break; - case '\0': // End - --format; - break; - case 'd': // Day - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mday, 2, buf, bufLim); - continue; - case 'a': // Day of week (short) - buf = base::utils::Str::addToBuff(base::consts::kDaysAbbrev[tInfo->tm_wday], buf, bufLim); - continue; - case 'A': // Day of week (long) - buf = base::utils::Str::addToBuff(base::consts::kDays[tInfo->tm_wday], buf, bufLim); - continue; - case 'M': // month - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mon + 1, 2, buf, bufLim); - continue; - case 'b': // month (short) - buf = base::utils::Str::addToBuff(base::consts::kMonthsAbbrev[tInfo->tm_mon], buf, bufLim); - continue; - case 'B': // month (long) - buf = base::utils::Str::addToBuff(base::consts::kMonths[tInfo->tm_mon], buf, bufLim); - continue; - case 'y': // year (two digits) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 2, buf, bufLim); - continue; - case 'Y': // year (four digits) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 4, buf, bufLim); - continue; - case 'h': // hour (12-hour) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour % 12, 2, buf, bufLim); - continue; - case 'H': // hour (24-hour) - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour, 2, buf, bufLim); - continue; - case 'm': // minute - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_min, 2, buf, bufLim); - continue; - case 's': // second - buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_sec, 2, buf, bufLim); - continue; - case 'z': // subsecond part - case 'g': - buf = base::utils::Str::convertAndAddToBuff(msec, ssPrec->m_width, buf, bufLim); - continue; - case 'F': // AM/PM - buf = base::utils::Str::addToBuff((tInfo->tm_hour >= 12) ? base::consts::kPm : base::consts::kAm, buf, bufLim); - continue; - default: - continue; - } - } - if (buf == bufLim) break; - *buf++ = *format; - } - return buf; -} - -// CommandLineArgs - -void CommandLineArgs::setArgs(int argc, char** argv) { - m_params.clear(); - m_paramsWithValue.clear(); - if (argc == 0 || argv == nullptr) { - return; - } - m_argc = argc; - m_argv = argv; - for (int i = 1; i < m_argc; ++i) { - const char* v = (strstr(m_argv[i], "=")); - if (v != nullptr && strlen(v) > 0) { - std::string key = std::string(m_argv[i]); - key = key.substr(0, key.find_first_of('=')); - if (hasParamWithValue(key.c_str())) { - ELPP_INTERNAL_INFO(1, "Skipping [" << key << "] arg since it already has value [" - << getParamValue(key.c_str()) << "]"); - } else { - m_paramsWithValue.insert(std::make_pair(key, std::string(v + 1))); - } - } - if (v == nullptr) { - if (hasParam(m_argv[i])) { - ELPP_INTERNAL_INFO(1, "Skipping [" << m_argv[i] << "] arg since it already exists"); - } else { - m_params.push_back(std::string(m_argv[i])); - } - } - } -} - -bool CommandLineArgs::hasParamWithValue(const char* paramKey) const { - return m_paramsWithValue.find(std::string(paramKey)) != m_paramsWithValue.end(); -} - -const char* CommandLineArgs::getParamValue(const char* paramKey) const { - std::unordered_map::const_iterator iter = m_paramsWithValue.find(std::string(paramKey)); - return iter != m_paramsWithValue.end() ? iter->second.c_str() : ""; -} - -bool CommandLineArgs::hasParam(const char* paramKey) const { - return std::find(m_params.begin(), m_params.end(), std::string(paramKey)) != m_params.end(); -} - -bool CommandLineArgs::empty(void) const { - return m_params.empty() && m_paramsWithValue.empty(); -} - -std::size_t CommandLineArgs::size(void) const { - return m_params.size() + m_paramsWithValue.size(); -} - -base::type::ostream_t& operator<<(base::type::ostream_t& os, const CommandLineArgs& c) { - for (int i = 1; i < c.m_argc; ++i) { - os << ELPP_LITERAL("[") << c.m_argv[i] << ELPP_LITERAL("]"); - if (i < c.m_argc - 1) { - os << ELPP_LITERAL(" "); - } - } - return os; -} - -} // namespace utils - -// el::base::threading -namespace threading { - -#if ELPP_THREADING_ENABLED -# if ELPP_USE_STD_THREADING -# if ELPP_ASYNC_LOGGING -static void msleep(int ms) { - // Only when async logging enabled - this is because async is strict on compiler -# if defined(ELPP_NO_SLEEP_FOR) - usleep(ms * 1000); -# else - std::this_thread::sleep_for(std::chrono::milliseconds(ms)); -# endif // defined(ELPP_NO_SLEEP_FOR) -} -# endif // ELPP_ASYNC_LOGGING -# endif // !ELPP_USE_STD_THREADING -#endif // ELPP_THREADING_ENABLED - -} // namespace threading - -// el::base - -// SubsecondPrecision - -void SubsecondPrecision::init(int width) { - if (width < 1 || width > 6) { - width = base::consts::kDefaultSubsecondPrecision; - } - m_width = width; - switch (m_width) { - case 3: - m_offset = 1000; - break; - case 4: - m_offset = 100; - break; - case 5: - m_offset = 10; - break; - case 6: - m_offset = 1; - break; - default: - m_offset = 1000; - break; - } -} - -// LogFormat - -LogFormat::LogFormat(void) : - m_level(Level::Unknown), - m_userFormat(base::type::string_t()), - m_format(base::type::string_t()), - m_dateTimeFormat(std::string()), - m_flags(0x0), - m_currentUser(base::utils::OS::currentUser()), - m_currentHost(base::utils::OS::currentHost()) { -} - -LogFormat::LogFormat(Level level, const base::type::string_t& format) - : m_level(level), m_userFormat(format), m_currentUser(base::utils::OS::currentUser()), - m_currentHost(base::utils::OS::currentHost()) { - parseFromFormat(m_userFormat); -} - -LogFormat::LogFormat(const LogFormat& logFormat): - m_level(logFormat.m_level), - m_userFormat(logFormat.m_userFormat), - m_format(logFormat.m_format), - m_dateTimeFormat(logFormat.m_dateTimeFormat), - m_flags(logFormat.m_flags), - m_currentUser(logFormat.m_currentUser), - m_currentHost(logFormat.m_currentHost) { -} - -LogFormat::LogFormat(LogFormat&& logFormat) { - m_level = std::move(logFormat.m_level); - m_userFormat = std::move(logFormat.m_userFormat); - m_format = std::move(logFormat.m_format); - m_dateTimeFormat = std::move(logFormat.m_dateTimeFormat); - m_flags = std::move(logFormat.m_flags); - m_currentUser = std::move(logFormat.m_currentUser); - m_currentHost = std::move(logFormat.m_currentHost); -} - -LogFormat& LogFormat::operator=(const LogFormat& logFormat) { - if (&logFormat != this) { - m_level = logFormat.m_level; - m_userFormat = logFormat.m_userFormat; - m_dateTimeFormat = logFormat.m_dateTimeFormat; - m_flags = logFormat.m_flags; - m_currentUser = logFormat.m_currentUser; - m_currentHost = logFormat.m_currentHost; - } - return *this; -} - -bool LogFormat::operator==(const LogFormat& other) { - return m_level == other.m_level && m_userFormat == other.m_userFormat && m_format == other.m_format && - m_dateTimeFormat == other.m_dateTimeFormat && m_flags == other.m_flags; -} - -/// @brief Updates format to be used while logging. -/// @param userFormat User provided format -void LogFormat::parseFromFormat(const base::type::string_t& userFormat) { - // We make copy because we will be changing the format - // i.e, removing user provided date format from original format - // and then storing it. - base::type::string_t formatCopy = userFormat; - m_flags = 0x0; - auto conditionalAddFlag = [&](const base::type::char_t* specifier, base::FormatFlags flag) { - std::size_t foundAt = base::type::string_t::npos; - while ((foundAt = formatCopy.find(specifier, foundAt + 1)) != base::type::string_t::npos) { - if (foundAt > 0 && formatCopy[foundAt - 1] == base::consts::kFormatSpecifierChar) { - if (hasFlag(flag)) { - // If we already have flag we remove the escape chars so that '%%' is turned to '%' - // even after specifier resolution - this is because we only replaceFirst specifier - formatCopy.erase(foundAt - 1, 1); - ++foundAt; - } - } else { - if (!hasFlag(flag)) addFlag(flag); - } - } - }; - conditionalAddFlag(base::consts::kAppNameFormatSpecifier, base::FormatFlags::AppName); - conditionalAddFlag(base::consts::kSeverityLevelFormatSpecifier, base::FormatFlags::Level); - conditionalAddFlag(base::consts::kSeverityLevelShortFormatSpecifier, base::FormatFlags::LevelShort); - conditionalAddFlag(base::consts::kLoggerIdFormatSpecifier, base::FormatFlags::LoggerId); - conditionalAddFlag(base::consts::kThreadIdFormatSpecifier, base::FormatFlags::ThreadId); - conditionalAddFlag(base::consts::kLogFileFormatSpecifier, base::FormatFlags::File); - conditionalAddFlag(base::consts::kLogFileBaseFormatSpecifier, base::FormatFlags::FileBase); - conditionalAddFlag(base::consts::kLogLineFormatSpecifier, base::FormatFlags::Line); - conditionalAddFlag(base::consts::kLogLocationFormatSpecifier, base::FormatFlags::Location); - conditionalAddFlag(base::consts::kLogFunctionFormatSpecifier, base::FormatFlags::Function); - conditionalAddFlag(base::consts::kCurrentUserFormatSpecifier, base::FormatFlags::User); - conditionalAddFlag(base::consts::kCurrentHostFormatSpecifier, base::FormatFlags::Host); - conditionalAddFlag(base::consts::kMessageFormatSpecifier, base::FormatFlags::LogMessage); - conditionalAddFlag(base::consts::kVerboseLevelFormatSpecifier, base::FormatFlags::VerboseLevel); - // For date/time we need to extract user's date format first - std::size_t dateIndex = std::string::npos; - if ((dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier)) != std::string::npos) { - while (dateIndex != std::string::npos && dateIndex > 0 && formatCopy[dateIndex - 1] == base::consts::kFormatSpecifierChar) { - dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier, dateIndex + 1); - } - if (dateIndex != std::string::npos) { - addFlag(base::FormatFlags::DateTime); - updateDateFormat(dateIndex, formatCopy); - } - } - m_format = formatCopy; - updateFormatSpec(); -} - -void LogFormat::updateDateFormat(std::size_t index, base::type::string_t& currFormat) { - if (hasFlag(base::FormatFlags::DateTime)) { - index += ELPP_STRLEN(base::consts::kDateTimeFormatSpecifier); - } - const base::type::char_t* ptr = currFormat.c_str() + index; - if ((currFormat.size() > index) && (ptr[0] == '{')) { - // User has provided format for date/time - ++ptr; - int count = 1; // Start by 1 in order to remove starting brace - std::stringstream ss; - for (; *ptr; ++ptr, ++count) { - if (*ptr == '}') { - ++count; // In order to remove ending brace - break; - } - ss << static_cast(*ptr); - } - currFormat.erase(index, count); - m_dateTimeFormat = ss.str(); - } else { - // No format provided, use default - if (hasFlag(base::FormatFlags::DateTime)) { - m_dateTimeFormat = std::string(base::consts::kDefaultDateTimeFormat); - } - } -} - -void LogFormat::updateFormatSpec(void) { - // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet. - if (m_level == Level::Debug) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kDebugLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kDebugLevelShortLogValue); - } else if (m_level == Level::Info) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kInfoLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kInfoLevelShortLogValue); - } else if (m_level == Level::Warning) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kWarningLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kWarningLevelShortLogValue); - } else if (m_level == Level::Error) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kErrorLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kErrorLevelShortLogValue); - } else if (m_level == Level::Fatal) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kFatalLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kFatalLevelShortLogValue); - } else if (m_level == Level::Verbose) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kVerboseLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kVerboseLevelShortLogValue); - } else if (m_level == Level::Trace) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, - base::consts::kTraceLevelLogValue); - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, - base::consts::kTraceLevelShortLogValue); - } - if (hasFlag(base::FormatFlags::User)) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kCurrentUserFormatSpecifier, - m_currentUser); - } - if (hasFlag(base::FormatFlags::Host)) { - base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kCurrentHostFormatSpecifier, - m_currentHost); - } - // Ignore Level::Global and Level::Unknown -} - -// TypedConfigurations - -TypedConfigurations::TypedConfigurations(Configurations* configurations, - LogStreamsReferenceMapPtr logStreamsReference) { - m_configurations = configurations; - m_logStreamsReference = logStreamsReference; - build(m_configurations); -} - -TypedConfigurations::TypedConfigurations(const TypedConfigurations& other) { - this->m_configurations = other.m_configurations; - this->m_logStreamsReference = other.m_logStreamsReference; - build(m_configurations); -} - -bool TypedConfigurations::enabled(Level level) { - return getConfigByVal(level, &m_enabledMap, "enabled"); -} - -bool TypedConfigurations::toFile(Level level) { - return getConfigByVal(level, &m_toFileMap, "toFile"); -} - -const std::string& TypedConfigurations::filename(Level level) { - return getConfigByRef(level, &m_filenameMap, "filename"); -} - -bool TypedConfigurations::toStandardOutput(Level level) { - return getConfigByVal(level, &m_toStandardOutputMap, "toStandardOutput"); -} - -const base::LogFormat& TypedConfigurations::logFormat(Level level) { - return getConfigByRef(level, &m_logFormatMap, "logFormat"); -} - -const base::SubsecondPrecision& TypedConfigurations::subsecondPrecision(Level level) { - return getConfigByRef(level, &m_subsecondPrecisionMap, "subsecondPrecision"); -} - -const base::MillisecondsWidth& TypedConfigurations::millisecondsWidth(Level level) { - return getConfigByRef(level, &m_subsecondPrecisionMap, "millisecondsWidth"); -} - -bool TypedConfigurations::performanceTracking(Level level) { - return getConfigByVal(level, &m_performanceTrackingMap, "performanceTracking"); -} - -base::type::fstream_t* TypedConfigurations::fileStream(Level level) { - return getConfigByRef(level, &m_fileStreamMap, "fileStream").get(); -} - -std::size_t TypedConfigurations::maxLogFileSize(Level level) { - return getConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize"); -} - -std::size_t TypedConfigurations::logFlushThreshold(Level level) { - return getConfigByVal(level, &m_logFlushThresholdMap, "logFlushThreshold"); -} - -void TypedConfigurations::build(Configurations* configurations) { - base::threading::ScopedLock scopedLock(lock()); - auto getBool = [] (std::string boolStr) -> bool { // Pass by value for trimming - base::utils::Str::trim(boolStr); - return (boolStr == "TRUE" || boolStr == "true" || boolStr == "1"); - }; - std::vector withFileSizeLimit; - for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) { - Configuration* conf = *it; - // We cannot use switch on strong enums because Intel C++ dont support them yet - if (conf->configurationType() == ConfigurationType::Enabled) { - setValue(conf->level(), getBool(conf->value()), &m_enabledMap); - } else if (conf->configurationType() == ConfigurationType::ToFile) { - setValue(conf->level(), getBool(conf->value()), &m_toFileMap); - } else if (conf->configurationType() == ConfigurationType::ToStandardOutput) { - setValue(conf->level(), getBool(conf->value()), &m_toStandardOutputMap); - } else if (conf->configurationType() == ConfigurationType::Filename) { - // We do not yet configure filename but we will configure in another - // loop. This is because if file cannot be created, we will force ToFile - // to be false. Because configuring logger is not necessarily performance - // sensitive operation, we can live with another loop; (by the way this loop - // is not very heavy either) - } else if (conf->configurationType() == ConfigurationType::Format) { - setValue(conf->level(), base::LogFormat(conf->level(), - base::type::string_t(conf->value().begin(), conf->value().end())), &m_logFormatMap); - } else if (conf->configurationType() == ConfigurationType::SubsecondPrecision) { - setValue(Level::Global, - base::SubsecondPrecision(static_cast(getULong(conf->value()))), &m_subsecondPrecisionMap); - } else if (conf->configurationType() == ConfigurationType::PerformanceTracking) { - setValue(Level::Global, getBool(conf->value()), &m_performanceTrackingMap); - } else if (conf->configurationType() == ConfigurationType::MaxLogFileSize) { - auto v = getULong(conf->value()); - setValue(conf->level(), static_cast(v), &m_maxLogFileSizeMap); - if (v != 0) { - withFileSizeLimit.push_back(conf); - } - } else if (conf->configurationType() == ConfigurationType::LogFlushThreshold) { - setValue(conf->level(), static_cast(getULong(conf->value())), &m_logFlushThresholdMap); - } - } - // As mentioned earlier, we will now set filename configuration in separate loop to deal with non-existent files - for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) { - Configuration* conf = *it; - if (conf->configurationType() == ConfigurationType::Filename) { - insertFile(conf->level(), conf->value()); - } - } - for (std::vector::iterator conf = withFileSizeLimit.begin(); - conf != withFileSizeLimit.end(); ++conf) { - // This is not unsafe as mutex is locked in currect scope - unsafeValidateFileRolling((*conf)->level(), base::defaultPreRollOutCallback); - } -} - -unsigned long TypedConfigurations::getULong(std::string confVal) { - bool valid = true; - base::utils::Str::trim(confVal); - valid = !confVal.empty() && std::find_if(confVal.begin(), confVal.end(), - [](char c) { - return !base::utils::Str::isDigit(c); - }) == confVal.end(); - if (!valid) { - valid = false; - ELPP_ASSERT(valid, "Configuration value not a valid integer [" << confVal << "]"); - return 0; - } - return atol(confVal.c_str()); -} - -std::string TypedConfigurations::resolveFilename(const std::string& filename) { - std::string resultingFilename = filename; - std::size_t dateIndex = std::string::npos; - std::string dateTimeFormatSpecifierStr = std::string(base::consts::kDateTimeFormatSpecifierForFilename); - if ((dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str())) != std::string::npos) { - while (dateIndex > 0 && resultingFilename[dateIndex - 1] == base::consts::kFormatSpecifierChar) { - dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str(), dateIndex + 1); - } - if (dateIndex != std::string::npos) { - const char* ptr = resultingFilename.c_str() + dateIndex; - // Goto end of specifier - ptr += dateTimeFormatSpecifierStr.size(); - std::string fmt; - if ((resultingFilename.size() > dateIndex) && (ptr[0] == '{')) { - // User has provided format for date/time - ++ptr; - int count = 1; // Start by 1 in order to remove starting brace - std::stringstream ss; - for (; *ptr; ++ptr, ++count) { - if (*ptr == '}') { - ++count; // In order to remove ending brace - break; - } - ss << *ptr; - } - resultingFilename.erase(dateIndex + dateTimeFormatSpecifierStr.size(), count); - fmt = ss.str(); - } else { - fmt = std::string(base::consts::kDefaultDateTimeFormatInFilename); - } - base::SubsecondPrecision ssPrec(3); - std::string now = base::utils::DateTime::getDateTime(fmt.c_str(), &ssPrec); - base::utils::Str::replaceAll(now, '/', '-'); // Replace path element since we are dealing with filename - base::utils::Str::replaceAll(resultingFilename, dateTimeFormatSpecifierStr, now); - } - } - return resultingFilename; -} - -void TypedConfigurations::insertFile(Level level, const std::string& fullFilename) { - std::string resolvedFilename = resolveFilename(fullFilename); - if (resolvedFilename.empty()) { - std::cerr << "Could not load empty file for logging, please re-check your configurations for level [" - << LevelHelper::convertToString(level) << "]"; - } - std::string filePath = base::utils::File::extractPathFromFilename(resolvedFilename, base::consts::kFilePathSeparator); - if (filePath.size() < resolvedFilename.size()) { - base::utils::File::createPath(filePath); - } - auto create = [&](Level level) { - base::LogStreamsReferenceMap::iterator filestreamIter = m_logStreamsReference->find(resolvedFilename); - base::type::fstream_t* fs = nullptr; - if (filestreamIter == m_logStreamsReference->end()) { - // We need a completely new stream, nothing to share with - fs = base::utils::File::newFileStream(resolvedFilename); - m_filenameMap.insert(std::make_pair(level, resolvedFilename)); - m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(fs))); - m_logStreamsReference->insert(std::make_pair(resolvedFilename, base::FileStreamPtr(m_fileStreamMap.at(level)))); - } else { - // Woops! we have an existing one, share it! - m_filenameMap.insert(std::make_pair(level, filestreamIter->first)); - m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(filestreamIter->second))); - fs = filestreamIter->second.get(); - } - if (fs == nullptr) { - // We display bad file error from newFileStream() - ELPP_INTERNAL_ERROR("Setting [TO_FILE] of [" - << LevelHelper::convertToString(level) << "] to FALSE", false); - setValue(level, false, &m_toFileMap); - } - }; - // If we dont have file conf for any level, create it for Level::Global first - // otherwise create for specified level - create(m_filenameMap.empty() && m_fileStreamMap.empty() ? Level::Global : level); -} - -bool TypedConfigurations::unsafeValidateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback) { - base::type::fstream_t* fs = unsafeGetConfigByRef(level, &m_fileStreamMap, "fileStream").get(); - if (fs == nullptr) { - return true; - } - std::size_t maxLogFileSize = unsafeGetConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize"); - std::size_t currFileSize = base::utils::File::getSizeOfFile(fs); - if (maxLogFileSize != 0 && currFileSize >= maxLogFileSize) { - std::string fname = unsafeGetConfigByRef(level, &m_filenameMap, "filename"); - ELPP_INTERNAL_INFO(1, "Truncating log file [" << fname << "] as a result of configurations for level [" - << LevelHelper::convertToString(level) << "]"); - fs->close(); - preRollOutCallback(fname.c_str(), currFileSize); - fs->open(fname, std::fstream::out | std::fstream::trunc); - return true; - } - return false; -} - -// RegisteredHitCounters - -bool RegisteredHitCounters::validateEveryN(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { - base::threading::ScopedLock scopedLock(lock()); - base::HitCounter* counter = get(filename, lineNumber); - if (counter == nullptr) { - registerNew(counter = new base::HitCounter(filename, lineNumber)); - } - counter->validateHitCounts(n); - bool result = (n >= 1 && counter->hitCounts() != 0 && counter->hitCounts() % n == 0); - return result; -} - -/// @brief Validates counter for hits >= N, i.e, registers new if does not exist otherwise updates original one -/// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned -bool RegisteredHitCounters::validateAfterN(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { - base::threading::ScopedLock scopedLock(lock()); - base::HitCounter* counter = get(filename, lineNumber); - if (counter == nullptr) { - registerNew(counter = new base::HitCounter(filename, lineNumber)); - } - // Do not use validateHitCounts here since we do not want to reset counter here - // Note the >= instead of > because we are incrementing - // after this check - if (counter->hitCounts() >= n) - return true; - counter->increment(); - return false; -} - -/// @brief Validates counter for hits are <= n, i.e, registers new if does not exist otherwise updates original one -/// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned -bool RegisteredHitCounters::validateNTimes(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { - base::threading::ScopedLock scopedLock(lock()); - base::HitCounter* counter = get(filename, lineNumber); - if (counter == nullptr) { - registerNew(counter = new base::HitCounter(filename, lineNumber)); - } - counter->increment(); - // Do not use validateHitCounts here since we do not want to reset counter here - if (counter->hitCounts() <= n) - return true; - return false; -} - -// RegisteredLoggers - -RegisteredLoggers::RegisteredLoggers(const LogBuilderPtr& defaultLogBuilder) : - m_defaultLogBuilder(defaultLogBuilder) { - m_defaultConfigurations.setToDefault(); - m_logStreamsReference = std::make_shared(); -} - -Logger* RegisteredLoggers::get(const std::string& id, bool forceCreation) { - base::threading::ScopedLock scopedLock(lock()); - Logger* logger_ = base::utils::Registry::get(id); - if (logger_ == nullptr && forceCreation) { - bool validId = Logger::isValidId(id); - if (!validId) { - ELPP_ASSERT(validId, "Invalid logger ID [" << id << "]. Not registering this logger."); - return nullptr; - } - logger_ = new Logger(id, m_defaultConfigurations, m_logStreamsReference); - logger_->m_logBuilder = m_defaultLogBuilder; - registerNew(id, logger_); - LoggerRegistrationCallback* callback = nullptr; - for (const std::pair& h - : m_loggerRegistrationCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - callback->handle(logger_); - } - } - } - return logger_; -} - -bool RegisteredLoggers::remove(const std::string& id) { - if (id == base::consts::kDefaultLoggerId) { - return false; - } - // get has internal lock - Logger* logger = base::utils::Registry::get(id); - if (logger != nullptr) { - // unregister has internal lock - unregister(logger); - } - return true; -} - -void RegisteredLoggers::unsafeFlushAll(void) { - ELPP_INTERNAL_INFO(1, "Flushing all log files"); - for (base::LogStreamsReferenceMap::iterator it = m_logStreamsReference->begin(); - it != m_logStreamsReference->end(); ++it) { - if (it->second.get() == nullptr) continue; - it->second->flush(); - } -} - -// VRegistry - -VRegistry::VRegistry(base::type::VerboseLevel level, base::type::EnumType* pFlags) : m_level(level), m_pFlags(pFlags) { -} - -/// @brief Sets verbose level. Accepted range is 0-9 -void VRegistry::setLevel(base::type::VerboseLevel level) { - base::threading::ScopedLock scopedLock(lock()); - if (level > 9) - m_level = base::consts::kMaxVerboseLevel; - else - m_level = level; -} - -void VRegistry::setModules(const char* modules) { - base::threading::ScopedLock scopedLock(lock()); - auto addSuffix = [](std::stringstream& ss, const char* sfx, const char* prev) { - if (prev != nullptr && base::utils::Str::endsWith(ss.str(), std::string(prev))) { - std::string chr(ss.str().substr(0, ss.str().size() - strlen(prev))); - ss.str(std::string("")); - ss << chr; - } - if (base::utils::Str::endsWith(ss.str(), std::string(sfx))) { - std::string chr(ss.str().substr(0, ss.str().size() - strlen(sfx))); - ss.str(std::string("")); - ss << chr; - } - ss << sfx; - }; - auto insert = [&](std::stringstream& ss, base::type::VerboseLevel level) { - if (!base::utils::hasFlag(LoggingFlag::DisableVModulesExtensions, *m_pFlags)) { - addSuffix(ss, ".h", nullptr); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".c", ".h"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".cpp", ".c"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".cc", ".cpp"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".cxx", ".cc"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".-inl.h", ".cxx"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".hxx", ".-inl.h"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".hpp", ".hxx"); - m_modules.insert(std::make_pair(ss.str(), level)); - addSuffix(ss, ".hh", ".hpp"); - } - m_modules.insert(std::make_pair(ss.str(), level)); - }; - bool isMod = true; - bool isLevel = false; - std::stringstream ss; - int level = -1; - for (; *modules; ++modules) { - switch (*modules) { - case '=': - isLevel = true; - isMod = false; - break; - case ',': - isLevel = false; - isMod = true; - if (!ss.str().empty() && level != -1) { - insert(ss, static_cast(level)); - ss.str(std::string("")); - level = -1; - } - break; - default: - if (isMod) { - ss << *modules; - } else if (isLevel) { - if (isdigit(*modules)) { - level = static_cast(*modules) - 48; - } - } - break; - } - } - if (!ss.str().empty() && level != -1) { - insert(ss, static_cast(level)); - } -} - -bool VRegistry::allowed(base::type::VerboseLevel vlevel, const char* file) { - base::threading::ScopedLock scopedLock(lock()); - if (m_modules.empty() || file == nullptr) { - return vlevel <= m_level; - } else { - char baseFilename[base::consts::kSourceFilenameMaxLength] = ""; - base::utils::File::buildBaseFilename(file, baseFilename); - std::unordered_map::iterator it = m_modules.begin(); - for (; it != m_modules.end(); ++it) { - if (base::utils::Str::wildCardMatch(baseFilename, it->first.c_str())) { - return vlevel <= it->second; - } - } - if (base::utils::hasFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified, *m_pFlags)) { - return true; - } - return false; - } -} - -void VRegistry::setFromArgs(const base::utils::CommandLineArgs* commandLineArgs) { - if (commandLineArgs->hasParam("-v") || commandLineArgs->hasParam("--verbose") || - commandLineArgs->hasParam("-V") || commandLineArgs->hasParam("--VERBOSE")) { - setLevel(base::consts::kMaxVerboseLevel); - } else if (commandLineArgs->hasParamWithValue("--v")) { - setLevel(static_cast(atoi(commandLineArgs->getParamValue("--v")))); - } else if (commandLineArgs->hasParamWithValue("--V")) { - setLevel(static_cast(atoi(commandLineArgs->getParamValue("--V")))); - } else if ((commandLineArgs->hasParamWithValue("-vmodule")) && vModulesEnabled()) { - setModules(commandLineArgs->getParamValue("-vmodule")); - } else if (commandLineArgs->hasParamWithValue("-VMODULE") && vModulesEnabled()) { - setModules(commandLineArgs->getParamValue("-VMODULE")); - } -} - -#if !defined(ELPP_DEFAULT_LOGGING_FLAGS) -# define ELPP_DEFAULT_LOGGING_FLAGS 0x0 -#endif // !defined(ELPP_DEFAULT_LOGGING_FLAGS) -// Storage -#if ELPP_ASYNC_LOGGING -Storage::Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker) : -#else -Storage::Storage(const LogBuilderPtr& defaultLogBuilder) : -#endif // ELPP_ASYNC_LOGGING - m_registeredHitCounters(new base::RegisteredHitCounters()), - m_registeredLoggers(new base::RegisteredLoggers(defaultLogBuilder)), - m_flags(ELPP_DEFAULT_LOGGING_FLAGS), - m_vRegistry(new base::VRegistry(0, &m_flags)), - -#if ELPP_ASYNC_LOGGING - m_asyncLogQueue(new base::AsyncLogQueue()), - m_asyncDispatchWorker(asyncDispatchWorker), -#endif // ELPP_ASYNC_LOGGING - - m_preRollOutCallback(base::defaultPreRollOutCallback) { - // Register default logger - m_registeredLoggers->get(std::string(base::consts::kDefaultLoggerId)); - // We register default logger anyway (worse case it's not going to register) just in case - m_registeredLoggers->get("default"); - -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - // Register performance logger and reconfigure format - Logger* performanceLogger = m_registeredLoggers->get(std::string(base::consts::kPerformanceLoggerId)); - m_registeredLoggers->get("performance"); - performanceLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%datetime %level %msg")); - performanceLogger->reconfigure(); -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - -#if defined(ELPP_SYSLOG) - // Register syslog logger and reconfigure format - Logger* sysLogLogger = m_registeredLoggers->get(std::string(base::consts::kSysLogLoggerId)); - sysLogLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%level: %msg")); - sysLogLogger->reconfigure(); -#endif // defined(ELPP_SYSLOG) - addFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified); -#if ELPP_ASYNC_LOGGING - installLogDispatchCallback(std::string("AsyncLogDispatchCallback")); -#else - installLogDispatchCallback(std::string("DefaultLogDispatchCallback")); -#endif // ELPP_ASYNC_LOGGING -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - installPerformanceTrackingCallback - (std::string("DefaultPerformanceTrackingCallback")); -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - ELPP_INTERNAL_INFO(1, "Easylogging++ has been initialized"); -#if ELPP_ASYNC_LOGGING - m_asyncDispatchWorker->start(); -#endif // ELPP_ASYNC_LOGGING -} - -Storage::~Storage(void) { - ELPP_INTERNAL_INFO(4, "Destroying storage"); -#if ELPP_ASYNC_LOGGING - ELPP_INTERNAL_INFO(5, "Replacing log dispatch callback to synchronous"); - uninstallLogDispatchCallback(std::string("AsyncLogDispatchCallback")); - installLogDispatchCallback(std::string("DefaultLogDispatchCallback")); - ELPP_INTERNAL_INFO(5, "Destroying asyncDispatchWorker"); - base::utils::safeDelete(m_asyncDispatchWorker); - ELPP_INTERNAL_INFO(5, "Destroying asyncLogQueue"); - base::utils::safeDelete(m_asyncLogQueue); -#endif // ELPP_ASYNC_LOGGING - ELPP_INTERNAL_INFO(5, "Destroying registeredHitCounters"); - base::utils::safeDelete(m_registeredHitCounters); - ELPP_INTERNAL_INFO(5, "Destroying registeredLoggers"); - base::utils::safeDelete(m_registeredLoggers); - ELPP_INTERNAL_INFO(5, "Destroying vRegistry"); - base::utils::safeDelete(m_vRegistry); -} - -bool Storage::hasCustomFormatSpecifier(const char* formatSpecifier) { - base::threading::ScopedLock scopedLock(customFormatSpecifiersLock()); - return std::find(m_customFormatSpecifiers.begin(), m_customFormatSpecifiers.end(), - formatSpecifier) != m_customFormatSpecifiers.end(); -} - -void Storage::installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) { - if (hasCustomFormatSpecifier(customFormatSpecifier.formatSpecifier())) { - return; - } - base::threading::ScopedLock scopedLock(customFormatSpecifiersLock()); - m_customFormatSpecifiers.push_back(customFormatSpecifier); -} - -bool Storage::uninstallCustomFormatSpecifier(const char* formatSpecifier) { - base::threading::ScopedLock scopedLock(customFormatSpecifiersLock()); - std::vector::iterator it = std::find(m_customFormatSpecifiers.begin(), - m_customFormatSpecifiers.end(), formatSpecifier); - if (it != m_customFormatSpecifiers.end() && strcmp(formatSpecifier, it->formatSpecifier()) == 0) { - m_customFormatSpecifiers.erase(it); - return true; - } - return false; -} - -void Storage::setApplicationArguments(int argc, char** argv) { - m_commandLineArgs.setArgs(argc, argv); - m_vRegistry->setFromArgs(commandLineArgs()); - // default log file -#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) - if (m_commandLineArgs.hasParamWithValue(base::consts::kDefaultLogFileParam)) { - Configurations c; - c.setGlobally(ConfigurationType::Filename, - std::string(m_commandLineArgs.getParamValue(base::consts::kDefaultLogFileParam))); - registeredLoggers()->setDefaultConfigurations(c); - for (base::RegisteredLoggers::iterator it = registeredLoggers()->begin(); - it != registeredLoggers()->end(); ++it) { - it->second->configure(c); - } - } -#endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) -#if defined(ELPP_LOGGING_FLAGS_FROM_ARG) - if (m_commandLineArgs.hasParamWithValue(base::consts::kLoggingFlagsParam)) { - int userInput = atoi(m_commandLineArgs.getParamValue(base::consts::kLoggingFlagsParam)); - if (ELPP_DEFAULT_LOGGING_FLAGS == 0x0) { - m_flags = userInput; - } else { - base::utils::addFlag(userInput, &m_flags); - } - } -#endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG) -} - -} // namespace base - -// LogDispatchCallback -#if defined(ELPP_THREAD_SAFE) -void LogDispatchCallback::handle(const LogDispatchData* data) { - base::threading::ScopedLock scopedLock(m_fileLocksMapLock); - std::string filename = data->logMessage()->logger()->typedConfigurations()->filename(data->logMessage()->level()); - auto lock = m_fileLocks.find(filename); - if (lock == m_fileLocks.end()) { - m_fileLocks.emplace(std::make_pair(filename, std::unique_ptr(new base::threading::Mutex))); - } -} -#else -void LogDispatchCallback::handle(const LogDispatchData* /*data*/) {} -#endif - -base::threading::Mutex& LogDispatchCallback::fileHandle(const LogDispatchData* data) { - auto it = m_fileLocks.find(data->logMessage()->logger()->typedConfigurations()->filename(data->logMessage()->level())); - return *(it->second.get()); -} - -namespace base { -// DefaultLogDispatchCallback - -void DefaultLogDispatchCallback::handle(const LogDispatchData* data) { -#if defined(ELPP_THREAD_SAFE) - LogDispatchCallback::handle(data); - base::threading::ScopedLock scopedLock(fileHandle(data)); -#endif - m_data = data; - dispatch(m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(), - m_data->dispatchAction() == base::DispatchAction::NormalLog)); -} - -void DefaultLogDispatchCallback::dispatch(base::type::string_t&& logLine) { - if (m_data->dispatchAction() == base::DispatchAction::NormalLog) { - if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) { - base::type::fstream_t* fs = m_data->logMessage()->logger()->m_typedConfigurations->fileStream( - m_data->logMessage()->level()); - if (fs != nullptr) { - fs->write(logLine.c_str(), logLine.size()); - if (fs->fail()) { - ELPP_INTERNAL_ERROR("Unable to write log to file [" - << m_data->logMessage()->logger()->m_typedConfigurations->filename(m_data->logMessage()->level()) << "].\n" - << "Few possible reasons (could be something else):\n" << " * Permission denied\n" - << " * Disk full\n" << " * Disk is not writable", true); - } else { - if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) - || (m_data->logMessage()->logger()->isFlushNeeded(m_data->logMessage()->level()))) { - m_data->logMessage()->logger()->flush(m_data->logMessage()->level(), fs); - } - } - } else { - ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(m_data->logMessage()->level()) << "] " - << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: " - << m_data->logMessage()->logger()->id() << "]", false); - } - } - if (m_data->logMessage()->logger()->m_typedConfigurations->toStandardOutput(m_data->logMessage()->level())) { - if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) - m_data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, m_data->logMessage()->level()); - ELPP_COUT << ELPP_COUT_LINE(logLine); - } - } -#if defined(ELPP_SYSLOG) - else if (m_data->dispatchAction() == base::DispatchAction::SysLog) { - // Determine syslog priority - int sysLogPriority = 0; - if (m_data->logMessage()->level() == Level::Fatal) - sysLogPriority = LOG_EMERG; - else if (m_data->logMessage()->level() == Level::Error) - sysLogPriority = LOG_ERR; - else if (m_data->logMessage()->level() == Level::Warning) - sysLogPriority = LOG_WARNING; - else if (m_data->logMessage()->level() == Level::Info) - sysLogPriority = LOG_INFO; - else if (m_data->logMessage()->level() == Level::Debug) - sysLogPriority = LOG_DEBUG; - else - sysLogPriority = LOG_NOTICE; -# if defined(ELPP_UNICODE) - char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str()); - syslog(sysLogPriority, "%s", line); - free(line); -# else - syslog(sysLogPriority, "%s", logLine.c_str()); -# endif - } -#endif // defined(ELPP_SYSLOG) -} - -#if ELPP_ASYNC_LOGGING - -// AsyncLogDispatchCallback - -void AsyncLogDispatchCallback::handle(const LogDispatchData* data) { - base::type::string_t logLine = data->logMessage()->logger()->logBuilder()->build(data->logMessage(), - data->dispatchAction() == base::DispatchAction::NormalLog); - if (data->dispatchAction() == base::DispatchAction::NormalLog - && data->logMessage()->logger()->typedConfigurations()->toStandardOutput(data->logMessage()->level())) { - if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) - data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, data->logMessage()->level()); - ELPP_COUT << ELPP_COUT_LINE(logLine); - } - // Save resources and only queue if we want to write to file otherwise just ignore handler - if (data->logMessage()->logger()->typedConfigurations()->toFile(data->logMessage()->level())) { - ELPP->asyncLogQueue()->push(AsyncLogItem(*(data->logMessage()), *data, logLine)); - } -} - -// AsyncDispatchWorker -AsyncDispatchWorker::AsyncDispatchWorker() { - setContinueRunning(false); -} - -AsyncDispatchWorker::~AsyncDispatchWorker() { - setContinueRunning(false); - ELPP_INTERNAL_INFO(6, "Stopping dispatch worker - Cleaning log queue"); - clean(); - ELPP_INTERNAL_INFO(6, "Log queue cleaned"); -} - -bool AsyncDispatchWorker::clean(void) { - std::mutex m; - std::unique_lock lk(m); - cv.wait(lk, [] { return !ELPP->asyncLogQueue()->empty(); }); - emptyQueue(); - lk.unlock(); - cv.notify_one(); - return ELPP->asyncLogQueue()->empty(); -} - -void AsyncDispatchWorker::emptyQueue(void) { - while (!ELPP->asyncLogQueue()->empty()) { - AsyncLogItem data = ELPP->asyncLogQueue()->next(); - handle(&data); - base::threading::msleep(100); - } -} - -void AsyncDispatchWorker::start(void) { - base::threading::msleep(5000); // 5s (why?) - setContinueRunning(true); - std::thread t1(&AsyncDispatchWorker::run, this); - t1.join(); -} - -void AsyncDispatchWorker::handle(AsyncLogItem* logItem) { - LogDispatchData* data = logItem->data(); - LogMessage* logMessage = logItem->logMessage(); - Logger* logger = logMessage->logger(); - base::TypedConfigurations* conf = logger->typedConfigurations(); - base::type::string_t logLine = logItem->logLine(); - if (data->dispatchAction() == base::DispatchAction::NormalLog) { - if (conf->toFile(logMessage->level())) { - base::type::fstream_t* fs = conf->fileStream(logMessage->level()); - if (fs != nullptr) { - fs->write(logLine.c_str(), logLine.size()); - if (fs->fail()) { - ELPP_INTERNAL_ERROR("Unable to write log to file [" - << conf->filename(logMessage->level()) << "].\n" - << "Few possible reasons (could be something else):\n" << " * Permission denied\n" - << " * Disk full\n" << " * Disk is not writable", true); - } else { - if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) || (logger->isFlushNeeded(logMessage->level()))) { - logger->flush(logMessage->level(), fs); - } - } - } else { - ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(logMessage->level()) << "] " - << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: " << logger->id() << "]", false); - } - } - } -# if defined(ELPP_SYSLOG) - else if (data->dispatchAction() == base::DispatchAction::SysLog) { - // Determine syslog priority - int sysLogPriority = 0; - if (logMessage->level() == Level::Fatal) - sysLogPriority = LOG_EMERG; - else if (logMessage->level() == Level::Error) - sysLogPriority = LOG_ERR; - else if (logMessage->level() == Level::Warning) - sysLogPriority = LOG_WARNING; - else if (logMessage->level() == Level::Info) - sysLogPriority = LOG_INFO; - else if (logMessage->level() == Level::Debug) - sysLogPriority = LOG_DEBUG; - else - sysLogPriority = LOG_NOTICE; -# if defined(ELPP_UNICODE) - char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str()); - syslog(sysLogPriority, "%s", line); - free(line); -# else - syslog(sysLogPriority, "%s", logLine.c_str()); -# endif - } -# endif // defined(ELPP_SYSLOG) -} - -void AsyncDispatchWorker::run(void) { - while (continueRunning()) { - emptyQueue(); - base::threading::msleep(10); // 10ms - } -} -#endif // ELPP_ASYNC_LOGGING - -// DefaultLogBuilder - -base::type::string_t DefaultLogBuilder::build(const LogMessage* logMessage, bool appendNewLine) const { - base::TypedConfigurations* tc = logMessage->logger()->typedConfigurations(); - const base::LogFormat* logFormat = &tc->logFormat(logMessage->level()); - base::type::string_t logLine = logFormat->format(); - char buff[base::consts::kSourceFilenameMaxLength + base::consts::kSourceLineMaxLength] = ""; - const char* bufLim = buff + sizeof(buff); - if (logFormat->hasFlag(base::FormatFlags::AppName)) { - // App name - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kAppNameFormatSpecifier, - logMessage->logger()->parentApplicationName()); - } - if (logFormat->hasFlag(base::FormatFlags::ThreadId)) { - // Thread ID - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kThreadIdFormatSpecifier, - ELPP->getThreadName(base::threading::getCurrentThreadId())); - } - if (logFormat->hasFlag(base::FormatFlags::DateTime)) { - // DateTime - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kDateTimeFormatSpecifier, - base::utils::DateTime::getDateTime(logFormat->dateTimeFormat().c_str(), - &tc->subsecondPrecision(logMessage->level()))); - } - if (logFormat->hasFlag(base::FormatFlags::Function)) { - // Function - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFunctionFormatSpecifier, logMessage->func()); - } - if (logFormat->hasFlag(base::FormatFlags::File)) { - // File - base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength); - base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFileFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::FileBase)) { - // FileBase - base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength); - base::utils::File::buildBaseFilename(logMessage->file(), buff); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFileBaseFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::Line)) { - // Line - char* buf = base::utils::Str::clearBuff(buff, base::consts::kSourceLineMaxLength); - buf = base::utils::Str::convertAndAddToBuff(logMessage->line(), base::consts::kSourceLineMaxLength, buf, bufLim, false); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogLineFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::Location)) { - // Location - char* buf = base::utils::Str::clearBuff(buff, - base::consts::kSourceFilenameMaxLength + base::consts::kSourceLineMaxLength); - base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff); - buf = base::utils::Str::addToBuff(buff, buf, bufLim); - buf = base::utils::Str::addToBuff(":", buf, bufLim); - buf = base::utils::Str::convertAndAddToBuff(logMessage->line(), base::consts::kSourceLineMaxLength, buf, bufLim, - false); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogLocationFormatSpecifier, std::string(buff)); - } - if (logMessage->level() == Level::Verbose && logFormat->hasFlag(base::FormatFlags::VerboseLevel)) { - // Verbose level - char* buf = base::utils::Str::clearBuff(buff, 1); - buf = base::utils::Str::convertAndAddToBuff(logMessage->verboseLevel(), 1, buf, bufLim, false); - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kVerboseLevelFormatSpecifier, std::string(buff)); - } - if (logFormat->hasFlag(base::FormatFlags::LogMessage)) { - // Log message - base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kMessageFormatSpecifier, logMessage->message()); - } -#if !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS) - el::base::threading::ScopedLock lock_(ELPP->customFormatSpecifiersLock()); - ELPP_UNUSED(lock_); - for (std::vector::const_iterator it = ELPP->customFormatSpecifiers()->begin(); - it != ELPP->customFormatSpecifiers()->end(); ++it) { - std::string fs(it->formatSpecifier()); - base::type::string_t wcsFormatSpecifier(fs.begin(), fs.end()); - base::utils::Str::replaceFirstWithEscape(logLine, wcsFormatSpecifier, it->resolver()(logMessage)); - } -#endif // !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS) - if (appendNewLine) logLine += ELPP_LITERAL("\n"); - return logLine; -} - -// LogDispatcher - -void LogDispatcher::dispatch(void) { - if (m_proceed && m_dispatchAction == base::DispatchAction::None) { - m_proceed = false; - } - if (!m_proceed) { - return; - } -#ifndef ELPP_NO_GLOBAL_LOCK - // see https://github.com/muflihun/easyloggingpp/issues/580 - // global lock is turned on by default unless - // ELPP_NO_GLOBAL_LOCK is defined - base::threading::ScopedLock scopedLock(ELPP->lock()); -#endif - base::TypedConfigurations* tc = m_logMessage->logger()->m_typedConfigurations; - if (ELPP->hasFlag(LoggingFlag::StrictLogFileSizeCheck)) { - tc->validateFileRolling(m_logMessage->level(), ELPP->preRollOutCallback()); - } - LogDispatchCallback* callback = nullptr; - LogDispatchData data; - for (const std::pair& h - : ELPP->m_logDispatchCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - data.setLogMessage(m_logMessage); - data.setDispatchAction(m_dispatchAction); - callback->handle(&data); - } - } -} - -// MessageBuilder - -void MessageBuilder::initialize(Logger* logger) { - m_logger = logger; - m_containerLogSeparator = ELPP->hasFlag(LoggingFlag::NewLineForContainer) ? - ELPP_LITERAL("\n ") : ELPP_LITERAL(", "); -} - -MessageBuilder& MessageBuilder::operator<<(const wchar_t* msg) { - if (msg == nullptr) { - m_logger->stream() << base::consts::kNullPointer; - return *this; - } -# if defined(ELPP_UNICODE) - m_logger->stream() << msg; -# else - char* buff_ = base::utils::Str::wcharPtrToCharPtr(msg); - m_logger->stream() << buff_; - free(buff_); -# endif - if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) { - m_logger->stream() << " "; - } - return *this; -} - -// Writer - -Writer& Writer::construct(Logger* logger, bool needLock) { - m_logger = logger; - initializeLogger(logger->id(), false, needLock); - m_messageBuilder.initialize(m_logger); - return *this; -} - -Writer& Writer::construct(int count, const char* loggerIds, ...) { - if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) { - va_list loggersList; - va_start(loggersList, loggerIds); - const char* id = loggerIds; - m_loggerIds.reserve(count); - for (int i = 0; i < count; ++i) { - m_loggerIds.push_back(std::string(id)); - id = va_arg(loggersList, const char*); - } - va_end(loggersList); - initializeLogger(m_loggerIds.at(0)); - } else { - initializeLogger(std::string(loggerIds)); - } - m_messageBuilder.initialize(m_logger); - return *this; -} - -void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool needLock) { - if (lookup) { - m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically)); - } - if (m_logger == nullptr) { - { - if (!ELPP->registeredLoggers()->has(std::string(base::consts::kDefaultLoggerId))) { - // Somehow default logger has been unregistered. Not good! Register again - ELPP->registeredLoggers()->get(std::string(base::consts::kDefaultLoggerId)); - } - } - Writer(Level::Debug, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) - << "Logger [" << loggerId << "] is not registered yet!"; - m_proceed = false; - } else { - if (needLock) { - m_logger->acquireLock(); // This should not be unlocked by checking m_proceed because - // m_proceed can be changed by lines below - } - if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging)) { - m_proceed = m_level == Level::Verbose ? m_logger->enabled(m_level) : - LevelHelper::castToInt(m_level) >= LevelHelper::castToInt(ELPP->m_loggingLevel); - } else { - m_proceed = m_logger->enabled(m_level); - } - } -} - -void Writer::processDispatch() { -#if ELPP_LOGGING_ENABLED - if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) { - bool firstDispatched = false; - base::type::string_t logMessage; - std::size_t i = 0; - do { - if (m_proceed) { - if (firstDispatched) { - m_logger->stream() << logMessage; - } else { - firstDispatched = true; - if (m_loggerIds.size() > 1) { - logMessage = m_logger->stream().str(); - } - } - triggerDispatch(); - } else if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } - if (i + 1 < m_loggerIds.size()) { - initializeLogger(m_loggerIds.at(i + 1)); - } - } while (++i < m_loggerIds.size()); - } else { - if (m_proceed) { - triggerDispatch(); - } else if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } - } -#else - if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } -#endif // ELPP_LOGGING_ENABLED -} - -void Writer::triggerDispatch(void) { - try { - if (m_proceed) { - if (m_msg == nullptr) { - LogMessage msg(m_level, m_file, m_line, m_func, m_verboseLevel, - m_logger); - base::LogDispatcher(m_proceed, &msg, m_dispatchAction).dispatch(); - } else { - base::LogDispatcher(m_proceed, m_msg, m_dispatchAction).dispatch(); - } - } - if (m_logger != nullptr) { - m_logger->stream().str(ELPP_LITERAL("")); - m_logger->releaseLock(); - } - if (m_proceed && m_level == Level::Fatal - && !ELPP->hasFlag(LoggingFlag::DisableApplicationAbortOnFatalLog)) { - base::Writer(Level::Warning, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) - << "Aborting application. Reason: Fatal log at [" << m_file << ":" << m_line << "]"; - std::stringstream reasonStream; - reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]" - << " If you wish to disable 'abort on fatal log' please use " - << "el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog)"; - base::utils::abort(1, reasonStream.str()); - } - m_proceed = false; - } - catch(std::exception & ex){ - // Extremely low memory situation; don't let exception be unhandled. - } -} - -// PErrorWriter - -PErrorWriter::~PErrorWriter(void) { - if (m_proceed) { -#if ELPP_COMPILER_MSVC - char buff[256]; - strerror_s(buff, 256, errno); - m_logger->stream() << ": " << buff << " [" << errno << "]"; -#else - m_logger->stream() << ": " << strerror(errno) << " [" << errno << "]"; -#endif - } -} - -// PerformanceTracker - -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - -PerformanceTracker::PerformanceTracker(const std::string& blockName, - base::TimestampUnit timestampUnit, - const std::string& loggerId, - bool scopedLog, Level level) : - m_blockName(blockName), m_timestampUnit(timestampUnit), m_loggerId(loggerId), m_scopedLog(scopedLog), - m_level(level), m_hasChecked(false), m_lastCheckpointId(std::string()), m_enabled(false) { -#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - // We store it locally so that if user happen to change configuration by the end of scope - // or before calling checkpoint, we still depend on state of configuration at time of construction - el::Logger* loggerPtr = ELPP->registeredLoggers()->get(loggerId, false); - m_enabled = loggerPtr != nullptr && loggerPtr->m_typedConfigurations->performanceTracking(m_level); - if (m_enabled) { - base::utils::DateTime::gettimeofday(&m_startTime); - } -#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED -} - -PerformanceTracker::~PerformanceTracker(void) { -#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - if (m_enabled) { - base::threading::ScopedLock scopedLock(lock()); - if (m_scopedLog) { - base::utils::DateTime::gettimeofday(&m_endTime); - base::type::string_t formattedTime = getFormattedTimeTaken(); - PerformanceTrackingData data(PerformanceTrackingData::DataType::Complete); - data.init(this); - data.m_formattedTimeTaken = formattedTime; - PerformanceTrackingCallback* callback = nullptr; - for (const std::pair& h - : ELPP->m_performanceTrackingCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - callback->handle(&data); - } - } - } - } -#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) -} - -void PerformanceTracker::checkpoint(const std::string& id, const char* file, base::type::LineNumber line, - const char* func) { -#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - if (m_enabled) { - base::threading::ScopedLock scopedLock(lock()); - base::utils::DateTime::gettimeofday(&m_endTime); - base::type::string_t formattedTime = m_hasChecked ? getFormattedTimeTaken(m_lastCheckpointTime) : ELPP_LITERAL(""); - PerformanceTrackingData data(PerformanceTrackingData::DataType::Checkpoint); - data.init(this); - data.m_checkpointId = id; - data.m_file = file; - data.m_line = line; - data.m_func = func; - data.m_formattedTimeTaken = formattedTime; - PerformanceTrackingCallback* callback = nullptr; - for (const std::pair& h - : ELPP->m_performanceTrackingCallbacks) { - callback = h.second.get(); - if (callback != nullptr && callback->enabled()) { - callback->handle(&data); - } - } - base::utils::DateTime::gettimeofday(&m_lastCheckpointTime); - m_hasChecked = true; - m_lastCheckpointId = id; - } -#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED - ELPP_UNUSED(id); - ELPP_UNUSED(file); - ELPP_UNUSED(line); - ELPP_UNUSED(func); -} - -const base::type::string_t PerformanceTracker::getFormattedTimeTaken(struct timeval startTime) const { - if (ELPP->hasFlag(LoggingFlag::FixedTimeFormat)) { - base::type::stringstream_t ss; - ss << base::utils::DateTime::getTimeDifference(m_endTime, - startTime, m_timestampUnit) << " " << base::consts::kTimeFormats[static_cast - (m_timestampUnit)].unit; - return ss.str(); - } - return base::utils::DateTime::formatTime(base::utils::DateTime::getTimeDifference(m_endTime, - startTime, m_timestampUnit), m_timestampUnit); -} - -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - -namespace debug { -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - -// StackTrace - -StackTrace::StackTraceEntry::StackTraceEntry(std::size_t index, const std::string& loc, const std::string& demang, - const std::string& hex, - const std::string& addr) : - m_index(index), - m_location(loc), - m_demangled(demang), - m_hex(hex), - m_addr(addr) { -} - -std::ostream& operator<<(std::ostream& ss, const StackTrace::StackTraceEntry& si) { - ss << "[" << si.m_index << "] " << si.m_location << (si.m_hex.empty() ? "" : "+") << si.m_hex << " " << si.m_addr << - (si.m_demangled.empty() ? "" : ":") << si.m_demangled; - return ss; -} - -std::ostream& operator<<(std::ostream& os, const StackTrace& st) { - std::vector::const_iterator it = st.m_stack.begin(); - while (it != st.m_stack.end()) { - os << " " << *it++ << "\n"; - } - return os; -} - -void StackTrace::generateNew(void) { -#ifdef HAVE_EXECINFO - m_stack.clear(); - void* stack[kMaxStack]; - unsigned int size = backtrace(stack, kMaxStack); - char** strings = backtrace_symbols(stack, size); - if (size > kStackStart) { // Skip StackTrace c'tor and generateNew - for (std::size_t i = kStackStart; i < size; ++i) { - std::string mangName; - std::string location; - std::string hex; - std::string addr; - - // entry: 2 crash.cpp.bin 0x0000000101552be5 _ZN2el4base5debug10StackTraceC1Ev + 21 - const std::string line(strings[i]); - auto p = line.find("_"); - if (p != std::string::npos) { - mangName = line.substr(p); - mangName = mangName.substr(0, mangName.find(" +")); - } - p = line.find("0x"); - if (p != std::string::npos) { - addr = line.substr(p); - addr = addr.substr(0, addr.find("_")); - } - // Perform demangling if parsed properly - if (!mangName.empty()) { - int status = 0; - char* demangName = abi::__cxa_demangle(mangName.data(), 0, 0, &status); - // if demangling is successful, output the demangled function name - if (status == 0) { - // Success (see http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html) - StackTraceEntry entry(i - 1, location, demangName, hex, addr); - m_stack.push_back(entry); - } else { - // Not successful - we will use mangled name - StackTraceEntry entry(i - 1, location, mangName, hex, addr); - m_stack.push_back(entry); - } - free(demangName); - } else { - StackTraceEntry entry(i - 1, line); - m_stack.push_back(entry); - } - } - } - free(strings); -#else - ELPP_INTERNAL_INFO(1, "Stacktrace generation not supported for selected compiler"); -#endif // ELPP_STACKTRACE -} - -// Static helper functions - -static std::string crashReason(int sig) { - std::stringstream ss; - bool foundReason = false; - for (int i = 0; i < base::consts::kCrashSignalsCount; ++i) { - if (base::consts::kCrashSignals[i].numb == sig) { - ss << "Application has crashed due to [" << base::consts::kCrashSignals[i].name << "] signal"; - if (ELPP->hasFlag(el::LoggingFlag::LogDetailedCrashReason)) { - ss << std::endl << - " " << base::consts::kCrashSignals[i].brief << std::endl << - " " << base::consts::kCrashSignals[i].detail; - } - foundReason = true; - } - } - if (!foundReason) { - ss << "Application has crashed due to unknown signal [" << sig << "]"; - } - return ss.str(); -} -/// @brief Logs reason of crash from sig -static void logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) { - if (sig == SIGINT && ELPP->hasFlag(el::LoggingFlag::IgnoreSigInt)) { - return; - } - std::stringstream ss; - ss << "CRASH HANDLED; "; - ss << crashReason(sig); -#if ELPP_STACKTRACE - if (stackTraceIfAvailable) { - ss << std::endl << " ======= Backtrace: =========" << std::endl << base::debug::StackTrace(); - } -#else - ELPP_UNUSED(stackTraceIfAvailable); -#endif // ELPP_STACKTRACE - ELPP_WRITE_LOG(el::base::Writer, level, base::DispatchAction::NormalLog, logger) << ss.str(); -} - -static inline void crashAbort(int sig) { - base::utils::abort(sig, std::string()); -} - -/// @brief Default application crash handler -/// -/// @detail This function writes log using 'default' logger, prints stack trace for GCC based compilers and aborts program. -static inline void defaultCrashHandler(int sig) { - base::debug::logCrashReason(sig, true, Level::Fatal, base::consts::kDefaultLoggerId); - base::debug::crashAbort(sig); -} - -// CrashHandler - -CrashHandler::CrashHandler(bool useDefault) { - if (useDefault) { - setHandler(defaultCrashHandler); - } -} - -void CrashHandler::setHandler(const Handler& cHandler) { - m_handler = cHandler; -#if defined(ELPP_HANDLE_SIGABRT) - int i = 0; // SIGABRT is at base::consts::kCrashSignals[0] -#else - int i = 1; -#endif // defined(ELPP_HANDLE_SIGABRT) - for (; i < base::consts::kCrashSignalsCount; ++i) { - m_handler = signal(base::consts::kCrashSignals[i].numb, cHandler); - } -} - -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) -} // namespace debug -} // namespace base - -// el - -// Helpers - -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - -void Helpers::crashAbort(int sig, const char* sourceFile, unsigned int long line) { - std::stringstream ss; - ss << base::debug::crashReason(sig).c_str(); - ss << " - [Called el::Helpers::crashAbort(" << sig << ")]"; - if (sourceFile != nullptr && strlen(sourceFile) > 0) { - ss << " - Source: " << sourceFile; - if (line > 0) - ss << ":" << line; - else - ss << " (line number not specified)"; - } - base::utils::abort(sig, ss.str()); -} - -void Helpers::logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) { - el::base::debug::logCrashReason(sig, stackTraceIfAvailable, level, logger); -} - -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - -// Loggers - -Logger* Loggers::getLogger(const std::string& identity, bool registerIfNotAvailable) { - return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable); -} - -void Loggers::setDefaultLogBuilder(el::LogBuilderPtr& logBuilderPtr) { - ELPP->registeredLoggers()->setDefaultLogBuilder(logBuilderPtr); -} - -bool Loggers::unregisterLogger(const std::string& identity) { - return ELPP->registeredLoggers()->remove(identity); -} - -bool Loggers::hasLogger(const std::string& identity) { - return ELPP->registeredLoggers()->has(identity); -} - -Logger* Loggers::reconfigureLogger(Logger* logger, const Configurations& configurations) { - if (!logger) return nullptr; - logger->configure(configurations); - return logger; -} - -Logger* Loggers::reconfigureLogger(const std::string& identity, const Configurations& configurations) { - return Loggers::reconfigureLogger(Loggers::getLogger(identity), configurations); -} - -Logger* Loggers::reconfigureLogger(const std::string& identity, ConfigurationType configurationType, - const std::string& value) { - Logger* logger = Loggers::getLogger(identity); - if (logger == nullptr) { - return nullptr; - } - logger->configurations()->set(Level::Global, configurationType, value); - logger->reconfigure(); - return logger; -} - -void Loggers::reconfigureAllLoggers(const Configurations& configurations) { - for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin(); - it != ELPP->registeredLoggers()->end(); ++it) { - Loggers::reconfigureLogger(it->second, configurations); - } -} - -void Loggers::reconfigureAllLoggers(Level level, ConfigurationType configurationType, - const std::string& value) { - for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin(); - it != ELPP->registeredLoggers()->end(); ++it) { - Logger* logger = it->second; - logger->configurations()->set(level, configurationType, value); - logger->reconfigure(); - } -} - -void Loggers::setDefaultConfigurations(const Configurations& configurations, bool reconfigureExistingLoggers) { - ELPP->registeredLoggers()->setDefaultConfigurations(configurations); - if (reconfigureExistingLoggers) { - Loggers::reconfigureAllLoggers(configurations); - } -} - -const Configurations* Loggers::defaultConfigurations(void) { - return ELPP->registeredLoggers()->defaultConfigurations(); -} - -const base::LogStreamsReferenceMapPtr Loggers::logStreamsReference(void) { - return ELPP->registeredLoggers()->logStreamsReference(); -} - -base::TypedConfigurations Loggers::defaultTypedConfigurations(void) { - return base::TypedConfigurations( - ELPP->registeredLoggers()->defaultConfigurations(), - ELPP->registeredLoggers()->logStreamsReference()); -} - -std::vector* Loggers::populateAllLoggerIds(std::vector* targetList) { - targetList->clear(); - for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->list().begin(); - it != ELPP->registeredLoggers()->list().end(); ++it) { - targetList->push_back(it->first); - } - return targetList; -} - -void Loggers::configureFromGlobal(const char* globalConfigurationFilePath) { - std::ifstream gcfStream(globalConfigurationFilePath, std::ifstream::in); - ELPP_ASSERT(gcfStream.is_open(), "Unable to open global configuration file [" << globalConfigurationFilePath - << "] for parsing."); - std::string line = std::string(); - std::stringstream ss; - Logger* logger = nullptr; - auto configure = [&](void) { - ELPP_INTERNAL_INFO(8, "Configuring logger: '" << logger->id() << "' with configurations \n" << ss.str() - << "\n--------------"); - Configurations c; - c.parseFromText(ss.str()); - logger->configure(c); - }; - while (gcfStream.good()) { - std::getline(gcfStream, line); - ELPP_INTERNAL_INFO(1, "Parsing line: " << line); - base::utils::Str::trim(line); - if (Configurations::Parser::isComment(line)) continue; - Configurations::Parser::ignoreComments(&line); - base::utils::Str::trim(line); - if (line.size() > 2 && base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationLoggerId))) { - if (!ss.str().empty() && logger != nullptr) { - configure(); - } - ss.str(std::string("")); - line = line.substr(2); - base::utils::Str::trim(line); - if (line.size() > 1) { - ELPP_INTERNAL_INFO(1, "Getting logger: '" << line << "'"); - logger = getLogger(line); - } - } else { - ss << line << "\n"; - } - } - if (!ss.str().empty() && logger != nullptr) { - configure(); - } -} - -bool Loggers::configureFromArg(const char* argKey) { -#if defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS) - ELPP_UNUSED(argKey); -#else - if (!Helpers::commandLineArgs()->hasParamWithValue(argKey)) { - return false; - } - configureFromGlobal(Helpers::commandLineArgs()->getParamValue(argKey)); -#endif // defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS) - return true; -} - -void Loggers::flushAll(void) { - ELPP->registeredLoggers()->flushAll(); -} - -void Loggers::setVerboseLevel(base::type::VerboseLevel level) { - ELPP->vRegistry()->setLevel(level); -} - -base::type::VerboseLevel Loggers::verboseLevel(void) { - return ELPP->vRegistry()->level(); -} - -void Loggers::setVModules(const char* modules) { - if (ELPP->vRegistry()->vModulesEnabled()) { - ELPP->vRegistry()->setModules(modules); - } -} - -void Loggers::clearVModules(void) { - ELPP->vRegistry()->clearModules(); -} - -// VersionInfo - -const std::string VersionInfo::version(void) { - return std::string("9.96.7"); -} -/// @brief Release date of current version -const std::string VersionInfo::releaseDate(void) { - return std::string("24-11-2018 0728hrs"); -} - -} // namespace el diff --git a/src/easylogging++.h b/src/easylogging++.h deleted file mode 100644 index 6e81edf..0000000 --- a/src/easylogging++.h +++ /dev/null @@ -1,4576 +0,0 @@ -// -// Bismillah ar-Rahmaan ar-Raheem -// -// Easylogging++ v9.96.7 -// Single-header only, cross-platform logging library for C++ applications -// -// Copyright (c) 2012-2018 Amrayn Web Services -// Copyright (c) 2012-2018 @abumusamq -// -// This library is released under the MIT Licence. -// https://github.com/amrayn/easyloggingpp/blob/master/LICENSE -// -// https://amrayn.com -// http://muflihun.com -// - -#ifndef EASYLOGGINGPP_H -#define EASYLOGGINGPP_H -// Compilers and C++0x/C++11 Evaluation -#if __cplusplus >= 201103L -# define ELPP_CXX11 1 -#endif // __cplusplus >= 201103L -#if (defined(__GNUC__)) -# define ELPP_COMPILER_GCC 1 -#else -# define ELPP_COMPILER_GCC 0 -#endif -#if ELPP_COMPILER_GCC -# define ELPP_GCC_VERSION (__GNUC__ * 10000 \ -+ __GNUC_MINOR__ * 100 \ -+ __GNUC_PATCHLEVEL__) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define ELPP_CXX0X 1 -# endif -#endif -// Visual C++ -#if defined(_MSC_VER) -# define ELPP_COMPILER_MSVC 1 -#else -# define ELPP_COMPILER_MSVC 0 -#endif -#define ELPP_CRT_DBG_WARNINGS ELPP_COMPILER_MSVC -#if ELPP_COMPILER_MSVC -# if (_MSC_VER == 1600) -# define ELPP_CXX0X 1 -# elif(_MSC_VER >= 1700) -# define ELPP_CXX11 1 -# endif -#endif -// Clang++ -#if (defined(__clang__) && (__clang__ == 1)) -# define ELPP_COMPILER_CLANG 1 -#else -# define ELPP_COMPILER_CLANG 0 -#endif -#if ELPP_COMPILER_CLANG -# if __has_include() -# include // Make __GLIBCXX__ defined when using libstdc++ -# if !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426 -# define ELPP_CLANG_SUPPORTS_THREAD -# endif // !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426 -# endif // __has_include() -#endif -#if (defined(__MINGW32__) || defined(__MINGW64__)) -# define ELPP_MINGW 1 -#else -# define ELPP_MINGW 0 -#endif -#if (defined(__CYGWIN__) && (__CYGWIN__ == 1)) -# define ELPP_CYGWIN 1 -#else -# define ELPP_CYGWIN 0 -#endif -#if (defined(__INTEL_COMPILER)) -# define ELPP_COMPILER_INTEL 1 -#else -# define ELPP_COMPILER_INTEL 0 -#endif -// Operating System Evaluation -// Windows -#if (defined(_WIN32) || defined(_WIN64)) -# define ELPP_OS_WINDOWS 1 -#else -# define ELPP_OS_WINDOWS 0 -#endif -// Linux -#if (defined(__linux) || defined(__linux__)) -# define ELPP_OS_LINUX 1 -#else -# define ELPP_OS_LINUX 0 -#endif -#if (defined(__APPLE__)) -# define ELPP_OS_MAC 1 -#else -# define ELPP_OS_MAC 0 -#endif -#if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) -# define ELPP_OS_FREEBSD 1 -#else -# define ELPP_OS_FREEBSD 0 -#endif -#if (defined(__sun)) -# define ELPP_OS_SOLARIS 1 -#else -# define ELPP_OS_SOLARIS 0 -#endif -#if (defined(_AIX)) -# define ELPP_OS_AIX 1 -#else -# define ELPP_OS_AIX 0 -#endif -#if (defined(__NetBSD__)) -# define ELPP_OS_NETBSD 1 -#else -# define ELPP_OS_NETBSD 0 -#endif -#if defined(__EMSCRIPTEN__) -# define ELPP_OS_EMSCRIPTEN 1 -#else -# define ELPP_OS_EMSCRIPTEN 0 -#endif -#if (defined(__QNX__) || defined(__QNXNTO__)) -# define ELPP_OS_QNX 1 -#else -# define ELPP_OS_QNX 0 -#endif -// Unix -#if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_NETBSD || ELPP_OS_SOLARIS || ELPP_OS_AIX || ELPP_OS_EMSCRIPTEN || ELPP_OS_QNX) && (!ELPP_OS_WINDOWS)) -# define ELPP_OS_UNIX 1 -#else -# define ELPP_OS_UNIX 0 -#endif -#if (defined(__ANDROID__)) -# define ELPP_OS_ANDROID 1 -#else -# define ELPP_OS_ANDROID 0 -#endif -// Evaluating Cygwin as *nix OS -#if !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN -# undef ELPP_OS_UNIX -# undef ELPP_OS_LINUX -# define ELPP_OS_UNIX 1 -# define ELPP_OS_LINUX 1 -#endif // !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN -#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_INFO) -# define ELPP_INTERNAL_DEBUGGING_OUT_INFO std::cout -#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) -#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_ERROR) -# define ELPP_INTERNAL_DEBUGGING_OUT_ERROR std::cerr -#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) -#if !defined(ELPP_INTERNAL_DEBUGGING_ENDL) -# define ELPP_INTERNAL_DEBUGGING_ENDL std::endl -#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) -#if !defined(ELPP_INTERNAL_DEBUGGING_MSG) -# define ELPP_INTERNAL_DEBUGGING_MSG(msg) msg -#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) -// Internal Assertions and errors -#if !defined(ELPP_DISABLE_ASSERT) -# if (defined(ELPP_DEBUG_ASSERT_FAILURE)) -# define ELPP_ASSERT(expr, msg) if (!(expr)) { \ -std::stringstream internalInfoStream; internalInfoStream << msg; \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR \ -<< "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" \ -<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" << ELPP_INTERNAL_DEBUGGING_ENDL; base::utils::abort(1, \ -"ELPP Assertion failure, please define ELPP_DEBUG_ASSERT_FAILURE"); } -# else -# define ELPP_ASSERT(expr, msg) if (!(expr)) { \ -std::stringstream internalInfoStream; internalInfoStream << msg; \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR\ -<< "ASSERTION FAILURE FROM EASYLOGGING++ (LINE: " \ -<< __LINE__ << ") [" #expr << "] WITH MESSAGE \"" << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" \ -<< ELPP_INTERNAL_DEBUGGING_ENDL; } -# endif // (defined(ELPP_DEBUG_ASSERT_FAILURE)) -#else -# define ELPP_ASSERT(x, y) -#endif //(!defined(ELPP_DISABLE_ASSERT) -#if ELPP_COMPILER_MSVC -# define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \ -{ char buff[256]; strerror_s(buff, 256, errno); \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << buff << " [" << errno << "]";} (void)0 -#else -# define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << strerror(errno) << " [" << errno << "]"; (void)0 -#endif // ELPP_COMPILER_MSVC -#if defined(ELPP_DEBUG_ERRORS) -# if !defined(ELPP_INTERNAL_ERROR) -# define ELPP_INTERNAL_ERROR(msg, pe) { \ -std::stringstream internalInfoStream; internalInfoStream << " " << msg; \ -ELPP_INTERNAL_DEBUGGING_OUT_ERROR \ -<< "ERROR FROM EASYLOGGING++ (LINE: " << __LINE__ << ") " \ -<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << ELPP_INTERNAL_DEBUGGING_ENDL; \ -if (pe) { ELPP_INTERNAL_DEBUGGING_OUT_ERROR << " "; ELPP_INTERNAL_DEBUGGING_WRITE_PERROR; }} (void)0 -# endif -#else -# undef ELPP_INTERNAL_INFO -# define ELPP_INTERNAL_ERROR(msg, pe) -#endif // defined(ELPP_DEBUG_ERRORS) -#if (defined(ELPP_DEBUG_INFO)) -# if !(defined(ELPP_INTERNAL_INFO_LEVEL)) -# define ELPP_INTERNAL_INFO_LEVEL 9 -# endif // !(defined(ELPP_INTERNAL_INFO_LEVEL)) -# if !defined(ELPP_INTERNAL_INFO) -# define ELPP_INTERNAL_INFO(lvl, msg) { if (lvl <= ELPP_INTERNAL_INFO_LEVEL) { \ -std::stringstream internalInfoStream; internalInfoStream << " " << msg; \ -ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) \ -<< ELPP_INTERNAL_DEBUGGING_ENDL; }} -# endif -#else -# undef ELPP_INTERNAL_INFO -# define ELPP_INTERNAL_INFO(lvl, msg) -#endif // (defined(ELPP_DEBUG_INFO)) -#if (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG)) -# if (ELPP_COMPILER_GCC && !ELPP_MINGW && !ELPP_CYGWIN && !ELPP_OS_ANDROID && !ELPP_OS_EMSCRIPTEN && !ELPP_OS_QNX) -# define ELPP_STACKTRACE 1 -# else -# if ELPP_COMPILER_MSVC -# pragma message("Stack trace not available for this compiler") -# else -# warning "Stack trace not available for this compiler"; -# endif // ELPP_COMPILER_MSVC -# define ELPP_STACKTRACE 0 -# endif // ELPP_COMPILER_GCC -#else -# define ELPP_STACKTRACE 0 -#endif // (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG)) -// Miscellaneous macros -#define ELPP_UNUSED(x) (void)x -#if ELPP_OS_UNIX -// Log file permissions for unix-based systems -# define ELPP_LOG_PERMS S_IRUSR | S_IWUSR | S_IXUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IXOTH -#endif // ELPP_OS_UNIX -#if defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC -# if defined(ELPP_EXPORT_SYMBOLS) -# define ELPP_EXPORT __declspec(dllexport) -# else -# define ELPP_EXPORT __declspec(dllimport) -# endif // defined(ELPP_EXPORT_SYMBOLS) -#else -# define ELPP_EXPORT -#endif // defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC -// Some special functions that are VC++ specific -#undef STRTOK -#undef STRERROR -#undef STRCAT -#undef STRCPY -#if ELPP_CRT_DBG_WARNINGS -# define STRTOK(a, b, c) strtok_s(a, b, c) -# define STRERROR(a, b, c) strerror_s(a, b, c) -# define STRCAT(a, b, len) strcat_s(a, len, b) -# define STRCPY(a, b, len) strcpy_s(a, len, b) -#else -# define STRTOK(a, b, c) strtok(a, b) -# define STRERROR(a, b, c) strerror(c) -# define STRCAT(a, b, len) strcat(a, b) -# define STRCPY(a, b, len) strcpy(a, b) -#endif -// Compiler specific support evaluations -#if (ELPP_MINGW && !defined(ELPP_FORCE_USE_STD_THREAD)) -# define ELPP_USE_STD_THREADING 0 -#else -# if ((ELPP_COMPILER_CLANG && defined(ELPP_CLANG_SUPPORTS_THREAD)) || \ - (!ELPP_COMPILER_CLANG && defined(ELPP_CXX11)) || \ - defined(ELPP_FORCE_USE_STD_THREAD)) -# define ELPP_USE_STD_THREADING 1 -# else -# define ELPP_USE_STD_THREADING 0 -# endif -#endif -#undef ELPP_FINAL -#if ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702) -# define ELPP_FINAL -#else -# define ELPP_FINAL final -#endif // ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702) -#if defined(ELPP_EXPERIMENTAL_ASYNC) -# define ELPP_ASYNC_LOGGING 1 -#else -# define ELPP_ASYNC_LOGGING 0 -#endif // defined(ELPP_EXPERIMENTAL_ASYNC) -#if defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING -# define ELPP_THREADING_ENABLED 1 -#else -# define ELPP_THREADING_ENABLED 0 -#endif // defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING -// Function macro ELPP_FUNC -#undef ELPP_FUNC -#if ELPP_COMPILER_MSVC // Visual C++ -# define ELPP_FUNC __FUNCSIG__ -#elif ELPP_COMPILER_GCC // GCC -# define ELPP_FUNC __PRETTY_FUNCTION__ -#elif ELPP_COMPILER_INTEL // Intel C++ -# define ELPP_FUNC __PRETTY_FUNCTION__ -#elif ELPP_COMPILER_CLANG // Clang++ -# define ELPP_FUNC __PRETTY_FUNCTION__ -#else -# if defined(__func__) -# define ELPP_FUNC __func__ -# else -# define ELPP_FUNC "" -# endif // defined(__func__) -#endif // defined(_MSC_VER) -#undef ELPP_VARIADIC_TEMPLATES_SUPPORTED -// Keep following line commented until features are fixed -#define ELPP_VARIADIC_TEMPLATES_SUPPORTED \ -(ELPP_COMPILER_GCC || ELPP_COMPILER_CLANG || ELPP_COMPILER_INTEL || (ELPP_COMPILER_MSVC && _MSC_VER >= 1800)) -// Logging Enable/Disable macros -#if defined(ELPP_DISABLE_LOGS) -#define ELPP_LOGGING_ENABLED 0 -#else -#define ELPP_LOGGING_ENABLED 1 -#endif -#if (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_DEBUG_LOG 1 -#else -# define ELPP_DEBUG_LOG 0 -#endif // (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_INFO_LOG 1 -#else -# define ELPP_INFO_LOG 0 -#endif // (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_WARNING_LOG 1 -#else -# define ELPP_WARNING_LOG 0 -#endif // (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_ERROR_LOG 1 -#else -# define ELPP_ERROR_LOG 0 -#endif // (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_FATAL_LOG 1 -#else -# define ELPP_FATAL_LOG 0 -#endif // (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_TRACE_LOG 1 -#else -# define ELPP_TRACE_LOG 0 -#endif // (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED)) -# define ELPP_VERBOSE_LOG 1 -#else -# define ELPP_VERBOSE_LOG 0 -#endif // (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED)) -#if (!(ELPP_CXX0X || ELPP_CXX11)) -# error "C++0x (or higher) support not detected! (Is `-std=c++11' missing?)" -#endif // (!(ELPP_CXX0X || ELPP_CXX11)) -// Headers -#if defined(ELPP_SYSLOG) -# include -#endif // defined(ELPP_SYSLOG) -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(ELPP_UNICODE) -# include -# if ELPP_OS_WINDOWS -# include -# endif // ELPP_OS_WINDOWS -#endif // defined(ELPP_UNICODE) -#ifdef HAVE_EXECINFO -# include -# include -#endif // ENABLE_EXECINFO -#if ELPP_OS_ANDROID -# include -#endif // ELPP_OS_ANDROID -#if ELPP_OS_UNIX -# include -# include -#elif ELPP_OS_WINDOWS -# include -# include -# if defined(WIN32_LEAN_AND_MEAN) -# if defined(ELPP_WINSOCK2) -# include -# else -# include -# endif // defined(ELPP_WINSOCK2) -# endif // defined(WIN32_LEAN_AND_MEAN) -#endif // ELPP_OS_UNIX -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if ELPP_THREADING_ENABLED -# if ELPP_USE_STD_THREADING -# include -# include -# else -# if ELPP_OS_UNIX -# include -# endif // ELPP_OS_UNIX -# endif // ELPP_USE_STD_THREADING -#endif // ELPP_THREADING_ENABLED -#if ELPP_ASYNC_LOGGING -# if defined(ELPP_NO_SLEEP_FOR) -# include -# endif // defined(ELPP_NO_SLEEP_FOR) -# include -# include -# include -#endif // ELPP_ASYNC_LOGGING -#if defined(ELPP_STL_LOGGING) -// For logging STL based templates -# include -# include -# include -# include -# include -# include -# if defined(ELPP_LOG_STD_ARRAY) -# include -# endif // defined(ELPP_LOG_STD_ARRAY) -# if defined(ELPP_LOG_UNORDERED_SET) -# include -# endif // defined(ELPP_UNORDERED_SET) -#endif // defined(ELPP_STL_LOGGING) -#if defined(ELPP_QT_LOGGING) -// For logging Qt based classes & templates -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -#endif // defined(ELPP_QT_LOGGING) -#if defined(ELPP_BOOST_LOGGING) -// For logging boost based classes & templates -# include -# include -# include -# include -# include -# include -# include -# include -#endif // defined(ELPP_BOOST_LOGGING) -#if defined(ELPP_WXWIDGETS_LOGGING) -// For logging wxWidgets based classes & templates -# include -#endif // defined(ELPP_WXWIDGETS_LOGGING) -#if defined(ELPP_UTC_DATETIME) -# define elpptime_r gmtime_r -# define elpptime_s gmtime_s -# define elpptime gmtime -#else -# define elpptime_r localtime_r -# define elpptime_s localtime_s -# define elpptime localtime -#endif // defined(ELPP_UTC_DATETIME) -// Forward declarations -namespace el { -class Logger; -class LogMessage; -class PerformanceTrackingData; -class Loggers; -class Helpers; -template class Callback; -class LogDispatchCallback; -class PerformanceTrackingCallback; -class LoggerRegistrationCallback; -class LogDispatchData; -namespace base { -class Storage; -class RegisteredLoggers; -class PerformanceTracker; -class MessageBuilder; -class Writer; -class PErrorWriter; -class LogDispatcher; -class DefaultLogBuilder; -class DefaultLogDispatchCallback; -#if ELPP_ASYNC_LOGGING -class AsyncLogDispatchCallback; -class AsyncDispatchWorker; -#endif // ELPP_ASYNC_LOGGING -class DefaultPerformanceTrackingCallback; -} // namespace base -} // namespace el -/// @brief Easylogging++ entry namespace -namespace el { -/// @brief Namespace containing base/internal functionality used by Easylogging++ -namespace base { -/// @brief Data types used by Easylogging++ -namespace type { -#undef ELPP_LITERAL -#undef ELPP_STRLEN -#undef ELPP_COUT -#if defined(ELPP_UNICODE) -# define ELPP_LITERAL(txt) L##txt -# define ELPP_STRLEN wcslen -# if defined ELPP_CUSTOM_COUT -# define ELPP_COUT ELPP_CUSTOM_COUT -# else -# define ELPP_COUT std::wcout -# endif // defined ELPP_CUSTOM_COUT -typedef wchar_t char_t; -typedef std::wstring string_t; -typedef std::wstringstream stringstream_t; -typedef std::wfstream fstream_t; -typedef std::wostream ostream_t; -#else -# define ELPP_LITERAL(txt) txt -# define ELPP_STRLEN strlen -# if defined ELPP_CUSTOM_COUT -# define ELPP_COUT ELPP_CUSTOM_COUT -# else -# define ELPP_COUT std::cout -# endif // defined ELPP_CUSTOM_COUT -typedef char char_t; -typedef std::string string_t; -typedef std::stringstream stringstream_t; -typedef std::fstream fstream_t; -typedef std::ostream ostream_t; -#endif // defined(ELPP_UNICODE) -#if defined(ELPP_CUSTOM_COUT_LINE) -# define ELPP_COUT_LINE(logLine) ELPP_CUSTOM_COUT_LINE(logLine) -#else -# define ELPP_COUT_LINE(logLine) logLine << std::flush -#endif // defined(ELPP_CUSTOM_COUT_LINE) -typedef unsigned int EnumType; -typedef unsigned short VerboseLevel; -typedef unsigned long int LineNumber; -typedef std::shared_ptr StoragePointer; -typedef std::shared_ptr LogDispatchCallbackPtr; -typedef std::shared_ptr PerformanceTrackingCallbackPtr; -typedef std::shared_ptr LoggerRegistrationCallbackPtr; -typedef std::unique_ptr PerformanceTrackerPtr; -} // namespace type -/// @brief Internal helper class that prevent copy constructor for class -/// -/// @detail When using this class simply inherit it privately -class NoCopy { - protected: - NoCopy(void) {} - private: - NoCopy(const NoCopy&); - NoCopy& operator=(const NoCopy&); -}; -/// @brief Internal helper class that makes all default constructors private. -/// -/// @detail This prevents initializing class making it static unless an explicit constructor is declared. -/// When using this class simply inherit it privately -class StaticClass { - private: - StaticClass(void); - StaticClass(const StaticClass&); - StaticClass& operator=(const StaticClass&); -}; -} // namespace base -/// @brief Represents enumeration for severity level used to determine level of logging -/// -/// @detail With Easylogging++, developers may disable or enable any level regardless of -/// what the severity is. Or they can choose to log using hierarchical logging flag -enum class Level : base::type::EnumType { - /// @brief Generic level that represents all the levels. Useful when setting global configuration for all levels - Global = 1, - /// @brief Information that can be useful to back-trace certain events - mostly useful than debug logs. - Trace = 2, - /// @brief Informational events most useful for developers to debug application - Debug = 4, - /// @brief Severe error information that will presumably abort application - Fatal = 8, - /// @brief Information representing errors in application but application will keep running - Error = 16, - /// @brief Useful when application has potentially harmful situations - Warning = 32, - /// @brief Information that can be highly useful and vary with verbose logging level. - Verbose = 64, - /// @brief Mainly useful to represent current progress of application - Info = 128, - /// @brief Represents unknown level - Unknown = 1010 -}; -} // namespace el -namespace std { -template<> struct hash { - public: - std::size_t operator()(const el::Level& l) const { - return hash {}(static_cast(l)); - } -}; -} -namespace el { -/// @brief Static class that contains helper functions for el::Level -class LevelHelper : base::StaticClass { - public: - /// @brief Represents minimum valid level. Useful when iterating through enum. - static const base::type::EnumType kMinValid = static_cast(Level::Trace); - /// @brief Represents maximum valid level. This is used internally and you should not need it. - static const base::type::EnumType kMaxValid = static_cast(Level::Info); - /// @brief Casts level to int, useful for iterating through enum. - static base::type::EnumType castToInt(Level level) { - return static_cast(level); - } - /// @brief Casts int(ushort) to level, useful for iterating through enum. - static Level castFromInt(base::type::EnumType l) { - return static_cast(l); - } - /// @brief Converts level to associated const char* - /// @return Upper case string based level. - static const char* convertToString(Level level); - /// @brief Converts from levelStr to Level - /// @param levelStr Upper case string based level. - /// Lower case is also valid but providing upper case is recommended. - static Level convertFromString(const char* levelStr); - /// @brief Applies specified function to each level starting from startIndex - /// @param startIndex initial value to start the iteration from. This is passed as pointer and - /// is left-shifted so this can be used inside function (fn) to represent current level. - /// @param fn function to apply with each level. This bool represent whether or not to stop iterating through levels. - static void forEachLevel(base::type::EnumType* startIndex, const std::function& fn); -}; -/// @brief Represents enumeration of ConfigurationType used to configure or access certain aspect -/// of logging -enum class ConfigurationType : base::type::EnumType { - /// @brief Determines whether or not corresponding level and logger of logging is enabled - /// You may disable all logs by using el::Level::Global - Enabled = 1, - /// @brief Whether or not to write corresponding log to log file - ToFile = 2, - /// @brief Whether or not to write corresponding level and logger log to standard output. - /// By standard output meaning termnal, command prompt etc - ToStandardOutput = 4, - /// @brief Determines format of logging corresponding level and logger. - Format = 8, - /// @brief Determines log file (full path) to write logs to for corresponding level and logger - Filename = 16, - /// @brief Specifies precision of the subsecond part. It should be within range (1-6). - SubsecondPrecision = 32, - /// @brief Alias of SubsecondPrecision (for backward compatibility) - MillisecondsWidth = SubsecondPrecision, - /// @brief Determines whether or not performance tracking is enabled. - /// - /// @detail This does not depend on logger or level. Performance tracking always uses 'performance' logger - PerformanceTracking = 64, - /// @brief Specifies log file max size. - /// - /// @detail If file size of corresponding log file (for corresponding level) is >= specified size, log file will - /// be truncated and re-initiated. - MaxLogFileSize = 128, - /// @brief Specifies number of log entries to hold until we flush pending log data - LogFlushThreshold = 256, - /// @brief Represents unknown configuration - Unknown = 1010 -}; -/// @brief Static class that contains helper functions for el::ConfigurationType -class ConfigurationTypeHelper : base::StaticClass { - public: - /// @brief Represents minimum valid configuration type. Useful when iterating through enum. - static const base::type::EnumType kMinValid = static_cast(ConfigurationType::Enabled); - /// @brief Represents maximum valid configuration type. This is used internally and you should not need it. - static const base::type::EnumType kMaxValid = static_cast(ConfigurationType::MaxLogFileSize); - /// @brief Casts configuration type to int, useful for iterating through enum. - static base::type::EnumType castToInt(ConfigurationType configurationType) { - return static_cast(configurationType); - } - /// @brief Casts int(ushort) to configuration type, useful for iterating through enum. - static ConfigurationType castFromInt(base::type::EnumType c) { - return static_cast(c); - } - /// @brief Converts configuration type to associated const char* - /// @returns Upper case string based configuration type. - static const char* convertToString(ConfigurationType configurationType); - /// @brief Converts from configStr to ConfigurationType - /// @param configStr Upper case string based configuration type. - /// Lower case is also valid but providing upper case is recommended. - static ConfigurationType convertFromString(const char* configStr); - /// @brief Applies specified function to each configuration type starting from startIndex - /// @param startIndex initial value to start the iteration from. This is passed by pointer and is left-shifted - /// so this can be used inside function (fn) to represent current configuration type. - /// @param fn function to apply with each configuration type. - /// This bool represent whether or not to stop iterating through configurations. - static inline void forEachConfigType(base::type::EnumType* startIndex, const std::function& fn); -}; -/// @brief Flags used while writing logs. This flags are set by user -enum class LoggingFlag : base::type::EnumType { - /// @brief Makes sure we have new line for each container log entry - NewLineForContainer = 1, - /// @brief Makes sure if -vmodule is used and does not specifies a module, then verbose - /// logging is allowed via that module. - AllowVerboseIfModuleNotSpecified = 2, - /// @brief When handling crashes by default, detailed crash reason will be logged as well - LogDetailedCrashReason = 4, - /// @brief Allows to disable application abortion when logged using FATAL level - DisableApplicationAbortOnFatalLog = 8, - /// @brief Flushes log with every log-entry (performance sensitive) - Disabled by default - ImmediateFlush = 16, - /// @brief Enables strict file rolling - StrictLogFileSizeCheck = 32, - /// @brief Make terminal output colorful for supported terminals - ColoredTerminalOutput = 64, - /// @brief Supports use of multiple logging in same macro, e.g, CLOG(INFO, "default", "network") - MultiLoggerSupport = 128, - /// @brief Disables comparing performance tracker's checkpoints - DisablePerformanceTrackingCheckpointComparison = 256, - /// @brief Disable VModules - DisableVModules = 512, - /// @brief Disable VModules extensions - DisableVModulesExtensions = 1024, - /// @brief Enables hierarchical logging - HierarchicalLogging = 2048, - /// @brief Creates logger automatically when not available - CreateLoggerAutomatically = 4096, - /// @brief Adds spaces b/w logs that separated by left-shift operator - AutoSpacing = 8192, - /// @brief Preserves time format and does not convert it to sec, hour etc (performance tracking only) - FixedTimeFormat = 16384, - // @brief Ignore SIGINT or crash - IgnoreSigInt = 32768, -}; -namespace base { -/// @brief Namespace containing constants used internally. -namespace consts { -static const char kFormatSpecifierCharValue = 'v'; -static const char kFormatSpecifierChar = '%'; -static const unsigned int kMaxLogPerCounter = 100000; -static const unsigned int kMaxLogPerContainer = 100; -static const unsigned int kDefaultSubsecondPrecision = 3; - -#ifdef ELPP_DEFAULT_LOGGER -static const char* kDefaultLoggerId = ELPP_DEFAULT_LOGGER; -#else -static const char* kDefaultLoggerId = "default"; -#endif - -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) -#ifdef ELPP_DEFAULT_PERFORMANCE_LOGGER -static const char* kPerformanceLoggerId = ELPP_DEFAULT_PERFORMANCE_LOGGER; -#else -static const char* kPerformanceLoggerId = "performance"; -#endif // ELPP_DEFAULT_PERFORMANCE_LOGGER -#endif - -#if defined(ELPP_SYSLOG) -static const char* kSysLogLoggerId = "syslog"; -#endif // defined(ELPP_SYSLOG) - -#if ELPP_OS_WINDOWS -static const char* kFilePathSeparator = "\\"; -#else -static const char* kFilePathSeparator = "/"; -#endif // ELPP_OS_WINDOWS - -static const std::size_t kSourceFilenameMaxLength = 100; -static const std::size_t kSourceLineMaxLength = 10; -static const Level kPerformanceTrackerDefaultLevel = Level::Info; -const struct { - double value; - const base::type::char_t* unit; -} kTimeFormats[] = { - { 1000.0f, ELPP_LITERAL("us") }, - { 1000.0f, ELPP_LITERAL("ms") }, - { 60.0f, ELPP_LITERAL("seconds") }, - { 60.0f, ELPP_LITERAL("minutes") }, - { 24.0f, ELPP_LITERAL("hours") }, - { 7.0f, ELPP_LITERAL("days") } -}; -static const int kTimeFormatsCount = sizeof(kTimeFormats) / sizeof(kTimeFormats[0]); -const struct { - int numb; - const char* name; - const char* brief; - const char* detail; -} kCrashSignals[] = { - // NOTE: Do not re-order, if you do please check CrashHandler(bool) constructor and CrashHandler::setHandler(..) - { - SIGABRT, "SIGABRT", "Abnormal termination", - "Program was abnormally terminated." - }, - { - SIGFPE, "SIGFPE", "Erroneous arithmetic operation", - "Arithmetic operation issue such as division by zero or operation resulting in overflow." - }, - { - SIGILL, "SIGILL", "Illegal instruction", - "Generally due to a corruption in the code or to an attempt to execute data." - }, - { - SIGSEGV, "SIGSEGV", "Invalid access to memory", - "Program is trying to read an invalid (unallocated, deleted or corrupted) or inaccessible memory." - }, - { - SIGINT, "SIGINT", "Interactive attention signal", - "Interruption generated (generally) by user or operating system." - }, -}; -static const int kCrashSignalsCount = sizeof(kCrashSignals) / sizeof(kCrashSignals[0]); -} // namespace consts -} // namespace base -typedef std::function PreRollOutCallback; -namespace base { -static inline void defaultPreRollOutCallback(const char*, std::size_t) {} -/// @brief Enum to represent timestamp unit -enum class TimestampUnit : base::type::EnumType { - Microsecond = 0, Millisecond = 1, Second = 2, Minute = 3, Hour = 4, Day = 5 -}; -/// @brief Format flags used to determine specifiers that are active for performance improvements. -enum class FormatFlags : base::type::EnumType { - DateTime = 1 << 1, - LoggerId = 1 << 2, - File = 1 << 3, - Line = 1 << 4, - Location = 1 << 5, - Function = 1 << 6, - User = 1 << 7, - Host = 1 << 8, - LogMessage = 1 << 9, - VerboseLevel = 1 << 10, - AppName = 1 << 11, - ThreadId = 1 << 12, - Level = 1 << 13, - FileBase = 1 << 14, - LevelShort = 1 << 15 -}; -/// @brief A subsecond precision class containing actual width and offset of the subsecond part -class SubsecondPrecision { - public: - SubsecondPrecision(void) { - init(base::consts::kDefaultSubsecondPrecision); - } - explicit SubsecondPrecision(int width) { - init(width); - } - bool operator==(const SubsecondPrecision& ssPrec) { - return m_width == ssPrec.m_width && m_offset == ssPrec.m_offset; - } - int m_width; - unsigned int m_offset; - private: - void init(int width); -}; -/// @brief Type alias of SubsecondPrecision -typedef SubsecondPrecision MillisecondsWidth; -/// @brief Namespace containing utility functions/static classes used internally -namespace utils { -/// @brief Deletes memory safely and points to null -template -static -typename std::enable_if::value, void>::type -safeDelete(T*& pointer) { - if (pointer == nullptr) - return; - delete pointer; - pointer = nullptr; -} -/// @brief Bitwise operations for C++11 strong enum class. This casts e into Flag_T and returns value after bitwise operation -/// Use these function as
flag = bitwise::Or(MyEnum::val1, flag);
-namespace bitwise { -template -static inline base::type::EnumType And(Enum e, base::type::EnumType flag) { - return static_cast(flag) & static_cast(e); -} -template -static inline base::type::EnumType Not(Enum e, base::type::EnumType flag) { - return static_cast(flag) & ~(static_cast(e)); -} -template -static inline base::type::EnumType Or(Enum e, base::type::EnumType flag) { - return static_cast(flag) | static_cast(e); -} -} // namespace bitwise -template -static inline void addFlag(Enum e, base::type::EnumType* flag) { - *flag = base::utils::bitwise::Or(e, *flag); -} -template -static inline void removeFlag(Enum e, base::type::EnumType* flag) { - *flag = base::utils::bitwise::Not(e, *flag); -} -template -static inline bool hasFlag(Enum e, base::type::EnumType flag) { - return base::utils::bitwise::And(e, flag) > 0x0; -} -} // namespace utils -namespace threading { -#if ELPP_THREADING_ENABLED -# if !ELPP_USE_STD_THREADING -namespace internal { -/// @brief A mutex wrapper for compiler that dont yet support std::recursive_mutex -class Mutex : base::NoCopy { - public: - Mutex(void) { -# if ELPP_OS_UNIX - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m_underlyingMutex, &attr); - pthread_mutexattr_destroy(&attr); -# elif ELPP_OS_WINDOWS - InitializeCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - virtual ~Mutex(void) { -# if ELPP_OS_UNIX - pthread_mutex_destroy(&m_underlyingMutex); -# elif ELPP_OS_WINDOWS - DeleteCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - inline void lock(void) { -# if ELPP_OS_UNIX - pthread_mutex_lock(&m_underlyingMutex); -# elif ELPP_OS_WINDOWS - EnterCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - inline bool try_lock(void) { -# if ELPP_OS_UNIX - return (pthread_mutex_trylock(&m_underlyingMutex) == 0); -# elif ELPP_OS_WINDOWS - return TryEnterCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - inline void unlock(void) { -# if ELPP_OS_UNIX - pthread_mutex_unlock(&m_underlyingMutex); -# elif ELPP_OS_WINDOWS - LeaveCriticalSection(&m_underlyingMutex); -# endif // ELPP_OS_UNIX - } - - private: -# if ELPP_OS_UNIX - pthread_mutex_t m_underlyingMutex; -# elif ELPP_OS_WINDOWS - CRITICAL_SECTION m_underlyingMutex; -# endif // ELPP_OS_UNIX -}; -/// @brief Scoped lock for compiler that dont yet support std::lock_guard -template -class ScopedLock : base::NoCopy { - public: - explicit ScopedLock(M& mutex) { - m_mutex = &mutex; - m_mutex->lock(); - } - - virtual ~ScopedLock(void) { - m_mutex->unlock(); - } - private: - M* m_mutex; - ScopedLock(void); -}; -} // namespace internal -typedef base::threading::internal::Mutex Mutex; -typedef base::threading::internal::ScopedLock ScopedLock; -# else -typedef std::recursive_mutex Mutex; -typedef std::lock_guard ScopedLock; -# endif // !ELPP_USE_STD_THREADING -#else -namespace internal { -/// @brief Mutex wrapper used when multi-threading is disabled. -class NoMutex : base::NoCopy { - public: - NoMutex(void) {} - inline void lock(void) {} - inline bool try_lock(void) { - return true; - } - inline void unlock(void) {} -}; -/// @brief Lock guard wrapper used when multi-threading is disabled. -template -class NoScopedLock : base::NoCopy { - public: - explicit NoScopedLock(Mutex&) { - } - virtual ~NoScopedLock(void) { - } - private: - NoScopedLock(void); -}; -} // namespace internal -typedef base::threading::internal::NoMutex Mutex; -typedef base::threading::internal::NoScopedLock ScopedLock; -#endif // ELPP_THREADING_ENABLED -/// @brief Base of thread safe class, this class is inheritable-only -class ThreadSafe { - public: - virtual inline void acquireLock(void) ELPP_FINAL { m_mutex.lock(); } - virtual inline void releaseLock(void) ELPP_FINAL { m_mutex.unlock(); } - virtual inline base::threading::Mutex& lock(void) ELPP_FINAL { return m_mutex; } - protected: - ThreadSafe(void) {} - virtual ~ThreadSafe(void) {} - private: - base::threading::Mutex m_mutex; -}; - -#if ELPP_THREADING_ENABLED -# if !ELPP_USE_STD_THREADING -/// @brief Gets ID of currently running threading in windows systems. On unix, nothing is returned. -static std::string getCurrentThreadId(void) { - std::stringstream ss; -# if (ELPP_OS_WINDOWS) - ss << GetCurrentThreadId(); -# endif // (ELPP_OS_WINDOWS) - return ss.str(); -} -# else -/// @brief Gets ID of currently running threading using std::this_thread::get_id() -static std::string getCurrentThreadId(void) { - std::stringstream ss; - ss << std::this_thread::get_id(); - return ss.str(); -} -# endif // !ELPP_USE_STD_THREADING -#else -static inline std::string getCurrentThreadId(void) { - return std::string(); -} -#endif // ELPP_THREADING_ENABLED -} // namespace threading -namespace utils { -class File : base::StaticClass { - public: - /// @brief Creates new out file stream for specified filename. - /// @return Pointer to newly created fstream or nullptr - static base::type::fstream_t* newFileStream(const std::string& filename); - - /// @brief Gets size of file provided in stream - static std::size_t getSizeOfFile(base::type::fstream_t* fs); - - /// @brief Determines whether or not provided path exist in current file system - static bool pathExists(const char* path, bool considerFile = false); - - /// @brief Creates specified path on file system - /// @param path Path to create. - static bool createPath(const std::string& path); - /// @brief Extracts path of filename with leading slash - static std::string extractPathFromFilename(const std::string& fullPath, - const char* separator = base::consts::kFilePathSeparator); - /// @brief builds stripped filename and puts it in buff - static void buildStrippedFilename(const char* filename, char buff[], - std::size_t limit = base::consts::kSourceFilenameMaxLength); - /// @brief builds base filename and puts it in buff - static void buildBaseFilename(const std::string& fullPath, char buff[], - std::size_t limit = base::consts::kSourceFilenameMaxLength, - const char* separator = base::consts::kFilePathSeparator); -}; -/// @brief String utilities helper class used internally. You should not use it. -class Str : base::StaticClass { - public: - /// @brief Checks if character is digit. Dont use libc implementation of it to prevent locale issues. - static inline bool isDigit(char c) { - return c >= '0' && c <= '9'; - } - - /// @brief Matches wildcards, '*' and '?' only supported. - static bool wildCardMatch(const char* str, const char* pattern); - - static std::string& ltrim(std::string& str); - static std::string& rtrim(std::string& str); - static std::string& trim(std::string& str); - - /// @brief Determines whether or not str starts with specified string - /// @param str String to check - /// @param start String to check against - /// @return Returns true if starts with specified string, false otherwise - static bool startsWith(const std::string& str, const std::string& start); - - /// @brief Determines whether or not str ends with specified string - /// @param str String to check - /// @param end String to check against - /// @return Returns true if ends with specified string, false otherwise - static bool endsWith(const std::string& str, const std::string& end); - - /// @brief Replaces all instances of replaceWhat with 'replaceWith'. Original variable is changed for performance. - /// @param [in,out] str String to replace from - /// @param replaceWhat Character to replace - /// @param replaceWith Character to replace with - /// @return Modified version of str - static std::string& replaceAll(std::string& str, char replaceWhat, char replaceWith); - - /// @brief Replaces all instances of 'replaceWhat' with 'replaceWith'. (String version) Replaces in place - /// @param str String to replace from - /// @param replaceWhat Character to replace - /// @param replaceWith Character to replace with - /// @return Modified (original) str - static std::string& replaceAll(std::string& str, const std::string& replaceWhat, - const std::string& replaceWith); - - static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, - const base::type::string_t& replaceWith); -#if defined(ELPP_UNICODE) - static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, - const std::string& replaceWith); -#endif // defined(ELPP_UNICODE) - /// @brief Converts string to uppercase - /// @param str String to convert - /// @return Uppercase string - static std::string& toUpper(std::string& str); - - /// @brief Compares cstring equality - uses strcmp - static bool cStringEq(const char* s1, const char* s2); - - /// @brief Compares cstring equality (case-insensitive) - uses toupper(char) - /// Dont use strcasecmp because of CRT (VC++) - static bool cStringCaseEq(const char* s1, const char* s2); - - /// @brief Returns true if c exist in str - static bool contains(const char* str, char c); - - static char* convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded = true); - static char* addToBuff(const char* str, char* buf, const char* bufLim); - static char* clearBuff(char buff[], std::size_t lim); - - /// @brief Converts wchar* to char* - /// NOTE: Need to free return value after use! - static char* wcharPtrToCharPtr(const wchar_t* line); -}; -/// @brief Operating System helper static class used internally. You should not use it. -class OS : base::StaticClass { - public: -#if ELPP_OS_WINDOWS - /// @brief Gets environment variables for Windows based OS. - /// We are not using getenv(const char*) because of CRT deprecation - /// @param varname Variable name to get environment variable value for - /// @return If variable exist the value of it otherwise nullptr - static const char* getWindowsEnvironmentVariable(const char* varname); -#endif // ELPP_OS_WINDOWS -#if ELPP_OS_ANDROID - /// @brief Reads android property value - static std::string getProperty(const char* prop); - - /// @brief Reads android device name - static std::string getDeviceName(void); -#endif // ELPP_OS_ANDROID - - /// @brief Runs command on terminal and returns the output. - /// - /// @detail This is applicable only on unix based systems, for all other OS, an empty string is returned. - /// @param command Bash command - /// @return Result of bash output or empty string if no result found. - static const std::string getBashOutput(const char* command); - - /// @brief Gets environment variable. This is cross-platform and CRT safe (for VC++) - /// @param variableName Environment variable name - /// @param defaultVal If no environment variable or value found the value to return by default - /// @param alternativeBashCommand If environment variable not found what would be alternative bash command - /// in order to look for value user is looking for. E.g, for 'user' alternative command will 'whoami' - static std::string getEnvironmentVariable(const char* variableName, const char* defaultVal, - const char* alternativeBashCommand = nullptr); - /// @brief Gets current username. - static std::string currentUser(void); - - /// @brief Gets current host name or computer name. - /// - /// @detail For android systems this is device name with its manufacturer and model separated by hyphen - static std::string currentHost(void); - /// @brief Whether or not terminal supports colors - static bool termSupportsColor(void); -}; -/// @brief Contains utilities for cross-platform date/time. This class make use of el::base::utils::Str -class DateTime : base::StaticClass { - public: - /// @brief Cross platform gettimeofday for Windows and unix platform. This can be used to determine current microsecond. - /// - /// @detail For unix system it uses gettimeofday(timeval*, timezone*) and for Windows, a separate implementation is provided - /// @param [in,out] tv Pointer that gets updated - static void gettimeofday(struct timeval* tv); - - /// @brief Gets current date and time with a subsecond part. - /// @param format User provided date/time format - /// @param ssPrec A pointer to base::SubsecondPrecision from configuration (non-null) - /// @returns string based date time in specified format. - static std::string getDateTime(const char* format, const base::SubsecondPrecision* ssPrec); - - /// @brief Converts timeval (struct from ctime) to string using specified format and subsecond precision - static std::string timevalToString(struct timeval tval, const char* format, - const el::base::SubsecondPrecision* ssPrec); - - /// @brief Formats time to get unit accordingly, units like second if > 1000 or minutes if > 60000 etc - static base::type::string_t formatTime(unsigned long long time, base::TimestampUnit timestampUnit); - - /// @brief Gets time difference in milli/micro second depending on timestampUnit - static unsigned long long getTimeDifference(const struct timeval& endTime, const struct timeval& startTime, - base::TimestampUnit timestampUnit); - - - static struct ::tm* buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo); - private: - static char* parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo, - std::size_t msec, const base::SubsecondPrecision* ssPrec); -}; -/// @brief Command line arguments for application if specified using el::Helpers::setArgs(..) or START_EASYLOGGINGPP(..) -class CommandLineArgs { - public: - CommandLineArgs(void) { - setArgs(0, static_cast(nullptr)); - } - CommandLineArgs(int argc, const char** argv) { - setArgs(argc, argv); - } - CommandLineArgs(int argc, char** argv) { - setArgs(argc, argv); - } - virtual ~CommandLineArgs(void) {} - /// @brief Sets arguments and parses them - inline void setArgs(int argc, const char** argv) { - setArgs(argc, const_cast(argv)); - } - /// @brief Sets arguments and parses them - void setArgs(int argc, char** argv); - /// @brief Returns true if arguments contain paramKey with a value (separated by '=') - bool hasParamWithValue(const char* paramKey) const; - /// @brief Returns value of arguments - /// @see hasParamWithValue(const char*) - const char* getParamValue(const char* paramKey) const; - /// @brief Return true if arguments has a param (not having a value) i,e without '=' - bool hasParam(const char* paramKey) const; - /// @brief Returns true if no params available. This exclude argv[0] - bool empty(void) const; - /// @brief Returns total number of arguments. This exclude argv[0] - std::size_t size(void) const; - friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const CommandLineArgs& c); - - private: - int m_argc; - char** m_argv; - std::unordered_map m_paramsWithValue; - std::vector m_params; -}; -/// @brief Abstract registry (aka repository) that provides basic interface for pointer repository specified by T_Ptr type. -/// -/// @detail Most of the functions are virtual final methods but anything implementing this abstract class should implement -/// unregisterAll() and deepCopy(const AbstractRegistry&) and write registerNew() method according to container -/// and few more methods; get() to find element, unregister() to unregister single entry. -/// Please note that this is thread-unsafe and should also implement thread-safety mechanisms in implementation. -template -class AbstractRegistry : public base::threading::ThreadSafe { - public: - typedef typename Container::iterator iterator; - typedef typename Container::const_iterator const_iterator; - - /// @brief Default constructor - AbstractRegistry(void) {} - - /// @brief Move constructor that is useful for base classes - AbstractRegistry(AbstractRegistry&& sr) { - if (this == &sr) { - return; - } - unregisterAll(); - m_list = std::move(sr.m_list); - } - - bool operator==(const AbstractRegistry& other) { - if (size() != other.size()) { - return false; - } - for (std::size_t i = 0; i < m_list.size(); ++i) { - if (m_list.at(i) != other.m_list.at(i)) { - return false; - } - } - return true; - } - - bool operator!=(const AbstractRegistry& other) { - if (size() != other.size()) { - return true; - } - for (std::size_t i = 0; i < m_list.size(); ++i) { - if (m_list.at(i) != other.m_list.at(i)) { - return true; - } - } - return false; - } - - /// @brief Assignment move operator - AbstractRegistry& operator=(AbstractRegistry&& sr) { - if (this == &sr) { - return *this; - } - unregisterAll(); - m_list = std::move(sr.m_list); - return *this; - } - - virtual ~AbstractRegistry(void) { - } - - /// @return Iterator pointer from start of repository - virtual inline iterator begin(void) ELPP_FINAL { - return m_list.begin(); - } - - /// @return Iterator pointer from end of repository - virtual inline iterator end(void) ELPP_FINAL { - return m_list.end(); - } - - - /// @return Constant iterator pointer from start of repository - virtual inline const_iterator cbegin(void) const ELPP_FINAL { - return m_list.cbegin(); - } - - /// @return End of repository - virtual inline const_iterator cend(void) const ELPP_FINAL { - return m_list.cend(); - } - - /// @return Whether or not repository is empty - virtual inline bool empty(void) const ELPP_FINAL { - return m_list.empty(); - } - - /// @return Size of repository - virtual inline std::size_t size(void) const ELPP_FINAL { - return m_list.size(); - } - - /// @brief Returns underlying container by reference - virtual inline Container& list(void) ELPP_FINAL { - return m_list; - } - - /// @brief Returns underlying container by constant reference. - virtual inline const Container& list(void) const ELPP_FINAL { - return m_list; - } - - /// @brief Unregisters all the pointers from current repository. - virtual void unregisterAll(void) = 0; - - protected: - virtual void deepCopy(const AbstractRegistry&) = 0; - void reinitDeepCopy(const AbstractRegistry& sr) { - unregisterAll(); - deepCopy(sr); - } - - private: - Container m_list; -}; - -/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (non-predicate version) -/// -/// @detail NOTE: This is thread-unsafe implementation (although it contains lock function, it does not use these functions) -/// of AbstractRegistry. Any implementation of this class should be -/// explicitly (by using lock functions) -template -class Registry : public AbstractRegistry> { - public: - typedef typename Registry::iterator iterator; - typedef typename Registry::const_iterator const_iterator; - - Registry(void) {} - - /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor. - Registry(const Registry& sr) : AbstractRegistry>() { - if (this == &sr) { - return; - } - this->reinitDeepCopy(sr); - } - - /// @brief Assignment operator that unregisters all the existing registries and deeply copies each of repo element - /// @see unregisterAll() - /// @see deepCopy(const AbstractRegistry&) - Registry& operator=(const Registry& sr) { - if (this == &sr) { - return *this; - } - this->reinitDeepCopy(sr); - return *this; - } - - virtual ~Registry(void) { - unregisterAll(); - } - - protected: - virtual void unregisterAll(void) ELPP_FINAL { - if (!this->empty()) { - for (auto&& curr : this->list()) { - base::utils::safeDelete(curr.second); - } - this->list().clear(); - } - } - -/// @brief Registers new registry to repository. - virtual void registerNew(const T_Key& uniqKey, T_Ptr* ptr) ELPP_FINAL { - unregister(uniqKey); - this->list().insert(std::make_pair(uniqKey, ptr)); - } - -/// @brief Unregisters single entry mapped to specified unique key - void unregister(const T_Key& uniqKey) { - T_Ptr* existing = get(uniqKey); - if (existing != nullptr) { - this->list().erase(uniqKey); - base::utils::safeDelete(existing); - } - } - -/// @brief Gets pointer from repository. If none found, nullptr is returned. - T_Ptr* get(const T_Key& uniqKey) { - iterator it = this->list().find(uniqKey); - return it == this->list().end() - ? nullptr - : it->second; - } - - private: - virtual void deepCopy(const AbstractRegistry>& sr) ELPP_FINAL { - for (const_iterator it = sr.cbegin(); it != sr.cend(); ++it) { - registerNew(it->first, new T_Ptr(*it->second)); - } - } -}; - -/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (predicate version) -/// -/// @detail NOTE: This is thread-unsafe implementation of AbstractRegistry. Any implementation of this class -/// should be made thread-safe explicitly -template -class RegistryWithPred : public AbstractRegistry> { - public: - typedef typename RegistryWithPred::iterator iterator; - typedef typename RegistryWithPred::const_iterator const_iterator; - - RegistryWithPred(void) { - } - - virtual ~RegistryWithPred(void) { - unregisterAll(); - } - - /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor. - RegistryWithPred(const RegistryWithPred& sr) : AbstractRegistry>() { - if (this == &sr) { - return; - } - this->reinitDeepCopy(sr); - } - - /// @brief Assignment operator that unregisters all the existing registries and deeply copies each of repo element - /// @see unregisterAll() - /// @see deepCopy(const AbstractRegistry&) - RegistryWithPred& operator=(const RegistryWithPred& sr) { - if (this == &sr) { - return *this; - } - this->reinitDeepCopy(sr); - return *this; - } - - friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const RegistryWithPred& sr) { - for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) { - os << ELPP_LITERAL(" ") << **it << ELPP_LITERAL("\n"); - } - return os; - } - - protected: - virtual void unregisterAll(void) ELPP_FINAL { - if (!this->empty()) { - for (auto&& curr : this->list()) { - base::utils::safeDelete(curr); - } - this->list().clear(); - } - } - - virtual void unregister(T_Ptr*& ptr) ELPP_FINAL { - if (ptr) { - iterator iter = this->begin(); - for (; iter != this->end(); ++iter) { - if (ptr == *iter) { - break; - } - } - if (iter != this->end() && *iter != nullptr) { - this->list().erase(iter); - base::utils::safeDelete(*iter); - } - } - } - - virtual inline void registerNew(T_Ptr* ptr) ELPP_FINAL { - this->list().push_back(ptr); - } - -/// @brief Gets pointer from repository with specified arguments. Arguments are passed to predicate -/// in order to validate pointer. - template - T_Ptr* get(const T& arg1, const T2 arg2) { - iterator iter = std::find_if(this->list().begin(), this->list().end(), Pred(arg1, arg2)); - if (iter != this->list().end() && *iter != nullptr) { - return *iter; - } - return nullptr; - } - - private: - virtual void deepCopy(const AbstractRegistry>& sr) { - for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) { - registerNew(new T_Ptr(**it)); - } - } -}; -class Utils { - public: - template - static bool installCallback(const std::string& id, std::unordered_map* mapT) { - if (mapT->find(id) == mapT->end()) { - mapT->insert(std::make_pair(id, TPtr(new T()))); - return true; - } - return false; - } - - template - static void uninstallCallback(const std::string& id, std::unordered_map* mapT) { - if (mapT->find(id) != mapT->end()) { - mapT->erase(id); - } - } - - template - static T* callback(const std::string& id, std::unordered_map* mapT) { - typename std::unordered_map::iterator iter = mapT->find(id); - if (iter != mapT->end()) { - return static_cast(iter->second.get()); - } - return nullptr; - } -}; -} // namespace utils -} // namespace base -/// @brief Base of Easylogging++ friendly class -/// -/// @detail After inheriting this class publicly, implement pure-virtual function `void log(std::ostream&) const` -class Loggable { - public: - virtual ~Loggable(void) {} - virtual void log(el::base::type::ostream_t&) const = 0; - private: - friend inline el::base::type::ostream_t& operator<<(el::base::type::ostream_t& os, const Loggable& loggable) { - loggable.log(os); - return os; - } -}; -namespace base { -/// @brief Represents log format containing flags and date format. This is used internally to start initial log -class LogFormat : public Loggable { - public: - LogFormat(void); - LogFormat(Level level, const base::type::string_t& format); - LogFormat(const LogFormat& logFormat); - LogFormat(LogFormat&& logFormat); - LogFormat& operator=(const LogFormat& logFormat); - virtual ~LogFormat(void) {} - bool operator==(const LogFormat& other); - - /// @brief Updates format to be used while logging. - /// @param userFormat User provided format - void parseFromFormat(const base::type::string_t& userFormat); - - inline Level level(void) const { - return m_level; - } - - inline const base::type::string_t& userFormat(void) const { - return m_userFormat; - } - - inline const base::type::string_t& format(void) const { - return m_format; - } - - inline const std::string& dateTimeFormat(void) const { - return m_dateTimeFormat; - } - - inline base::type::EnumType flags(void) const { - return m_flags; - } - - inline bool hasFlag(base::FormatFlags flag) const { - return base::utils::hasFlag(flag, m_flags); - } - - virtual void log(el::base::type::ostream_t& os) const { - os << m_format; - } - - protected: - /// @brief Updates date time format if available in currFormat. - /// @param index Index where %datetime, %date or %time was found - /// @param [in,out] currFormat current format that is being used to format - virtual void updateDateFormat(std::size_t index, base::type::string_t& currFormat) ELPP_FINAL; - - /// @brief Updates %level from format. This is so that we dont have to do it at log-writing-time. It uses m_format and m_level - virtual void updateFormatSpec(void) ELPP_FINAL; - - inline void addFlag(base::FormatFlags flag) { - base::utils::addFlag(flag, &m_flags); - } - - private: - Level m_level; - base::type::string_t m_userFormat; - base::type::string_t m_format; - std::string m_dateTimeFormat; - base::type::EnumType m_flags; - std::string m_currentUser; - std::string m_currentHost; - friend class el::Logger; // To resolve loggerId format specifier easily -}; -} // namespace base -/// @brief Resolving function for format specifier -typedef std::function FormatSpecifierValueResolver; -/// @brief User-provided custom format specifier -/// @see el::Helpers::installCustomFormatSpecifier -/// @see FormatSpecifierValueResolver -class CustomFormatSpecifier { - public: - CustomFormatSpecifier(const char* formatSpecifier, const FormatSpecifierValueResolver& resolver) : - m_formatSpecifier(formatSpecifier), m_resolver(resolver) {} - inline const char* formatSpecifier(void) const { - return m_formatSpecifier; - } - inline const FormatSpecifierValueResolver& resolver(void) const { - return m_resolver; - } - inline bool operator==(const char* formatSpecifier) { - return strcmp(m_formatSpecifier, formatSpecifier) == 0; - } - - private: - const char* m_formatSpecifier; - FormatSpecifierValueResolver m_resolver; -}; -/// @brief Represents single configuration that has representing level, configuration type and a string based value. -/// -/// @detail String based value means any value either its boolean, integer or string itself, it will be embedded inside quotes -/// and will be parsed later. -/// -/// Consider some examples below: -/// * el::Configuration confEnabledInfo(el::Level::Info, el::ConfigurationType::Enabled, "true"); -/// * el::Configuration confMaxLogFileSizeInfo(el::Level::Info, el::ConfigurationType::MaxLogFileSize, "2048"); -/// * el::Configuration confFilenameInfo(el::Level::Info, el::ConfigurationType::Filename, "/var/log/my.log"); -class Configuration : public Loggable { - public: - Configuration(const Configuration& c); - Configuration& operator=(const Configuration& c); - - virtual ~Configuration(void) { - } - - /// @brief Full constructor used to sets value of configuration - Configuration(Level level, ConfigurationType configurationType, const std::string& value); - - /// @brief Gets level of current configuration - inline Level level(void) const { - return m_level; - } - - /// @brief Gets configuration type of current configuration - inline ConfigurationType configurationType(void) const { - return m_configurationType; - } - - /// @brief Gets string based configuration value - inline const std::string& value(void) const { - return m_value; - } - - /// @brief Set string based configuration value - /// @param value Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values - /// use them in quotes. They will be parsed when configuring - inline void setValue(const std::string& value) { - m_value = value; - } - - virtual void log(el::base::type::ostream_t& os) const; - - /// @brief Used to find configuration from configuration (pointers) repository. Avoid using it. - class Predicate { - public: - Predicate(Level level, ConfigurationType configurationType); - - bool operator()(const Configuration* conf) const; - - private: - Level m_level; - ConfigurationType m_configurationType; - }; - - private: - Level m_level; - ConfigurationType m_configurationType; - std::string m_value; -}; - -/// @brief Thread-safe Configuration repository -/// -/// @detail This repository represents configurations for all the levels and configuration type mapped to a value. -class Configurations : public base::utils::RegistryWithPred { - public: - /// @brief Default constructor with empty repository - Configurations(void); - - /// @brief Constructor used to set configurations using configuration file. - /// @param configurationFile Full path to configuration file - /// @param useDefaultsForRemaining Lets you set the remaining configurations to default. - /// @param base If provided, this configuration will be based off existing repository that this argument is pointing to. - /// @see parseFromFile(const std::string&, Configurations* base) - /// @see setRemainingToDefault() - Configurations(const std::string& configurationFile, bool useDefaultsForRemaining = true, - Configurations* base = nullptr); - - virtual ~Configurations(void) { - } - - /// @brief Parses configuration from file. - /// @param configurationFile Full path to configuration file - /// @param base Configurations to base new configuration repository off. This value is used when you want to use - /// existing Configurations to base all the values and then set rest of configuration via configuration file. - /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you - /// do not proceed without successful parse. - bool parseFromFile(const std::string& configurationFile, Configurations* base = nullptr); - - /// @brief Parse configurations from configuration string. - /// - /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary - /// new line characters are provided. - /// @param base Configurations to base new configuration repository off. This value is used when you want to use - /// existing Configurations to base all the values and then set rest of configuration via configuration text. - /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you - /// do not proceed without successful parse. - bool parseFromText(const std::string& configurationsString, Configurations* base = nullptr); - - /// @brief Sets configuration based-off an existing configurations. - /// @param base Pointer to existing configurations. - void setFromBase(Configurations* base); - - /// @brief Determines whether or not specified configuration type exists in the repository. - /// - /// @detail Returns as soon as first level is found. - /// @param configurationType Type of configuration to check existence for. - bool hasConfiguration(ConfigurationType configurationType); - - /// @brief Determines whether or not specified configuration type exists for specified level - /// @param level Level to check - /// @param configurationType Type of configuration to check existence for. - bool hasConfiguration(Level level, ConfigurationType configurationType); - - /// @brief Sets value of configuration for specified level. - /// - /// @detail Any existing configuration for specified level will be replaced. Also note that configuration types - /// ConfigurationType::SubsecondPrecision and ConfigurationType::PerformanceTracking will be ignored if not set for - /// Level::Global because these configurations are not dependant on level. - /// @param level Level to set configuration for (el::Level). - /// @param configurationType Type of configuration (el::ConfigurationType) - /// @param value A string based value. Regardless of what the data type of configuration is, it will always be string - /// from users' point of view. This is then parsed later to be used internally. - /// @see Configuration::setValue(const std::string& value) - /// @see el::Level - /// @see el::ConfigurationType - void set(Level level, ConfigurationType configurationType, const std::string& value); - - /// @brief Sets single configuration based on other single configuration. - /// @see set(Level level, ConfigurationType configurationType, const std::string& value) - void set(Configuration* conf); - - inline Configuration* get(Level level, ConfigurationType configurationType) { - base::threading::ScopedLock scopedLock(lock()); - return RegistryWithPred::get(level, configurationType); - } - - /// @brief Sets configuration for all levels. - /// @param configurationType Type of configuration - /// @param value String based value - /// @see Configurations::set(Level level, ConfigurationType configurationType, const std::string& value) - inline void setGlobally(ConfigurationType configurationType, const std::string& value) { - setGlobally(configurationType, value, false); - } - - /// @brief Clears repository so that all the configurations are unset - inline void clear(void) { - base::threading::ScopedLock scopedLock(lock()); - unregisterAll(); - } - - /// @brief Gets configuration file used in parsing this configurations. - /// - /// @detail If this repository was set manually or by text this returns empty string. - inline const std::string& configurationFile(void) const { - return m_configurationFile; - } - - /// @brief Sets configurations to "factory based" configurations. - void setToDefault(void); - - /// @brief Lets you set the remaining configurations to default. - /// - /// @detail By remaining, it means that the level/type a configuration does not exist for. - /// This function is useful when you want to minimize chances of failures, e.g, if you have a configuration file that sets - /// configuration for all the configurations except for Enabled or not, we use this so that ENABLED is set to default i.e, - /// true. If you dont do this explicitly (either by calling this function or by using second param in Constructor - /// and try to access a value, an error is thrown - void setRemainingToDefault(void); - - /// @brief Parser used internally to parse configurations from file or text. - /// - /// @detail This class makes use of base::utils::Str. - /// You should not need this unless you are working on some tool for Easylogging++ - class Parser : base::StaticClass { - public: - /// @brief Parses configuration from file. - /// @param configurationFile Full path to configuration file - /// @param sender Sender configurations pointer. Usually 'this' is used from calling class - /// @param base Configurations to base new configuration repository off. This value is used when you want to use - /// existing Configurations to base all the values and then set rest of configuration via configuration file. - /// @return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you - /// do not proceed without successful parse. - static bool parseFromFile(const std::string& configurationFile, Configurations* sender, - Configurations* base = nullptr); - - /// @brief Parse configurations from configuration string. - /// - /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary - /// new line characters are provided. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you - /// do not proceed without successful parse (This is recommended) - /// @param configurationsString the configuration in plain text format - /// @param sender Sender configurations pointer. Usually 'this' is used from calling class - /// @param base Configurations to base new configuration repository off. This value is used when you want to use - /// existing Configurations to base all the values and then set rest of configuration via configuration text. - /// @return True if successfully parsed, false otherwise. - static bool parseFromText(const std::string& configurationsString, Configurations* sender, - Configurations* base = nullptr); - - private: - friend class el::Loggers; - static void ignoreComments(std::string* line); - static bool isLevel(const std::string& line); - static bool isComment(const std::string& line); - static inline bool isConfig(const std::string& line); - static bool parseLine(std::string* line, std::string* currConfigStr, std::string* currLevelStr, Level* currLevel, - Configurations* conf); - }; - - private: - std::string m_configurationFile; - bool m_isFromFile; - friend class el::Loggers; - - /// @brief Unsafely sets configuration if does not already exist - void unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value); - - /// @brief Thread unsafe set - void unsafeSet(Level level, ConfigurationType configurationType, const std::string& value); - - /// @brief Sets configurations for all levels including Level::Global if includeGlobalLevel is true - /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value) - void setGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel); - - /// @brief Sets configurations (Unsafely) for all levels including Level::Global if includeGlobalLevel is true - /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value) - void unsafeSetGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel); -}; - -namespace base { -typedef std::shared_ptr FileStreamPtr; -typedef std::unordered_map LogStreamsReferenceMap; -typedef std::shared_ptr LogStreamsReferenceMapPtr; -/// @brief Configurations with data types. -/// -/// @detail el::Configurations have string based values. This is whats used internally in order to read correct configurations. -/// This is to perform faster while writing logs using correct configurations. -/// -/// This is thread safe and final class containing non-virtual destructor (means nothing should inherit this class) -class TypedConfigurations : public base::threading::ThreadSafe { - public: - /// @brief Constructor to initialize (construct) the object off el::Configurations - /// @param configurations Configurations pointer/reference to base this typed configurations off. - /// @param logStreamsReference Use ELPP->registeredLoggers()->logStreamsReference() - TypedConfigurations(Configurations* configurations, LogStreamsReferenceMapPtr logStreamsReference); - - TypedConfigurations(const TypedConfigurations& other); - - virtual ~TypedConfigurations(void) { - } - - const Configurations* configurations(void) const { - return m_configurations; - } - - bool enabled(Level level); - bool toFile(Level level); - const std::string& filename(Level level); - bool toStandardOutput(Level level); - const base::LogFormat& logFormat(Level level); - const base::SubsecondPrecision& subsecondPrecision(Level level = Level::Global); - const base::MillisecondsWidth& millisecondsWidth(Level level = Level::Global); - bool performanceTracking(Level level = Level::Global); - base::type::fstream_t* fileStream(Level level); - std::size_t maxLogFileSize(Level level); - std::size_t logFlushThreshold(Level level); - - private: - Configurations* m_configurations; - std::unordered_map m_enabledMap; - std::unordered_map m_toFileMap; - std::unordered_map m_filenameMap; - std::unordered_map m_toStandardOutputMap; - std::unordered_map m_logFormatMap; - std::unordered_map m_subsecondPrecisionMap; - std::unordered_map m_performanceTrackingMap; - std::unordered_map m_fileStreamMap; - std::unordered_map m_maxLogFileSizeMap; - std::unordered_map m_logFlushThresholdMap; - LogStreamsReferenceMapPtr m_logStreamsReference = nullptr; - - friend class el::Helpers; - friend class el::base::MessageBuilder; - friend class el::base::Writer; - friend class el::base::DefaultLogDispatchCallback; - friend class el::base::LogDispatcher; - - template - inline Conf_T getConfigByVal(Level level, const std::unordered_map* confMap, const char* confName) { - base::threading::ScopedLock scopedLock(lock()); - return unsafeGetConfigByVal(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope - } - - template - inline Conf_T& getConfigByRef(Level level, std::unordered_map* confMap, const char* confName) { - base::threading::ScopedLock scopedLock(lock()); - return unsafeGetConfigByRef(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope - } - - template - Conf_T unsafeGetConfigByVal(Level level, const std::unordered_map* confMap, const char* confName) { - ELPP_UNUSED(confName); - typename std::unordered_map::const_iterator it = confMap->find(level); - if (it == confMap->end()) { - try { - return confMap->at(Level::Global); - } catch (...) { - ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level [" - << LevelHelper::convertToString(level) << "]" - << std::endl << "Please ensure you have properly configured logger.", false); - return Conf_T(); - } - } - return it->second; - } - - template - Conf_T& unsafeGetConfigByRef(Level level, std::unordered_map* confMap, const char* confName) { - ELPP_UNUSED(confName); - typename std::unordered_map::iterator it = confMap->find(level); - if (it == confMap->end()) { - try { - return confMap->at(Level::Global); - } catch (...) { - ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level [" - << LevelHelper::convertToString(level) << "]" - << std::endl << "Please ensure you have properly configured logger.", false); - } - } - return it->second; - } - - template - void setValue(Level level, const Conf_T& value, std::unordered_map* confMap, - bool includeGlobalLevel = true) { - // If map is empty and we are allowed to add into generic level (Level::Global), do it! - if (confMap->empty() && includeGlobalLevel) { - confMap->insert(std::make_pair(Level::Global, value)); - return; - } - // If same value exist in generic level already, dont add it to explicit level - typename std::unordered_map::iterator it = confMap->find(Level::Global); - if (it != confMap->end() && it->second == value) { - return; - } - // Now make sure we dont double up values if we really need to add it to explicit level - it = confMap->find(level); - if (it == confMap->end()) { - // Value not found for level, add new - confMap->insert(std::make_pair(level, value)); - } else { - // Value found, just update value - confMap->at(level) = value; - } - } - - void build(Configurations* configurations); - unsigned long getULong(std::string confVal); - std::string resolveFilename(const std::string& filename); - void insertFile(Level level, const std::string& fullFilename); - bool unsafeValidateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback); - - inline bool validateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback) { - base::threading::ScopedLock scopedLock(lock()); - return unsafeValidateFileRolling(level, preRollOutCallback); - } -}; -/// @brief Class that keeps record of current line hit for occasional logging -class HitCounter { - public: - HitCounter(void) : - m_filename(""), - m_lineNumber(0), - m_hitCounts(0) { - } - - HitCounter(const char* filename, base::type::LineNumber lineNumber) : - m_filename(filename), - m_lineNumber(lineNumber), - m_hitCounts(0) { - } - - HitCounter(const HitCounter& hitCounter) : - m_filename(hitCounter.m_filename), - m_lineNumber(hitCounter.m_lineNumber), - m_hitCounts(hitCounter.m_hitCounts) { - } - - HitCounter& operator=(const HitCounter& hitCounter) { - if (&hitCounter != this) { - m_filename = hitCounter.m_filename; - m_lineNumber = hitCounter.m_lineNumber; - m_hitCounts = hitCounter.m_hitCounts; - } - return *this; - } - - virtual ~HitCounter(void) { - } - - /// @brief Resets location of current hit counter - inline void resetLocation(const char* filename, base::type::LineNumber lineNumber) { - m_filename = filename; - m_lineNumber = lineNumber; - } - - /// @brief Validates hit counts and resets it if necessary - inline void validateHitCounts(std::size_t n) { - if (m_hitCounts >= base::consts::kMaxLogPerCounter) { - m_hitCounts = (n >= 1 ? base::consts::kMaxLogPerCounter % n : 0); - } - ++m_hitCounts; - } - - inline const char* filename(void) const { - return m_filename; - } - - inline base::type::LineNumber lineNumber(void) const { - return m_lineNumber; - } - - inline std::size_t hitCounts(void) const { - return m_hitCounts; - } - - inline void increment(void) { - ++m_hitCounts; - } - - class Predicate { - public: - Predicate(const char* filename, base::type::LineNumber lineNumber) - : m_filename(filename), - m_lineNumber(lineNumber) { - } - inline bool operator()(const HitCounter* counter) { - return ((counter != nullptr) && - (strcmp(counter->m_filename, m_filename) == 0) && - (counter->m_lineNumber == m_lineNumber)); - } - - private: - const char* m_filename; - base::type::LineNumber m_lineNumber; - }; - - private: - const char* m_filename; - base::type::LineNumber m_lineNumber; - std::size_t m_hitCounts; -}; -/// @brief Repository for hit counters used across the application -class RegisteredHitCounters : public base::utils::RegistryWithPred { - public: - /// @brief Validates counter for every N, i.e, registers new if does not exist otherwise updates original one - /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned - bool validateEveryN(const char* filename, base::type::LineNumber lineNumber, std::size_t n); - - /// @brief Validates counter for hits >= N, i.e, registers new if does not exist otherwise updates original one - /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned - bool validateAfterN(const char* filename, base::type::LineNumber lineNumber, std::size_t n); - - /// @brief Validates counter for hits are <= n, i.e, registers new if does not exist otherwise updates original one - /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned - bool validateNTimes(const char* filename, base::type::LineNumber lineNumber, std::size_t n); - - /// @brief Gets hit counter registered at specified position - inline const base::HitCounter* getCounter(const char* filename, base::type::LineNumber lineNumber) { - base::threading::ScopedLock scopedLock(lock()); - return get(filename, lineNumber); - } -}; -/// @brief Action to be taken for dispatching -enum class DispatchAction : base::type::EnumType { - None = 1, NormalLog = 2, SysLog = 4 -}; -} // namespace base -template -class Callback : protected base::threading::ThreadSafe { - public: - Callback(void) : m_enabled(true) {} - inline bool enabled(void) const { - return m_enabled; - } - inline void setEnabled(bool enabled) { - base::threading::ScopedLock scopedLock(lock()); - m_enabled = enabled; - } - protected: - virtual void handle(const T* handlePtr) = 0; - private: - bool m_enabled; -}; -class LogDispatchData { - public: - LogDispatchData() : m_logMessage(nullptr), m_dispatchAction(base::DispatchAction::None) {} - inline const LogMessage* logMessage(void) const { - return m_logMessage; - } - inline base::DispatchAction dispatchAction(void) const { - return m_dispatchAction; - } - inline void setLogMessage(LogMessage* logMessage) { - m_logMessage = logMessage; - } - inline void setDispatchAction(base::DispatchAction dispatchAction) { - m_dispatchAction = dispatchAction; - } - private: - LogMessage* m_logMessage; - base::DispatchAction m_dispatchAction; - friend class base::LogDispatcher; - -}; -class LogDispatchCallback : public Callback { - protected: - virtual void handle(const LogDispatchData* data); - base::threading::Mutex& fileHandle(const LogDispatchData* data); - private: - friend class base::LogDispatcher; - std::unordered_map> m_fileLocks; - base::threading::Mutex m_fileLocksMapLock; -}; -class PerformanceTrackingCallback : public Callback { - private: - friend class base::PerformanceTracker; -}; -class LoggerRegistrationCallback : public Callback { - private: - friend class base::RegisteredLoggers; -}; -class LogBuilder : base::NoCopy { - public: - LogBuilder() : m_termSupportsColor(base::utils::OS::termSupportsColor()) {} - virtual ~LogBuilder(void) { - ELPP_INTERNAL_INFO(3, "Destroying log builder...") - } - virtual base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const = 0; - void convertToColoredOutput(base::type::string_t* logLine, Level level); - private: - bool m_termSupportsColor; - friend class el::base::DefaultLogDispatchCallback; -}; -typedef std::shared_ptr LogBuilderPtr; -/// @brief Represents a logger holding ID and configurations we need to write logs -/// -/// @detail This class does not write logs itself instead its used by writer to read configurations from. -class Logger : public base::threading::ThreadSafe, public Loggable { - public: - Logger(const std::string& id, base::LogStreamsReferenceMapPtr logStreamsReference); - Logger(const std::string& id, const Configurations& configurations, base::LogStreamsReferenceMapPtr logStreamsReference); - Logger(const Logger& logger); - Logger& operator=(const Logger& logger); - - virtual ~Logger(void) { - base::utils::safeDelete(m_typedConfigurations); - } - - virtual inline void log(el::base::type::ostream_t& os) const { - os << m_id.c_str(); - } - - /// @brief Configures the logger using specified configurations. - void configure(const Configurations& configurations); - - /// @brief Reconfigures logger using existing configurations - void reconfigure(void); - - inline const std::string& id(void) const { - return m_id; - } - - inline const std::string& parentApplicationName(void) const { - return m_parentApplicationName; - } - - inline void setParentApplicationName(const std::string& parentApplicationName) { - m_parentApplicationName = parentApplicationName; - } - - inline Configurations* configurations(void) { - return &m_configurations; - } - - inline base::TypedConfigurations* typedConfigurations(void) { - return m_typedConfigurations; - } - - static bool isValidId(const std::string& id); - - /// @brief Flushes logger to sync all log files for all levels - void flush(void); - - void flush(Level level, base::type::fstream_t* fs); - - inline bool isFlushNeeded(Level level) { - return ++m_unflushedCount.find(level)->second >= m_typedConfigurations->logFlushThreshold(level); - } - - inline LogBuilder* logBuilder(void) const { - return m_logBuilder.get(); - } - - inline void setLogBuilder(const LogBuilderPtr& logBuilder) { - m_logBuilder = logBuilder; - } - - inline bool enabled(Level level) const { - return m_typedConfigurations->enabled(level); - } - -#if ELPP_VARIADIC_TEMPLATES_SUPPORTED -# define LOGGER_LEVEL_WRITERS_SIGNATURES(FUNCTION_NAME)\ -template \ -inline void FUNCTION_NAME(const char*, const T&, const Args&...);\ -template \ -inline void FUNCTION_NAME(const T&); - - template - inline void verbose(int, const char*, const T&, const Args&...); - - template - inline void verbose(int, const T&); - - LOGGER_LEVEL_WRITERS_SIGNATURES(info) - LOGGER_LEVEL_WRITERS_SIGNATURES(debug) - LOGGER_LEVEL_WRITERS_SIGNATURES(warn) - LOGGER_LEVEL_WRITERS_SIGNATURES(error) - LOGGER_LEVEL_WRITERS_SIGNATURES(fatal) - LOGGER_LEVEL_WRITERS_SIGNATURES(trace) -# undef LOGGER_LEVEL_WRITERS_SIGNATURES -#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED - private: - std::string m_id; - base::TypedConfigurations* m_typedConfigurations; - base::type::stringstream_t m_stream; - std::string m_parentApplicationName; - bool m_isConfigured; - Configurations m_configurations; - std::unordered_map m_unflushedCount; - base::LogStreamsReferenceMapPtr m_logStreamsReference = nullptr; - LogBuilderPtr m_logBuilder; - - friend class el::LogMessage; - friend class el::Loggers; - friend class el::Helpers; - friend class el::base::RegisteredLoggers; - friend class el::base::DefaultLogDispatchCallback; - friend class el::base::MessageBuilder; - friend class el::base::Writer; - friend class el::base::PErrorWriter; - friend class el::base::Storage; - friend class el::base::PerformanceTracker; - friend class el::base::LogDispatcher; - - Logger(void); - -#if ELPP_VARIADIC_TEMPLATES_SUPPORTED - template - void log_(Level, int, const char*, const T&, const Args&...); - - template - inline void log_(Level, int, const T&); - - template - void log(Level, const char*, const T&, const Args&...); - - template - inline void log(Level, const T&); -#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED - - void initUnflushedCount(void); - - inline base::type::stringstream_t& stream(void) { - return m_stream; - } - - void resolveLoggerFormatSpec(void) const; -}; -namespace base { -/// @brief Loggers repository -class RegisteredLoggers : public base::utils::Registry { - public: - explicit RegisteredLoggers(const LogBuilderPtr& defaultLogBuilder); - - virtual ~RegisteredLoggers(void) { - unsafeFlushAll(); - } - - inline void setDefaultConfigurations(const Configurations& configurations) { - base::threading::ScopedLock scopedLock(lock()); - m_defaultConfigurations.setFromBase(const_cast(&configurations)); - } - - inline Configurations* defaultConfigurations(void) { - return &m_defaultConfigurations; - } - - Logger* get(const std::string& id, bool forceCreation = true); - - template - inline bool installLoggerRegistrationCallback(const std::string& id) { - return base::utils::Utils::installCallback(id, - &m_loggerRegistrationCallbacks); - } - - template - inline void uninstallLoggerRegistrationCallback(const std::string& id) { - base::utils::Utils::uninstallCallback(id, &m_loggerRegistrationCallbacks); - } - - template - inline T* loggerRegistrationCallback(const std::string& id) { - return base::utils::Utils::callback(id, &m_loggerRegistrationCallbacks); - } - - bool remove(const std::string& id); - - inline bool has(const std::string& id) { - return get(id, false) != nullptr; - } - - inline void unregister(Logger*& logger) { - base::threading::ScopedLock scopedLock(lock()); - base::utils::Registry::unregister(logger->id()); - } - - inline LogStreamsReferenceMapPtr logStreamsReference(void) { - return m_logStreamsReference; - } - - inline void flushAll(void) { - base::threading::ScopedLock scopedLock(lock()); - unsafeFlushAll(); - } - - inline void setDefaultLogBuilder(LogBuilderPtr& logBuilderPtr) { - base::threading::ScopedLock scopedLock(lock()); - m_defaultLogBuilder = logBuilderPtr; - } - - private: - LogBuilderPtr m_defaultLogBuilder; - Configurations m_defaultConfigurations; - base::LogStreamsReferenceMapPtr m_logStreamsReference = nullptr; - std::unordered_map m_loggerRegistrationCallbacks; - friend class el::base::Storage; - - void unsafeFlushAll(void); -}; -/// @brief Represents registries for verbose logging -class VRegistry : base::NoCopy, public base::threading::ThreadSafe { - public: - explicit VRegistry(base::type::VerboseLevel level, base::type::EnumType* pFlags); - - /// @brief Sets verbose level. Accepted range is 0-9 - void setLevel(base::type::VerboseLevel level); - - inline base::type::VerboseLevel level(void) const { - return m_level; - } - - inline void clearModules(void) { - base::threading::ScopedLock scopedLock(lock()); - m_modules.clear(); - } - - void setModules(const char* modules); - - bool allowed(base::type::VerboseLevel vlevel, const char* file); - - inline const std::unordered_map& modules(void) const { - return m_modules; - } - - void setFromArgs(const base::utils::CommandLineArgs* commandLineArgs); - - /// @brief Whether or not vModules enabled - inline bool vModulesEnabled(void) { - return !base::utils::hasFlag(LoggingFlag::DisableVModules, *m_pFlags); - } - - private: - base::type::VerboseLevel m_level; - base::type::EnumType* m_pFlags; - std::unordered_map m_modules; -}; -} // namespace base -class LogMessage { - public: - LogMessage(Level level, const std::string& file, base::type::LineNumber line, const std::string& func, - base::type::VerboseLevel verboseLevel, Logger* logger) : - m_level(level), m_file(file), m_line(line), m_func(func), - m_verboseLevel(verboseLevel), m_logger(logger), m_message(logger->stream().str()) { - } - inline Level level(void) const { - return m_level; - } - inline const std::string& file(void) const { - return m_file; - } - inline base::type::LineNumber line(void) const { - return m_line; - } - inline const std::string& func(void) const { - return m_func; - } - inline base::type::VerboseLevel verboseLevel(void) const { - return m_verboseLevel; - } - inline Logger* logger(void) const { - return m_logger; - } - inline const base::type::string_t& message(void) const { - return m_message; - } - private: - Level m_level; - std::string m_file; - base::type::LineNumber m_line; - std::string m_func; - base::type::VerboseLevel m_verboseLevel; - Logger* m_logger; - base::type::string_t m_message; -}; -namespace base { -#if ELPP_ASYNC_LOGGING -class AsyncLogItem { - public: - explicit AsyncLogItem(const LogMessage& logMessage, const LogDispatchData& data, const base::type::string_t& logLine) - : m_logMessage(logMessage), m_dispatchData(data), m_logLine(logLine) {} - virtual ~AsyncLogItem() {} - inline LogMessage* logMessage(void) { - return &m_logMessage; - } - inline LogDispatchData* data(void) { - return &m_dispatchData; - } - inline base::type::string_t logLine(void) { - return m_logLine; - } - private: - LogMessage m_logMessage; - LogDispatchData m_dispatchData; - base::type::string_t m_logLine; -}; -class AsyncLogQueue : public base::threading::ThreadSafe { - public: - virtual ~AsyncLogQueue() { - ELPP_INTERNAL_INFO(6, "~AsyncLogQueue"); - } - - inline AsyncLogItem next(void) { - base::threading::ScopedLock scopedLock(lock()); - AsyncLogItem result = m_queue.front(); - m_queue.pop(); - return result; - } - - inline void push(const AsyncLogItem& item) { - base::threading::ScopedLock scopedLock(lock()); - m_queue.push(item); - } - inline void pop(void) { - base::threading::ScopedLock scopedLock(lock()); - m_queue.pop(); - } - inline AsyncLogItem front(void) { - base::threading::ScopedLock scopedLock(lock()); - return m_queue.front(); - } - inline bool empty(void) { - base::threading::ScopedLock scopedLock(lock()); - return m_queue.empty(); - } - private: - std::queue m_queue; -}; -class IWorker { - public: - virtual ~IWorker() {} - virtual void start() = 0; -}; -#endif // ELPP_ASYNC_LOGGING -/// @brief Easylogging++ management storage -class Storage : base::NoCopy, public base::threading::ThreadSafe { - public: -#if ELPP_ASYNC_LOGGING - Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker); -#else - explicit Storage(const LogBuilderPtr& defaultLogBuilder); -#endif // ELPP_ASYNC_LOGGING - - virtual ~Storage(void); - - inline bool validateEveryNCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t occasion) { - return hitCounters()->validateEveryN(filename, lineNumber, occasion); - } - - inline bool validateAfterNCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { - return hitCounters()->validateAfterN(filename, lineNumber, n); - } - - inline bool validateNTimesCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { - return hitCounters()->validateNTimes(filename, lineNumber, n); - } - - inline base::RegisteredHitCounters* hitCounters(void) const { - return m_registeredHitCounters; - } - - inline base::RegisteredLoggers* registeredLoggers(void) const { - return m_registeredLoggers; - } - - inline base::VRegistry* vRegistry(void) const { - return m_vRegistry; - } - -#if ELPP_ASYNC_LOGGING - inline base::AsyncLogQueue* asyncLogQueue(void) const { - return m_asyncLogQueue; - } -#endif // ELPP_ASYNC_LOGGING - - inline const base::utils::CommandLineArgs* commandLineArgs(void) const { - return &m_commandLineArgs; - } - - inline void addFlag(LoggingFlag flag) { - base::utils::addFlag(flag, &m_flags); - } - - inline void removeFlag(LoggingFlag flag) { - base::utils::removeFlag(flag, &m_flags); - } - - inline bool hasFlag(LoggingFlag flag) const { - return base::utils::hasFlag(flag, m_flags); - } - - inline base::type::EnumType flags(void) const { - return m_flags; - } - - inline void setFlags(base::type::EnumType flags) { - m_flags = flags; - } - - inline void setPreRollOutCallback(const PreRollOutCallback& callback) { - m_preRollOutCallback = callback; - } - - inline void unsetPreRollOutCallback(void) { - m_preRollOutCallback = base::defaultPreRollOutCallback; - } - - inline PreRollOutCallback& preRollOutCallback(void) { - return m_preRollOutCallback; - } - - bool hasCustomFormatSpecifier(const char* formatSpecifier); - void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier); - bool uninstallCustomFormatSpecifier(const char* formatSpecifier); - - const std::vector* customFormatSpecifiers(void) const { - return &m_customFormatSpecifiers; - } - - base::threading::Mutex& customFormatSpecifiersLock() { - return m_customFormatSpecifiersLock; - } - - inline void setLoggingLevel(Level level) { - m_loggingLevel = level; - } - - template - inline bool installLogDispatchCallback(const std::string& id) { - return base::utils::Utils::installCallback(id, &m_logDispatchCallbacks); - } - - template - inline void uninstallLogDispatchCallback(const std::string& id) { - base::utils::Utils::uninstallCallback(id, &m_logDispatchCallbacks); - } - template - inline T* logDispatchCallback(const std::string& id) { - return base::utils::Utils::callback(id, &m_logDispatchCallbacks); - } - -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - template - inline bool installPerformanceTrackingCallback(const std::string& id) { - return base::utils::Utils::installCallback(id, - &m_performanceTrackingCallbacks); - } - - template - inline void uninstallPerformanceTrackingCallback(const std::string& id) { - base::utils::Utils::uninstallCallback(id, - &m_performanceTrackingCallbacks); - } - - template - inline T* performanceTrackingCallback(const std::string& id) { - return base::utils::Utils::callback(id, &m_performanceTrackingCallbacks); - } -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - - /// @brief Sets thread name for current thread. Requires std::thread - inline void setThreadName(const std::string& name) { - if (name.empty()) return; - base::threading::ScopedLock scopedLock(m_threadNamesLock); - m_threadNames[base::threading::getCurrentThreadId()] = name; - } - - inline std::string getThreadName(const std::string& threadId) { - base::threading::ScopedLock scopedLock(m_threadNamesLock); - std::unordered_map::const_iterator it = m_threadNames.find(threadId); - if (it == m_threadNames.end()) { - return threadId; - } - return it->second; - } - private: - base::RegisteredHitCounters* m_registeredHitCounters; - base::RegisteredLoggers* m_registeredLoggers; - base::type::EnumType m_flags; - base::VRegistry* m_vRegistry; -#if ELPP_ASYNC_LOGGING - base::AsyncLogQueue* m_asyncLogQueue; - base::IWorker* m_asyncDispatchWorker; -#endif // ELPP_ASYNC_LOGGING - base::utils::CommandLineArgs m_commandLineArgs; - PreRollOutCallback m_preRollOutCallback; - std::unordered_map m_logDispatchCallbacks; - std::unordered_map m_performanceTrackingCallbacks; - std::unordered_map m_threadNames; - std::vector m_customFormatSpecifiers; - base::threading::Mutex m_customFormatSpecifiersLock; - base::threading::Mutex m_threadNamesLock; - Level m_loggingLevel; - - friend class el::Helpers; - friend class el::base::DefaultLogDispatchCallback; - friend class el::LogBuilder; - friend class el::base::MessageBuilder; - friend class el::base::Writer; - friend class el::base::PerformanceTracker; - friend class el::base::LogDispatcher; - - void setApplicationArguments(int argc, char** argv); - - inline void setApplicationArguments(int argc, const char** argv) { - setApplicationArguments(argc, const_cast(argv)); - } -}; -extern ELPP_EXPORT base::type::StoragePointer elStorage; -#define ELPP el::base::elStorage -class DefaultLogDispatchCallback : public LogDispatchCallback { - protected: - void handle(const LogDispatchData* data); - private: - const LogDispatchData* m_data; - void dispatch(base::type::string_t&& logLine); -}; -#if ELPP_ASYNC_LOGGING -class AsyncLogDispatchCallback : public LogDispatchCallback { - protected: - void handle(const LogDispatchData* data); -}; -class AsyncDispatchWorker : public base::IWorker, public base::threading::ThreadSafe { - public: - AsyncDispatchWorker(); - virtual ~AsyncDispatchWorker(); - - bool clean(void); - void emptyQueue(void); - virtual void start(void); - void handle(AsyncLogItem* logItem); - void run(void); - - void setContinueRunning(bool value) { - base::threading::ScopedLock scopedLock(m_continueRunningLock); - m_continueRunning = value; - } - - bool continueRunning(void) const { - return m_continueRunning; - } - private: - std::condition_variable cv; - bool m_continueRunning; - base::threading::Mutex m_continueRunningLock; -}; -#endif // ELPP_ASYNC_LOGGING -} // namespace base -namespace base { -class DefaultLogBuilder : public LogBuilder { - public: - base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const; -}; -/// @brief Dispatches log messages -class LogDispatcher : base::NoCopy { - public: - LogDispatcher(bool proceed, LogMessage* logMessage, base::DispatchAction dispatchAction) : - m_proceed(proceed), - m_logMessage(logMessage), - m_dispatchAction(std::move(dispatchAction)) { - } - - void dispatch(void); - - private: - bool m_proceed; - LogMessage* m_logMessage; - base::DispatchAction m_dispatchAction; -}; -#if defined(ELPP_STL_LOGGING) -/// @brief Workarounds to write some STL logs -/// -/// @detail There is workaround needed to loop through some stl containers. In order to do that, we need iterable containers -/// of same type and provide iterator interface and pass it on to writeIterator(). -/// Remember, this is passed by value in constructor so that we dont change original containers. -/// This operation is as expensive as Big-O(std::min(class_.size(), base::consts::kMaxLogPerContainer)) -namespace workarounds { -/// @brief Abstract IterableContainer template that provides interface for iterable classes of type T -template -class IterableContainer { - public: - typedef typename Container::iterator iterator; - typedef typename Container::const_iterator const_iterator; - IterableContainer(void) {} - virtual ~IterableContainer(void) {} - iterator begin(void) { - return getContainer().begin(); - } - iterator end(void) { - return getContainer().end(); - } - private: - virtual Container& getContainer(void) = 0; -}; -/// @brief Implements IterableContainer and provides iterable std::priority_queue class -template, typename Comparator = std::less> -class IterablePriorityQueue : public IterableContainer, - public std::priority_queue { - public: - IterablePriorityQueue(std::priority_queue queue_) { - std::size_t count_ = 0; - while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) { - this->push(queue_.top()); - queue_.pop(); - } - } - private: - inline Container& getContainer(void) { - return this->c; - } -}; -/// @brief Implements IterableContainer and provides iterable std::queue class -template> -class IterableQueue : public IterableContainer, public std::queue { - public: - IterableQueue(std::queue queue_) { - std::size_t count_ = 0; - while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) { - this->push(queue_.front()); - queue_.pop(); - } - } - private: - inline Container& getContainer(void) { - return this->c; - } -}; -/// @brief Implements IterableContainer and provides iterable std::stack class -template> -class IterableStack : public IterableContainer, public std::stack { - public: - IterableStack(std::stack stack_) { - std::size_t count_ = 0; - while (++count_ < base::consts::kMaxLogPerContainer && !stack_.empty()) { - this->push(stack_.top()); - stack_.pop(); - } - } - private: - inline Container& getContainer(void) { - return this->c; - } -}; -} // namespace workarounds -#endif // defined(ELPP_STL_LOGGING) -// Log message builder -class MessageBuilder { - public: - MessageBuilder(void) : m_logger(nullptr), m_containerLogSeparator(ELPP_LITERAL("")) {} - void initialize(Logger* logger); - -# define ELPP_SIMPLE_LOG(LOG_TYPE)\ -MessageBuilder& operator<<(LOG_TYPE msg) {\ -m_logger->stream() << msg;\ -if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {\ -m_logger->stream() << " ";\ -}\ -return *this;\ -} - - inline MessageBuilder& operator<<(const std::string& msg) { - return operator<<(msg.c_str()); - } - ELPP_SIMPLE_LOG(char) - ELPP_SIMPLE_LOG(bool) - ELPP_SIMPLE_LOG(signed short) - ELPP_SIMPLE_LOG(unsigned short) - ELPP_SIMPLE_LOG(signed int) - ELPP_SIMPLE_LOG(unsigned int) - ELPP_SIMPLE_LOG(signed long) - ELPP_SIMPLE_LOG(unsigned long) - ELPP_SIMPLE_LOG(float) - ELPP_SIMPLE_LOG(double) - ELPP_SIMPLE_LOG(char*) - ELPP_SIMPLE_LOG(const char*) - ELPP_SIMPLE_LOG(const void*) - ELPP_SIMPLE_LOG(long double) - inline MessageBuilder& operator<<(const std::wstring& msg) { - return operator<<(msg.c_str()); - } - MessageBuilder& operator<<(const wchar_t* msg); - // ostream manipulators - inline MessageBuilder& operator<<(std::ostream& (*OStreamMani)(std::ostream&)) { - m_logger->stream() << OStreamMani; - return *this; - } -#define ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} -#define ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} -#define ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} -#define ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} -#define ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(temp) \ -template \ -inline MessageBuilder& operator<<(const temp& template_inst) { \ -return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ -} - -#if defined(ELPP_STL_LOGGING) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::vector) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::list) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::deque) - ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::set) - ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::multiset) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::map) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::multimap) - template - inline MessageBuilder& operator<<(const std::queue& queue_) { - base::workarounds::IterableQueue iterableQueue_ = - static_cast >(queue_); - return writeIterator(iterableQueue_.begin(), iterableQueue_.end(), iterableQueue_.size()); - } - template - inline MessageBuilder& operator<<(const std::stack& stack_) { - base::workarounds::IterableStack iterableStack_ = - static_cast >(stack_); - return writeIterator(iterableStack_.begin(), iterableStack_.end(), iterableStack_.size()); - } - template - inline MessageBuilder& operator<<(const std::priority_queue& priorityQueue_) { - base::workarounds::IterablePriorityQueue iterablePriorityQueue_ = - static_cast >(priorityQueue_); - return writeIterator(iterablePriorityQueue_.begin(), iterablePriorityQueue_.end(), iterablePriorityQueue_.size()); - } - template - MessageBuilder& operator<<(const std::pair& pair_) { - m_logger->stream() << ELPP_LITERAL("("); - operator << (static_cast(pair_.first)); - m_logger->stream() << ELPP_LITERAL(", "); - operator << (static_cast(pair_.second)); - m_logger->stream() << ELPP_LITERAL(")"); - return *this; - } - template - MessageBuilder& operator<<(const std::bitset& bitset_) { - m_logger->stream() << ELPP_LITERAL("["); - operator << (bitset_.to_string()); - m_logger->stream() << ELPP_LITERAL("]"); - return *this; - } -# if defined(ELPP_LOG_STD_ARRAY) - template - inline MessageBuilder& operator<<(const std::array& array) { - return writeIterator(array.begin(), array.end(), array.size()); - } -# endif // defined(ELPP_LOG_STD_ARRAY) -# if defined(ELPP_LOG_UNORDERED_MAP) - ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_map) - ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_multimap) -# endif // defined(ELPP_LOG_UNORDERED_MAP) -# if defined(ELPP_LOG_UNORDERED_SET) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_set) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_multiset) -# endif // defined(ELPP_LOG_UNORDERED_SET) -#endif // defined(ELPP_STL_LOGGING) -#if defined(ELPP_QT_LOGGING) - inline MessageBuilder& operator<<(const QString& msg) { -# if defined(ELPP_UNICODE) - m_logger->stream() << msg.toStdWString(); -# else - m_logger->stream() << msg.toStdString(); -# endif // defined(ELPP_UNICODE) - return *this; - } - inline MessageBuilder& operator<<(const QByteArray& msg) { - return operator << (QString(msg)); - } - inline MessageBuilder& operator<<(const QStringRef& msg) { - return operator<<(msg.toString()); - } - inline MessageBuilder& operator<<(qint64 msg) { -# if defined(ELPP_UNICODE) - m_logger->stream() << QString::number(msg).toStdWString(); -# else - m_logger->stream() << QString::number(msg).toStdString(); -# endif // defined(ELPP_UNICODE) - return *this; - } - inline MessageBuilder& operator<<(quint64 msg) { -# if defined(ELPP_UNICODE) - m_logger->stream() << QString::number(msg).toStdWString(); -# else - m_logger->stream() << QString::number(msg).toStdString(); -# endif // defined(ELPP_UNICODE) - return *this; - } - inline MessageBuilder& operator<<(QChar msg) { - m_logger->stream() << msg.toLatin1(); - return *this; - } - inline MessageBuilder& operator<<(const QLatin1String& msg) { - m_logger->stream() << msg.latin1(); - return *this; - } - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QList) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QVector) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QQueue) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QSet) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QLinkedList) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QStack) - template - MessageBuilder& operator<<(const QPair& pair_) { - m_logger->stream() << ELPP_LITERAL("("); - operator << (static_cast(pair_.first)); - m_logger->stream() << ELPP_LITERAL(", "); - operator << (static_cast(pair_.second)); - m_logger->stream() << ELPP_LITERAL(")"); - return *this; - } - template - MessageBuilder& operator<<(const QMap& map_) { - m_logger->stream() << ELPP_LITERAL("["); - QList keys = map_.keys(); - typename QList::const_iterator begin = keys.begin(); - typename QList::const_iterator end = keys.end(); - int max_ = static_cast(base::consts::kMaxLogPerContainer); // to prevent warning - for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { - m_logger->stream() << ELPP_LITERAL("("); - operator << (static_cast(*begin)); - m_logger->stream() << ELPP_LITERAL(", "); - operator << (static_cast(map_.value(*begin))); - m_logger->stream() << ELPP_LITERAL(")"); - m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeparator : ELPP_LITERAL("")); - } - if (begin != end) { - m_logger->stream() << ELPP_LITERAL("..."); - } - m_logger->stream() << ELPP_LITERAL("]"); - return *this; - } - template - inline MessageBuilder& operator<<(const QMultiMap& map_) { - operator << (static_cast>(map_)); - return *this; - } - template - MessageBuilder& operator<<(const QHash& hash_) { - m_logger->stream() << ELPP_LITERAL("["); - QList keys = hash_.keys(); - typename QList::const_iterator begin = keys.begin(); - typename QList::const_iterator end = keys.end(); - int max_ = static_cast(base::consts::kMaxLogPerContainer); // prevent type warning - for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { - m_logger->stream() << ELPP_LITERAL("("); - operator << (static_cast(*begin)); - m_logger->stream() << ELPP_LITERAL(", "); - operator << (static_cast(hash_.value(*begin))); - m_logger->stream() << ELPP_LITERAL(")"); - m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeparator : ELPP_LITERAL("")); - } - if (begin != end) { - m_logger->stream() << ELPP_LITERAL("..."); - } - m_logger->stream() << ELPP_LITERAL("]"); - return *this; - } - template - inline MessageBuilder& operator<<(const QMultiHash& multiHash_) { - operator << (static_cast>(multiHash_)); - return *this; - } -#endif // defined(ELPP_QT_LOGGING) -#if defined(ELPP_BOOST_LOGGING) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::vector) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::stable_vector) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::list) - ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::deque) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::map) - ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::flat_map) - ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::set) - ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::flat_set) -#endif // defined(ELPP_BOOST_LOGGING) - - /// @brief Macro used internally that can be used externally to make containers easylogging++ friendly - /// - /// @detail This macro expands to write an ostream& operator<< for container. This container is expected to - /// have begin() and end() methods that return respective iterators - /// @param ContainerType Type of container e.g, MyList from WX_DECLARE_LIST(int, MyList); in wxwidgets - /// @param SizeMethod Method used to get size of container. - /// @param ElementInstance Instance of element to be fed out. Instance name is "elem". See WXELPP_ENABLED macro - /// for an example usage -#define MAKE_CONTAINERELPP_FRIENDLY(ContainerType, SizeMethod, ElementInstance) \ -el::base::type::ostream_t& operator<<(el::base::type::ostream_t& ss, const ContainerType& container) {\ -const el::base::type::char_t* sep = ELPP->hasFlag(el::LoggingFlag::NewLineForContainer) ? \ -ELPP_LITERAL("\n ") : ELPP_LITERAL(", ");\ -ContainerType::const_iterator elem = container.begin();\ -ContainerType::const_iterator endElem = container.end();\ -std::size_t size_ = container.SizeMethod; \ -ss << ELPP_LITERAL("[");\ -for (std::size_t i = 0; elem != endElem && i < el::base::consts::kMaxLogPerContainer; ++i, ++elem) { \ -ss << ElementInstance;\ -ss << ((i < size_ - 1) ? sep : ELPP_LITERAL(""));\ -}\ -if (elem != endElem) {\ -ss << ELPP_LITERAL("...");\ -}\ -ss << ELPP_LITERAL("]");\ -return ss;\ -} -#if defined(ELPP_WXWIDGETS_LOGGING) - ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(wxVector) -# define ELPP_WX_PTR_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), *(*elem)) -# define ELPP_WX_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), (*elem)) -# define ELPP_WX_HASH_MAP_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), \ -ELPP_LITERAL("(") << elem->first << ELPP_LITERAL(", ") << elem->second << ELPP_LITERAL(")") -#else -# define ELPP_WX_PTR_ENABLED(ContainerType) -# define ELPP_WX_ENABLED(ContainerType) -# define ELPP_WX_HASH_MAP_ENABLED(ContainerType) -#endif // defined(ELPP_WXWIDGETS_LOGGING) - // Other classes - template - ELPP_SIMPLE_LOG(const Class&) -#undef ELPP_SIMPLE_LOG -#undef ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG -#undef ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG -#undef ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG -#undef ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG -#undef ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG - private: - Logger* m_logger; - const base::type::char_t* m_containerLogSeparator; - - template - MessageBuilder& writeIterator(Iterator begin_, Iterator end_, std::size_t size_) { - m_logger->stream() << ELPP_LITERAL("["); - for (std::size_t i = 0; begin_ != end_ && i < base::consts::kMaxLogPerContainer; ++i, ++begin_) { - operator << (*begin_); - m_logger->stream() << ((i < size_ - 1) ? m_containerLogSeparator : ELPP_LITERAL("")); - } - if (begin_ != end_) { - m_logger->stream() << ELPP_LITERAL("..."); - } - m_logger->stream() << ELPP_LITERAL("]"); - if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) { - m_logger->stream() << " "; - } - return *this; - } -}; -/// @brief Writes nothing - Used when certain log is disabled -class NullWriter : base::NoCopy { - public: - NullWriter(void) {} - - // Null manipulator - inline NullWriter& operator<<(std::ostream& (*)(std::ostream&)) { - return *this; - } - - template - inline NullWriter& operator<<(const T&) { - return *this; - } - - inline operator bool() { - return true; - } -}; -/// @brief Main entry point of each logging -class Writer : base::NoCopy { - public: - Writer(Level level, const char* file, base::type::LineNumber line, - const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog, - base::type::VerboseLevel verboseLevel = 0) : - m_msg(nullptr), m_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel), - m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) { - } - - Writer(LogMessage* msg, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog) : - m_msg(msg), m_level(msg != nullptr ? msg->level() : Level::Unknown), - m_line(0), m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) { - } - - virtual ~Writer(void) { - processDispatch(); - } - - template - inline Writer& operator<<(const T& log) { -#if ELPP_LOGGING_ENABLED - if (m_proceed) { - m_messageBuilder << log; - } -#endif // ELPP_LOGGING_ENABLED - return *this; - } - - inline Writer& operator<<(std::ostream& (*log)(std::ostream&)) { -#if ELPP_LOGGING_ENABLED - if (m_proceed) { - m_messageBuilder << log; - } -#endif // ELPP_LOGGING_ENABLED - return *this; - } - - inline operator bool() { - return true; - } - - Writer& construct(Logger* logger, bool needLock = true); - Writer& construct(int count, const char* loggerIds, ...); - protected: - LogMessage* m_msg; - Level m_level; - const char* m_file; - const base::type::LineNumber m_line; - const char* m_func; - base::type::VerboseLevel m_verboseLevel; - Logger* m_logger; - bool m_proceed; - base::MessageBuilder m_messageBuilder; - base::DispatchAction m_dispatchAction; - std::vector m_loggerIds; - friend class el::Helpers; - - void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true); - void processDispatch(); - void triggerDispatch(void); -}; -class PErrorWriter : public base::Writer { - public: - PErrorWriter(Level level, const char* file, base::type::LineNumber line, - const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog, - base::type::VerboseLevel verboseLevel = 0) : - base::Writer(level, file, line, func, dispatchAction, verboseLevel) { - } - - virtual ~PErrorWriter(void); -}; -} // namespace base -// Logging from Logger class. Why this is here? Because we have Storage and Writer class available -#if ELPP_VARIADIC_TEMPLATES_SUPPORTED -template -void Logger::log_(Level level, int vlevel, const char* s, const T& value, const Args&... args) { - base::MessageBuilder b; - b.initialize(this); - while (*s) { - if (*s == base::consts::kFormatSpecifierChar) { - if (*(s + 1) == base::consts::kFormatSpecifierChar) { - ++s; - } else { - if (*(s + 1) == base::consts::kFormatSpecifierCharValue) { - ++s; - b << value; - log_(level, vlevel, ++s, args...); - return; - } - } - } - b << *s++; - } - ELPP_INTERNAL_ERROR("Too many arguments provided. Unable to handle. Please provide more format specifiers", false); -} -template -void Logger::log_(Level level, int vlevel, const T& log) { - if (level == Level::Verbose) { - if (ELPP->vRegistry()->allowed(vlevel, __FILE__)) { - base::Writer(Level::Verbose, "FILE", 0, "FUNCTION", - base::DispatchAction::NormalLog, vlevel).construct(this, false) << log; - } else { - stream().str(ELPP_LITERAL("")); - releaseLock(); - } - } else { - base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log; - } -} -template -inline void Logger::log(Level level, const char* s, const T& value, const Args&... args) { - acquireLock(); // released in Writer! - log_(level, 0, s, value, args...); -} -template -inline void Logger::log(Level level, const T& log) { - acquireLock(); // released in Writer! - log_(level, 0, log); -} -# if ELPP_VERBOSE_LOG -template -inline void Logger::verbose(int vlevel, const char* s, const T& value, const Args&... args) { - acquireLock(); // released in Writer! - log_(el::Level::Verbose, vlevel, s, value, args...); -} -template -inline void Logger::verbose(int vlevel, const T& log) { - acquireLock(); // released in Writer! - log_(el::Level::Verbose, vlevel, log); -} -# else -template -inline void Logger::verbose(int, const char*, const T&, const Args&...) { - return; -} -template -inline void Logger::verbose(int, const T&) { - return; -} -# endif // ELPP_VERBOSE_LOG -# define LOGGER_LEVEL_WRITERS(FUNCTION_NAME, LOG_LEVEL)\ -template \ -inline void Logger::FUNCTION_NAME(const char* s, const T& value, const Args&... args) {\ -log(LOG_LEVEL, s, value, args...);\ -}\ -template \ -inline void Logger::FUNCTION_NAME(const T& value) {\ -log(LOG_LEVEL, value);\ -} -# define LOGGER_LEVEL_WRITERS_DISABLED(FUNCTION_NAME, LOG_LEVEL)\ -template \ -inline void Logger::FUNCTION_NAME(const char*, const T&, const Args&...) {\ -return;\ -}\ -template \ -inline void Logger::FUNCTION_NAME(const T&) {\ -return;\ -} - -# if ELPP_INFO_LOG -LOGGER_LEVEL_WRITERS(info, Level::Info) -# else -LOGGER_LEVEL_WRITERS_DISABLED(info, Level::Info) -# endif // ELPP_INFO_LOG -# if ELPP_DEBUG_LOG -LOGGER_LEVEL_WRITERS(debug, Level::Debug) -# else -LOGGER_LEVEL_WRITERS_DISABLED(debug, Level::Debug) -# endif // ELPP_DEBUG_LOG -# if ELPP_WARNING_LOG -LOGGER_LEVEL_WRITERS(warn, Level::Warning) -# else -LOGGER_LEVEL_WRITERS_DISABLED(warn, Level::Warning) -# endif // ELPP_WARNING_LOG -# if ELPP_ERROR_LOG -LOGGER_LEVEL_WRITERS(error, Level::Error) -# else -LOGGER_LEVEL_WRITERS_DISABLED(error, Level::Error) -# endif // ELPP_ERROR_LOG -# if ELPP_FATAL_LOG -LOGGER_LEVEL_WRITERS(fatal, Level::Fatal) -# else -LOGGER_LEVEL_WRITERS_DISABLED(fatal, Level::Fatal) -# endif // ELPP_FATAL_LOG -# if ELPP_TRACE_LOG -LOGGER_LEVEL_WRITERS(trace, Level::Trace) -# else -LOGGER_LEVEL_WRITERS_DISABLED(trace, Level::Trace) -# endif // ELPP_TRACE_LOG -# undef LOGGER_LEVEL_WRITERS -# undef LOGGER_LEVEL_WRITERS_DISABLED -#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED -#if ELPP_COMPILER_MSVC -# define ELPP_VARIADIC_FUNC_MSVC(variadicFunction, variadicArgs) variadicFunction variadicArgs -# define ELPP_VARIADIC_FUNC_MSVC_RUN(variadicFunction, ...) ELPP_VARIADIC_FUNC_MSVC(variadicFunction, (__VA_ARGS__)) -# define el_getVALength(...) ELPP_VARIADIC_FUNC_MSVC_RUN(el_resolveVALength, 0, ## __VA_ARGS__,\ -10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -#else -# if ELPP_COMPILER_CLANG -# define el_getVALength(...) el_resolveVALength(0, __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -# else -# define el_getVALength(...) el_resolveVALength(0, ## __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -# endif // ELPP_COMPILER_CLANG -#endif // ELPP_COMPILER_MSVC -#define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N -#define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#define ELPP_WRITE_LOG_IF(writer, condition, level, dispatchAction, ...) if (condition) \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#define ELPP_WRITE_LOG_EVERY_N(writer, occasion, level, dispatchAction, ...) \ -ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion) && \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#define ELPP_WRITE_LOG_AFTER_N(writer, n, level, dispatchAction, ...) \ -ELPP->validateAfterNCounter(__FILE__, __LINE__, n) && \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#define ELPP_WRITE_LOG_N_TIMES(writer, n, level, dispatchAction, ...) \ -ELPP->validateNTimesCounter(__FILE__, __LINE__, n) && \ -writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) -class PerformanceTrackingData { - public: - enum class DataType : base::type::EnumType { - Checkpoint = 1, Complete = 2 - }; - // Do not use constructor, will run into multiple definition error, use init(PerformanceTracker*) - explicit PerformanceTrackingData(DataType dataType) : m_performanceTracker(nullptr), - m_dataType(dataType), m_firstCheckpoint(false), m_file(""), m_line(0), m_func("") {} - inline const std::string* blockName(void) const; - inline const struct timeval* startTime(void) const; - inline const struct timeval* endTime(void) const; - inline const struct timeval* lastCheckpointTime(void) const; - inline const base::PerformanceTracker* performanceTracker(void) const { - return m_performanceTracker; - } - inline PerformanceTrackingData::DataType dataType(void) const { - return m_dataType; - } - inline bool firstCheckpoint(void) const { - return m_firstCheckpoint; - } - inline std::string checkpointId(void) const { - return m_checkpointId; - } - inline const char* file(void) const { - return m_file; - } - inline base::type::LineNumber line(void) const { - return m_line; - } - inline const char* func(void) const { - return m_func; - } - inline const base::type::string_t* formattedTimeTaken() const { - return &m_formattedTimeTaken; - } - inline const std::string& loggerId(void) const; - private: - base::PerformanceTracker* m_performanceTracker; - base::type::string_t m_formattedTimeTaken; - PerformanceTrackingData::DataType m_dataType; - bool m_firstCheckpoint; - std::string m_checkpointId; - const char* m_file; - base::type::LineNumber m_line; - const char* m_func; - inline void init(base::PerformanceTracker* performanceTracker, bool firstCheckpoint = false) { - m_performanceTracker = performanceTracker; - m_firstCheckpoint = firstCheckpoint; - } - - friend class el::base::PerformanceTracker; -}; -namespace base { -/// @brief Represents performanceTracker block of code that conditionally adds performance status to log -/// either when goes outside the scope of when checkpoint() is called -class PerformanceTracker : public base::threading::ThreadSafe, public Loggable { - public: - PerformanceTracker(const std::string& blockName, - base::TimestampUnit timestampUnit = base::TimestampUnit::Millisecond, - const std::string& loggerId = std::string(el::base::consts::kPerformanceLoggerId), - bool scopedLog = true, Level level = base::consts::kPerformanceTrackerDefaultLevel); - /// @brief Copy constructor - PerformanceTracker(const PerformanceTracker& t) : - m_blockName(t.m_blockName), m_timestampUnit(t.m_timestampUnit), m_loggerId(t.m_loggerId), m_scopedLog(t.m_scopedLog), - m_level(t.m_level), m_hasChecked(t.m_hasChecked), m_lastCheckpointId(t.m_lastCheckpointId), m_enabled(t.m_enabled), - m_startTime(t.m_startTime), m_endTime(t.m_endTime), m_lastCheckpointTime(t.m_lastCheckpointTime) { - } - virtual ~PerformanceTracker(void); - /// @brief A checkpoint for current performanceTracker block. - void checkpoint(const std::string& id = std::string(), const char* file = __FILE__, - base::type::LineNumber line = __LINE__, - const char* func = ""); - inline Level level(void) const { - return m_level; - } - private: - std::string m_blockName; - base::TimestampUnit m_timestampUnit; - std::string m_loggerId; - bool m_scopedLog; - Level m_level; - bool m_hasChecked; - std::string m_lastCheckpointId; - bool m_enabled; - struct timeval m_startTime, m_endTime, m_lastCheckpointTime; - - PerformanceTracker(void); - - friend class el::PerformanceTrackingData; - friend class base::DefaultPerformanceTrackingCallback; - - const inline base::type::string_t getFormattedTimeTaken() const { - return getFormattedTimeTaken(m_startTime); - } - - const base::type::string_t getFormattedTimeTaken(struct timeval startTime) const; - - virtual inline void log(el::base::type::ostream_t& os) const { - os << getFormattedTimeTaken(); - } -}; -class DefaultPerformanceTrackingCallback : public PerformanceTrackingCallback { - protected: - void handle(const PerformanceTrackingData* data) { - m_data = data; - base::type::stringstream_t ss; - if (m_data->dataType() == PerformanceTrackingData::DataType::Complete) { - ss << ELPP_LITERAL("Executed [") << m_data->blockName()->c_str() << ELPP_LITERAL("] in [") << - *m_data->formattedTimeTaken() << ELPP_LITERAL("]"); - } else { - ss << ELPP_LITERAL("Performance checkpoint"); - if (!m_data->checkpointId().empty()) { - ss << ELPP_LITERAL(" [") << m_data->checkpointId().c_str() << ELPP_LITERAL("]"); - } - ss << ELPP_LITERAL(" for block [") << m_data->blockName()->c_str() << ELPP_LITERAL("] : [") << - *m_data->performanceTracker(); - if (!ELPP->hasFlag(LoggingFlag::DisablePerformanceTrackingCheckpointComparison) - && m_data->performanceTracker()->m_hasChecked) { - ss << ELPP_LITERAL(" ([") << *m_data->formattedTimeTaken() << ELPP_LITERAL("] from "); - if (m_data->performanceTracker()->m_lastCheckpointId.empty()) { - ss << ELPP_LITERAL("last checkpoint"); - } else { - ss << ELPP_LITERAL("checkpoint '") << m_data->performanceTracker()->m_lastCheckpointId.c_str() << ELPP_LITERAL("'"); - } - ss << ELPP_LITERAL(")]"); - } else { - ss << ELPP_LITERAL("]"); - } - } - el::base::Writer(m_data->performanceTracker()->level(), m_data->file(), m_data->line(), m_data->func()).construct(1, - m_data->loggerId().c_str()) << ss.str(); - } - private: - const PerformanceTrackingData* m_data; -}; -} // namespace base -inline const std::string* PerformanceTrackingData::blockName() const { - return const_cast(&m_performanceTracker->m_blockName); -} -inline const struct timeval* PerformanceTrackingData::startTime() const { - return const_cast(&m_performanceTracker->m_startTime); -} -inline const struct timeval* PerformanceTrackingData::endTime() const { - return const_cast(&m_performanceTracker->m_endTime); -} -inline const struct timeval* PerformanceTrackingData::lastCheckpointTime() const { - return const_cast(&m_performanceTracker->m_lastCheckpointTime); -} -inline const std::string& PerformanceTrackingData::loggerId(void) const { - return m_performanceTracker->m_loggerId; -} -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) -namespace base { -/// @brief Contains some internal debugging tools like crash handler and stack tracer -namespace debug { -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) -class StackTrace : base::NoCopy { - public: - static const unsigned int kMaxStack = 64; - static const unsigned int kStackStart = 2; // We want to skip c'tor and StackTrace::generateNew() - class StackTraceEntry { - public: - StackTraceEntry(std::size_t index, const std::string& loc, const std::string& demang, const std::string& hex, - const std::string& addr); - StackTraceEntry(std::size_t index, const std::string& loc) : - m_index(index), - m_location(loc) { - } - std::size_t m_index; - std::string m_location; - std::string m_demangled; - std::string m_hex; - std::string m_addr; - friend std::ostream& operator<<(std::ostream& ss, const StackTraceEntry& si); - - private: - StackTraceEntry(void); - }; - - StackTrace(void) { - generateNew(); - } - - virtual ~StackTrace(void) { - } - - inline std::vector& getLatestStack(void) { - return m_stack; - } - - friend std::ostream& operator<<(std::ostream& os, const StackTrace& st); - - private: - std::vector m_stack; - - void generateNew(void); -}; -/// @brief Handles unexpected crashes -class CrashHandler : base::NoCopy { - public: - typedef void (*Handler)(int); - - explicit CrashHandler(bool useDefault); - explicit CrashHandler(const Handler& cHandler) { - setHandler(cHandler); - } - void setHandler(const Handler& cHandler); - - private: - Handler m_handler; -}; -#else -class CrashHandler { - public: - explicit CrashHandler(bool) {} -}; -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) -} // namespace debug -} // namespace base -extern base::debug::CrashHandler elCrashHandler; -#define MAKE_LOGGABLE(ClassType, ClassInstance, OutputStreamInstance) \ -el::base::type::ostream_t& operator<<(el::base::type::ostream_t& OutputStreamInstance, const ClassType& ClassInstance) -/// @brief Initializes syslog with process ID, options and facility. calls closelog() on d'tor -class SysLogInitializer { - public: - SysLogInitializer(const char* processIdent, int options = 0, int facility = 0) { -#if defined(ELPP_SYSLOG) - (void)base::consts::kSysLogLoggerId; - openlog(processIdent, options, facility); -#else - ELPP_UNUSED(processIdent); - ELPP_UNUSED(options); - ELPP_UNUSED(facility); -#endif // defined(ELPP_SYSLOG) - } - virtual ~SysLogInitializer(void) { -#if defined(ELPP_SYSLOG) - closelog(); -#endif // defined(ELPP_SYSLOG) - } -}; -#define ELPP_INITIALIZE_SYSLOG(id, opt, fac) el::SysLogInitializer elSyslogInit(id, opt, fac) -/// @brief Static helpers for developers -class Helpers : base::StaticClass { - public: - /// @brief Shares logging repository (base::Storage) - static inline void setStorage(base::type::StoragePointer storage) { - ELPP = storage; - } - /// @return Main storage repository - static inline base::type::StoragePointer storage() { - return ELPP; - } - /// @brief Sets application arguments and figures out whats active for logging and whats not. - static inline void setArgs(int argc, char** argv) { - ELPP->setApplicationArguments(argc, argv); - } - /// @copydoc setArgs(int argc, char** argv) - static inline void setArgs(int argc, const char** argv) { - ELPP->setApplicationArguments(argc, const_cast(argv)); - } - /// @brief Sets thread name for current thread. Requires std::thread - static inline void setThreadName(const std::string& name) { - ELPP->setThreadName(name); - } - static inline std::string getThreadName() { - return ELPP->getThreadName(base::threading::getCurrentThreadId()); - } -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - /// @brief Overrides default crash handler and installs custom handler. - /// @param crashHandler A functor with no return type that takes single int argument. - /// Handler is a typedef with specification: void (*Handler)(int) - static inline void setCrashHandler(const el::base::debug::CrashHandler::Handler& crashHandler) { - el::elCrashHandler.setHandler(crashHandler); - } - /// @brief Abort due to crash with signal in parameter - /// @param sig Crash signal - static void crashAbort(int sig, const char* sourceFile = "", unsigned int long line = 0); - /// @brief Logs reason of crash as per sig - /// @param sig Crash signal - /// @param stackTraceIfAvailable Includes stack trace if available - /// @param level Logging level - /// @param logger Logger to use for logging - static void logCrashReason(int sig, bool stackTraceIfAvailable = false, - Level level = Level::Fatal, const char* logger = base::consts::kDefaultLoggerId); -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) - /// @brief Installs pre rollout callback, this callback is triggered when log file is about to be rolled out - /// (can be useful for backing up) - static inline void installPreRollOutCallback(const PreRollOutCallback& callback) { - ELPP->setPreRollOutCallback(callback); - } - /// @brief Uninstalls pre rollout callback - static inline void uninstallPreRollOutCallback(void) { - ELPP->unsetPreRollOutCallback(); - } - /// @brief Installs post log dispatch callback, this callback is triggered when log is dispatched - template - static inline bool installLogDispatchCallback(const std::string& id) { - return ELPP->installLogDispatchCallback(id); - } - /// @brief Uninstalls log dispatch callback - template - static inline void uninstallLogDispatchCallback(const std::string& id) { - ELPP->uninstallLogDispatchCallback(id); - } - template - static inline T* logDispatchCallback(const std::string& id) { - return ELPP->logDispatchCallback(id); - } -#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - /// @brief Installs post performance tracking callback, this callback is triggered when performance tracking is finished - template - static inline bool installPerformanceTrackingCallback(const std::string& id) { - return ELPP->installPerformanceTrackingCallback(id); - } - /// @brief Uninstalls post performance tracking handler - template - static inline void uninstallPerformanceTrackingCallback(const std::string& id) { - ELPP->uninstallPerformanceTrackingCallback(id); - } - template - static inline T* performanceTrackingCallback(const std::string& id) { - return ELPP->performanceTrackingCallback(id); - } -#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) - /// @brief Converts template to std::string - useful for loggable classes to log containers within log(std::ostream&) const - template - static std::string convertTemplateToStdString(const T& templ) { - el::Logger* logger = - ELPP->registeredLoggers()->get(el::base::consts::kDefaultLoggerId); - if (logger == nullptr) { - return std::string(); - } - base::MessageBuilder b; - b.initialize(logger); - logger->acquireLock(); - b << templ; -#if defined(ELPP_UNICODE) - std::string s = std::string(logger->stream().str().begin(), logger->stream().str().end()); -#else - std::string s = logger->stream().str(); -#endif // defined(ELPP_UNICODE) - logger->stream().str(ELPP_LITERAL("")); - logger->releaseLock(); - return s; - } - /// @brief Returns command line arguments (pointer) provided to easylogging++ - static inline const el::base::utils::CommandLineArgs* commandLineArgs(void) { - return ELPP->commandLineArgs(); - } - /// @brief Reserve space for custom format specifiers for performance - /// @see std::vector::reserve - static inline void reserveCustomFormatSpecifiers(std::size_t size) { - ELPP->m_customFormatSpecifiers.reserve(size); - } - /// @brief Installs user defined format specifier and handler - static inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) { - ELPP->installCustomFormatSpecifier(customFormatSpecifier); - } - /// @brief Uninstalls user defined format specifier and handler - static inline bool uninstallCustomFormatSpecifier(const char* formatSpecifier) { - return ELPP->uninstallCustomFormatSpecifier(formatSpecifier); - } - /// @brief Returns true if custom format specifier is installed - static inline bool hasCustomFormatSpecifier(const char* formatSpecifier) { - return ELPP->hasCustomFormatSpecifier(formatSpecifier); - } - static inline void validateFileRolling(Logger* logger, Level level) { - if (ELPP == nullptr || logger == nullptr) return; - logger->m_typedConfigurations->validateFileRolling(level, ELPP->preRollOutCallback()); - } -}; -/// @brief Static helpers to deal with loggers and their configurations -class Loggers : base::StaticClass { - public: - /// @brief Gets existing or registers new logger - static Logger* getLogger(const std::string& identity, bool registerIfNotAvailable = true); - /// @brief Changes default log builder for future loggers - static void setDefaultLogBuilder(el::LogBuilderPtr& logBuilderPtr); - /// @brief Installs logger registration callback, this callback is triggered when new logger is registered - template - static inline bool installLoggerRegistrationCallback(const std::string& id) { - return ELPP->registeredLoggers()->installLoggerRegistrationCallback(id); - } - /// @brief Uninstalls log dispatch callback - template - static inline void uninstallLoggerRegistrationCallback(const std::string& id) { - ELPP->registeredLoggers()->uninstallLoggerRegistrationCallback(id); - } - template - static inline T* loggerRegistrationCallback(const std::string& id) { - return ELPP->registeredLoggers()->loggerRegistrationCallback(id); - } - /// @brief Unregisters logger - use it only when you know what you are doing, you may unregister - /// loggers initialized / used by third-party libs. - static bool unregisterLogger(const std::string& identity); - /// @brief Whether or not logger with id is registered - static bool hasLogger(const std::string& identity); - /// @brief Reconfigures specified logger with new configurations - static Logger* reconfigureLogger(Logger* logger, const Configurations& configurations); - /// @brief Reconfigures logger with new configurations after looking it up using identity - static Logger* reconfigureLogger(const std::string& identity, const Configurations& configurations); - /// @brief Reconfigures logger's single configuration - static Logger* reconfigureLogger(const std::string& identity, ConfigurationType configurationType, - const std::string& value); - /// @brief Reconfigures all the existing loggers with new configurations - static void reconfigureAllLoggers(const Configurations& configurations); - /// @brief Reconfigures single configuration for all the loggers - static inline void reconfigureAllLoggers(ConfigurationType configurationType, const std::string& value) { - reconfigureAllLoggers(Level::Global, configurationType, value); - } - /// @brief Reconfigures single configuration for all the loggers for specified level - static void reconfigureAllLoggers(Level level, ConfigurationType configurationType, - const std::string& value); - /// @brief Sets default configurations. This configuration is used for future (and conditionally for existing) loggers - static void setDefaultConfigurations(const Configurations& configurations, - bool reconfigureExistingLoggers = false); - /// @brief Returns current default - static const Configurations* defaultConfigurations(void); - /// @brief Returns log stream reference pointer if needed by user - static const base::LogStreamsReferenceMapPtr logStreamsReference(void); - /// @brief Default typed configuration based on existing defaultConf - static base::TypedConfigurations defaultTypedConfigurations(void); - /// @brief Populates all logger IDs in current repository. - /// @param [out] targetList List of fill up. - static std::vector* populateAllLoggerIds(std::vector* targetList); - /// @brief Sets configurations from global configuration file. - static void configureFromGlobal(const char* globalConfigurationFilePath); - /// @brief Configures loggers using command line arg. Ensure you have already set command line args, - /// @return False if invalid argument or argument with no value provided, true if attempted to configure logger. - /// If true is returned that does not mean it has been configured successfully, it only means that it - /// has attempted to configure logger using configuration file provided in argument - static bool configureFromArg(const char* argKey); - /// @brief Flushes all loggers for all levels - Be careful if you dont know how many loggers are registered - static void flushAll(void); - /// @brief Adds logging flag used internally. - static inline void addFlag(LoggingFlag flag) { - ELPP->addFlag(flag); - } - /// @brief Removes logging flag used internally. - static inline void removeFlag(LoggingFlag flag) { - ELPP->removeFlag(flag); - } - /// @brief Determines whether or not certain flag is active - static inline bool hasFlag(LoggingFlag flag) { - return ELPP->hasFlag(flag); - } - /// @brief Adds flag and removes it when scope goes out - class ScopedAddFlag { - public: - ScopedAddFlag(LoggingFlag flag) : m_flag(flag) { - Loggers::addFlag(m_flag); - } - ~ScopedAddFlag(void) { - Loggers::removeFlag(m_flag); - } - private: - LoggingFlag m_flag; - }; - /// @brief Removes flag and add it when scope goes out - class ScopedRemoveFlag { - public: - ScopedRemoveFlag(LoggingFlag flag) : m_flag(flag) { - Loggers::removeFlag(m_flag); - } - ~ScopedRemoveFlag(void) { - Loggers::addFlag(m_flag); - } - private: - LoggingFlag m_flag; - }; - /// @brief Sets hierarchy for logging. Needs to enable logging flag (HierarchicalLogging) - static void setLoggingLevel(Level level) { - ELPP->setLoggingLevel(level); - } - /// @brief Sets verbose level on the fly - static void setVerboseLevel(base::type::VerboseLevel level); - /// @brief Gets current verbose level - static base::type::VerboseLevel verboseLevel(void); - /// @brief Sets vmodules as specified (on the fly) - static void setVModules(const char* modules); - /// @brief Clears vmodules - static void clearVModules(void); -}; -class VersionInfo : base::StaticClass { - public: - /// @brief Current version number - static const std::string version(void); - - /// @brief Release date of current version - static const std::string releaseDate(void); -}; -} // namespace el -#undef VLOG_IS_ON -/// @brief Determines whether verbose logging is on for specified level current file. -#define VLOG_IS_ON(verboseLevel) (ELPP->vRegistry()->allowed(verboseLevel, __FILE__)) -#undef TIMED_BLOCK -#undef TIMED_SCOPE -#undef TIMED_SCOPE_IF -#undef TIMED_FUNC -#undef TIMED_FUNC_IF -#undef ELPP_MIN_UNIT -#if defined(ELPP_PERFORMANCE_MICROSECONDS) -# define ELPP_MIN_UNIT el::base::TimestampUnit::Microsecond -#else -# define ELPP_MIN_UNIT el::base::TimestampUnit::Millisecond -#endif // (defined(ELPP_PERFORMANCE_MICROSECONDS)) -/// @brief Performance tracked scope. Performance gets written when goes out of scope using -/// 'performance' logger. -/// -/// @detail Please note in order to check the performance at a certain time you can use obj->checkpoint(); -/// @see el::base::PerformanceTracker -/// @see el::base::PerformanceTracker::checkpoint -// Note: Do not surround this definition with null macro because of obj instance -#define TIMED_SCOPE_IF(obj, blockname, condition) el::base::type::PerformanceTrackerPtr obj( condition ? \ - new el::base::PerformanceTracker(blockname, ELPP_MIN_UNIT) : nullptr ) -#define TIMED_SCOPE(obj, blockname) TIMED_SCOPE_IF(obj, blockname, true) -#define TIMED_BLOCK(obj, blockName) for (struct { int i; el::base::type::PerformanceTrackerPtr timer; } obj = { 0, \ - el::base::type::PerformanceTrackerPtr(new el::base::PerformanceTracker(blockName, ELPP_MIN_UNIT)) }; obj.i < 1; ++obj.i) -/// @brief Performance tracked function. Performance gets written when goes out of scope using -/// 'performance' logger. -/// -/// @detail Please note in order to check the performance at a certain time you can use obj->checkpoint(); -/// @see el::base::PerformanceTracker -/// @see el::base::PerformanceTracker::checkpoint -#define TIMED_FUNC_IF(obj,condition) TIMED_SCOPE_IF(obj, ELPP_FUNC, condition) -#define TIMED_FUNC(obj) TIMED_SCOPE(obj, ELPP_FUNC) -#undef PERFORMANCE_CHECKPOINT -#undef PERFORMANCE_CHECKPOINT_WITH_ID -#define PERFORMANCE_CHECKPOINT(obj) obj->checkpoint(std::string(), __FILE__, __LINE__, ELPP_FUNC) -#define PERFORMANCE_CHECKPOINT_WITH_ID(obj, id) obj->checkpoint(id, __FILE__, __LINE__, ELPP_FUNC) -#undef ELPP_COUNTER -#undef ELPP_COUNTER_POS -/// @brief Gets hit counter for file/line -#define ELPP_COUNTER (ELPP->hitCounters()->getCounter(__FILE__, __LINE__)) -/// @brief Gets hit counter position for file/line, -1 if not registered yet -#define ELPP_COUNTER_POS (ELPP_COUNTER == nullptr ? -1 : ELPP_COUNTER->hitCounts()) -// Undef levels to support LOG(LEVEL) -#undef INFO -#undef WARNING -#undef DEBUG -#undef ERROR -#undef FATAL -#undef TRACE -#undef VERBOSE -// Undef existing -#undef CINFO -#undef CWARNING -#undef CDEBUG -#undef CFATAL -#undef CERROR -#undef CTRACE -#undef CVERBOSE -#undef CINFO_IF -#undef CWARNING_IF -#undef CDEBUG_IF -#undef CERROR_IF -#undef CFATAL_IF -#undef CTRACE_IF -#undef CVERBOSE_IF -#undef CINFO_EVERY_N -#undef CWARNING_EVERY_N -#undef CDEBUG_EVERY_N -#undef CERROR_EVERY_N -#undef CFATAL_EVERY_N -#undef CTRACE_EVERY_N -#undef CVERBOSE_EVERY_N -#undef CINFO_AFTER_N -#undef CWARNING_AFTER_N -#undef CDEBUG_AFTER_N -#undef CERROR_AFTER_N -#undef CFATAL_AFTER_N -#undef CTRACE_AFTER_N -#undef CVERBOSE_AFTER_N -#undef CINFO_N_TIMES -#undef CWARNING_N_TIMES -#undef CDEBUG_N_TIMES -#undef CERROR_N_TIMES -#undef CFATAL_N_TIMES -#undef CTRACE_N_TIMES -#undef CVERBOSE_N_TIMES -// Normal logs -#if ELPP_INFO_LOG -# define CINFO(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE(writer, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE(writer, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel)) writer(\ -el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#else -# define CVERBOSE(writer, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// Conditional logs -#if ELPP_INFO_LOG -# define CINFO_IF(writer, condition_, dispatchAction, ...) \ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE_IF(writer, condition_, dispatchAction, ...)\ -ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel) && (condition_)) writer( \ -el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) -#else -# define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// Occasional logs -#if ELPP_INFO_LOG -# define CINFO_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...)\ -ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...)\ -CVERBOSE_IF(writer, ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion), vlevel, dispatchAction, __VA_ARGS__) -#else -# define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// After N logs -#if ELPP_INFO_LOG -# define CINFO_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE_AFTER_N(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...)\ -CVERBOSE_IF(writer, ELPP->validateAfterNCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__) -#else -# define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// N Times logs -#if ELPP_INFO_LOG -# define CINFO_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__) -#else -# define CINFO_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_INFO_LOG -#if ELPP_WARNING_LOG -# define CWARNING_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__) -#else -# define CWARNING_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_WARNING_LOG -#if ELPP_DEBUG_LOG -# define CDEBUG_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__) -#else -# define CDEBUG_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_DEBUG_LOG -#if ELPP_ERROR_LOG -# define CERROR_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__) -#else -# define CERROR_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_ERROR_LOG -#if ELPP_FATAL_LOG -# define CFATAL_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__) -#else -# define CFATAL_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_FATAL_LOG -#if ELPP_TRACE_LOG -# define CTRACE_N_TIMES(writer, n, dispatchAction, ...)\ -ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__) -#else -# define CTRACE_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_TRACE_LOG -#if ELPP_VERBOSE_LOG -# define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...)\ -CVERBOSE_IF(writer, ELPP->validateNTimesCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__) -#else -# define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter() -#endif // ELPP_VERBOSE_LOG -// -// Custom Loggers - Requires (level, dispatchAction, loggerId/s) -// -// undef existing -#undef CLOG -#undef CLOG_VERBOSE -#undef CVLOG -#undef CLOG_IF -#undef CLOG_VERBOSE_IF -#undef CVLOG_IF -#undef CLOG_EVERY_N -#undef CVLOG_EVERY_N -#undef CLOG_AFTER_N -#undef CVLOG_AFTER_N -#undef CLOG_N_TIMES -#undef CVLOG_N_TIMES -// Normal logs -#define CLOG(LEVEL, ...)\ -C##LEVEL(el::base::Writer, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG(vlevel, ...) CVERBOSE(el::base::Writer, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -// Conditional logs -#define CLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG_IF(condition, vlevel, ...)\ -CVERBOSE_IF(el::base::Writer, condition, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -// Hit counts based logs -#define CLOG_EVERY_N(n, LEVEL, ...)\ -C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG_EVERY_N(n, vlevel, ...)\ -CVERBOSE_EVERY_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CLOG_AFTER_N(n, LEVEL, ...)\ -C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG_AFTER_N(n, vlevel, ...)\ -CVERBOSE_AFTER_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CLOG_N_TIMES(n, LEVEL, ...)\ -C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CVLOG_N_TIMES(n, vlevel, ...)\ -CVERBOSE_N_TIMES(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) -// -// Default Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros -// -// undef existing -#undef LOG -#undef VLOG -#undef LOG_IF -#undef VLOG_IF -#undef LOG_EVERY_N -#undef VLOG_EVERY_N -#undef LOG_AFTER_N -#undef VLOG_AFTER_N -#undef LOG_N_TIMES -#undef VLOG_N_TIMES -#undef ELPP_CURR_FILE_LOGGER_ID -#if defined(ELPP_DEFAULT_LOGGER) -# define ELPP_CURR_FILE_LOGGER_ID ELPP_DEFAULT_LOGGER -#else -# define ELPP_CURR_FILE_LOGGER_ID el::base::consts::kDefaultLoggerId -#endif -#undef ELPP_TRACE -#define ELPP_TRACE CLOG(TRACE, ELPP_CURR_FILE_LOGGER_ID) -// Normal logs -#define LOG(LEVEL) CLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG(vlevel) CVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Conditional logs -#define LOG_IF(condition, LEVEL) CLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG_IF(condition, vlevel) CVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Hit counts based logs -#define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG_EVERY_N(n, vlevel) CVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#define LOG_AFTER_N(n, LEVEL) CLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG_AFTER_N(n, vlevel) CVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#define LOG_N_TIMES(n, LEVEL) CLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define VLOG_N_TIMES(n, vlevel) CVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Generic PLOG() -#undef CPLOG -#undef CPLOG_IF -#undef PLOG -#undef PLOG_IF -#undef DCPLOG -#undef DCPLOG_IF -#undef DPLOG -#undef DPLOG_IF -#define CPLOG(LEVEL, ...)\ -C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define CPLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::PErrorWriter, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define DCPLOG(LEVEL, ...)\ -if (ELPP_DEBUG_LOG) C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define DCPLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::PErrorWriter, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::NormalLog, __VA_ARGS__) -#define PLOG(LEVEL) CPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define PLOG_IF(condition, LEVEL) CPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DPLOG(LEVEL) DCPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DPLOG_IF(condition, LEVEL) DCPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -// Generic SYSLOG() -#undef CSYSLOG -#undef CSYSLOG_IF -#undef CSYSLOG_EVERY_N -#undef CSYSLOG_AFTER_N -#undef CSYSLOG_N_TIMES -#undef SYSLOG -#undef SYSLOG_IF -#undef SYSLOG_EVERY_N -#undef SYSLOG_AFTER_N -#undef SYSLOG_N_TIMES -#undef DCSYSLOG -#undef DCSYSLOG_IF -#undef DCSYSLOG_EVERY_N -#undef DCSYSLOG_AFTER_N -#undef DCSYSLOG_N_TIMES -#undef DSYSLOG -#undef DSYSLOG_IF -#undef DSYSLOG_EVERY_N -#undef DSYSLOG_AFTER_N -#undef DSYSLOG_N_TIMES -#if defined(ELPP_SYSLOG) -# define CSYSLOG(LEVEL, ...)\ -C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define CSYSLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define CSYSLOG_EVERY_N(n, LEVEL, ...) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define CSYSLOG_AFTER_N(n, LEVEL, ...) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define CSYSLOG_N_TIMES(n, LEVEL, ...) C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define SYSLOG(LEVEL) CSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId) -# define SYSLOG_IF(condition, LEVEL) CSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId) -# define SYSLOG_EVERY_N(n, LEVEL) CSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define SYSLOG_AFTER_N(n, LEVEL) CSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define SYSLOG_N_TIMES(n, LEVEL) CSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define DCSYSLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DCSYSLOG_IF(condition, LEVEL, ...)\ -C##LEVEL##_IF(el::base::Writer, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DCSYSLOG_EVERY_N(n, LEVEL, ...)\ -if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DCSYSLOG_AFTER_N(n, LEVEL, ...)\ -if (ELPP_DEBUG_LOG) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DCSYSLOG_N_TIMES(n, LEVEL, ...)\ -if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) -# define DSYSLOG(LEVEL) DCSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId) -# define DSYSLOG_IF(condition, LEVEL) DCSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId) -# define DSYSLOG_EVERY_N(n, LEVEL) DCSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define DSYSLOG_AFTER_N(n, LEVEL) DCSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId) -# define DSYSLOG_N_TIMES(n, LEVEL) DCSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId) -#else -# define CSYSLOG(LEVEL, ...) el::base::NullWriter() -# define CSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter() -# define CSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter() -# define CSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter() -# define CSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter() -# define SYSLOG(LEVEL) el::base::NullWriter() -# define SYSLOG_IF(condition, LEVEL) el::base::NullWriter() -# define SYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter() -# define SYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter() -# define SYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter() -# define DCSYSLOG(LEVEL, ...) el::base::NullWriter() -# define DCSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter() -# define DCSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter() -# define DCSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter() -# define DCSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter() -# define DSYSLOG(LEVEL) el::base::NullWriter() -# define DSYSLOG_IF(condition, LEVEL) el::base::NullWriter() -# define DSYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter() -# define DSYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter() -# define DSYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter() -#endif // defined(ELPP_SYSLOG) -// -// Custom Debug Only Loggers - Requires (level, loggerId/s) -// -// undef existing -#undef DCLOG -#undef DCVLOG -#undef DCLOG_IF -#undef DCVLOG_IF -#undef DCLOG_EVERY_N -#undef DCVLOG_EVERY_N -#undef DCLOG_AFTER_N -#undef DCVLOG_AFTER_N -#undef DCLOG_N_TIMES -#undef DCVLOG_N_TIMES -// Normal logs -#define DCLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG(LEVEL, __VA_ARGS__) -#define DCLOG_VERBOSE(vlevel, ...) if (ELPP_DEBUG_LOG) CLOG_VERBOSE(vlevel, __VA_ARGS__) -#define DCVLOG(vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG(vlevel, __VA_ARGS__) -// Conditional logs -#define DCLOG_IF(condition, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_IF(condition, LEVEL, __VA_ARGS__) -#define DCVLOG_IF(condition, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_IF(condition, vlevel, __VA_ARGS__) -// Hit counts based logs -#define DCLOG_EVERY_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_EVERY_N(n, LEVEL, __VA_ARGS__) -#define DCVLOG_EVERY_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_EVERY_N(n, vlevel, __VA_ARGS__) -#define DCLOG_AFTER_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_AFTER_N(n, LEVEL, __VA_ARGS__) -#define DCVLOG_AFTER_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_AFTER_N(n, vlevel, __VA_ARGS__) -#define DCLOG_N_TIMES(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_N_TIMES(n, LEVEL, __VA_ARGS__) -#define DCVLOG_N_TIMES(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_N_TIMES(n, vlevel, __VA_ARGS__) -// -// Default Debug Only Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros -// -#if !defined(ELPP_NO_DEBUG_MACROS) -// undef existing -#undef DLOG -#undef DVLOG -#undef DLOG_IF -#undef DVLOG_IF -#undef DLOG_EVERY_N -#undef DVLOG_EVERY_N -#undef DLOG_AFTER_N -#undef DVLOG_AFTER_N -#undef DLOG_N_TIMES -#undef DVLOG_N_TIMES -// Normal logs -#define DLOG(LEVEL) DCLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG(vlevel) DCVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Conditional logs -#define DLOG_IF(condition, LEVEL) DCLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG_IF(condition, vlevel) DCVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID) -// Hit counts based logs -#define DLOG_EVERY_N(n, LEVEL) DCLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG_EVERY_N(n, vlevel) DCVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#define DLOG_AFTER_N(n, LEVEL) DCLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG_AFTER_N(n, vlevel) DCVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#define DLOG_N_TIMES(n, LEVEL) DCLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) -#define DVLOG_N_TIMES(n, vlevel) DCVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) -#endif // defined(ELPP_NO_DEBUG_MACROS) -#if !defined(ELPP_NO_CHECK_MACROS) -// Check macros -#undef CCHECK -#undef CPCHECK -#undef CCHECK_EQ -#undef CCHECK_NE -#undef CCHECK_LT -#undef CCHECK_GT -#undef CCHECK_LE -#undef CCHECK_GE -#undef CCHECK_BOUNDS -#undef CCHECK_NOTNULL -#undef CCHECK_STRCASEEQ -#undef CCHECK_STRCASENE -#undef CHECK -#undef PCHECK -#undef CHECK_EQ -#undef CHECK_NE -#undef CHECK_LT -#undef CHECK_GT -#undef CHECK_LE -#undef CHECK_GE -#undef CHECK_BOUNDS -#undef CHECK_NOTNULL -#undef CHECK_STRCASEEQ -#undef CHECK_STRCASENE -#define CCHECK(condition, ...) CLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] " -#define CPCHECK(condition, ...) CPLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] " -#define CHECK(condition) CCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) -#define PCHECK(condition) CPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) -#define CCHECK_EQ(a, b, ...) CCHECK(a == b, __VA_ARGS__) -#define CCHECK_NE(a, b, ...) CCHECK(a != b, __VA_ARGS__) -#define CCHECK_LT(a, b, ...) CCHECK(a < b, __VA_ARGS__) -#define CCHECK_GT(a, b, ...) CCHECK(a > b, __VA_ARGS__) -#define CCHECK_LE(a, b, ...) CCHECK(a <= b, __VA_ARGS__) -#define CCHECK_GE(a, b, ...) CCHECK(a >= b, __VA_ARGS__) -#define CCHECK_BOUNDS(val, min, max, ...) CCHECK(val >= min && val <= max, __VA_ARGS__) -#define CHECK_EQ(a, b) CCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_NE(a, b) CCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_LT(a, b) CCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_GT(a, b) CCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_LE(a, b) CCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_GE(a, b) CCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_BOUNDS(val, min, max) CCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID) -#define CCHECK_NOTNULL(ptr, ...) CCHECK((ptr) != nullptr, __VA_ARGS__) -#define CCHECK_STREQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \ -<< "Check failed: [" << #str1 << " == " << #str2 << "] " -#define CCHECK_STRNE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \ -<< "Check failed: [" << #str1 << " != " << #str2 << "] " -#define CCHECK_STRCASEEQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \ -<< "Check failed: [" << #str1 << " == " << #str2 << "] " -#define CCHECK_STRCASENE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \ -<< "Check failed: [" << #str1 << " != " << #str2 << "] " -#define CHECK_NOTNULL(ptr) CCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_STREQ(str1, str2) CCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_STRNE(str1, str2) CCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_STRCASEEQ(str1, str2) CCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define CHECK_STRCASENE(str1, str2) CCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#undef DCCHECK -#undef DCCHECK_EQ -#undef DCCHECK_NE -#undef DCCHECK_LT -#undef DCCHECK_GT -#undef DCCHECK_LE -#undef DCCHECK_GE -#undef DCCHECK_BOUNDS -#undef DCCHECK_NOTNULL -#undef DCCHECK_STRCASEEQ -#undef DCCHECK_STRCASENE -#undef DCPCHECK -#undef DCHECK -#undef DCHECK_EQ -#undef DCHECK_NE -#undef DCHECK_LT -#undef DCHECK_GT -#undef DCHECK_LE -#undef DCHECK_GE -#undef DCHECK_BOUNDS_ -#undef DCHECK_NOTNULL -#undef DCHECK_STRCASEEQ -#undef DCHECK_STRCASENE -#undef DPCHECK -#define DCCHECK(condition, ...) if (ELPP_DEBUG_LOG) CCHECK(condition, __VA_ARGS__) -#define DCCHECK_EQ(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_EQ(a, b, __VA_ARGS__) -#define DCCHECK_NE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_NE(a, b, __VA_ARGS__) -#define DCCHECK_LT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LT(a, b, __VA_ARGS__) -#define DCCHECK_GT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GT(a, b, __VA_ARGS__) -#define DCCHECK_LE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LE(a, b, __VA_ARGS__) -#define DCCHECK_GE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GE(a, b, __VA_ARGS__) -#define DCCHECK_BOUNDS(val, min, max, ...) if (ELPP_DEBUG_LOG) CCHECK_BOUNDS(val, min, max, __VA_ARGS__) -#define DCCHECK_NOTNULL(ptr, ...) if (ELPP_DEBUG_LOG) CCHECK_NOTNULL((ptr), __VA_ARGS__) -#define DCCHECK_STREQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STREQ(str1, str2, __VA_ARGS__) -#define DCCHECK_STRNE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRNE(str1, str2, __VA_ARGS__) -#define DCCHECK_STRCASEEQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASEEQ(str1, str2, __VA_ARGS__) -#define DCCHECK_STRCASENE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASENE(str1, str2, __VA_ARGS__) -#define DCPCHECK(condition, ...) if (ELPP_DEBUG_LOG) CPCHECK(condition, __VA_ARGS__) -#define DCHECK(condition) DCCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_EQ(a, b) DCCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_NE(a, b) DCCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_LT(a, b) DCCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_GT(a, b) DCCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_LE(a, b) DCCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_GE(a, b) DCCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_BOUNDS(val, min, max) DCCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_NOTNULL(ptr) DCCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_STREQ(str1, str2) DCCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_STRNE(str1, str2) DCCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_STRCASEEQ(str1, str2) DCCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define DCHECK_STRCASENE(str1, str2) DCCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) -#define DPCHECK(condition) DCPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) -#endif // defined(ELPP_NO_CHECK_MACROS) -#if defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING) -# define ELPP_USE_DEF_CRASH_HANDLER false -#else -# define ELPP_USE_DEF_CRASH_HANDLER true -#endif // defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING) -#define ELPP_CRASH_HANDLER_INIT -#define ELPP_INIT_EASYLOGGINGPP(val) \ -namespace el { \ -namespace base { \ -el::base::type::StoragePointer elStorage(val); \ -} \ -el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER); \ -} - -#if ELPP_ASYNC_LOGGING -# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()),\ -new el::base::AsyncDispatchWorker())) -#else -# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()))) -#endif // ELPP_ASYNC_LOGGING -#define INITIALIZE_NULL_EASYLOGGINGPP \ -namespace el {\ -namespace base {\ -el::base::type::StoragePointer elStorage;\ -}\ -el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\ -} -#define SHARE_EASYLOGGINGPP(initializedStorage)\ -namespace el {\ -namespace base {\ -el::base::type::StoragePointer elStorage(initializedStorage);\ -}\ -el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\ -} - -#if defined(ELPP_UNICODE) -# define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv); std::locale::global(std::locale("")) -#else -# define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv) -#endif // defined(ELPP_UNICODE) -#endif // EASYLOGGINGPP_H diff --git a/src/global_context.cc b/src/global_context.cc deleted file mode 100644 index c711671..0000000 --- a/src/global_context.cc +++ /dev/null @@ -1,39 +0,0 @@ -#include "pch.h" -#include "global_context.h" -#include "http_server.h" -#include "easylogging++.h" -#include "hooks.h" - - -namespace wxhelper { - -void GlobalContext::initialize(HMODULE module) { - module_ = module; - DWORD base = Utils::GetWeChatWinBase(); - config.emplace(); - config->Initialize(); - log.emplace(); - log->Initialize(); - hide_module.emplace(); - #ifndef _DEBUG - hide_module->Hide(module_); - #endif - - HttpServer::GetInstance().Init(config->GetPort()); - HttpServer::GetInstance().HttpStart(); - DB::GetInstance().init(base); - contact_mgr.emplace(ContactMgr{base}); - misc_mgr.emplace(MiscMgr{base}); - send_mgr.emplace(SendMessageMgr{base}); - account_mgr.emplace(AccountMgr{base}); - chat_room_mgr.emplace(ChatRoomMgr{base}); - sns_mgr.emplace(SNSMgr{base}); -} - -void GlobalContext::finally() { - HttpServer::GetInstance().HttpClose(); - hooks::UnHookLog(); - hooks::UnHookRecvMsg(); - hooks::UnHookSearchContact(); -} -} // namespace wxhelper \ No newline at end of file diff --git a/src/global_context.h b/src/global_context.h deleted file mode 100644 index 0a6a7fa..0000000 --- a/src/global_context.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef GLOBAL_CONTEXT_H_ -#define GLOBAL_CONTEXT_H_ -#include "account_mgr.h" -#include "config.h" -#include "contact_mgr.h" -#include "db.h" -#include "hide_module.h" -#include "http_server.h" -#include "log.h" -#include "misc_mgr.h" -#include "send_message_mgr.h" -#include "chat_room_mgr.h" -#include "sns_mgr.h" -#include "singleton.h" - -namespace wxhelper { - -enum class GlobalContextState { NOT_INITIALIZED, INITIALIZING, INITIALIZED }; - -class GlobalContext :public Singleton{ - public: - void initialize(HMODULE module); - void finally(); - - public: - std::optional config; - std::optional hide_module; - std::optional log; - std::optional contact_mgr; - std::optional misc_mgr; - std::optional send_mgr; - std::optional account_mgr; - std::optional chat_room_mgr; - std::optional sns_mgr; - - GlobalContextState state = GlobalContextState::INITIALIZED; - - private: - HMODULE module_; -}; - -} // namespace wxhelper -#endif \ No newline at end of file diff --git a/src/handler.h b/src/handler.h deleted file mode 100644 index 985843a..0000000 --- a/src/handler.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef WXHELPER_HANDLER_H_ -#define WXHELPER_HANDLER_H_ -#include -namespace wxhelper { -class Handler { - public: - virtual void HandlerRequest(struct mg_connection *c, void *ev_data) = 0; -}; -} // namespace wxhelper -#endif \ No newline at end of file diff --git a/src/hide_module.cc b/src/hide_module.cc deleted file mode 100644 index 81e1b0d..0000000 --- a/src/hide_module.cc +++ /dev/null @@ -1,64 +0,0 @@ -#include "pch.h" -#include "hide_module.h" - - -namespace wxhelper { - -void HideModule::Hide(const char* module_name) { - HMODULE hMod = ::GetModuleHandleA(module_name); - PLIST_ENTRY Head, Cur; - PPEB_LDR_DATA ldr; - PLDR_MODULE ldm; - - __asm { - mov eax, fs: [0x30] - mov ecx, [eax + 0x0c] - mov ldr, ecx - } - Head = &(ldr->InLoadOrderModuleList); - Cur = Head->Flink; - do { - ldm = CONTAINING_RECORD(Cur, LDR_MODULE, InLoadOrderModuleList); - if (hMod == ldm->BaseAddress) { - ldm->InLoadOrderModuleList.Blink->Flink = - ldm->InLoadOrderModuleList.Flink; - ldm->InLoadOrderModuleList.Flink->Blink = - ldm->InLoadOrderModuleList.Blink; - ldm->InInitializationOrderModuleList.Blink->Flink = - ldm->InInitializationOrderModuleList.Flink; - ldm->InInitializationOrderModuleList.Flink->Blink = - ldm->InInitializationOrderModuleList.Blink; - ldm->InMemoryOrderModuleList.Blink->Flink = - ldm->InMemoryOrderModuleList.Flink; - ldm->InMemoryOrderModuleList.Flink->Blink = - ldm->InMemoryOrderModuleList.Blink; - break; - } - Cur = Cur->Flink; - } while (Head != Cur); -} - -void HideModule::Hide(HMODULE module) { - void* peb_ptr = nullptr; - _asm { - PUSH EAX - MOV EAX, FS:[0x30] - MOV peb_ptr, EAX - POP EAX - } - void* ldr_ptr = *((void**)((unsigned char*)peb_ptr + 0xc)); - void* cur_ptr = *((void**)((unsigned char*)ldr_ptr + 0x0c)); - void* next_ptr = cur_ptr; - do { - void* next = *((void**)((unsigned char*)next_ptr)); - void* last = *((void**)((unsigned char*)next_ptr + 0x4)); - void* base_addr = *((void**)((unsigned char*)next_ptr + 0x18)); - if (base_addr == module) { - *((void**)((unsigned char*)last)) = next; - *((void**)((unsigned char*)next + 0x4)) = last; - cur_ptr = next; - } - next_ptr = *((void**)next_ptr); - } while (cur_ptr != next_ptr); -} -} // namespace wxhelper diff --git a/src/hide_module.h b/src/hide_module.h deleted file mode 100644 index 1cc4c0f..0000000 --- a/src/hide_module.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef WXHELEPER_HIDE_MODULE_H_ -#define WXHELEPER_HIDE_MODULE_H_ -#include -namespace wxhelper { -typedef struct _UNICODE_STRING { - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; -} UNICODE_STRING, *PUNICODE_STRING; - -typedef struct _PEB_LDR_DATA { - ULONG Length; - BOOLEAN Initialized; - PVOID SsHandle; - LIST_ENTRY InLoadOrderModuleList; - LIST_ENTRY InMemoryOrderModuleList; - LIST_ENTRY InInitializationOrderModuleList; -} PEB_LDR_DATA, *PPEB_LDR_DATA; - -typedef struct _LDR_DATA_TABLE_ENTRY { - LIST_ENTRY InLoadOrderModuleList; - LIST_ENTRY InMemoryOrderModuleList; - LIST_ENTRY InInitializationOrderModuleList; - void* BaseAddress; - void* EntryPoint; - ULONG SizeOfImage; - UNICODE_STRING FullDllName; - UNICODE_STRING BaseDllName; - ULONG Flags; - SHORT LoadCount; - SHORT TlsIndex; - HANDLE SectionHandle; - ULONG CheckSum; - ULONG TimeDateStamp; -} LDR_MODULE, *PLDR_MODULE; - - -class HideModule { - private: - /* data */ - public: - static void Hide(const char* module_name); - static void Hide(HMODULE module); -}; - - -} // namespace wxhelper -#endif \ No newline at end of file diff --git a/src/hooks.cc b/src/hooks.cc deleted file mode 100644 index c5147f9..0000000 --- a/src/hooks.cc +++ /dev/null @@ -1,533 +0,0 @@ -#include -#include - -#include - -#include "easylogging++.h" -#include "pch.h" -#include "wechat_function.h" -using namespace nlohmann; -using namespace std; -namespace wxhelper { -namespace hooks { -static int server_port_ = 0; -static bool msg_hook_flag_ = false; -static char server_ip_[16] = "127.0.0.1"; - -static char msg_asm_code_[5] = {0}; -static DWORD msg_back_addr_ = 0; -static DWORD msg_next_addr_ = 0; - -static char sns_asm_code_[5] = {0}; -static DWORD sns_back_addr_ = 0; -static DWORD sns_next_addr_ = 0; - -static bool log_hook_flag_ = false; -static char log_asm_code_[5] = {0}; -static DWORD log_back_addr_ = 0; -static DWORD log_next_addr_ = 0; - -static bool search_contact_flag_ = false; -static char search_contact_asm_code_[5] = {0}; -static DWORD search_contact_back_addr_ = 0; -static DWORD search_contact_next_addr_ = 0; - -static bool error_code_flag_ = false; -static char error_code_asm_code_[5] = {0}; -static DWORD error_code_back_addr_ = 0; -static DWORD error_code_next_addr_ = 0; - -bool user_info_flag_ = false; -static char user_info_asm_code_[5] = {0}; -static DWORD user_info_back_addr_ = 0; -static DWORD user_info_next_addr_ = 0; - -UserInfo userinfo = {}; - -void SendSocketMessage(InnerMessageStruct *msg) { - if (msg == NULL) { - return; - } - unique_ptr sms(msg); - json j_msg = - json::parse(msg->buffer, msg->buffer + msg->length, nullptr, false); - if (j_msg.is_discarded() == true) { - return; - } - string jstr = j_msg.dump() + "\n"; - - if (server_port_ == 0) { - LOG(INFO) << "http server port error :" << server_port_; - return; - } - SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (client_socket < 0) { - LOG(INFO) << "socket init fail"; - return; - } - BOOL status = false; - sockaddr_in client_addr; - memset(&client_addr, 0, sizeof(client_addr)); - client_addr.sin_family = AF_INET; - client_addr.sin_port = htons((u_short)server_port_); - InetPtonA(AF_INET, server_ip_, &client_addr.sin_addr.s_addr); - if (connect(client_socket, reinterpret_cast(&client_addr), - sizeof(sockaddr)) < 0) { - LOG(INFO) << "socket connect fail"; - return; - } - char recv_buf[1024] = {0}; - int ret = send(client_socket, jstr.c_str(), jstr.size(), 0); - if (ret == -1 || ret == 0) { - LOG(INFO) << "socket send fail ,ret:" << ret; - closesocket(client_socket); - return; - } - memset(recv_buf, 0, sizeof(recv_buf)); - ret = recv(client_socket, recv_buf, sizeof(recv_buf), 0); - closesocket(client_socket); - if (ret == -1 || ret == 0) { - LOG(INFO) << "socket recv fail ,ret:" << ret; - } -} - -void __cdecl OnRecvMsg(DWORD msg_addr) { - json j_msg; - unsigned long long msgid = *(unsigned long long *)(msg_addr + 0x30); - j_msg["msgId"] = msgid; - j_msg["pid"] = GetCurrentProcessId(); - j_msg["type"] = *(DWORD *)(msg_addr + 0x38); - j_msg["isSendMsg"] = *(BOOL *)(msg_addr + 0x3C); - if (j_msg["isSendMsg"].get()) { - j_msg["isSendByPhone"] = (int)(*(BYTE *)(msg_addr + 0xD8)); - } - j_msg["time"] = - Utils::WstringToUTF8(Utils::GetTimeW(*(DWORD *)(msg_addr + 0x44))); - j_msg["timestamp"] = *(DWORD *)(msg_addr + 0x44); - j_msg["fromGroup"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x48)); - int length = *(DWORD *)(msg_addr + 0x178); - if (length == 0) { - j_msg["fromUser"] = j_msg["fromGroup"].get(); - } else { - j_msg["fromUser"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x174)); - } - int content_len = *(DWORD *)(msg_addr + 0x74); - if (content_len > 0) { - j_msg["content"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x70)); - } - int sign_len = *(DWORD *)(msg_addr + 0x18C); - if (sign_len > 0) { - j_msg["sign"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x188)); - } - int thumb_len = *(DWORD *)(msg_addr + 0x1A0); - if (thumb_len > 0) { - j_msg["thumbPath"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x19C)); - } - int path_len = *(DWORD *)(msg_addr + 0x1B4); - if (path_len > 0) { - j_msg["path"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x1B0)); - } - - int signature_len = *(DWORD *)(msg_addr + 0x1F4); - if (signature_len > 0) { - j_msg["signature"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x1F0)); - } - - string jstr = j_msg.dump() + '\n'; - InnerMessageStruct *inner_msg = new InnerMessageStruct; - inner_msg->buffer = new char[jstr.size() + 1]; - memcpy(inner_msg->buffer, jstr.c_str(), jstr.size() + 1); - inner_msg->length = jstr.size(); - HANDLE thread = CreateThread( - NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, inner_msg, NULL, 0); - if (thread) { - CloseHandle(thread); - } -} - -/// @brief hook msg implement -_declspec(naked) void HandleSyncMsg() { - __asm { - PUSHAD - PUSHFD - PUSH ECX - CALL OnRecvMsg - ADD ESP, 0x4 - POPFD - POPAD - CALL msg_next_addr_ - JMP msg_back_addr_ - } -} - -void __cdecl OnSnsTimeLineMsg(DWORD msg_addr) { - json j_sns; - DWORD begin_addr = *(DWORD *)(msg_addr + 0x20); - DWORD end_addr = *(DWORD *)(msg_addr + 0x24); - if (begin_addr == 0) { - j_sns = {{"data", json::array()}}; - } else { - while (begin_addr < end_addr) { - json j_item; - j_item["snsId"] = *(unsigned long long *)(begin_addr); - j_item["createTime"] = *(DWORD *)(begin_addr + 0x2C); - - j_item["senderId"] = Utils::WstringToUTF8(READ_WSTRING(begin_addr, 0x18)); - - j_item["content"] = Utils::WstringToUTF8(READ_WSTRING(begin_addr, 0x3c)); - - j_item["xml"] = Utils::WstringToUTF8(READ_WSTRING(begin_addr, 0x384)); - - j_sns["data"].push_back(j_item); - begin_addr += 0xB48; - } - } - string jstr = j_sns.dump() + '\n'; - InnerMessageStruct *inner_msg = new InnerMessageStruct; - inner_msg->buffer = new char[jstr.size() + 1]; - memcpy(inner_msg->buffer, jstr.c_str(), jstr.size() + 1); - inner_msg->length = jstr.size(); - HANDLE thread = CreateThread( - NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, inner_msg, NULL, 0); - if (thread) { - CloseHandle(thread); - } -} - -/// @brief hook sns msg implement -_declspec(naked) void HandleSNSMsg() { - __asm { - PUSHAD - PUSHFD - PUSH [ESP + 0x24] - CALL OnSnsTimeLineMsg - ADD ESP, 0x4 - POPFD - POPAD - CALL sns_next_addr_ - JMP sns_back_addr_ - } -} - -int HookRecvMsg(char *client_ip, int port) { - server_port_ = port; - strcpy_s(server_ip_, client_ip); - DWORD base = Utils::GetWeChatWinBase(); - if (!base) { - return -1; - } - - if (msg_hook_flag_) { - return 2; - } - - DWORD hook_recv_msg_addr = base + WX_RECV_MSG_HOOK_OFFSET; - msg_next_addr_ = base + WX_RECV_MSG_HOOK_NEXT_OFFSET; - msg_back_addr_ = hook_recv_msg_addr + 0x5; - LOG(INFO) << "base" << base; - LOG(INFO) << "msg_next_addr_" << msg_next_addr_; - LOG(INFO) << "msg_back_addr_" << msg_back_addr_; - Utils::HookAnyAddress(hook_recv_msg_addr, (LPVOID)HandleSyncMsg, - msg_asm_code_); - - DWORD hook_sns_msg_addr = base + WX_SNS_HOOK_OFFSET; - sns_next_addr_ = base + WX_SNS_HOOK_NEXT_OFFSET; - sns_back_addr_ = hook_sns_msg_addr + 0x5; - LOG(INFO) << "base" << base; - LOG(INFO) << "sns_next_addr_" << sns_next_addr_; - LOG(INFO) << "sns_back_addr_" << sns_back_addr_; - Utils::HookAnyAddress(hook_sns_msg_addr, (LPVOID)HandleSNSMsg, sns_asm_code_); - - msg_hook_flag_ = true; - return 1; -} - -int UnHookRecvMsg() { - server_port_ = 0; - if (!msg_hook_flag_) { - LOG(INFO) << "this port already hooked"; - return 2; - } - DWORD base = Utils::GetWeChatWinBase(); - DWORD hook_recv_msg_addr = base + WX_RECV_MSG_HOOK_OFFSET; - DWORD hook_sns_addr = base + WX_SNS_HOOK_OFFSET; - Utils::UnHookAnyAddress(hook_recv_msg_addr, msg_asm_code_); - Utils::UnHookAnyAddress(hook_sns_addr, sns_asm_code_); - msg_hook_flag_ = false; - return 1; -} - -void PrintLog(DWORD addr) { - if (!addr) { - return; - } - DWORD dwId = 0; - char *msg = (char *)addr; - int size = MultiByteToWideChar(CP_UTF8, 0, msg, -1, 0, 0); - wchar_t *w_msg = new wchar_t[size + 1]; - memset(w_msg, 0, (size + 1) * 2); - MultiByteToWideChar(CP_UTF8, 0, msg, -1, w_msg, size); - size = WideCharToMultiByte(CP_ACP, 0, w_msg, -1, 0, 0, 0, 0); - char *ansi_message = new char[size + 1]; - memset(ansi_message, 0, size + 1); - WideCharToMultiByte(CP_ACP, 0, w_msg, -1, ansi_message, size, 0, 0); - delete[] w_msg; - w_msg = NULL; - LOG(INFO) << ansi_message; - delete[] ansi_message; - ansi_message = NULL; -} - -_declspec(naked) void HandleLog() { - __asm { - PUSHAD - PUSHFD - PUSH EAX - CALL PrintLog - ADD ESP, 0x4 - POPFD - POPAD - CALL log_next_addr_ - JMP log_back_addr_ - } -} - -int HookLog() { - DWORD base = Utils::GetWeChatWinBase(); - if (!base) { - return -1; - } - if (log_hook_flag_) { - return 2; - } - DWORD hook_log_addr = base + WX_HOOK_LOG_OFFSET; - log_next_addr_ = base + WX_HOOK_LOG_NEXT_OFFSET; - log_back_addr_ = hook_log_addr + 0x5; - Utils::HookAnyAddress(hook_log_addr, (LPVOID)HandleLog, log_asm_code_); - log_hook_flag_ = true; - return 1; -} -int UnHookLog() { - if (!log_hook_flag_) { - return 1; - } - DWORD base = Utils::GetWeChatWinBase(); - DWORD hook_log_addr = base + WX_HOOK_LOG_OFFSET; - Utils::UnHookAnyAddress(hook_log_addr, log_asm_code_); - log_hook_flag_ = FALSE; - return 1; -} - -void SetErrorCode(int code) { userinfo.error_code = code; } - -void SetUserInfoDetail(DWORD address) { - LOG(INFO) << "hook userinfo addr" <<&userinfo; - DWORD length = *(DWORD *)(address + 0x8); - userinfo.keyword = new wchar_t[length + 1]; - userinfo.keyword_len = length; - if (length) { - memcpy(userinfo.keyword, (wchar_t *)(*(DWORD *)(address + 0x4)), - (length + 1) * sizeof(wchar_t)); - } else { - ZeroMemory(userinfo.keyword, (length + 1) * sizeof(wchar_t)); - } - - length = *(DWORD *)(address + 0x1C); - userinfo.v3 = new wchar_t[length + 1]; - userinfo.v3_len = length; - if (length) { - memcpy(userinfo.v3, (wchar_t *)(*(DWORD *)(address + 0x18)), - (length + 1) * sizeof(wchar_t)); - } else { - ZeroMemory(userinfo.v3, (length + 1) * sizeof(wchar_t)); - } - - length = *(DWORD *)(address + 0x30); - userinfo.big_image = new wchar_t[length + 1]; - userinfo.big_image_len = length; - if (length) { - memcpy(userinfo.big_image, (wchar_t *)(*(DWORD *)(address + 0x2C)), - (length + 1) * sizeof(wchar_t)); - } else { - ZeroMemory(userinfo.big_image, (length + 1) * sizeof(wchar_t)); - } - - length = *(DWORD *)(address + 0xC8); - userinfo.nickname = new wchar_t[length + 1]; - userinfo.nickname_len = length; - if (length) { - memcpy(userinfo.nickname, (wchar_t *)(*(DWORD *)(address + 0xC4)), - (length + 1) * sizeof(wchar_t)); - } else { - ZeroMemory(userinfo.nickname, (length + 1) * sizeof(wchar_t)); - } - - length = *(DWORD *)(address + 0x108); - userinfo.v2 = new wchar_t[length + 1]; - userinfo.v2_len = length; - if (length) { - memcpy(userinfo.v2, (wchar_t *)(*(DWORD *)(address + 0x104)), - (length + 1) * sizeof(wchar_t)); - } else { - ZeroMemory(userinfo.v2, (length + 1) * sizeof(wchar_t)); - } - - length = *(DWORD *)(address + 0x16C); - userinfo.small_image = new wchar_t[length + 1]; - userinfo.small_image_len = length; - if (length) { - memcpy(userinfo.small_image, (wchar_t *)(*(DWORD *)(address + 0x168)), - (length + 1) * sizeof(wchar_t)); - } else { - ZeroMemory(userinfo.small_image, (length + 1) * sizeof(wchar_t)); - } - - length = *(DWORD *)(address + 0x1F8); - userinfo.signature = new wchar_t[length + 1]; - userinfo.signature_len = length; - if (length) { - memcpy(userinfo.signature, (wchar_t *)(*(DWORD *)(address + 0x1F4)), - (length + 1) * sizeof(wchar_t)); - } else { - ZeroMemory(userinfo.signature, (length + 1) * sizeof(wchar_t)); - } - - length = *(DWORD *)(address + 0x20C); - userinfo.nation = new wchar_t[length + 1]; - userinfo.nation_len = length; - if (length) { - memcpy(userinfo.nation, (wchar_t *)(*(DWORD *)(address + 0x208)), - (length + 1) * sizeof(wchar_t)); - } else { - ZeroMemory(userinfo.nation, (length + 1) * sizeof(wchar_t)); - } - - length = *(DWORD *)(address + 0x220); - userinfo.province = new wchar_t[length + 1]; - userinfo.province_len = length; - if (length) { - memcpy(userinfo.province, (wchar_t *)(*(DWORD *)(address + 0x21C)), - (length + 1) * sizeof(wchar_t)); - } else { - ZeroMemory(userinfo.province, (length + 1) * sizeof(wchar_t)); - } - - length = *(DWORD *)(address + 0x234); - userinfo.city = new wchar_t[length + 1]; - userinfo.city_len = length; - if (length) { - memcpy(userinfo.city, (wchar_t *)(*(DWORD *)(address + 0x230)), - (length + 1) * sizeof(wchar_t)); - } else { - ZeroMemory(userinfo.city, (length + 1) * sizeof(wchar_t)); - } - - userinfo.sex = *(DWORD *)(address + 0x1BC); - userinfo.over = true; -} - -void DeleteUserInfoCache() { - if (userinfo.keyword) { - delete userinfo.keyword; - } - if (userinfo.v2) { - delete userinfo.v2; - } - if (userinfo.v3) { - delete userinfo.v3; - } - if (userinfo.nickname) { - delete userinfo.nickname; - } - if (userinfo.nation) { - delete userinfo.nation; - } - if (userinfo.province) { - delete userinfo.province; - } - if (userinfo.city) { - delete userinfo.city; - } - if (userinfo.signature) { - delete userinfo.signature; - } - if (userinfo.small_image) { - delete userinfo.small_image; - } - if (userinfo.big_image) { - delete userinfo.big_image; - } - ZeroMemory(&userinfo, sizeof(UserInfo)); - userinfo.error_code = 1; -} - -__declspec(naked) void HandleErrorCode() { - __asm { - PUSHAD; - PUSHFD; - PUSH ESI; - CALL SetErrorCode; - ADD ESP, 0x4; - POPFD; - POPAD; - CALL error_code_next_addr_; - JMP error_code_back_addr_; - } -} - -__declspec(naked) void HandleUserInfoDetail() { - __asm { - PUSHAD; - PUSHFD; - PUSH dword ptr [EBP + 0x14]; - CALL SetUserInfoDetail; - ADD ESP, 0x4; - POPFD; - POPAD; - CALL user_info_next_addr_; - JMP user_info_back_addr_; - } -} - -int HookSearchContact() { - DWORD base = Utils::GetWeChatWinBase(); - if (!base) { - return -1; - } - if (search_contact_flag_) { - return 2; - } - DWORD hook_error_code_addr = base + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET; - error_code_next_addr_ = base + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSET; - error_code_back_addr_ = hook_error_code_addr + 0x5; - Utils::HookAnyAddress(hook_error_code_addr, (LPVOID)HandleErrorCode, - error_code_asm_code_); - - DWORD hook_user_info_addr = base + WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET; - user_info_next_addr_ = base + WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSET; - user_info_back_addr_ = hook_user_info_addr + 0x5; - - Utils::HookAnyAddress(hook_user_info_addr, (LPVOID)HandleUserInfoDetail, - user_info_asm_code_); - error_code_flag_ = true; - user_info_flag_ = true; - return 1; -} - -int UnHookSearchContact() { - DWORD base = Utils::GetWeChatWinBase(); - DWORD hook_user_info_addr = base + WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET; - DWORD hook_error_code_addr = base + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET; - - if (!user_info_flag_) return 2; - Utils::UnHookAnyAddress(hook_user_info_addr, user_info_asm_code_); - user_info_flag_ = false; - - if (!error_code_flag_) return 2; - Utils::UnHookAnyAddress(hook_error_code_addr, error_code_asm_code_); - error_code_flag_ = false; - - return 1; -} -} // namespace hooks -} // namespace wxhelper \ No newline at end of file diff --git a/src/hooks.h b/src/hooks.h deleted file mode 100644 index 960712e..0000000 --- a/src/hooks.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef WXHELPER_HOOKS_H_ -#define WXHELPER_HOOKS_H_ -#include "Windows.h" -#include "wechat_function.h" -namespace wxhelper { -namespace hooks { -extern UserInfo userinfo; -extern bool user_info_flag_ ; - -int HookRecvMsg(char* client_ip, int port); - -int UnHookRecvMsg(); - -void SendSocketMessage(InnerMessageStruct* msg); - -int HookLog(); -int UnHookLog(); -int HookSearchContact(); -int UnHookSearchContact(); -void DeleteUserInfoCache(); -} // namespace hooks -} // namespace wxhelper -#endif \ No newline at end of file diff --git a/src/http_handler.cc b/src/http_handler.cc deleted file mode 100644 index 8450ca6..0000000 --- a/src/http_handler.cc +++ /dev/null @@ -1,598 +0,0 @@ -#include "pch.h" -#include "http_handler.h" - -#include - -#include "utils.h" -#include "account_mgr.h" -#include "api_route.h" -#include "chat_room_mgr.h" -#include "contact_mgr.h" -#include "db.h" -#include "easylogging++.h" -#include "hooks.h" -#include "misc_mgr.h" -#include "send_message_mgr.h" -#include "sns_mgr.h" -#include "global_context.h" -#include "hooks.h" - -using namespace std; -using namespace nlohmann; - -namespace wxhelper { -string GetParamOfGetReq(mg_http_message *hm, string name) { - string ret; - char *buffer = new char[hm->query.len + 1]; - ZeroMemory(buffer, hm->query.len + 1); - int len = mg_http_get_var(&hm->query, name.c_str(), buffer, hm->query.len); - if (len > 0) ret = string(buffer, len); - delete[] buffer; - buffer = NULL; - return ret; -} - -int GetIntParam(json data, string key) { - int result; - try { - result = data[key].get(); - } catch (json::exception) { - result = STRING2INT(data[key].get()); - } - return result; -} - -wstring GetWStringParam(json data, string key) { - return Utils::UTF8ToWstring(data[key].get()); -} - -unsigned long long GetULong64Param(json j_data, string key) { - unsigned long long result = 0; - try { - result = j_data[key].get(); - } catch (json::exception) { - string value = j_data[key].get(); - istringstream is(value); - is >> result; - } - return result; -} - -static vector getArrayParam(json j_data, string key) { - vector result; - wstring param = GetWStringParam(j_data, key); - result = Utils::split(param, L','); - return result; -} - -string Dispatch(struct mg_connection *c, struct mg_http_message *hm) { - int is_post = 0; - string ret; - if (mg_vcasecmp(&hm->method, "POST") == 0) { - is_post = 1; - } - el::Logger *defaultLogger = el::Loggers::getLogger("default"); - defaultLogger->info("method: %v body: %v", hm->method.ptr, hm->body.ptr); - LOG_IF(is_post != 1, INFO) << "request method is not post"; - - if (is_post == 0) { - json ret_data = {{"result", "ERROR"}, {"msg", "not support method"}}; - ret = ret_data.dump(); - return ret; - } - - json j_param = - json::parse(hm->body.ptr, hm->body.ptr + hm->body.len, nullptr, false); - if (hm->body.len != 0 && j_param.is_discarded() == true) { - json ret_data = {{"result", "ERROR"}, {"msg", "json string is invalid."}}; - ret = ret_data.dump(); - return ret; - } - int api_number = STRING2INT(GetParamOfGetReq(hm, "type")); - GlobalContext& g_context = GlobalContext::GetInstance(); - switch (api_number) { - case WECHAT_IS_LOGIN: { - int success = -1; - success = g_context.account_mgr->CheckLogin(); - json ret_data = {{"result", "OK"}, {"code", success}}; - ret = ret_data.dump(); - break; - } - case WECHAT_GET_SELF_INFO: { - SelfInfoInner self_info; - int success = g_context.account_mgr->GetSelfInfo(self_info); - json ret_data = {{"result", "OK"}, {"code", success}}; - if (success) { - json j_info = { - {"name", self_info.name}, - {"city", self_info.city}, - {"province", self_info.province}, - {"country", self_info.country}, - {"account", self_info.account}, - {"wxid", self_info.wxid}, - {"mobile", self_info.mobile}, - {"headImage", self_info.head_img}, - {"signature", self_info.signature}, - {"dataSavePath", self_info.data_save_path}, - {"currentDataPath", self_info.current_data_path}, - {"dbKey", self_info.db_key}, - }; - ret_data["data"] = j_info; - } - ret = ret_data.dump(); - break; - } - case WECHAT_MSG_SEND_TEXT: { - wstring wxid = GetWStringParam(j_param, "wxid"); - wstring msg = GetWStringParam(j_param, "msg"); - int success = g_context.send_mgr->SendText(WS2LPWS(wxid), WS2LPWS(msg)); - json ret_data = {{"result", "OK"}, {"code", success}}; - ret = ret_data.dump(); - break; - } - case WECHAT_MSG_SEND_AT: { - wstring chat_room_id = GetWStringParam(j_param, "chatRoomId"); - vector wxids = getArrayParam(j_param, "wxids"); - wstring msg = GetWStringParam(j_param, "msg"); - vector wxid_list; - for (unsigned int i = 0; i < wxids.size(); i++) { - wxid_list.push_back(WS2LPWS(wxids[i])); - } - int success = g_context.send_mgr->SendAtText(WS2LPWS(chat_room_id), wxid_list.data(), - wxid_list.size(), WS2LPWS(msg)); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_MSG_SEND_CARD: { - break; - } - case WECHAT_MSG_SEND_IMAGE: { - wstring receiver = GetWStringParam(j_param, "wxid"); - wstring img_path = GetWStringParam(j_param, "imagePath"); - int success = - g_context.send_mgr->SendImage(WS2LPWS(receiver), WS2LPWS(img_path)); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_MSG_SEND_FILE: { - wstring receiver = GetWStringParam(j_param, "wxid"); - wstring file_path = GetWStringParam(j_param, "filePath"); - int success = - g_context.send_mgr->SendFile(WS2LPWS(receiver), WS2LPWS(file_path)); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_MSG_SEND_ARTICLE: { - break; - } - case WECHAT_MSG_SEND_APP: { - break; - } - case WECHAT_MSG_START_HOOK: { - int port = GetIntParam(j_param, "port"); - wstring ip = GetWStringParam(j_param, "ip"); - string client_ip = Utils::WstringToUTF8(ip); - char ip_cstr[16]; - strcpy_s(ip_cstr, client_ip.c_str()); - int success = hooks::HookRecvMsg(ip_cstr, port); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_MSG_STOP_HOOK: { - int success = hooks::UnHookRecvMsg(); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_MSG_START_IMAGE_HOOK: { - break; - } - case WECHAT_MSG_STOP_IMAGE_HOOK: { - break; - } - case WECHAT_MSG_START_VOICE_HOOK: { - break; - } - case WECHAT_MSG_STOP_VOICE_HOOK: { - break; - } - case WECHAT_CONTACT_GET_LIST: { - break; - } - case WECHAT_CONTACT_CHECK_STATUS: { - break; - } - case WECHAT_CONTACT_DEL: { - break; - } - case WECHAT_CONTACT_SEARCH_BY_CACHE: { - break; - } - case WECHAT_CONTACT_SEARCH_BY_NET: { - wstring keyword = GetWStringParam(j_param, "keyword"); - UserInfo *user = nullptr; - int success = g_context.misc_mgr->SearchContactNetScene(WS2LPWS(keyword), &user); - json ret_data = {{"code", success}, {"result", "OK"}}; - if (user) { - json info = { - {"bigImage", Utils::WCharToUTF8(user->big_image)}, - {"smallImage", Utils::WCharToUTF8(user->small_image)}, - {"city", Utils::WCharToUTF8(user->city)}, - {"nation", Utils::WCharToUTF8(user->nation)}, - {"nickname", Utils::WCharToUTF8(user->nickname)}, - {"province", Utils::WCharToUTF8(user->province)}, - {"sex", user->sex}, - {"signature", Utils::WCharToUTF8(user->signature)}, - {"v2", Utils::WCharToUTF8(user->v2)}, - {"v3", Utils::WCharToUTF8(user->v3)}, - }; - ret_data["userInfo"] = info; - } - ret = ret_data.dump(); - break; - } - case WECHAT_CONTACT_ADD_BY_WXID: { - wstring user_id = GetWStringParam(j_param, "wxid"); - wstring msg = GetWStringParam(j_param, "msg"); - int success = g_context.contact_mgr->AddFriendByWxid(WS2LPWS(user_id),WS2LPWS(msg)); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_CONTACT_ADD_BY_V3: { - break; - } - case WECHAT_CONTACT_ADD_BY_PUBLIC_ID: { - break; - } - case WECHAT_CONTACT_VERIFY_APPLY: { - wstring v3 = GetWStringParam(j_param, "v3"); - wstring v4 = GetWStringParam(j_param, "v4"); - int success = g_context.contact_mgr->VerifyApply(WS2LPWS(v3),WS2LPWS(v4)); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_CONTACT_EDIT_REMARK: { - break; - } - case WECHAT_CHATROOM_GET_MEMBER_LIST: { - wstring room_id = GetWStringParam(j_param, "chatRoomId"); - ChatRoomInner out{0}; - int success = g_context.chat_room_mgr->GetMemberFromChatRoom(WS2LPWS(room_id), out); - json ret_data = {{"code", success}, {"result", "OK"}}; - if (success) { - json member_info = { - {"admin", Utils::WstringToUTF8(out.admin)}, - {"chatRoomId", Utils::WstringToUTF8(out.chat_room)}, - {"members", out.members}, - }; - ret_data["data"] = member_info; - } - ret = ret_data.dump(); - break; - } - case WECHAT_CHATROOM_GET_MEMBER_NICKNAME: { - wstring room_id = GetWStringParam(j_param, "chatRoomId"); - wstring member_id = GetWStringParam(j_param, "memberId"); - - wstring nickname =g_context.chat_room_mgr->GetChatRoomMemberNickname( - WS2LPWS(room_id), WS2LPWS(member_id)); - json ret_data = {{"code", 1}, - {"result", "OK"}, - {"nickname", Utils::WstringToUTF8(nickname)}}; - ret = ret_data.dump(); - break; - } - case WECHAT_CHATROOM_DEL_MEMBER: { - wstring room_id = GetWStringParam(j_param, "chatRoomId"); - vector wxids = getArrayParam(j_param, "memberIds"); - vector wxid_list; - for (unsigned int i = 0; i < wxids.size(); i++) { - wxid_list.push_back(WS2LPWS(wxids[i])); - } - int success = g_context.chat_room_mgr->DelMemberFromChatRoom( - WS2LPWS(room_id), wxid_list.data(), wxid_list.size()); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_CHATROOM_ADD_MEMBER: { - wstring room_id = GetWStringParam(j_param, "chatRoomId"); - vector wxids = getArrayParam(j_param, "memberIds"); - vector wxid_list; - for (unsigned int i = 0; i < wxids.size(); i++) { - wxid_list.push_back(WS2LPWS(wxids[i])); - } - int success = g_context.chat_room_mgr->AddMemberToChatRoom( - WS2LPWS(room_id), wxid_list.data(), wxid_list.size()); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_CHATROOM_SET_ANNOUNCEMENT: { - break; - } - case WECHAT_CHATROOM_SET_CHATROOM_NAME: { - break; - } - case WECHAT_CHATROOM_SET_SELF_NICKNAME: { - wstring room_id = GetWStringParam(j_param, "chatRoomId"); - wstring wxid = GetWStringParam(j_param, "wxid"); - wstring nick = GetWStringParam(j_param, "nickName"); - int success = g_context.chat_room_mgr->ModChatRoomMemberNickName( - WS2LPWS(room_id), WS2LPWS(wxid), WS2LPWS(nick)); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_DATABASE_GET_HANDLES: { - vector v_ptr = DB::GetInstance().GetDbHandles(); - json ret_data = {{"data", json::array()}, {"result", "OK"}}; - for (unsigned int i = 0; i < v_ptr.size(); i++) { - json db_info; - db_info["tables"] = json::array(); - DatabaseInfo *db = reinterpret_cast(v_ptr[i]); - db_info["handle"] = db->handle; - wstring dbname(db->db_name); - db_info["databaseName"] = Utils::WstringToUTF8(dbname); - for (auto table : db->tables) { - json table_info = {{"name", table.name}, - {"tableName", table.table_name}, - {"sql", table.sql}, - {"rootpage", table.rootpage}}; - db_info["tables"].push_back(table_info); - } - ret_data["data"].push_back(db_info); - } - ret = ret_data.dump(); - break; - } - case WECHAT_DATABASE_BACKUP: { - break; - } - case WECHAT_DATABASE_QUERY: { - DWORD db_handle = GetIntParam(j_param, "dbHandle"); - wstring sql = GetWStringParam(j_param, "sql"); - string sql_str = Utils::WstringToUTF8(sql); - vector> items; - int success = DB::GetInstance().Select(db_handle, sql_str.c_str(), items); - json ret_data = { - {"data", json::array()}, {"code", success}, {"result", "OK"}}; - if (success == 0) { - ret = ret_data.dump(); - break; - } - for (auto it : items) { - json temp_arr = json::array(); - for (size_t i = 0; i < it.size(); i++) { - temp_arr.push_back(it[i]); - } - ret_data["data"].push_back(temp_arr); - } - ret = ret_data.dump(); - break; - } - case WECHAT_SET_VERSION: { - break; - } - case WECHAT_LOG_START_HOOK: { - int success = hooks::HookLog(); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_LOG_STOP_HOOK: { - int success = hooks::UnHookLog(); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_BROWSER_OPEN_WITH_URL: { - break; - } - case WECHAT_GET_PUBLIC_MSG: { - break; - } - case WECHAT_MSG_FORWARD_MESSAGE: { - wstring wxid = GetWStringParam(j_param, "wxid"); - ULONG64 msgid = GetULong64Param(j_param, "msgid"); - int success =g_context.send_mgr->ForwardMsg(WS2LPWS(wxid), msgid); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_GET_QRCODE_IMAGE: { - break; - } - case WECHAT_GET_A8KEY: { - break; - } - case WECHAT_MSG_SEND_XML: { - break; - } - case WECHAT_LOGOUT: { - int success = g_context.account_mgr->Logout(); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_GET_TRANSFER: { - wstring wxid = GetWStringParam(j_param, "wxid"); - wstring transcationid = GetWStringParam(j_param, "transcationId"); - wstring transferid = GetWStringParam(j_param, "transferId"); - BOOL response =g_context.misc_mgr->DoConfirmReceipt( - WS2LPWS(wxid), WS2LPWS(transcationid), WS2LPWS(transferid)); - json ret_data = {{"msg", response}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_GET_CONTACT_ALL: { - vector vec; - int success = g_context.contact_mgr->GetAllContact(vec); - json ret_data = { - {"data", json::array()}, {"code", success}, {"result", "OK"}}; - - for (unsigned int i = 0; i < vec.size(); i++) { - json item = { - {"customAccount", - vec[i].custom_account.length > 0 - ? vec[i].custom_account.ptr != nullptr - ? Utils::WCharToUTF8(vec[i].custom_account.ptr) - : string() - : string()}, - {"delFlag", vec[i].del_flag}, - {"userName", vec[i].encrypt_name.length > 0 - ? vec[i].encrypt_name.ptr != nullptr - ? Utils::WCharToUTF8(vec[i].encrypt_name.ptr) - : string() - : string()}, - {"type", vec[i].type}, - {"verifyFlag", vec[i].verify_flag}, - {"verifyFlag", vec[i].verify_flag}, - {"wxid", vec[i].wxid.length > 0 - ? Utils::WCharToUTF8(vec[i].wxid.ptr) - : string()}, - }; - ret_data["data"].push_back(item); - } - ret = ret_data.dump(); - break; - } - case WECHAT_GET_CHATROOM_INFO: { - wstring room_id = GetWStringParam(j_param, "chatRoomId"); - ChatRoomInfoInner chat_room_detail{0}; - int success = g_context.chat_room_mgr->GetChatRoomDetailInfo(WS2LPWS(room_id), - chat_room_detail); - json ret_data = {{"code", success}, {"result", "OK"}}; - if (!success) { - break; - } - json detail = { - {"chatRoomId", - chat_room_detail.chat_room_id.length > 0 - ? Utils::WCharToUTF8(chat_room_detail.chat_room_id.ptr) - : string()}, - {"notice", chat_room_detail.notice.length > 0 - ? Utils::WCharToUTF8(chat_room_detail.notice.ptr) - : string()}, - {"admin", chat_room_detail.admin.length > 0 - ? Utils::WCharToUTF8(chat_room_detail.admin.ptr) - : string()}, - {"xml", chat_room_detail.xml.length > 0 - ? Utils::WCharToUTF8(chat_room_detail.xml.ptr) - : string()}, - }; - ret_data["data"] = detail; - ret = ret_data.dump(); - break; - } - case WECHAT_GET_IMG_BY_NAME: { - wstring image_path = GetWStringParam( j_param, "imagePath"); - wstring save_path = GetWStringParam( j_param, "savePath"); - int success = - g_context.misc_mgr->GetImgByName(WS2LPWS(image_path),WS2LPWS(save_path)); json - ret_data = {{"code", success}, {"result", "OK"}}; ret = - ret_data.dump(); - break; - } - case WECHAT_DO_OCR: { - wstring image_path = GetWStringParam(j_param, "imagePath"); - string text(""); - int success = g_context.misc_mgr->DoOCRTask(WS2LPWS(image_path), text); - json ret_data = {{"code", success}, {"result", "OK"}, {"text", text}}; - ret = ret_data.dump(); - break; - } - case WECHAT_SEND_PAT_MSG: { - wstring room_id = GetWStringParam(j_param, "chatRoomId"); - wstring wxid = GetWStringParam(j_param, "wxid"); - int success = g_context.misc_mgr->SendPatMsg(WS2LPWS(room_id), WS2LPWS(wxid)); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_SET_TOP_MSG: { - wstring wxid = GetWStringParam(j_param, "wxid"); - ULONG64 msgid = GetULong64Param(j_param, "msgid"); - int success = g_context.chat_room_mgr->SetTopMsg(WS2LPWS(wxid), msgid); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_REMOVE_TOP_MSG: { - wstring room_id = GetWStringParam(j_param, "chatRoomId"); - ULONG64 msgid = GetULong64Param(j_param, "msgid"); - int success = g_context.chat_room_mgr->RemoveTopMsg(WS2LPWS(room_id), msgid); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_SNS_GET_FIRST_PAGE: { - int success = g_context.sns_mgr->GetFirstPage(); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_SNS_GET_NEXT_PAGE: { - ULONG64 snsid = GetULong64Param(j_param, "snsId"); - int success = g_context.sns_mgr->GetNextPage(snsid); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_CONTACT_NAME: { - wstring pri_id = GetWStringParam(j_param, "id"); - wstring name = g_context.contact_mgr->GetContactOrChatRoomNickname(WS2LPWS(pri_id)); - json ret_data = { - {"code", 1}, {"result", "OK"}, {"name", Utils::WstringToUTF8(name)}}; - ret = ret_data.dump(); - break; - } - case WECHAT_ATTACH_DOWNLOAD: { - ULONG64 msg_id = GetULong64Param(j_param, "msgId"); - int success = g_context.misc_mgr->DoDownloadTask(msg_id); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - case WECHAT_GET_VOICE: { - ULONG64 msg_id = GetULong64Param(j_param, "msgId"); - wstring voice_dir = GetWStringParam(j_param, "voiceDir"); - int success = g_context.misc_mgr->GetVoice(msg_id, WS2LPWS(voice_dir)); - json ret_data = {{"code", success}, {"result", "OK"}}; - ret = ret_data.dump(); - break; - } - default: - break; - } - - return ret; -} - -HttpHandler::HttpHandler() {} -HttpHandler::~HttpHandler() {} -void HttpHandler::HandlerRequest(struct mg_connection *c, void *ev_data) { - struct mg_http_message *hm = (struct mg_http_message *)ev_data; - string ret = R"({"result":"OK"})"; - if (mg_http_match_uri(hm, "/api/")) { - try { - ret = Dispatch(c, hm); - } catch (json::exception &e) { - json res = {{"result", "ERROR"}, {"msg", e.what()}}; - ret = res.dump(); - } - if (ret != "") { - mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s\n", ret.c_str()); - } - } else { - mg_http_reply(c, 500, NULL, "%s", "Invalid URI"); - } -} - -} // namespace wxhelper \ No newline at end of file diff --git a/src/http_handler.h b/src/http_handler.h deleted file mode 100644 index 828d678..0000000 --- a/src/http_handler.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef WXHELPER_HTTP_HANDLER_H_ -#define WXHELPER_HTTP_HANDLER_H_ -#include "handler.h" -#include "mongoose.h" -#include -#include -#include -namespace wxhelper { -class HttpHandler : public Handler { - public: - HttpHandler(); - ~HttpHandler(); - void HandlerRequest(struct mg_connection *c, void *ev_data); -}; - -} // namespace wxhelper -#endif diff --git a/src/http_server.cc b/src/http_server.cc deleted file mode 100644 index 0a839fd..0000000 --- a/src/http_server.cc +++ /dev/null @@ -1,100 +0,0 @@ -#include "pch.h" -#include "http_server.h" - -#include - -#include "api_route.h" - -#pragma comment(lib, "ws2_32.lib") -using namespace std; -using namespace nlohmann; - -namespace wxhelper { -HttpServer& HttpServer::GetInstance() { - static HttpServer p; - return p; -} - -void HttpServer::Init(int port) { - port_ = port; - running_ = false; - http_handler_ = new HttpHandler(); - mg_mgr_init(&mgr_); - -} - -HttpServer::~HttpServer() { - mg_mgr_free(&mgr_); - delete http_handler_; -} - -bool HttpServer::HttpStart() { - if (running_) { - return true; - } -#ifdef _DEBUG - Utils::CreateConsole(); -#endif - running_ = true; - thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartHttpServer, NULL, - NULL, 0); - return true; -} - -void HttpServer::StartHttpServer() { - string lsten_addr = "http://0.0.0.0:" + to_string(GetInstance().port_); - mg_http_listen(&GetInstance().mgr_, lsten_addr.c_str(), EventHandler, - &GetInstance().mgr_); - for (;;) mg_mgr_poll(&GetInstance().mgr_, 1000); -} - -void HttpServer::EventHandler(struct mg_connection *c, - int ev, void *ev_data, void *fn_data) { - if (ev == MG_EV_OPEN) { - // c->is_hexdumping = 1; - } else if (ev == MG_EV_HTTP_MSG) { - struct mg_http_message *hm = (struct mg_http_message *)ev_data; - if (mg_http_match_uri(hm, "/websocket")) { - mg_ws_upgrade(c, hm, NULL); - } else if (mg_http_match_uri(hm, "/api/")) { - GetInstance().HandleHttpRequest(c,hm); - } else { - mg_http_reply(c, 500, NULL, "%s", "Invalid URI"); - } - } else if (ev == MG_EV_WS_MSG) { - - GetInstance().HandleWebsocketRequest(c,ev_data); - } - (void)fn_data; -} - -void HttpServer::HandleHttpRequest(struct mg_connection *c, - void *ev_data) { - - http_handler_->HandlerRequest(c,ev_data); -} - -void HttpServer::HandleWebsocketRequest(struct mg_connection *c, - void *ev_data) { - // Got websocket frame. Received data is wm->data. Echo it back! - struct mg_ws_message *wm = (struct mg_ws_message *)ev_data; - mg_ws_send(c, wm->data.ptr, wm->data.len, WEBSOCKET_OP_TEXT); -} - -bool HttpServer::HttpClose() { - if (!running_) { - return true; - } - #ifdef _DEBUG - Utils::CloseConsole(); - #endif - running_ = false; - if (thread_) { - WaitForSingleObject(thread_, -1); - CloseHandle(thread_); - thread_ = NULL; - } - return true; -} - -} // namespace wxhelper \ No newline at end of file diff --git a/src/http_server.h b/src/http_server.h deleted file mode 100644 index b4b170c..0000000 --- a/src/http_server.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef WXHELPER_HTTP_SERVER_H_ -#define WXHELPER_HTTP_SERVER_H_ - -#include - -#include "http_handler.h" -namespace wxhelper { -class HttpServer { - public: - static HttpServer &GetInstance(); - bool HttpStart(); - bool HttpClose(); - void Init(int port); - - private: - HttpServer(){}; - HttpServer(const HttpServer &) = delete; - HttpServer &operator=(const HttpServer &) = delete; - ~HttpServer(); - static void StartHttpServer(); - static void EventHandler(struct mg_connection *c, int ev, void *ev_data, - void *fn_data); - void HandleHttpRequest(struct mg_connection *c, void *ev_data); - void HandleWebsocketRequest(struct mg_connection *c, void *ev_data); - - private: - int port_; - bool running_; - struct mg_mgr mgr_; - HttpHandler *http_handler_; - HANDLE thread_; -}; -} // namespace wxhelper - -#endif diff --git a/src/log.cc b/src/log.cc deleted file mode 100644 index c955235..0000000 --- a/src/log.cc +++ /dev/null @@ -1,37 +0,0 @@ -#include "log.h" - -#include "easylogging++.h" -INITIALIZE_EASYLOGGINGPP -namespace wxhelper { -Log::Log(/* args */) {} - -Log::~Log() {} - -void Log::Initialize() { - - el::Configurations conf; - // 启用日志 - conf.setGlobally(el::ConfigurationType::Enabled, "true"); - // 设置日志文件目录以及文件名 - conf.setGlobally(el::ConfigurationType::Filename, - "log\\log_%datetime{%Y%M%d %H%m%s}.log"); - // 设置日志文件最大文件大小 - conf.setGlobally(el::ConfigurationType::MaxLogFileSize, "20971520"); - // 是否写入文件 - conf.setGlobally(el::ConfigurationType::ToFile, "true"); - // 是否输出控制台 - conf.setGlobally(el::ConfigurationType::ToStandardOutput, "true"); - // 设置日志输出格式 - conf.setGlobally(el::ConfigurationType::Format, - "[%datetime] [%thread] [%loc] [%level] : %msg"); - // 设置日志文件写入周期,如下每100条刷新到输出流中 - #ifdef _DEBUG - conf.setGlobally(el::ConfigurationType::LogFlushThreshold, "1"); - #else - conf.setGlobally(el::ConfigurationType::LogFlushThreshold, "100"); - #endif - // 设置配置文件 - el::Loggers::reconfigureAllLoggers(conf); -} - -} // namespace wxhelper \ No newline at end of file diff --git a/src/log.h b/src/log.h deleted file mode 100644 index 9718263..0000000 --- a/src/log.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef WXHELPER_LOG_H_ -#define WXHELPER_LOG_H_ -namespace wxhelper{ - class Log - { - private: - /* data */ - public: - Log(/* args */); - ~Log(); - void Initialize(); - }; - - - -} - -#endif \ No newline at end of file diff --git a/src/misc_mgr.cc b/src/misc_mgr.cc deleted file mode 100644 index 8462307..0000000 --- a/src/misc_mgr.cc +++ /dev/null @@ -1,436 +0,0 @@ -#include "misc_mgr.h" - -#include "pch.h" -#include "wechat_function.h" -#include "base64.h" -#include "db.h" -#include "hooks.h" -#include "easylogging++.h" -#define BUFSIZE 1024 - -#define JPEG0 0xFF -#define JPEG1 0xD8 -#define JPEG2 0xFF -#define PNG0 0x89 -#define PNG1 0x50 -#define PNG2 0x4E -#define BMP0 0x42 -#define BMP1 0x4D -#define GIF0 0x47 -#define GIF1 0x49 -#define GIF2 0x46 -using namespace std; -namespace wxhelper { -MiscMgr::MiscMgr(DWORD base) : BaseMgr::BaseMgr(base) {} -MiscMgr::~MiscMgr() {} -int MiscMgr::SendPatMsg(wchar_t *chat_room_id, wchar_t *wxid) { - int success = -1; - WeChatString chat_room(chat_room_id); - WeChatString self_wxid(wxid); - DWORD get_pat_mgr_addr = base_addr_ + WX_PAT_MGR_OFFSET; - DWORD send_pat_msg_addr = base_addr_ + WX_SEND_PAT_MSG_OFFSET; - DWORD ret_addr = base_addr_ + WX_RET_OFFSET; - __asm { - PUSHAD - CALL get_pat_mgr_addr - PUSH ret_addr - PUSH 0x0 - PUSH EAX - LEA ECX,chat_room - LEA EDX,self_wxid - CALL send_pat_msg_addr - ADD ESP,0xc - MOVZX EAX,AL - MOV success,EAX - POPAD - } - return success; -} - -int MiscMgr::DoOCRTask(wchar_t *img_path, std::string &result) { - int success = -1; - WeChatString path(img_path); - WeChatString null_obj = {0}; - WeChatString ocr_result = {0}; - DWORD ocr_manager_addr = base_addr_ + WX_OCR_MANAGER_OFFSET; - DWORD do_ocr_task_addr = base_addr_ + WX_DO_OCR_TASK_OFFSET; - DWORD init_addr = base_addr_ + WX_INIT_OBJ_OFFSET; - DWORD flag = 0; - __asm { - PUSHAD - PUSHFD - LEA ECX,ocr_result - CALL init_addr - CALL ocr_manager_addr - LEA ECX,null_obj - PUSH ECX - LEA ECX,flag - PUSH ECX - LEA ECX,ocr_result - PUSH ECX - PUSH 0x0 - LEA ECX,path - PUSH ECX - MOV ECX,EAX - CALL do_ocr_task_addr - MOV success,EAX - POPFD - POPAD - } - - if (success == 0) { - DWORD addr = (DWORD)&ocr_result; - DWORD ptr = *(DWORD *)addr; - DWORD num = *(DWORD *)(addr + 0x4); - if (num <= 0) { - return success; - } - - DWORD header = *(DWORD *)ptr; - for (unsigned int i = 0; i < num - 1; i++) { - DWORD content = *(DWORD *)header; - result += Utils::WstringToUTF8(READ_WSTRING(content, 0x14)); - result += "\r\n"; - header = content; - } - } - return success; -} - -int MiscMgr::DoConfirmReceipt(wchar_t *wxid, wchar_t *transcationid, - wchar_t *transferid) { - int success = -1; - WeChatString recv_id(wxid); - WeChatString transcation_id(transcationid); - WeChatString transfer_id(transferid); - char pay_info[0x134] = {0}; - DWORD new_pay_info_addr = base_addr_ + WX_NEW_WCPAYINFO_OFFSET; - DWORD free_pay_info_addr = base_addr_ + WX_FREE_WCPAYINFO_OFFSET; - DWORD do_confirm_addr = base_addr_ + WX_CONFIRM_RECEIPT_OFFSET; - __asm { - PUSHAD - LEA ECX,pay_info - CALL new_pay_info_addr - MOV dword ptr [pay_info + 0x4], 0x1 - MOV dword ptr [pay_info + 0x4C], 0x1 - POPAD - } - memcpy(&pay_info[0x1c], &transcation_id, sizeof(transcation_id)); - memcpy(&pay_info[0x38], &transfer_id, sizeof(transfer_id)); - - __asm { - PUSHAD - PUSH 0x1 - SUB ESP,0x8 - LEA EDX,recv_id - LEA ECX,pay_info - CALL do_confirm_addr - MOV success,EAX - ADD ESP,0xC - PUSH 0x0 - LEA ECX,pay_info - CALL free_pay_info_addr - POPAD - } - - return success; -} - -int MiscMgr::DoDownloadTask(ULONG64 msg_id) { - int success = -1; - int db_index = 0; - int local_id = DB::GetInstance().GetLocalIdByMsgId(msg_id, db_index); - if (local_id < 1) { - return -2; - } - - char chat_msg[0x2D8] = {0}; - DWORD new_chat_msg_addr = base_addr_ + WX_NEW_CHAT_MSG_OFFSET; - DWORD get_chat_mgr_addr = base_addr_ + WX_CHAT_MGR_OFFSET; - DWORD pre_download_mgr_addr = base_addr_ + WX_GET_PRE_DOWNLOAD_MGR_OFFSET; - DWORD push_attach_task_addr = base_addr_ + WX_PUSH_ATTACH_TASK_OFFSET; - DWORD free_addr = base_addr_ + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET; - DWORD get_by_local_Id_addr = base_addr_ + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET; - DWORD get_current_data_path_addr = base_addr_ + WX_GET_CURRENT_DATA_PATH_OFFSET; - DWORD free_app_msg_info_addr = base_addr_ + WX_FREE_APP_MSG_INFO_OFFSET; - DWORD push_thumb_task_addr = base_addr_ + WX_PUSH_THUMB_TASK_OFFSET; - DWORD video_mgr_addr = base_addr_ + WX_VIDEO_MGR_OFFSET; - DWORD download_video_image_addr = base_addr_ + WX_VIDEO_MGR_OFFSET; - - WeChatString current_data_path; - - __asm { - PUSHAD - PUSHFD - LEA ECX,current_data_path - CALL get_current_data_path_addr - - LEA ECX,chat_msg - CALL new_chat_msg_addr - - CALL get_chat_mgr_addr - PUSH dword ptr [db_index] - LEA ECX,chat_msg - PUSH dword ptr [local_id] - CALL get_by_local_Id_addr - ADD ESP,0x8 - POPFD - POPAD - } - wstring save_path = L""; - wstring thumb_path = L""; - if (current_data_path.length > 0) { - save_path += current_data_path.ptr; - save_path += L"wxhelper"; - } else { - return -1; - } - - if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) { - return -3; - } - DWORD type = *(DWORD *)(chat_msg + 0x38); - wchar_t *content = *(wchar_t **)(chat_msg + 0x70); - - switch (type) { - case 0x3: { - save_path += L"\\image"; - if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) { - return -3; - } - save_path = save_path +L"\\"+ to_wstring(msg_id) + L".png"; - break; - } - case 0x3E: - case 0x2B: { - save_path += L"\\video"; - if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) { - return -3; - } - thumb_path = save_path + L"\\"+ to_wstring(msg_id) + L".jpg"; - save_path = save_path + L"\\"+ to_wstring(msg_id) + L".mp4"; - - break; - } - case 0x31: { - save_path += L"\\file"; - wcout << save_path << endl; - if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) { - return -3; - } - char xml_app_msg[0xC80] = {0}; - DWORD new_app_msg_addr = base_addr_ + WX_APP_MSG_INFO_OFFSET; - DWORD get_xml_addr = base_addr_ + WX_GET_APP_MSG_XML_OFFSET; - WeChatString w_content(content); - - __asm { - PUSHAD - PUSHFD - LEA ECX,xml_app_msg - CALL new_app_msg_addr - PUSH 0x1 - LEA EAX,w_content - PUSH EAX - LEA ECX,xml_app_msg - CALL get_xml_addr - MOV success,EAX - LEA ECX,xml_app_msg - CALL free_app_msg_info_addr - POPFD - POPAD - } - if (success != 1) { - return -4; - } - WeChatString *file_name = (WeChatString *)((DWORD)xml_app_msg + 0x44); - save_path = save_path +L"\\" + to_wstring(msg_id) + L"_" + - wstring(file_name->ptr, file_name->length); - break; - } - default: - break; - } - WeChatString w_save_path(save_path); - WeChatString w_thumb_path(thumb_path); - int temp =1; - memcpy(&chat_msg[0x19C], &w_thumb_path, sizeof(w_thumb_path)); - memcpy(&chat_msg[0x1B0], &w_save_path, sizeof(w_save_path)); - memcpy(&chat_msg[0x29C], &temp, sizeof(temp)); - // note: the image has been downloaded and will not be downloaded again - // use low-level method - // this function does not work, need to modify chatmsg. - // if (type == 0x3E || type == 0x2B){ - // __asm{ - // PUSHAD - // PUSHFD - // CALL video_mgr_addr - // LEA ECX,chat_msg - // PUSH ECX - // MOV ECX,EAX - // CALL download_video_image_addr - // POPFD - // POPAD - // } - // } - - __asm { - PUSHAD - PUSHFD - CALL pre_download_mgr_addr - PUSH 0x1 - PUSH 0x0 - LEA ECX,chat_msg - PUSH ECX - MOV ECX,EAX - CALL push_attach_task_addr - MOV success,EAX - LEA ECX,chat_msg - PUSH 0x0 - CALL free_addr - POPFD - POPAD - } - - return success; -} - -int MiscMgr::GetVoice(ULONG64 msg_id, wchar_t *dir) { - int success = -1; - string buff = DB::GetInstance().GetVoiceBuffByMsgId(msg_id); - if (buff.size() == 0) { - success = 0; - return success; - } - wstring save_path = wstring(dir); - if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) { - success = -2; - return success; - } - save_path = save_path + L"\\" + to_wstring(msg_id) + L".amr"; - HANDLE file_handle = CreateFileW(save_path.c_str(), GENERIC_ALL, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (file_handle == INVALID_HANDLE_VALUE) { - #ifdef _DEBUG - wcout <<" save_path =" < 0) { - for (unsigned int i = 0; i < bytes_read; i++) { - buffer[i]^=key; - } - } - if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) { - CloseHandle(h_origin_file); - CloseHandle(save_img); - return 0; - } - - do { - if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) { - if (key > 0) { - for (unsigned int i = 0; i < bytes_read; i++) { - buffer[i] ^= key; - } - } - if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) { - CloseHandle(h_origin_file); - CloseHandle(save_img); - return 0; - } - } - } while (bytes_read == BUFSIZE); - CloseHandle(h_origin_file); - CloseHandle(save_img); - return 1; -} - -int MiscMgr::SearchContactNetScene(wchar_t *keyword,UserInfo ** user) { - int success = -1; - hooks::HookSearchContact(); - hooks::DeleteUserInfoCache(); - DWORD search_contact_mgr_addr = base_addr_ + WX_SEARCH_CONTACT_MGR_OFFSET; - DWORD search_contact_addr = base_addr_ + WX_SEARCH_CONTACT_OFFSET; - WeChatString key(keyword); - - __asm { - pushad; - pushfd; - call search_contact_mgr_addr; - lea ebx, key; - push ebx; - mov ecx, eax; - call search_contact_addr; - popfd; - popad; - } - success = 1; - while (hooks::userinfo.error_code == 1 && hooks::user_info_flag_) { - Sleep(20); - } - if (hooks::userinfo.error_code == 0) { - while (hooks::userinfo.over == false && hooks::user_info_flag_) { - Sleep(20); - } - } - *user= &hooks::userinfo; - LOG(INFO)<<"user:" < -#include "Windows.h" -#include "base_mgr.h" -#include "wechat_function.h" -namespace wxhelper { -class MiscMgr :public BaseMgr{ - public: - MiscMgr(DWORD base); - ~MiscMgr(); - int SendPatMsg(wchar_t* chat_room_id, wchar_t* wxid); - int DoOCRTask(wchar_t* img_path, std::string& result); - int DoConfirmReceipt(wchar_t* wxid, wchar_t* transcationid, - wchar_t* transferid); - int DoDownloadTask(ULONG64 msg_id); - - int GetVoice(ULONG64 msg_id, wchar_t* dir); - int GetImgByName(wchar_t* file_path,wchar_t* save_dir); - int SearchContactNetScene(wchar_t *keyword,UserInfo ** user); -}; -} // namespace wxhelper - -#endif \ No newline at end of file diff --git a/src/new_sqlite3.h b/src/new_sqlite3.h deleted file mode 100644 index 28323f5..0000000 --- a/src/new_sqlite3.h +++ /dev/null @@ -1,195 +0,0 @@ -#ifndef NEW_SQLITE3_H_ -#define NEW_SQLITE3_H_ -#include "Windows.h" -#define SQLITE_OK 0 /* Successful result */ -/* beginning-of-error-codes */ -#define SQLITE_ERROR 1 /* Generic error */ -#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ -#define SQLITE_PERM 3 /* Access permission denied */ -#define SQLITE_ABORT 4 /* Callback routine requested an abort */ -#define SQLITE_BUSY 5 /* The database file is locked */ -#define SQLITE_LOCKED 6 /* A table in the database is locked */ -#define SQLITE_NOMEM 7 /* A malloc() failed */ -#define SQLITE_READONLY 8 /* Attempt to write a readonly database */ -#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ -#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ -#define SQLITE_CORRUPT 11 /* The database disk image is malformed */ -#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */ -#define SQLITE_FULL 13 /* Insertion failed because database is full */ -#define SQLITE_CANTOPEN 14 /* Unable to open the database file */ -#define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Internal use only */ -#define SQLITE_SCHEMA 17 /* The database schema changed */ -#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ -#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ -#define SQLITE_MISMATCH 20 /* Data type mismatch */ -#define SQLITE_MISUSE 21 /* Library used incorrectly */ -#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ -#define SQLITE_AUTH 23 /* Authorization denied */ -#define SQLITE_FORMAT 24 /* Not used */ -#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ -#define SQLITE_NOTADB 26 /* File opened that is not a database file */ -#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ -#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ -#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ -#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ -/* end-of-error-codes */ - -/* -** CAPI3REF: Extended Result Codes -** KEYWORDS: {extended result code definitions} -** -** In its default configuration, SQLite API routines return one of 30 integer -** [result codes]. However, experience has shown that many of -** these result codes are too coarse-grained. They do not provide as -** much information about problems as programmers might like. In an effort to -** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8] -** and later) include -** support for additional result codes that provide more detailed information -** about errors. These [extended result codes] are enabled or disabled -** on a per database connection basis using the -** [sqlite3_extended_result_codes()] API. Or, the extended code for -** the most recent error can be obtained using -** [sqlite3_extended_errcode()]. -*/ -#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1 << 8)) -#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2 << 8)) -#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3 << 8)) -#define SQLITE_IOERR_READ (SQLITE_IOERR | (1 << 8)) -#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2 << 8)) -#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3 << 8)) -#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4 << 8)) -#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5 << 8)) -#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6 << 8)) -#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7 << 8)) -#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8 << 8)) -#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9 << 8)) -#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10 << 8)) -#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11 << 8)) -#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12 << 8)) -#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13 << 8)) -#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14 << 8)) -#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15 << 8)) -#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16 << 8)) -#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17 << 8)) -#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18 << 8)) -#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19 << 8)) -#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20 << 8)) -#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21 << 8)) -#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22 << 8)) -#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23 << 8)) -#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24 << 8)) -#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25 << 8)) -#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26 << 8)) -#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27 << 8)) -#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28 << 8)) -#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29 << 8)) -#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30 << 8)) -#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31 << 8)) -#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32 << 8)) -#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33 << 8)) -#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1 << 8)) -#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2 << 8)) -#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1 << 8)) -#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2 << 8)) -#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3 << 8)) -#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1 << 8)) -#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2 << 8)) -#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3 << 8)) -#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4 << 8)) -#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5 << 8)) /* Not Used */ -#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6 << 8)) -#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1 << 8)) -#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2 << 8)) -#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3 << 8)) -#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1 << 8)) -#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2 << 8)) -#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3 << 8)) -#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4 << 8)) -#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5 << 8)) -#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6 << 8)) -#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2 << 8)) -#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1 << 8)) -#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2 << 8)) -#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3 << 8)) -#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4 << 8)) -#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5 << 8)) -#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6 << 8)) -#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7 << 8)) -#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8 << 8)) -#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9 << 8)) -#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT | (10 << 8)) -#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT | (11 << 8)) -#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT | (12 << 8)) -#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1 << 8)) -#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2 << 8)) -#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1 << 8)) -#define SQLITE_AUTH_USER (SQLITE_AUTH | (1 << 8)) -#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1 << 8)) -#define SQLITE_OK_SYMLINK (SQLITE_OK | (2 << 8)) /* internal use only */ - - -#define SQLITE_INTEGER 1 -#define SQLITE_FLOAT 2 -#define SQLITE_BLOB 4 -#define SQLITE_NULL 5 -#define SQLITE_TEXT 3 - -#define SQLITE3_EXEC_OFFSET 0x1e24f70 -#define SQLITE3_BACKUP_INIT_OFFSET 0x1dea900 -#define SQLITE3_PREPARE_OFFSET 0x1e2b8c0 -#define SQLITE3_OPEN_OFFSET 0x1e598b0 -#define SQLITE3_BACKUP_STEP_OFFSET 0x1dead00 -#define SQLITE3_BACKUP_REMAINING_OFFSET 0x1deb440 -#define SQLITE3_BACKUP_PAGECOUNT_OFFSET 0x1deb450 -#define SQLITE3_BACKUP_FINISH_OFFSET 0x1deb340 -#define SQLITE3_SLEEP_OFFSET 0x1e5a0f0 -#define SQLITE3_ERRCODE_OFFSET 0x1e58550 -#define SQLITE3_CLOSE_OFFSET 0x1e56cd0 -#define SQLITE3_STEP_OFFSET 0x1df3770 -#define SQLITE3_COLUMN_COUNT_OFFSET 0x1df3c80 -#define SQLITE3_COLUMN_NAME_OFFSET 0x1df4570 -#define SQLITE3_COLUMN_TYPE_OFFSET 0x1df4410 -#define SQLITE3_COLUMN_BLOB_OFFSET 0x1df3cc0 -#define SQLITE3_COLUMN_BYTES_OFFSET 0x1df3da0 -#define SQLITE3_FINALIZE_OFFSET 0x1df2740 - -typedef int (*Sqlite3_callback)(void*, int, char**, char**); - -typedef int(__cdecl* Sqlite3_exec)(DWORD, /* An open database */ - const char* sql, /* SQL to be evaluated */ - Sqlite3_callback, /* Callback function */ - void*, /* 1st argument to callback */ - char** errmsg /* Error msg written here */ -); -typedef DWORD(__cdecl* Sqlite3_backup_init)( - DWORD* pDest, /* Destination database handle */ - const char* zDestName, /* Destination database name */ - DWORD* pSource, /* Source database handle */ - const char* zSourceName /* Source database name */ -); -typedef int(__cdecl* Sqlite3_prepare)( - DWORD db, /* Database handle */ - const char* zSql, /* SQL statement, UTF-8 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - DWORD** ppStmt, /* OUT: Statement handle */ - const char** pzTail /* OUT: Pointer to unused portion of zSql */ -); -typedef int(__cdecl* Sqlite3_open)(const char* filename, DWORD** ppDb); -typedef int(__cdecl* Sqlite3_backup_step)(DWORD* p, int nPage); -typedef int(__cdecl* Sqlite3_backup_remaining)(DWORD* p); -typedef int(__cdecl* Sqlite3_backup_pagecount)(DWORD* p); -typedef int(__cdecl* Sqlite3_backup_finish)(DWORD* p); -typedef int(__cdecl* Sqlite3_sleep)(int); -typedef int(__cdecl* Sqlite3_errcode)(DWORD* db); -typedef int(__cdecl* Sqlite3_close)(DWORD*); - -typedef int(__cdecl* Sqlite3_step)(DWORD*); -typedef int(__cdecl* Sqlite3_column_count)(DWORD* pStmt); -typedef const char*(__cdecl* Sqlite3_column_name)(DWORD*, int N); -typedef int(__cdecl* Sqlite3_column_type)(DWORD*, int iCol); -typedef const void*(__cdecl* Sqlite3_column_blob)(DWORD*, int iCol); -typedef int(__cdecl* Sqlite3_column_bytes)(DWORD*, int iCol); -typedef int(__cdecl* Sqlite3_finalize)(DWORD* pStmt); - -#endif \ No newline at end of file diff --git a/src/pch.h b/src/pch.h deleted file mode 100644 index 7dc3789..0000000 --- a/src/pch.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef PCH_H -#define PCH_H - - -#define GLOG_NO_ABBREVIATED_SEVERITIES -#include "framework.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "Windows.h" -#include "utils.h" - -#endif // PCH_H - - diff --git a/src/send_message_mgr.cc b/src/send_message_mgr.cc deleted file mode 100644 index ec71383..0000000 --- a/src/send_message_mgr.cc +++ /dev/null @@ -1,236 +0,0 @@ -#include "pch.h" -#include "send_message_mgr.h" - -#include "easylogging++.h" - -#include "wechat_function.h" -#include "db.h" -#include "contact_mgr.h" - -namespace wxhelper { -SendMessageMgr::SendMessageMgr(DWORD base):BaseMgr(base) {} -SendMessageMgr::~SendMessageMgr() {} -int SendMessageMgr::SendText(wchar_t* wxid, wchar_t* msg) { - int success = -1; - WeChatString to_user(wxid); - WeChatString text_msg(msg); - wchar_t** msg_pptr = &text_msg.ptr; - DWORD send_message_mgr_addr = base_addr_ + WX_SEND_MESSAGE_MGR_OFFSET; - DWORD send_text_msg_addr = base_addr_ + WX_SEND_TEXT_OFFSET; - DWORD free_chat_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET; - char chat_msg[0x2D8] = {0}; - __asm { - PUSHAD - CALL send_message_mgr_addr - PUSH 0x0 - PUSH 0x0 - PUSH 0x0 - PUSH 0x1 - PUSH 0x0 - MOV EAX,msg_pptr - PUSH EAX - LEA EDX,to_user - LEA ECX,chat_msg - CALL send_text_msg_addr - MOV success,EAX - ADD ESP,0x18 - LEA ECX,chat_msg - CALL free_chat_msg_addr - POPAD - } - LOG_IF((success == -1), ERROR) << "SendText fail"; - return success; -} -int SendMessageMgr::SendAtText(wchar_t* chat_room_id, wchar_t** wxids, int len, - wchar_t* msg) { - int success = -1; - WeChatString * at_users = new WeChatString[len+1]; - std::wstring at_msg = L""; - int number =0; - for (int i = 0; i < len; i++) { - std::wstring nickname; - if (!lstrcmpiW((wchar_t *)wxids[i], (wchar_t *)L"notify@all")) { - nickname = L"所有人"; - } else { - ContactMgr contact{base_addr_}; - nickname = contact.GetContactOrChatRoomNickname(wxids[i]); - } - if (nickname.length() == 0) { - continue; - } - - WeChatString temp = {0}; - temp.ptr = (wchar_t *)wxids[i]; - temp.length = wcslen((wchar_t *)wxids[i]); - temp.max_length = wcslen((wchar_t *)wxids[i]) * 2; - memcpy(&at_users[number], &temp, sizeof(WeChatString)); - at_msg = at_msg + L"@" + nickname + L" "; - number++; - } - if (number < 1){ - return success; - } - std::wstring origin(msg); - at_msg += origin; - AtInner at_list = {0}; - at_list.start = (DWORD)at_users; - at_list.finsh = (DWORD)&at_users[number]; - at_list.end = (DWORD)&at_users[number]; - WeChatString to_user(chat_room_id); - WeChatString text_msg((wchar_t *)at_msg.c_str()); - wchar_t **msg_pptr = &text_msg.ptr; - - DWORD send_message_mgr_addr = base_addr_ + WX_SEND_MESSAGE_MGR_OFFSET; - DWORD send_text_msg_addr = base_addr_ + WX_SEND_TEXT_OFFSET; - DWORD free_chat_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET; - char chat_msg[0x2D8] = {0}; - __asm{ - PUSHAD - CALL send_message_mgr_addr - PUSH 0x0 - PUSH 0x0 - PUSH 0x0 - PUSH 0x1 - LEA EAX,at_list - PUSH EAX - MOV EAX,msg_pptr - PUSH EAX - LEA EDX,to_user - LEA ECX,chat_msg - CALL send_text_msg_addr - MOV success,EAX - ADD ESP,0x18 - LEA ECX,chat_msg - CALL free_chat_msg_addr - POPAD - } - LOG_IF((success == -1), ERROR) << "SendText fail"; - return success; -} -int SendMessageMgr::SendImage(wchar_t* wxid, wchar_t* image_path) { - int success = -1; - WeChatString to_user(wxid); - WeChatString path(image_path); - char chat_msg[0x2D8] = {0}; - DWORD send_message_mgr_addr = base_addr_ + WX_SEND_MESSAGE_MGR_OFFSET; - DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; - DWORD send_image_msg_addr = base_addr_ + WX_SEND_IMAGE_OFFSET; - DWORD free_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET; - DWORD temp = 0; - WeChatString null_obj = {0}; - __asm { - PUSHAD - CALL send_message_mgr_addr - SUB ESP,0x14 - MOV temp,EAX - LEA EAX,null_obj - MOV ECX,ESP - LEA EDI,path - PUSH EAX - CALL init_chat_msg_addr - MOV ECX,dword ptr [temp] - LEA EAX,to_user - PUSH EDI - PUSH EAX - LEA EAX,chat_msg - PUSH EAX - CALL send_image_msg_addr - MOV success,EAX - LEA ECX,chat_msg - CALL free_msg_addr - POPAD - } - LOG_IF((success == -1), ERROR) << "SendImage fail"; - return success; -} -int SendMessageMgr::SendFile(wchar_t* wxid, wchar_t* file_path) { - int success = -1; - WeChatString to_user(wxid); - WeChatString path(file_path); - char chat_msg[0x2D8] = {0}; - DWORD app_msg_mgr_addr = base_addr_ + WX_APP_MSG_MGR_OFFSET; - DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; - DWORD send_file_addr = base_addr_ + WX_SEND_FILE_OFFSET; - DWORD free_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET; - DWORD temp = 0; - WeChatString null_obj = {0}; - __asm { - PUSHAD - PUSHFD - CALL app_msg_mgr_addr - SUB ESP,0x14 - MOV temp,EAX - LEA EAX,null_obj - MOV ECX,ESP - PUSH EAX - CALL init_chat_msg_addr - PUSH 0x0 - SUB ESP,0x14 - MOV EDI,ESP - MOV dword ptr [EDI],0 - MOV dword ptr [EDI + 0x4],0 - MOV dword ptr [EDI + 0x8],0 - MOV dword ptr [EDI + 0xc],0 - MOV dword ptr [EDI + 0x10],0 - SUB ESP,0x14 - LEA EAX,path - MOV ECX,ESP - PUSH EAX - CALL init_chat_msg_addr - SUB ESP,0x14 - LEA EAX,to_user - MOV ECX,ESP - PUSH EAX - CALL init_chat_msg_addr - MOV ECX,dword ptr [temp] - LEA EAX,chat_msg - PUSH EAX - CALL send_file_addr - MOV AL,byte ptr [eax + 0x38] - MOVZX EAX,AL - MOV success,EAX - LEA ECX,chat_msg - CALL free_msg_addr - POPFD - POPAD - } - if (success == 0x31) { - return 1; - } - LOG_IF((success == -1), ERROR) << "SendFile fail"; - return success; -} - -int SendMessageMgr::ForwardMsg(wchar_t* wxid, unsigned long long msgid) { - int success = 0; - - int db_index = 0; - int localid = DB::GetInstance().GetLocalIdByMsgId(msgid, db_index); - - if (localid == 0) return 0; - WeChatString to_user(wxid); - DWORD forward_msg_addr = base_addr_ + WX_FORWARD_MSG_OFFSET; - DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET; - __asm { - PUSHAD - PUSHFD - MOV EDX, DWORD PTR [db_index] - PUSH EDX - MOV EAX, DWORD PTR [localid] - PUSH EAX - SUB ESP,0x14 - MOV ECX,ESP - LEA ESI,to_user - PUSH ESI - CALL init_chat_msg_addr - XOR ECX,ECX - CALL forward_msg_addr - MOVZX EAX,AL - MOV success,EAX - ADD ESP,0x1c - POPFD - POPAD - } - return success; -} -} // namespace wxhelper \ No newline at end of file diff --git a/src/send_message_mgr.h b/src/send_message_mgr.h deleted file mode 100644 index 7e34db5..0000000 --- a/src/send_message_mgr.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef WXHELPER_SEND_MESSAGE_MGR_H_ -#define WXHELPER_SEND_MESSAGE_MGR_H_ -#include "base_mgr.h" -namespace wxhelper { -class SendMessageMgr:public BaseMgr { - public: - explicit SendMessageMgr(DWORD base); - ~SendMessageMgr(); - int SendText(wchar_t* wxid, wchar_t* msg); - int SendAtText(wchar_t* chat_room_id, wchar_t** wxids, int len, wchar_t* msg); - int SendImage(wchar_t *wxid, wchar_t *image_path); - int SendFile(wchar_t *wxid, wchar_t *file_path); - int ForwardMsg(wchar_t *wxid, unsigned long long msgid); - - private: -}; -} // namespace wxhelper -#endif \ No newline at end of file diff --git a/src/singleton.h b/src/singleton.h deleted file mode 100644 index 826a09c..0000000 --- a/src/singleton.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef WXHELPER_SINGLETON_H_ -#define WXHELPER_SINGLETON_H_ -template -class Singleton { - protected: - Singleton() {} - ~Singleton() {} - - Singleton(const Singleton&) = delete; - Singleton& operator=(const Singleton&) = delete; - - Singleton(Singleton&&) = delete; - Singleton& operator=(Singleton&&) = delete; - - public: - static T& GetInstance() { - static T instance{}; - return instance; - } -}; -#endif diff --git a/src/sns_mgr.cc b/src/sns_mgr.cc deleted file mode 100644 index 274e91d..0000000 --- a/src/sns_mgr.cc +++ /dev/null @@ -1,52 +0,0 @@ -#include "pch.h" -#include "sns_mgr.h" - - -#include "wechat_function.h" - - -namespace wxhelper { -SNSMgr::SNSMgr(DWORD base):BaseMgr(base) {} -SNSMgr::~SNSMgr() {} -int SNSMgr::GetFirstPage() { - int success = -1; - DWORD sns_data_mgr_addr = base_addr_ + WX_SNS_DATA_MGR_OFFSET; - DWORD get_first_page_addr = base_addr_ + WX_SNS_GET_FIRST_PAGE_OFFSET; - - char buff[0xB44] = {}; - __asm { - PUSHAD - CALL sns_data_mgr_addr - PUSH 0x1 - LEA ECX,buff - PUSH ECX - MOV ECX,EAX - CALL get_first_page_addr - MOV success,EAX - POPAD - } - - return success; -} -int SNSMgr::GetNextPage(ULONG64 sns_id) { - int success = -1; - DWORD sns_data_mgr_addr = base_addr_ + WX_SNS_DATA_MGR_OFFSET; - DWORD get_next_page_addr = base_addr_ + WX_SNS_GET_NEXT_PAGE_OFFSET; - VectorInner temp = {}; - __asm { - PUSHAD - CALL sns_data_mgr_addr - LEA ECX,temp - PUSH ECX - MOV EBX,dword ptr [sns_id + 0x4] - PUSH EBX - MOV EDI,dword ptr [sns_id ] - PUSH EDI - MOV ECX,EAX - CALL get_next_page_addr - MOV success,EAX - POPAD - } - return success; -} -} // namespace wxhelper \ No newline at end of file diff --git a/src/sns_mgr.h b/src/sns_mgr.h deleted file mode 100644 index cb90059..0000000 --- a/src/sns_mgr.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef WXHELPER_SNS_MGR_H_ -#define WXHELPER_SNS_MGR_H_ -#include "Windows.h" -#include "base_mgr.h" -namespace wxhelper{ - class SNSMgr:public BaseMgr{ - public: - explicit SNSMgr(DWORD base); - ~SNSMgr(); - int GetFirstPage(); - int GetNextPage(ULONG64 sns_id); - }; -} -#endif \ No newline at end of file diff --git a/src/utils.cc b/src/utils.cc deleted file mode 100644 index d92bd2b..0000000 --- a/src/utils.cc +++ /dev/null @@ -1,214 +0,0 @@ -#include "utils.h" - -#include "pch.h" - -namespace wxhelper { -std::wstring Utils::UTF8ToWstring(const std::string &str) { - return Utils::AnsiToWstring(str, CP_UTF8); -} - -std::string Utils::WstringToUTF8(const std::wstring &str) { - return Utils::WstringToAnsi(str, CP_UTF8); -} - -std::wstring Utils::AnsiToWstring(const std::string &input, DWORD locale) { - int wchar_len = MultiByteToWideChar(locale, 0, input.c_str(), -1, NULL, 0); - if (wchar_len > 0) { - std::vector temp(wchar_len); - MultiByteToWideChar(CP_UTF8, 0, input.c_str(), -1, &temp[0], wchar_len); - return std::wstring(&temp[0]); - } - - return std::wstring(); -} - -std::string Utils::WstringToAnsi(const std::wstring &input, DWORD locale) { - int char_len = WideCharToMultiByte(locale, 0, input.c_str(), -1, 0, 0, 0, 0); - if (char_len > 0) { - std::vector temp(char_len); - WideCharToMultiByte(locale, 0, input.c_str(), -1, &temp[0], char_len, 0, 0); - return std::string(&temp[0]); - } - return std::string(); -} - -DWORD Utils::GetWeChatWinBase() { - return (DWORD)GetModuleHandleA("WeChatWin.dll"); -} - -bool Utils::CreateConsole() { - if (AllocConsole()) { - AttachConsole(GetCurrentProcessId()); - FILE *retStream; - freopen_s(&retStream, "CONOUT$", "w", stdout); - if (!retStream) throw std::runtime_error("Stdout redirection failed."); - freopen_s(&retStream, "CONOUT$", "w", stderr); - if (!retStream) throw std::runtime_error("Stderr redirection failed."); - return false; - } - return true; -} - -void Utils::CloseConsole() { - fclose(stdin); - fclose(stdout); - fclose(stderr); - FreeConsole(); -} - -std::string Utils::EncodeHexString(const std::string &str) { - const std::string hex_table = "0123456789abcdef"; - std::string sb; - for (int i = 0; i < str.length(); i++) { - sb += hex_table.at((str[i] & 0xf0) >> 4); - sb += hex_table.at((str[i] & 0x0f) >> 0); - } - return sb; -} - -std::string Utils::Hex2String(const std::string &hex_str) { - std::string ret; - const std::string hex_table = "0123456789abcdef"; - for (int i = 0; i < hex_str.length(); i += 2) { - ret += BYTE(hex_table.find(hex_str.at(i)) << 4 | - hex_table.find(hex_str.at(i + 1))); - } - return ret; -} - -std::string Utils::Bytes2Hex(const BYTE *bytes, const int length) { - if (bytes == NULL) { - return ""; - } - std::string buff; - const int len = length; - for (int j = 0; j < len; j++) { - int high = bytes[j] / 16, low = bytes[j] % 16; - buff += (high < 10) ? ('0' + high) : ('a' + high - 10); - buff += (low < 10) ? ('0' + low) : ('a' + low - 10); - } - return buff; -} - -void Utils::Hex2Bytes(const std::string &hex, BYTE *bytes) { - int byte_len = hex.length() / 2; - std::string str; - unsigned int n; - for (int i = 0; i < byte_len; i++) { - str = hex.substr(i * 2, 2); - sscanf_s(str.c_str(), "%x", &n); - bytes[i] = n; - } -} - -bool Utils::IsDigit(std::string str) { - if (str.length() == 0) { - return false; - } - for (auto it : str) { - if (it < '0' || it > '9') { - return false; - } - } - return true; -} - -bool Utils::FindOrCreateDirectoryW(const wchar_t *path) { - WIN32_FIND_DATAW fd; - HANDLE hFind = ::FindFirstFileW(path, &fd); - if (hFind != INVALID_HANDLE_VALUE && - (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - FindClose(hFind); - return true; - } - - if (!::CreateDirectoryW(path, NULL)) { - return false; - } - return true; -} - -void Utils::HookAnyAddress(DWORD hook_addr, LPVOID jmp_addr, char *origin) { - BYTE jmp_code[5] = {0}; - jmp_code[0] = 0xE9; - *(DWORD *)&jmp_code[1] = (DWORD)jmp_addr - hook_addr - 5; - DWORD old_protext = 0; - VirtualProtect((LPVOID)hook_addr, 5, PAGE_EXECUTE_READWRITE, &old_protext); - ReadProcessMemory(GetCurrentProcess(), (LPVOID)hook_addr, origin, 5, 0); - memcpy((void *)hook_addr, jmp_code, 5); - VirtualProtect((LPVOID)hook_addr, 5, old_protext, &old_protext); -} - -void Utils::UnHookAnyAddress(DWORD hook_addr, char *origin) { - DWORD old_protext = 0; - VirtualProtect((LPVOID)hook_addr, 5, PAGE_EXECUTE_READWRITE, &old_protext); - WriteProcessMemory(GetCurrentProcess(), (LPVOID)hook_addr, origin, 5, 0); - VirtualProtect((LPVOID)hook_addr, 5, old_protext, &old_protext); -} - -std::wstring Utils::GetTimeW(long long timestamp) { - wchar_t *wstr = new wchar_t[20]; - memset(wstr, 0, 20 * 2); - tm tm_out; - localtime_s(&tm_out, ×tamp); - swprintf_s(wstr, 20, L"%04d-%02d-%02d %02d:%02d:%02d", 1900 + tm_out.tm_year, - tm_out.tm_mon + 1, tm_out.tm_mday, tm_out.tm_hour, tm_out.tm_min, - tm_out.tm_sec); - std::wstring str_time(wstr); - delete[] wstr; - return str_time; -} - -std::string Utils::WCharToUTF8(wchar_t *wstr) { - int c_size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, FALSE); - if (c_size > 0) { - char *buffer = new char[c_size]; - WideCharToMultiByte(CP_UTF8, 0, wstr, -1, buffer, c_size, NULL, FALSE); - std::string str(buffer); - delete[] buffer; - buffer = NULL; - return str; - } - return std::string(); -} - -bool Utils::IsTextUtf8(const char *str,int length) { - char endian = 1; - bool littlen_endian = (*(char *)&endian == 1); - - size_t i; - int bytes_num; - unsigned char chr; - - i = 0; - bytes_num = 0; - while (i < length) { - if (littlen_endian) { - chr = *(str + i); - } else { // Big Endian - chr = (*(str + i) << 8) | *(str + i + 1); - i++; - } - - if (bytes_num == 0) { - if ((chr & 0x80) != 0) { - while ((chr & 0x80) != 0) { - chr <<= 1; - bytes_num++; - } - if ((bytes_num < 2) || (bytes_num > 6)) { - return false; - } - bytes_num--; - } - } else { - if ((chr & 0xC0) != 0x80) { - return false; - } - bytes_num--; - } - i++; - } - return (bytes_num == 0); -} -} // namespace wxhelper \ No newline at end of file diff --git a/src/utils.h b/src/utils.h deleted file mode 100644 index 284c324..0000000 --- a/src/utils.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef WXHELPER_UTILS_H_ -#define WXHELPER_UTILS_H_ -#include - -#include -#include -#define STRING2INT(str) (Utils::IsDigit(str) ? stoi(str) : 0) -#define WS2LPWS(wstr) (LPWSTR) wstr.c_str() -#define READ_WSTRING(addr, offset) ((*(DWORD *)(addr + offset + 0x4) == 0) ? std::wstring(L"") : std::wstring((wchar_t *)(*(DWORD *)(addr + offset)), *(DWORD *)(addr + offset + 0x4))) - - -namespace wxhelper { - -class Utils { - public: - static std::wstring UTF8ToWstring(const std::string &str); - - static std::string WstringToUTF8(const std::wstring &str); - - static std::wstring AnsiToWstring(const std::string &input, - DWORD locale = CP_ACP); - - static std::string WstringToAnsi(const std::wstring &input, - DWORD locale = CP_ACP); - - static DWORD GetWeChatWinBase(); - - static bool CreateConsole(); - - static void CloseConsole(); - - static std::string EncodeHexString(const std::string &str); - - static std::string Hex2String(const std::string &hex_str); - - static std::string Bytes2Hex(const BYTE *bytes, const int length); - - static void Hex2Bytes(const std::string &hex, BYTE *bytes); - - static bool IsDigit(std::string str); - - static bool FindOrCreateDirectoryW(const wchar_t *path); - - static void HookAnyAddress(DWORD hook_addr, LPVOID jmp_addr, char *origin); - static void UnHookAnyAddress(DWORD hook_addr, char *origin); - static std::wstring GetTimeW(long long timestamp); - - static std::string WCharToUTF8(wchar_t *wstr); - - static bool IsTextUtf8(const char * str,int length) ; - - template - static std::vector split(T1 str, T2 letter) { - std::vector arr; - size_t pos; - while ((pos = str.find_first_of(letter)) != T1::npos) { - T1 str1 = str.substr(0, pos); - arr.push_back(str1); - str = str.substr(pos + 1, str.length() - pos - 1); - } - arr.push_back(str); - return arr; - } - - template - static T1 replace(T1 source, T2 replaced, T1 replaceto) { - std::vector v_arr = split(source, replaced); - if (v_arr.size() < 2) return source; - T1 temp; - for (unsigned int i = 0; i < v_arr.size() - 1; i++) { - temp += v_arr[i]; - temp += replaceto; - } - temp += v_arr[v_arr.size() - 1]; - return temp; - } -}; -} // namespace wxhelper -#endif \ No newline at end of file diff --git a/src/wechat_function.h b/src/wechat_function.h deleted file mode 100644 index a8719eb..0000000 --- a/src/wechat_function.h +++ /dev/null @@ -1,772 +0,0 @@ -#ifndef WXHELPER_WECHAT_FUNCTION_H_ -#define WXHELPER_WECHAT_FUNCTION_H_ -#include -#include - -// snsDataMgr -#define WX_SNS_DATA_MGR_OFFSET 0xc39680 -// chatRoomMgr -#define WX_CHAT_ROOM_MGR_OFFSET 0x78cf20 -// contactMgr -#define WX_CONTACT_MGR_OFFSET 0x75a4a0 -// syncMgr -#define WX_SYNC_MGR_OFFSET 0xa87fd0 -// preDownloadMgr -#define WX_GET_PRE_DOWNLOAD_MGR_OFFSET 0x80f110 -// chatMgr -#define WX_CHAT_MGR_OFFSET 0x792700 -// videoMgr -#define WX_VIDEO_MGR_OFFSET 0x829820 -// patMgr -#define WX_PAT_MGR_OFFSET 0x931730 -// searchContactMgr -#define WX_SEARCH_CONTACT_MGR_OFFSET 0xa6cb00 -// appMsgMgr -#define WX_APP_MSG_MGR_OFFSET 0x76ae20 -// sendMessageMgr -#define WX_SEND_MESSAGE_MGR_OFFSET 0x768140 - - -// setChatMsgValue -#define WX_INIT_CHAT_MSG_OFFSET 0xf59e40 - -// chatMsg -#define WX_NEW_CHAT_MSG_OFFSET 0x76f010 -#define WX_FREE_CHAT_MSG_OFFSET 0x756960 -#define WX_FREE_CHAT_MSG_2_OFFSET 0x6f4ea0 -#define WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET 0x756e30 - - -//sns -#define WX_SNS_GET_FIRST_PAGE_OFFSET 0x14e2140 -#define WX_SNS_GET_NEXT_PAGE_OFFSET 0x14e21e0 - -//chat room -#define WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET 0xbde090 -// chatRoomInfo -#define WX_NEW_CHAT_ROOM_INFO_OFFSET 0xe99c40 -#define WX_FREE_CHAT_ROOM_INFO_OFFSET 0xe99f40 -#define WX_DEL_CHAT_ROOM_MEMBER_OFFSET 0xbd22a0 -#define WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET 0xbd1dc0 - - -// chatRoom -#define WX_INIT_CHAT_ROOM_OFFSET 0xe97890 -#define WX_FREE_CHAT_ROOM_OFFSET 0xe97ab0 - -#define WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET 0xbdf260 -#define WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET 0xbd9680 - -#define WX_TOP_MSG_OFFSET 0xbe1840 -#define WX_REMOVE_TOP_MSG_OFFSET 0xbe1620 - -#define WX_GET_MEMBER_NICKNAME_OFFSET 0xbdf3f0 - -#define WX_FREE_CONTACT_OFFSET 0xea7880 - -// wcpayinfo -#define WX_NEW_WCPAYINFO_OFFSET 0x7b2e60 -#define WX_FREE_WCPAYINFO_OFFSET 0x79c250 -#define WX_CONFIRM_RECEIPT_OFFSET 0x15e2c20 - - -//contact -#define WX_CONTACT_GET_LIST_OFFSET 0xc089f0 -#define WX_CONTACT_DEL_OFFSET 0xb9b3b0 - -#define WX_SET_VALUE_OFFSET 0x1f80900 -#define WX_DO_DEL_CONTACT_OFFSET 0xca6480 -#define WX_GET_CONTACT_OFFSET 0xc04e00 -#define WX_DO_VERIFY_USER_OFFSET 0xc02100 -#define WX_VERIFY_MSG_OFFSET 0xf59d40 -#define WX_VERIFY_OK_OFFSET 0xa18bd0 -#define WX_NEW_ADD_FRIEND_HELPER_OFFSET 0xa17d50 -#define WX_FREE_ADD_FRIEND_HELPER_OFFSET 0xa17e70 - -// pushAttachTask - - -#define WX_PUSH_ATTACH_TASK_OFFSET 0x82bb40 - -#define WX_FREE_CHAT_MSG_OFFSET 0x756960 -#define WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET 0xbc0370 -#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc872c0 -#define WX_APP_MSG_INFO_OFFSET 0x7b3d20 -#define WX_GET_APP_MSG_XML_OFFSET 0xe628a0 -#define WX_FREE_APP_MSG_INFO_OFFSET 0x79d900 -#define WX_PUSH_THUMB_TASK_OFFSET 0x82ba40 -#define WX_DOWNLOAD_VIDEO_IMG_OFFSET 0xd46c30 - - - - - -// pat -#define WX_SEND_PAT_MSG_OFFSET 0x1421940 -#define WX_RET_OFFSET 0x1D58751 - - -//search hook -#define WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET 0xe17054 -#define WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSET 0xf57a20 -#define WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET 0xa8ceb0 -#define WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSET 0xa8d100 -#define WX_SEARCH_CONTACT_OFFSET 0xcd1510 - - - -//login -#define WX_LOGOUT_OFFSET 0xe58870 -#define WX_ACCOUNT_SERVICE_OFFSET 0x768c80 -#define WX_GET_APP_DATA_SAVE_PATH_OFFSET 0xf3a610 -#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc872c0 - - -//forward -#define WX_FORWARD_MSG_OFFSET 0xce6730 -// send file -#define WX_SEND_FILE_OFFSET 0xb6d1f0 -// send image -#define WX_SEND_IMAGE_OFFSET 0xce6640 -// send text -#define WX_SEND_TEXT_OFFSET 0xce6c80 - - -//ocr -#define WX_INIT_OBJ_OFFSET 0x80a800 -#define WX_OCR_MANAGER_OFFSET 0x80f270 -#define WX_DO_OCR_TASK_OFFSET 0x13da3e0 - - -//storage - -#define CONTACT_G_PINSTANCE_OFFSET 0x2ffddc8 -#define DB_MICRO_MSG_OFFSET 0x68 -#define DB_CHAT_MSG_OFFSET 0x1C0 -#define DB_MISC_OFFSET 0x3D8 -#define DB_EMOTION_OFFSET 0x558 -#define DB_MEDIA_OFFSET 0x9B8 -#define DB_BIZCHAT_MSG_OFFSET 0x1120 -#define DB_FUNCTION_MSG_OFFSET 0x11B0 -#define DB_NAME_OFFSET 0x14 - -#define STORAGE_START_OFFSET 0x13f8 -#define STORAGE_END_OFFSET 0x13fc - -#define PUBLIC_MSG_MGR_OFFSET 0x303df74 -#define MULTI_DB_MSG_MGR_OFFSET 0x30403b8 -#define FAVORITE_STORAGE_MGR_OFFSET 0x303fd40 -#define FTS_FAVORITE_MGR_OFFSET 0x2ffe908 - -#define OP_LOG_STORAGE_VFTABLE 0x2AD3A20 -#define CHAT_MSG_STORAGE_VFTABLE 0x2AC10F0 -#define CHAT_CR_MSG_STORAGE_VFTABLE 0x2ABEF14 -#define SESSION_STORAGE_VFTABLE 0x2AD3578 -#define APP_INFO_STORAGE_VFTABLE 0x2ABCC58 -#define HEAD_IMG_STORAGE_VFTABLE 0x2ACD9DC -#define HEAD_IMG_URL_STORAGE_VFTABLE 0x2ACDF70 - -#define BIZ_INFO_STORAGE_VFTABLE 0x2ABD718 -#define TICKET_INFO_STORAGE_VFTABLE 0x2AD5400 -#define CHAT_ROOM_STORAGE_VFTABLE 0x2AC299C -#define CHAT_ROOM_INFO_STORAGE_VFTABLE 0x2AC245C -#define MEDIA_STORAGE_VFTABLE 0x2ACE998 -#define NAME_2_ID_STORAGE_VFTABLE 0x2AD222C -#define EMOTION_PACKAGE_STORAGE_VFTABLE 0x2AC6400 - -#define EMOTION_STORAGE_VFTABLE 0x2AC7018 -#define BUFINFO_STORAGE_VFTABLE 0x2AC3178 - -#define CUSTOM_EMOTION_STORAGE_VFTABLE 0x2AC4E90 -#define DEL_SESSIONINFO_STORAGE_VFTABLE 0x2AC5F98 -#define FUNCTION_MSG_STORAGE_VFTABLE 0x2ACD10C - -#define FUNCTION_MSG_TASK_STORAGE_VFTABLE 0x2ACC5C8 -#define REVOKE_MSG_STORAGE_VFTABLE 0x2AD27BC - - - -/*******************hook*********************************************/ - - -// hook image -#define WX_HOOK_IMG_OFFSET 0xd723dc -#define WX_HOOK_IMG_NEXT_OFFSET 0xe91d90 - - - -// hook log -#define WX_HOOK_LOG_OFFSET 0xf57d67 -#define WX_HOOK_LOG_NEXT_OFFSET 0x240ea71 - -// hook msg - -#define WX_RECV_MSG_HOOK_OFFSET 0xd19a0b -#define WX_RECV_MSG_HOOK_NEXT_OFFSET 0x756960 -#define WX_SNS_HOOK_OFFSET 0x14f9e15 -#define WX_SNS_HOOK_NEXT_OFFSET 0x14fa0a0 - - -// hook voice -#define WX_HOOK_VOICE_OFFSET 0xd4d8d8 -#define WX_HOOK_VOICE_NEXT_OFFSET 0x203d130 -#define WX_SELF_ID_OFFSET 0x2FFD484 - -/*******************hook end*********************************************/ - - -/***************************sqlite3***************************************/ -#define SQLITE_OK 0 /* Successful result */ -/* beginning-of-error-codes */ -#define SQLITE_ERROR 1 /* Generic error */ -#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ -#define SQLITE_PERM 3 /* Access permission denied */ -#define SQLITE_ABORT 4 /* Callback routine requested an abort */ -#define SQLITE_BUSY 5 /* The database file is locked */ -#define SQLITE_LOCKED 6 /* A table in the database is locked */ -#define SQLITE_NOMEM 7 /* A malloc() failed */ -#define SQLITE_READONLY 8 /* Attempt to write a readonly database */ -#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ -#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ -#define SQLITE_CORRUPT 11 /* The database disk image is malformed */ -#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */ -#define SQLITE_FULL 13 /* Insertion failed because database is full */ -#define SQLITE_CANTOPEN 14 /* Unable to open the database file */ -#define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Internal use only */ -#define SQLITE_SCHEMA 17 /* The database schema changed */ -#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ -#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ -#define SQLITE_MISMATCH 20 /* Data type mismatch */ -#define SQLITE_MISUSE 21 /* Library used incorrectly */ -#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ -#define SQLITE_AUTH 23 /* Authorization denied */ -#define SQLITE_FORMAT 24 /* Not used */ -#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ -#define SQLITE_NOTADB 26 /* File opened that is not a database file */ -#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ -#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ -#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ -#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ -/* end-of-error-codes */ - -/* -** CAPI3REF: Extended Result Codes -** KEYWORDS: {extended result code definitions} -** -** In its default configuration, SQLite API routines return one of 30 integer -** [result codes]. However, experience has shown that many of -** these result codes are too coarse-grained. They do not provide as -** much information about problems as programmers might like. In an effort to -** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8] -** and later) include -** support for additional result codes that provide more detailed information -** about errors. These [extended result codes] are enabled or disabled -** on a per database connection basis using the -** [sqlite3_extended_result_codes()] API. Or, the extended code for -** the most recent error can be obtained using -** [sqlite3_extended_errcode()]. -*/ -#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1 << 8)) -#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2 << 8)) -#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3 << 8)) -#define SQLITE_IOERR_READ (SQLITE_IOERR | (1 << 8)) -#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2 << 8)) -#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3 << 8)) -#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4 << 8)) -#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5 << 8)) -#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6 << 8)) -#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7 << 8)) -#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8 << 8)) -#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9 << 8)) -#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10 << 8)) -#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11 << 8)) -#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12 << 8)) -#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13 << 8)) -#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14 << 8)) -#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15 << 8)) -#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16 << 8)) -#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17 << 8)) -#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18 << 8)) -#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19 << 8)) -#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20 << 8)) -#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21 << 8)) -#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22 << 8)) -#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23 << 8)) -#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24 << 8)) -#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25 << 8)) -#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26 << 8)) -#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27 << 8)) -#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28 << 8)) -#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29 << 8)) -#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30 << 8)) -#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31 << 8)) -#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32 << 8)) -#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33 << 8)) -#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1 << 8)) -#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2 << 8)) -#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1 << 8)) -#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2 << 8)) -#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3 << 8)) -#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1 << 8)) -#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2 << 8)) -#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3 << 8)) -#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4 << 8)) -#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5 << 8)) /* Not Used */ -#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6 << 8)) -#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1 << 8)) -#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2 << 8)) -#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3 << 8)) -#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1 << 8)) -#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2 << 8)) -#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3 << 8)) -#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4 << 8)) -#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5 << 8)) -#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6 << 8)) -#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2 << 8)) -#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1 << 8)) -#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2 << 8)) -#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3 << 8)) -#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4 << 8)) -#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5 << 8)) -#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6 << 8)) -#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7 << 8)) -#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8 << 8)) -#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9 << 8)) -#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT | (10 << 8)) -#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT | (11 << 8)) -#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT | (12 << 8)) -#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1 << 8)) -#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2 << 8)) -#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1 << 8)) -#define SQLITE_AUTH_USER (SQLITE_AUTH | (1 << 8)) -#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1 << 8)) -#define SQLITE_OK_SYMLINK (SQLITE_OK | (2 << 8)) /* internal use only */ - - -#define SQLITE_INTEGER 1 -#define SQLITE_FLOAT 2 -#define SQLITE_BLOB 4 -#define SQLITE_NULL 5 -#define SQLITE_TEXT 3 - -#define SQLITE3_EXEC_OFFSET 0x1e24f70 -#define SQLITE3_BACKUP_INIT_OFFSET 0x1dea900 -#define SQLITE3_PREPARE_OFFSET 0x1e2b8c0 -#define SQLITE3_OPEN_OFFSET 0x1e598b0 -#define SQLITE3_BACKUP_STEP_OFFSET 0x1dead00 -#define SQLITE3_BACKUP_REMAINING_OFFSET 0x1deb440 -#define SQLITE3_BACKUP_PAGECOUNT_OFFSET 0x1deb450 -#define SQLITE3_BACKUP_FINISH_OFFSET 0x1deb340 -#define SQLITE3_SLEEP_OFFSET 0x1e5a0f0 -#define SQLITE3_ERRCODE_OFFSET 0x1e58550 -#define SQLITE3_CLOSE_OFFSET 0x1e56cd0 -#define SQLITE3_STEP_OFFSET 0x1df3770 -#define SQLITE3_COLUMN_COUNT_OFFSET 0x1df3c80 -#define SQLITE3_COLUMN_NAME_OFFSET 0x1df4570 -#define SQLITE3_COLUMN_TYPE_OFFSET 0x1df4410 -#define SQLITE3_COLUMN_BLOB_OFFSET 0x1df3cc0 -#define SQLITE3_COLUMN_BYTES_OFFSET 0x1df3da0 -#define SQLITE3_FINALIZE_OFFSET 0x1df2740 - -typedef int (*Sqlite3_callback)(void*, int, char**, char**); - -typedef int(__cdecl* Sqlite3_exec)(DWORD, /* An open database */ - const char* sql, /* SQL to be evaluated */ - Sqlite3_callback, /* Callback function */ - void*, /* 1st argument to callback */ - char** errmsg /* Error msg written here */ -); -typedef DWORD(__cdecl* Sqlite3_backup_init)( - DWORD* pDest, /* Destination database handle */ - const char* zDestName, /* Destination database name */ - DWORD* pSource, /* Source database handle */ - const char* zSourceName /* Source database name */ -); -typedef int(__cdecl* Sqlite3_prepare)( - DWORD db, /* Database handle */ - const char* zSql, /* SQL statement, UTF-8 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - DWORD** ppStmt, /* OUT: Statement handle */ - const char** pzTail /* OUT: Pointer to unused portion of zSql */ -); -typedef int(__cdecl* Sqlite3_open)(const char* filename, DWORD** ppDb); -typedef int(__cdecl* Sqlite3_backup_step)(DWORD* p, int nPage); -typedef int(__cdecl* Sqlite3_backup_remaining)(DWORD* p); -typedef int(__cdecl* Sqlite3_backup_pagecount)(DWORD* p); -typedef int(__cdecl* Sqlite3_backup_finish)(DWORD* p); -typedef int(__cdecl* Sqlite3_sleep)(int); -typedef int(__cdecl* Sqlite3_errcode)(DWORD* db); -typedef int(__cdecl* Sqlite3_close)(DWORD*); - -typedef int(__cdecl* Sqlite3_step)(DWORD*); -typedef int(__cdecl* Sqlite3_column_count)(DWORD* pStmt); -typedef const char*(__cdecl* Sqlite3_column_name)(DWORD*, int N); -typedef int(__cdecl* Sqlite3_column_type)(DWORD*, int iCol); -typedef const void*(__cdecl* Sqlite3_column_blob)(DWORD*, int iCol); -typedef int(__cdecl* Sqlite3_column_bytes)(DWORD*, int iCol); -typedef int(__cdecl* Sqlite3_finalize)(DWORD* pStmt); - - -/***************************sqlite3 end*************************************/ - -struct SqlResult { - char *column_name; - DWORD column_name_len; - char *content; - DWORD content_len; - BOOL is_blob; -}; - -struct WeChatString { - wchar_t *ptr; - DWORD length; - DWORD max_length; - DWORD c_ptr = 0; - DWORD c_len = 0; - WeChatString() { WeChatString(NULL); } - - WeChatString(std::wstring &s) { - ptr = (wchar_t *)(s.c_str()); - length = s.length(); - max_length = s.length() * 2; - } - WeChatString(const wchar_t *pStr) { WeChatString((wchar_t *)pStr); } - WeChatString(int tmp) { - ptr = NULL; - length = 0x0; - max_length = 0x0; - } - WeChatString(wchar_t *pStr) { - ptr = pStr; - length = wcslen(pStr); - max_length = wcslen(pStr) * 2; - } - void set_value(const wchar_t *pStr) { - ptr = (wchar_t *)pStr; - length = wcslen(pStr); - max_length = wcslen(pStr) * 2; - } -}; - - -struct SelfInfoInner{ - std::string name; - std::string city; - std::string province; - std::string country; - std::string account; - std::string wxid; - std::string mobile; - std::string head_img; - std::string data_save_path; - std::string signature; - std::string current_data_path; - std::string db_key; -}; - -struct VectorInner { -#ifdef _DEBUG - DWORD head; -#endif - DWORD start; - DWORD finsh; - DWORD end; -}; - -struct TableInfo { - char *name; - DWORD name_len; - char *table_name; - DWORD table_name_len; - char *sql; - DWORD sql_len; - char *rootpage; - DWORD rootpage_len; -}; - -struct DatabaseInfo { - DWORD handle = 0; - wchar_t *db_name = NULL; - DWORD db_name_len = 0; - std::vector tables; - DWORD count = 0; - DWORD extrainfo = 0; -}; - - -struct Contact { - WeChatString wxid; - WeChatString custom_account; - WeChatString encrypt_name; - WeChatString nick_name; - WeChatString pinyin; - WeChatString pinyin_all; - int del_flag; - int type; - int verify_flag; -}; - -struct ChatRoomInfo { - DWORD vftable; - WeChatString chat_room_id; - WeChatString notice; - WeChatString admin; - DWORD filed_40; - DWORD filed_44; - DWORD filed_48; - DWORD filed_4C; - WeChatString xml; - DWORD filed_64; - DWORD filed_68; - DWORD filed_6C; - DWORD filed_70; - DWORD filed_74; - DWORD filed_78; - DWORD filed_7C; - DWORD filed_80; - DWORD filed_84; - DWORD filed_88; - DWORD filed_8c; - DWORD filed_90; - DWORD filed_94; - DWORD filed_98; - DWORD filed_9C; - DWORD filed_A0; -}; - -struct ChatRoomInfoInner { - WeChatString chat_room_id; - WeChatString notice; - WeChatString admin; - WeChatString xml; - - ~ChatRoomInfoInner(){ - if(chat_room_id.ptr){ - delete []chat_room_id.ptr; - chat_room_id.ptr = nullptr; - } - if(notice.ptr){ - delete []notice.ptr; - notice.ptr = nullptr; - } - if(admin.ptr){ - delete []admin.ptr; - admin.ptr = nullptr; - } - if(xml.ptr){ - delete []xml.ptr; - xml.ptr = nullptr; - } - } -}; - -struct ChatRoomInner{ - char* members; - wchar_t* chat_room; - wchar_t* admin; - ~ChatRoomInner(){ - delete []members; - delete []chat_room; - delete []admin; - } -}; - -struct UserInfo { - int error_code; - wchar_t *keyword; - int keyword_len; - wchar_t *v3; - int v3_len; - wchar_t *nickname; - int nickname_len; - wchar_t *signature; - int signature_len; - wchar_t *v2; - int v2_len; - wchar_t *nation; - int nation_len; - wchar_t *province; - int province_len; - wchar_t *city; - int city_len; - wchar_t *big_image; - int big_image_len; - wchar_t *small_image; - int small_image_len; - DWORD sex; - BOOL over; -}; - -struct AtInner{ - DWORD start; - DWORD finsh; - DWORD end; -}; - -struct ChatMsg { - DWORD **field0_0x0; - DWORD field1_0x4; - ULONG64 sequence; - DWORD field3_0x10; - DWORD field4_0x14; - ULONG64 msgSequence; - DWORD localId; - DWORD field7_0x24; - DWORD field8_0x28; - DWORD field9_0x2c; - ULONG64 msgId; - DWORD type; - DWORD isSendMsg; - DWORD msgStatus; - DWORD timestamp; - WeChatString talker; - DWORD field16_0x5c; - DWORD field17_0x60; - DWORD field18_0x64; - DWORD field19_0x68; - DWORD field20_0x6c; - WeChatString content; - DWORD field22_0x84; - DWORD field23_0x88; - DWORD field24_0x8c; - DWORD field25_0x90; - DWORD field26_0x94; - DWORD field27_0x98; - DWORD field28_0x9c; - DWORD field29_0xa0; - DWORD field30_0xa4; - DWORD field31_0xa8; - DWORD field32_0xac; - DWORD field33_0xb0; - DWORD field34_0xb4; - DWORD field35_0xb8; - DWORD field36_0xbc; - DWORD field37_0xc0; - DWORD field38_0xc4; - DWORD field39_0xc8; - DWORD field40_0xcc; - DWORD field41_0xd0; - DWORD field42_0xd4; - DWORD field43_0xd8; - DWORD field44_0xdc; - DWORD field45_0xe0; - DWORD field46_0xe4; - DWORD field47_0xe8; - DWORD field48_0xec; - DWORD field49_0xf0; - DWORD field50_0xf4; - DWORD field51_0xf8; - DWORD field52_0xfc; - DWORD field53_0x100; - DWORD field54_0x104; - DWORD field55_0x108; - DWORD field56_0x10c; - DWORD field57_0x110; - DWORD field58_0x114; - DWORD field59_0x118; - DWORD field60_0x11c; - DWORD field61_0x120; - DWORD field62_0x124; - DWORD field63_0x128; - DWORD field64_0x12c; - DWORD field65_0x130; - DWORD field66_0x134; - DWORD field67_0x138; - DWORD field68_0x13c; - DWORD field69_0x140; - DWORD field70_0x144; - DWORD field71_0x148; - DWORD field72_0x14c; - DWORD field73_0x150; - DWORD field74_0x154; - DWORD field75_0x158; - DWORD field76_0x15c; - DWORD field77_0x160; - DWORD field78_0x164; - DWORD field79_0x168; - DWORD field80_0x16c; - DWORD field81_0x170; - WeChatString fromGroup; - WeChatString sign; - WeChatString thumbPath; - WeChatString path; - DWORD field86_0x1c4; - DWORD field87_0x1c8; - DWORD field88_0x1cc; - DWORD field89_0x1d0; - DWORD field90_0x1d4; - DWORD field91_0x1d8; - DWORD field92_0x1dc; - DWORD field93_0x1e0; - DWORD field94_0x1e4; - DWORD field95_0x1e8; - DWORD field96_0x1ec; - WeChatString signature; - DWORD field98_0x204; - DWORD field99_0x208; - DWORD field100_0x20c; - DWORD field101_0x210; - DWORD field102_0x214; - DWORD field103_0x218; - DWORD field104_0x21c; - DWORD field105_0x220; - DWORD field106_0x224; - DWORD field107_0x228; - DWORD field108_0x22c; - DWORD field109_0x230; - DWORD field110_0x234; - DWORD field111_0x238; - DWORD field112_0x23c; - DWORD field113_0x240; - DWORD field114_0x244; - DWORD field115_0x248; - DWORD field116_0x24c; - DWORD field117_0x250; - DWORD field118_0x254; - DWORD field119_0x258; - DWORD field120_0x25c; - DWORD field121_0x260; - DWORD field122_0x264; - DWORD field123_0x268; - DWORD field124_0x26c; - DWORD field125_0x270; - DWORD field126_0x274; - DWORD field127_0x278; - DWORD field128_0x27c; - DWORD field129_0x280; - DWORD field130_0x284; - DWORD field131_0x288; - DWORD field132_0x28c; - DWORD field133_0x290; - DWORD field134_0x294; - DWORD field135_0x298; - DWORD field136_0x29c; - DWORD field137_0x2a0; - DWORD field138_0x2a4; - DWORD field139_0x2a8; - DWORD field140_0x2ac; - DWORD field141_0x2b0; - int field142_0x2b4; -}; - -struct InnerMessageStruct { - char *buffer; - int length; - ~InnerMessageStruct() { - if (this->buffer != NULL) { - delete[] this->buffer; - this->buffer = NULL; - } - } -}; - -struct Unkown{ - DWORD field1 = 0; - DWORD field2= 0; - DWORD field3= 0; - DWORD field4= 0; - DWORD field5= 0; - DWORD field6= 0; -}; -#endif \ No newline at end of file