aboutsummaryrefslogtreecommitdiff
path: root/Src/Wasabi/bfc
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Wasabi/bfc')
-rw-r--r--Src/Wasabi/bfc/assert.cpp104
-rw-r--r--Src/Wasabi/bfc/assert.h1
-rw-r--r--Src/Wasabi/bfc/bfc.sln30
-rw-r--r--Src/Wasabi/bfc/bfc.vcxproj304
-rw-r--r--Src/Wasabi/bfc/bfc.vcxproj.filters330
-rw-r--r--Src/Wasabi/bfc/bfc.xcodeproj/project.pbxproj420
-rw-r--r--Src/Wasabi/bfc/bfc_assert.h39
-rw-r--r--Src/Wasabi/bfc/bitlist.h41
-rw-r--r--Src/Wasabi/bfc/common.h23
-rw-r--r--Src/Wasabi/bfc/critsec.cpp73
-rw-r--r--Src/Wasabi/bfc/critsec.h96
-rw-r--r--Src/Wasabi/bfc/depend.cpp211
-rw-r--r--Src/Wasabi/bfc/depend.h152
-rw-r--r--Src/Wasabi/bfc/depview.cpp2
-rw-r--r--Src/Wasabi/bfc/depview.h103
-rw-r--r--Src/Wasabi/bfc/dispatch.h622
-rw-r--r--Src/Wasabi/bfc/draw/convolve.cpp60
-rw-r--r--Src/Wasabi/bfc/draw/convolve.h24
-rw-r--r--Src/Wasabi/bfc/draw/drawpoly.cpp458
-rw-r--r--Src/Wasabi/bfc/draw/drawpoly.h16
-rw-r--r--Src/Wasabi/bfc/draw/gradient.cpp309
-rw-r--r--Src/Wasabi/bfc/draw/gradient.h67
-rw-r--r--Src/Wasabi/bfc/draw/skinfilter.cpp17
-rw-r--r--Src/Wasabi/bfc/draw/skinfilter.h11
-rw-r--r--Src/Wasabi/bfc/error.h6
-rw-r--r--Src/Wasabi/bfc/file/filename.cpp2
-rw-r--r--Src/Wasabi/bfc/file/filename.h26
-rw-r--r--Src/Wasabi/bfc/file/readdir.cpp129
-rw-r--r--Src/Wasabi/bfc/file/readdir.h48
-rw-r--r--Src/Wasabi/bfc/file/recursedir.cpp67
-rw-r--r--Src/Wasabi/bfc/file/recursedir.h73
-rw-r--r--Src/Wasabi/bfc/file/splitpath.c213
-rw-r--r--Src/Wasabi/bfc/file/splitpath.h26
-rw-r--r--Src/Wasabi/bfc/file/tmpnamestr.h18
-rw-r--r--Src/Wasabi/bfc/file/wildcharsenum.cpp64
-rw-r--r--Src/Wasabi/bfc/file/wildcharsenum.h34
-rw-r--r--Src/Wasabi/bfc/foreach.cpp22
-rw-r--r--Src/Wasabi/bfc/foreach.h55
-rw-r--r--Src/Wasabi/bfc/freelist.cpp81
-rw-r--r--Src/Wasabi/bfc/freelist.h93
-rw-r--r--Src/Wasabi/bfc/loadlib.cpp85
-rw-r--r--Src/Wasabi/bfc/loadlib.h35
-rw-r--r--Src/Wasabi/bfc/memblock.cpp66
-rw-r--r--Src/Wasabi/bfc/memblock.h101
-rw-r--r--Src/Wasabi/bfc/multipatch.h412
-rw-r--r--Src/Wasabi/bfc/named.h25
-rw-r--r--Src/Wasabi/bfc/node.cpp8
-rw-r--r--Src/Wasabi/bfc/node.h118
-rw-r--r--Src/Wasabi/bfc/nsguid.cpp174
-rw-r--r--Src/Wasabi/bfc/nsguid.h33
-rw-r--r--Src/Wasabi/bfc/pair.h14
-rw-r--r--Src/Wasabi/bfc/parse/Makefile.am4
-rw-r--r--Src/Wasabi/bfc/parse/Makefile.in372
-rw-r--r--Src/Wasabi/bfc/parse/PathParseW.cpp55
-rw-r--r--Src/Wasabi/bfc/parse/hierarchyparser.cpp99
-rw-r--r--Src/Wasabi/bfc/parse/hierarchyparser.h55
-rw-r--r--Src/Wasabi/bfc/parse/paramparser.cpp20
-rw-r--r--Src/Wasabi/bfc/parse/paramparser.h23
-rw-r--r--Src/Wasabi/bfc/parse/pathparse.cpp54
-rw-r--r--Src/Wasabi/bfc/parse/pathparse.h152
-rw-r--r--Src/Wasabi/bfc/platform/Makefile.am6
-rw-r--r--Src/Wasabi/bfc/platform/Makefile.in376
-rw-r--r--Src/Wasabi/bfc/platform/export.h20
-rw-r--r--Src/Wasabi/bfc/platform/guid.h1
-rw-r--r--Src/Wasabi/bfc/platform/linux.h437
-rw-r--r--Src/Wasabi/bfc/platform/linux/linux.cpp961
-rw-r--r--Src/Wasabi/bfc/platform/minmax.h19
-rw-r--r--Src/Wasabi/bfc/platform/platform.cpp6
-rw-r--r--Src/Wasabi/bfc/platform/platform.h498
-rw-r--r--Src/Wasabi/bfc/platform/std_string_osx.cpp246
-rw-r--r--Src/Wasabi/bfc/platform/strcmp.h15
-rw-r--r--Src/Wasabi/bfc/platform/types.h2
-rw-r--r--Src/Wasabi/bfc/platform/win32.h34
-rw-r--r--Src/Wasabi/bfc/precomp_wasabi_bfc.cpp1
-rw-r--r--Src/Wasabi/bfc/precomp_wasabi_bfc.h22
-rw-r--r--Src/Wasabi/bfc/ptrlist.cpp330
-rw-r--r--Src/Wasabi/bfc/ptrlist.h777
-rw-r--r--Src/Wasabi/bfc/reentryfilter.h78
-rw-r--r--Src/Wasabi/bfc/stack.cpp77
-rw-r--r--Src/Wasabi/bfc/stack.h42
-rw-r--r--Src/Wasabi/bfc/std_file.cpp428
-rw-r--r--Src/Wasabi/bfc/std_file.h101
-rw-r--r--Src/Wasabi/bfc/std_keyboard.cpp51
-rw-r--r--Src/Wasabi/bfc/std_keyboard.h46
-rw-r--r--Src/Wasabi/bfc/std_math.cpp18
-rw-r--r--Src/Wasabi/bfc/std_math.h48
-rw-r--r--Src/Wasabi/bfc/std_mem.h71
-rw-r--r--Src/Wasabi/bfc/std_mkncc.h11
-rw-r--r--Src/Wasabi/bfc/std_string.cpp254
-rw-r--r--Src/Wasabi/bfc/std_string.h11
-rw-r--r--Src/Wasabi/bfc/std_wnd.cpp1098
-rw-r--r--Src/Wasabi/bfc/string/PathString.cpp7
-rw-r--r--Src/Wasabi/bfc/string/PathString.h21
-rw-r--r--Src/Wasabi/bfc/string/StringW.cpp783
-rw-r--r--Src/Wasabi/bfc/string/StringW.h467
-rw-r--r--Src/Wasabi/bfc/string/bfcstring.h473
-rw-r--r--Src/Wasabi/bfc/string/bigstring.cpp95
-rw-r--r--Src/Wasabi/bfc/string/bigstring.h56
-rw-r--r--Src/Wasabi/bfc/string/encodedstr.cpp156
-rw-r--r--Src/Wasabi/bfc/string/encodedstr.h42
-rw-r--r--Src/Wasabi/bfc/string/playstring.cpp57
-rw-r--r--Src/Wasabi/bfc/string/playstring.h49
-rw-r--r--Src/Wasabi/bfc/string/string.cpp884
-rw-r--r--Src/Wasabi/bfc/string/stringdict.h96
-rw-r--r--Src/Wasabi/bfc/string/url.cpp205
-rw-r--r--Src/Wasabi/bfc/string/url.h33
-rw-r--r--Src/Wasabi/bfc/string/utf8.cpp25
-rw-r--r--Src/Wasabi/bfc/string/utf8.h8
-rw-r--r--Src/Wasabi/bfc/test.cpp5
-rw-r--r--Src/Wasabi/bfc/thread.cpp124
-rw-r--r--Src/Wasabi/bfc/thread.h145
-rw-r--r--Src/Wasabi/bfc/tlist.h156
-rw-r--r--Src/Wasabi/bfc/util/base64.cpp315
-rw-r--r--Src/Wasabi/bfc/util/base64.h16
-rw-r--r--Src/Wasabi/bfc/util/findopenrect.cpp251
-rw-r--r--Src/Wasabi/bfc/util/findopenrect.h63
-rw-r--r--Src/Wasabi/bfc/util/inifile.cpp56
-rw-r--r--Src/Wasabi/bfc/util/inifile.h28
-rw-r--r--Src/Wasabi/bfc/util/profile.c288
-rw-r--r--Src/Wasabi/bfc/util/profile.h26
-rw-r--r--Src/Wasabi/bfc/util/profiler.cpp6
-rw-r--r--Src/Wasabi/bfc/util/profiler.h128
-rw-r--r--Src/Wasabi/bfc/util/timefmt.cpp71
-rw-r--r--Src/Wasabi/bfc/util/timefmt.h46
-rw-r--r--Src/Wasabi/bfc/wasabi_std.cpp1198
-rw-r--r--Src/Wasabi/bfc/wasabi_std.h366
-rw-r--r--Src/Wasabi/bfc/wasabi_std_rect.cpp77
-rw-r--r--Src/Wasabi/bfc/wasabi_std_rect.h22
-rw-r--r--Src/Wasabi/bfc/wasabi_std_wnd.h86
129 files changed, 19390 insertions, 0 deletions
diff --git a/Src/Wasabi/bfc/assert.cpp b/Src/Wasabi/bfc/assert.cpp
new file mode 100644
index 00000000..6fb2aed3
--- /dev/null
+++ b/Src/Wasabi/bfc/assert.cpp
@@ -0,0 +1,104 @@
+#include "precomp_wasabi_bfc.h"
+#ifdef WIN32
+#include <windows.h>
+#endif
+#ifdef __APPLE__
+#include <unistd.h>
+#endif
+
+#include "bfc_assert.h"
+
+#ifdef ASSERTS_ENABLED
+
+static int in_assert = 0;
+
+// we try to use wsprintf because it can make for a smaller .exe
+#ifdef WIN32
+#define ASSERT_SPRINTF wsprintfA
+#elif defined(LINUX)
+#define ASSERT_SPRINTF sprintf
+#elif defined(__APPLE__)
+#define ASSERT_SPRINTF sprintf
+#else
+#error port me!
+#endif
+
+#ifdef WIN32
+static int isDebuggerPresent() {
+ HINSTANCE kernel32 = LoadLibrary(L"kernel32.dll");
+ if (kernel32 == NULL) return 0;
+ BOOL (WINAPI *IsDebuggerPresent)() = NULL;
+ IsDebuggerPresent = (BOOL (WINAPI *)())GetProcAddress(kernel32, "IsDebuggerPresent");
+ if (IsDebuggerPresent == NULL) return 0;
+ int ret = (*IsDebuggerPresent)();
+ FreeLibrary(kernel32);
+ return ret;
+}
+#endif
+
+static void assert_kill()
+{
+#ifdef _WIN32
+#ifndef _WIN64
+ __asm { int 3 };
+#else
+ ExitProcess(0);
+#endif
+#endif
+}
+void _assert_handler(const char *reason, const char *file, int line) {
+ char msg[4096] = {0};
+ ASSERT_SPRINTF(msg, "Expression: %s\nFile: %s\nLine: %d\n", reason, file, line);
+
+#ifdef WIN32
+ OutputDebugStringA(msg);
+ if (in_assert)
+ {
+ assert_kill();
+ }
+ in_assert = 1;
+
+ ATOM a = AddAtom(L"BYPASS_DEACTIVATE_MGR"); // so we don't need to call api->appdeactivation_setbypass
+
+ if (isDebuggerPresent() || MessageBoxA(NULL, msg, "Assertion failed", MB_OKCANCEL|MB_TASKMODAL) == IDCANCEL) {
+ assert_kill();
+ } else
+ ExitProcess(0);
+ DeleteAtom(a);
+#elif defined(LINUX)
+ kill(getpid(), SIGSEGV );
+#elif defined(__APPLE__)
+ kill(getpid(), SIGSEGV );
+#else
+#error port me!
+#endif
+ in_assert = 0;
+}
+
+void _assert_handler_str(const char *string, const char *reason, const char *file, int line)
+{
+ char msg[4096] = {0};
+ ASSERT_SPRINTF(msg, "\"%s\"\nExpression: %s\nFile: %s\nLine: %d\n", string, reason ? reason : "", file, line);
+
+#ifdef WIN32
+ OutputDebugStringA(msg);
+ if (in_assert) assert_kill();
+ in_assert = 1;
+
+ ATOM a = AddAtom(L"BYPASS_DEACTIVATE_MGR");
+ if (isDebuggerPresent() || MessageBoxA(NULL, msg, "Assertion failed", MB_OKCANCEL|MB_TASKMODAL) == IDCANCEL) {
+ assert_kill();
+ } else
+ ExitProcess(0);
+ DeleteAtom(a);
+#elif defined(LINUX)
+ kill(getpid(), SIGSEGV );
+#elif defined(__APPLE__)
+ kill(getpid(), SIGSEGV );
+#else
+#error port me!
+#endif
+ in_assert = 0;
+}
+
+#endif
diff --git a/Src/Wasabi/bfc/assert.h b/Src/Wasabi/bfc/assert.h
new file mode 100644
index 00000000..6f02203b
--- /dev/null
+++ b/Src/Wasabi/bfc/assert.h
@@ -0,0 +1 @@
+#include "bfc_assert.h" \ No newline at end of file
diff --git a/Src/Wasabi/bfc/bfc.sln b/Src/Wasabi/bfc/bfc.sln
new file mode 100644
index 00000000..e60d468a
--- /dev/null
+++ b/Src/Wasabi/bfc/bfc.sln
@@ -0,0 +1,30 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29424.173
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bfc", "bfc.vcxproj", "{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.Build.0 = Debug|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.ActiveCfg = Debug|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.Build.0 = Debug|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.ActiveCfg = Release|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.Build.0 = Release|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.ActiveCfg = Release|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {0E7F9665-971C-48B6-BF28-5952406042A2}
+ EndGlobalSection
+EndGlobal
diff --git a/Src/Wasabi/bfc/bfc.vcxproj b/Src/Wasabi/bfc/bfc.vcxproj
new file mode 100644
index 00000000..08e1c2aa
--- /dev/null
+++ b/Src/Wasabi/bfc/bfc.vcxproj
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}</ProjectGuid>
+ <RootNamespace>bfc</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnableManifest>false</VcpkgEnableManifest>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;..;../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;_LIB;_WIN32_WINNT=0x0601;WINVER=0x0601;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+ </Lib>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;..;../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;_LIB;_WIN32_WINNT=0x0601;WINVER=0x0601;_CRT_SECURE_NO_WARNINGS;WIN64;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+ </Lib>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>.;..;../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;_LIB;_WIN32_WINNT=0x0601;WINVER=0x0601;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+ </Lib>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>.;..;../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;_LIB;_WIN32_WINNT=0x0601;WINVER=0x0601;_CRT_SECURE_NO_WARNINGS;WIN64;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+ </Lib>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\api\skin\xmlobject.cpp" />
+ <ClCompile Include="..\api\syscb\callbacks\wndcb.cpp" />
+ <ClCompile Include="..\api\wnd\paintcb.cpp" />
+ <ClCompile Include="..\api\xml\xmlwrite.cpp" />
+ <ClCompile Include="assert.cpp" />
+ <ClCompile Include="critsec.cpp" />
+ <ClCompile Include="depend.cpp" />
+ <ClCompile Include="depview.cpp" />
+ <ClCompile Include="file\filename.cpp" />
+ <ClCompile Include="file\readdir.cpp" />
+ <ClCompile Include="file\recursedir.cpp" />
+ <ClCompile Include="file\wildcharsenum.cpp" />
+ <ClCompile Include="foreach.cpp" />
+ <ClCompile Include="freelist.cpp" />
+ <ClCompile Include="loadlib.cpp" />
+ <ClCompile Include="memblock.cpp" />
+ <ClCompile Include="node.cpp" />
+ <ClCompile Include="nsguid.cpp" />
+ <ClCompile Include="parse\hierarchyparser.cpp" />
+ <ClCompile Include="parse\paramparser.cpp" />
+ <ClCompile Include="parse\pathparse.cpp" />
+ <ClCompile Include="parse\PathParseW.cpp" />
+ <ClCompile Include="platform\platform.cpp" />
+ <ClCompile Include="precomp_wasabi_bfc.cpp" />
+ <ClCompile Include="ptrlist.cpp" />
+ <ClCompile Include="stack.cpp" />
+ <ClCompile Include="std_string.cpp" />
+ <ClCompile Include="wasabi_std.cpp" />
+ <ClCompile Include="std_keyboard.cpp" />
+ <ClCompile Include="std_math.cpp" />
+ <ClCompile Include="wasabi_std_rect.cpp" />
+ <ClCompile Include="std_wnd.cpp" />
+ <ClCompile Include="string\bigstring.cpp" />
+ <ClCompile Include="string\encodedstr.cpp" />
+ <ClCompile Include="string\PathString.cpp" />
+ <ClCompile Include="string\playstring.cpp" />
+ <ClCompile Include="string\string.cpp" />
+ <ClCompile Include="string\StringW.cpp" />
+ <ClCompile Include="string\url.cpp" />
+ <ClCompile Include="string\utf8.cpp" />
+ <ClCompile Include="thread.cpp" />
+ <ClCompile Include="util\base64.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\api\xml\xmlwrite.h" />
+ <ClInclude Include="assert.h" />
+ <ClInclude Include="bitlist.h" />
+ <ClInclude Include="common.h" />
+ <ClInclude Include="critsec.h" />
+ <ClInclude Include="depend.h" />
+ <ClInclude Include="depview.h" />
+ <ClInclude Include="dispatch.h" />
+ <ClInclude Include="file\filename.h" />
+ <ClInclude Include="file\readdir.h" />
+ <ClInclude Include="file\recursedir.h" />
+ <ClInclude Include="file\tmpnamestr.h" />
+ <ClInclude Include="file\wildcharsenum.h" />
+ <ClInclude Include="foreach.h" />
+ <ClInclude Include="freelist.h" />
+ <ClInclude Include="loadlib.h" />
+ <ClInclude Include="memblock.h" />
+ <ClInclude Include="multipatch.h" />
+ <ClInclude Include="named.h" />
+ <ClInclude Include="node.h" />
+ <ClInclude Include="nsguid.h" />
+ <ClInclude Include="pair.h" />
+ <ClInclude Include="parse\hierarchyparser.h" />
+ <ClInclude Include="parse\paramparser.h" />
+ <ClInclude Include="parse\pathparse.h" />
+ <ClInclude Include="platform\guid.h" />
+ <ClInclude Include="platform\platform.h" />
+ <ClInclude Include="platform\types.h" />
+ <ClInclude Include="platform\win32.h" />
+ <ClInclude Include="precomp_wasabi_bfc.h" />
+ <ClInclude Include="ptrlist.h" />
+ <ClInclude Include="reentryfilter.h" />
+ <ClInclude Include="stack.h" />
+ <ClInclude Include="std_string.h" />
+ <ClInclude Include="wasabi_std.h" />
+ <ClInclude Include="std_keyboard.h" />
+ <ClInclude Include="std_math.h" />
+ <ClInclude Include="std_mem.h" />
+ <ClInclude Include="std_mkncc.h" />
+ <ClInclude Include="wasabi_std_rect.h" />
+ <ClInclude Include="wasabi_std_wnd.h" />
+ <ClInclude Include="string\bigstring.h" />
+ <ClInclude Include="string\encodedstr.h" />
+ <ClInclude Include="string\PathString.h" />
+ <ClInclude Include="string\playstring.h" />
+ <ClInclude Include="string\stringdict.h" />
+ <ClInclude Include="string\StringW.h" />
+ <ClInclude Include="string\url.h" />
+ <ClInclude Include="string\utf8.h" />
+ <ClInclude Include="thread.h" />
+ <ClInclude Include="tlist.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Wasabi/bfc/bfc.vcxproj.filters b/Src/Wasabi/bfc/bfc.vcxproj.filters
new file mode 100644
index 00000000..6e118fc7
--- /dev/null
+++ b/Src/Wasabi/bfc/bfc.vcxproj.filters
@@ -0,0 +1,330 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="assert.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="util\base64.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="critsec.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="depend.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="depview.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="foreach.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="freelist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="loadlib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="memblock.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="node.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="nsguid.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\api\wnd\paintcb.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="precomp_wasabi_bfc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ptrlist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stack.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wasabi_std.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="std_keyboard.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="std_math.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wasabi_std_rect.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="std_wnd.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="thread.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\api\syscb\callbacks\wndcb.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\api\skin\xmlobject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\api\xml\xmlwrite.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="file\filename.cpp">
+ <Filter>Source Files\file</Filter>
+ </ClCompile>
+ <ClCompile Include="file\readdir.cpp">
+ <Filter>Source Files\file</Filter>
+ </ClCompile>
+ <ClCompile Include="file\recursedir.cpp">
+ <Filter>Source Files\file</Filter>
+ </ClCompile>
+ <ClCompile Include="file\wildcharsenum.cpp">
+ <Filter>Source Files\file</Filter>
+ </ClCompile>
+ <ClCompile Include="parse\hierarchyparser.cpp">
+ <Filter>Source Files\parse</Filter>
+ </ClCompile>
+ <ClCompile Include="parse\pathparse.cpp">
+ <Filter>Source Files\parse</Filter>
+ </ClCompile>
+ <ClCompile Include="parse\PathParseW.cpp">
+ <Filter>Source Files\parse</Filter>
+ </ClCompile>
+ <ClCompile Include="parse\paramparser.cpp">
+ <Filter>Source Files\parse</Filter>
+ </ClCompile>
+ <ClCompile Include="platform\platform.cpp">
+ <Filter>Source Files\platform</Filter>
+ </ClCompile>
+ <ClCompile Include="string\bigstring.cpp">
+ <Filter>Source Files\string</Filter>
+ </ClCompile>
+ <ClCompile Include="string\encodedstr.cpp">
+ <Filter>Source Files\string</Filter>
+ </ClCompile>
+ <ClCompile Include="string\PathString.cpp">
+ <Filter>Source Files\string</Filter>
+ </ClCompile>
+ <ClCompile Include="string\playstring.cpp">
+ <Filter>Source Files\string</Filter>
+ </ClCompile>
+ <ClCompile Include="string\string.cpp">
+ <Filter>Source Files\string</Filter>
+ </ClCompile>
+ <ClCompile Include="string\StringW.cpp">
+ <Filter>Source Files\string</Filter>
+ </ClCompile>
+ <ClCompile Include="string\url.cpp">
+ <Filter>Source Files\string</Filter>
+ </ClCompile>
+ <ClCompile Include="string\utf8.cpp">
+ <Filter>Source Files\string</Filter>
+ </ClCompile>
+ <ClCompile Include="std_string.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="assert.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="bitlist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="common.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="critsec.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="depend.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="depview.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="dispatch.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="foreach.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="freelist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="loadlib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="memblock.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="multipatch.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="named.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="node.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="nsguid.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="pair.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="precomp_wasabi_bfc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ptrlist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="reentryfilter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="stack.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="wasabi_std.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="std_keyboard.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="std_math.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="std_mem.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="std_mkncc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="wasabi_std_rect.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="wasabi_std_wnd.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="thread.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="tlist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\api\xml\xmlwrite.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="file\filename.h">
+ <Filter>Header Files\file</Filter>
+ </ClInclude>
+ <ClInclude Include="file\readdir.h">
+ <Filter>Header Files\file</Filter>
+ </ClInclude>
+ <ClInclude Include="file\recursedir.h">
+ <Filter>Header Files\file</Filter>
+ </ClInclude>
+ <ClInclude Include="file\tmpnamestr.h">
+ <Filter>Header Files\file</Filter>
+ </ClInclude>
+ <ClInclude Include="file\wildcharsenum.h">
+ <Filter>Header Files\file</Filter>
+ </ClInclude>
+ <ClInclude Include="parse\hierarchyparser.h">
+ <Filter>Header Files\parse</Filter>
+ </ClInclude>
+ <ClInclude Include="parse\paramparser.h">
+ <Filter>Header Files\parse</Filter>
+ </ClInclude>
+ <ClInclude Include="parse\pathparse.h">
+ <Filter>Header Files\parse</Filter>
+ </ClInclude>
+ <ClInclude Include="platform\guid.h">
+ <Filter>Header Files\platform</Filter>
+ </ClInclude>
+ <ClInclude Include="platform\platform.h">
+ <Filter>Header Files\platform</Filter>
+ </ClInclude>
+ <ClInclude Include="platform\types.h">
+ <Filter>Header Files\platform</Filter>
+ </ClInclude>
+ <ClInclude Include="platform\win32.h">
+ <Filter>Header Files\platform</Filter>
+ </ClInclude>
+ <ClInclude Include="string\bigstring.h">
+ <Filter>Header Files\string</Filter>
+ </ClInclude>
+ <ClInclude Include="string\encodedstr.h">
+ <Filter>Header Files\string</Filter>
+ </ClInclude>
+ <ClInclude Include="string\PathString.h">
+ <Filter>Header Files\string</Filter>
+ </ClInclude>
+ <ClInclude Include="string\playstring.h">
+ <Filter>Header Files\string</Filter>
+ </ClInclude>
+ <ClInclude Include="string\stringdict.h">
+ <Filter>Header Files\string</Filter>
+ </ClInclude>
+ <ClInclude Include="string\StringW.h">
+ <Filter>Header Files\string</Filter>
+ </ClInclude>
+ <ClInclude Include="string\url.h">
+ <Filter>Header Files\string</Filter>
+ </ClInclude>
+ <ClInclude Include="string\utf8.h">
+ <Filter>Header Files\string</Filter>
+ </ClInclude>
+ <ClInclude Include="std_string.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{ea13d5da-ba29-4aba-9cc6-513111cdccdd}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Ressource Files">
+ <UniqueIdentifier>{98c6da9b-0ae2-4651-b2b7-d18955ab070b}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{eb99ed8d-24b3-49f4-a133-2230d8639174}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\file">
+ <UniqueIdentifier>{25082a5c-f115-4e1b-ab9d-8e4839d35387}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\file">
+ <UniqueIdentifier>{fc562171-49a0-4835-a294-bb908d57d63a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\parse">
+ <UniqueIdentifier>{f238eb6c-4230-48b8-b26f-5c9ac444ba78}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\parse">
+ <UniqueIdentifier>{23d80b59-49ab-47a0-ad85-42ca540d3292}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\platform">
+ <UniqueIdentifier>{115977e8-a187-48e9-ac59-c71015d1fc43}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\platform">
+ <UniqueIdentifier>{3f34098f-2b62-4216-8c91-f0ecc8b4ccb3}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\string">
+ <UniqueIdentifier>{980a7b39-f9e8-42a1-91e3-409438cc880d}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\string">
+ <UniqueIdentifier>{b693b9e8-2d93-47bf-9f05-75e1becf6a89}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\util">
+ <UniqueIdentifier>{509bf000-4810-4f14-8f2e-4f7aa9e9b1a1}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\draw">
+ <UniqueIdentifier>{1822ef05-8dbd-4088-828b-07246221f95e}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\draw">
+ <UniqueIdentifier>{1bd5a793-ec99-4a4b-a886-8a2f97805864}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Wasabi/bfc/bfc.xcodeproj/project.pbxproj b/Src/Wasabi/bfc/bfc.xcodeproj/project.pbxproj
new file mode 100644
index 00000000..051fb511
--- /dev/null
+++ b/Src/Wasabi/bfc/bfc.xcodeproj/project.pbxproj
@@ -0,0 +1,420 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 0C165B5C0BDDA30D00D223E0 /* foreach.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C165B5A0BDDA30D00D223E0 /* foreach.cpp */; };
+ 0C165B5D0BDDA30D00D223E0 /* foreach.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C165B5B0BDDA30D00D223E0 /* foreach.h */; };
+ 0C165BEC0BDDA54300D223E0 /* memblock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C165BEA0BDDA54300D223E0 /* memblock.cpp */; };
+ 0C165BED0BDDA54300D223E0 /* memblock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C165BEB0BDDA54300D223E0 /* memblock.h */; };
+ 0C165C100BDDA5EF00D223E0 /* ptrlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C165C0E0BDDA5EF00D223E0 /* ptrlist.h */; };
+ 0C165C110BDDA5EF00D223E0 /* ptrlist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C165C0F0BDDA5EF00D223E0 /* ptrlist.cpp */; };
+ 0C165C150BDDA60100D223E0 /* std_string_osx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C165C130BDDA60100D223E0 /* std_string_osx.cpp */; };
+ 0C165C220BDDA62500D223E0 /* stack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C165C200BDDA62500D223E0 /* stack.cpp */; };
+ 0C165C230BDDA62500D223E0 /* stack.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C165C210BDDA62500D223E0 /* stack.h */; };
+ 0C165C270BDDA63900D223E0 /* std.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C165C250BDDA63900D223E0 /* std.cpp */; };
+ 0C165C280BDDA63900D223E0 /* std.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C165C260BDDA63900D223E0 /* std.h */; };
+ 0C165CA60BDDAA7D00D223E0 /* std_rect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C165CA40BDDAA7D00D223E0 /* std_rect.cpp */; };
+ 0C165CA70BDDAA7D00D223E0 /* std_rect.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C165CA50BDDAA7D00D223E0 /* std_rect.h */; };
+ 0C165CAE0BDDAA9100D223E0 /* std_wnd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C165CAC0BDDAA9100D223E0 /* std_wnd.cpp */; };
+ 0C165CAF0BDDAA9100D223E0 /* std_wnd.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C165CAD0BDDAA9100D223E0 /* std_wnd.h */; };
+ 0C1A569C0BE8380B004EB596 /* std_keyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C1A569A0BE8380B004EB596 /* std_keyboard.h */; };
+ 0C1A569D0BE8380B004EB596 /* std_keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C1A569B0BE8380B004EB596 /* std_keyboard.cpp */; };
+ 0C2D19A90C0BE18400ED9158 /* critsec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C2D19A80C0BE18400ED9158 /* critsec.cpp */; };
+ 0C34965D0BDDB1CE00806EE5 /* paramparser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C34965B0BDDB1CE00806EE5 /* paramparser.cpp */; };
+ 0C34965E0BDDB1CE00806EE5 /* paramparser.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C34965C0BDDB1CE00806EE5 /* paramparser.h */; };
+ 0C34966E0BDDB20600806EE5 /* hierarchyparser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C34966C0BDDB20600806EE5 /* hierarchyparser.cpp */; };
+ 0C34966F0BDDB20600806EE5 /* hierarchyparser.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C34966D0BDDB20600806EE5 /* hierarchyparser.h */; };
+ 0C3496790BDDB22F00806EE5 /* PathParseW.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C3496780BDDB22F00806EE5 /* PathParseW.cpp */; };
+ 0C3496910BDDB2F800806EE5 /* depend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C34968F0BDDB2F800806EE5 /* depend.cpp */; };
+ 0C3496920BDDB2F800806EE5 /* depend.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C3496900BDDB2F800806EE5 /* depend.h */; };
+ 0C3496960BDDB30500806EE5 /* depview.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C3496940BDDB30500806EE5 /* depview.cpp */; };
+ 0C3496970BDDB30500806EE5 /* depview.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C3496950BDDB30500806EE5 /* depview.h */; };
+ 0C5425030C1398DE00F2D2CC /* string.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5425010C1398DE00F2D2CC /* string.cpp */; };
+ 0C7926BF0BF7C65600EB510B /* wildcharsenum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C7926BD0BF7C65600EB510B /* wildcharsenum.cpp */; };
+ 0C7926C00BF7C65600EB510B /* wildcharsenum.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C7926BE0BF7C65600EB510B /* wildcharsenum.h */; };
+ 0C92FCA80BF41F6000D5B70C /* gradient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C92FCA60BF41F6000D5B70C /* gradient.cpp */; };
+ 0C92FCA90BF41F6000D5B70C /* gradient.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C92FCA70BF41F6000D5B70C /* gradient.h */; };
+ 0CAAB89B0BE5473700EDF43D /* playstring.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CAAB8990BE5473700EDF43D /* playstring.cpp */; };
+ 0CAAB89C0BE5473700EDF43D /* playstring.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CAAB89A0BE5473700EDF43D /* playstring.h */; };
+ 0CAAB8C00BE5482E00EDF43D /* filename.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CAAB8BE0BE5482E00EDF43D /* filename.h */; };
+ 0CAAB8C10BE5482E00EDF43D /* filename.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CAAB8BF0BE5482E00EDF43D /* filename.cpp */; };
+ 0CAAB8FA0BE5490C00EDF43D /* StringW.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CAAB8F80BE5490C00EDF43D /* StringW.cpp */; };
+ 0CAAB8FB0BE5490C00EDF43D /* StringW.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CAAB8F90BE5490C00EDF43D /* StringW.h */; };
+ 0CB242CE0BF7884E006C6DD0 /* assert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CB242CC0BF7884E006C6DD0 /* assert.cpp */; };
+ 0CC1B69B0BEE870C0082991E /* std_file.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CC1B69A0BEE870C0082991E /* std_file.h */; };
+ 0CC1B6B10BEE877A0082991E /* std_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CC1B6B00BEE877A0082991E /* std_file.cpp */; };
+ 0CCF0E3A0C000D1100B207E8 /* nsguid.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CCF0E380C000D1100B207E8 /* nsguid.h */; };
+ 0CCF0E3B0C000D1100B207E8 /* nsguid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CCF0E390C000D1100B207E8 /* nsguid.cpp */; };
+ 0CCF0E9E0C00129E00B207E8 /* url.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CCF0E9C0C00129E00B207E8 /* url.h */; };
+ 0CCF0E9F0C00129E00B207E8 /* url.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CCF0E9D0C00129E00B207E8 /* url.cpp */; };
+ 0CE6AE520BDD9EEC0077EB3C /* critsec.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CE6AE500BDD9EEC0077EB3C /* critsec.h */; };
+ D2AAC0700554677100DB518D /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB77AAFE841565C02AAC07 /* Carbon.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 08FB77AAFE841565C02AAC07 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
+ 0C165B5A0BDDA30D00D223E0 /* foreach.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = foreach.cpp; sourceTree = "<group>"; };
+ 0C165B5B0BDDA30D00D223E0 /* foreach.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = foreach.h; sourceTree = "<group>"; };
+ 0C165BEA0BDDA54300D223E0 /* memblock.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = memblock.cpp; sourceTree = "<group>"; };
+ 0C165BEB0BDDA54300D223E0 /* memblock.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = memblock.h; sourceTree = "<group>"; };
+ 0C165C0E0BDDA5EF00D223E0 /* ptrlist.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ptrlist.h; sourceTree = "<group>"; };
+ 0C165C0F0BDDA5EF00D223E0 /* ptrlist.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ptrlist.cpp; sourceTree = "<group>"; };
+ 0C165C130BDDA60100D223E0 /* std_string_osx.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = std_string_osx.cpp; path = platform/std_string_osx.cpp; sourceTree = "<group>"; };
+ 0C165C200BDDA62500D223E0 /* stack.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = stack.cpp; sourceTree = "<group>"; };
+ 0C165C210BDDA62500D223E0 /* stack.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack.h; sourceTree = "<group>"; };
+ 0C165C250BDDA63900D223E0 /* std.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = std.cpp; sourceTree = "<group>"; };
+ 0C165C260BDDA63900D223E0 /* std.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = std.h; sourceTree = "<group>"; };
+ 0C165CA40BDDAA7D00D223E0 /* std_rect.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = std_rect.cpp; sourceTree = "<group>"; };
+ 0C165CA50BDDAA7D00D223E0 /* std_rect.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = std_rect.h; sourceTree = "<group>"; };
+ 0C165CAC0BDDAA9100D223E0 /* std_wnd.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = std_wnd.cpp; sourceTree = "<group>"; };
+ 0C165CAD0BDDAA9100D223E0 /* std_wnd.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = std_wnd.h; sourceTree = "<group>"; };
+ 0C1A569A0BE8380B004EB596 /* std_keyboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = std_keyboard.h; sourceTree = "<group>"; };
+ 0C1A569B0BE8380B004EB596 /* std_keyboard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = std_keyboard.cpp; sourceTree = "<group>"; };
+ 0C2D19A80C0BE18400ED9158 /* critsec.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = critsec.cpp; sourceTree = "<group>"; };
+ 0C34965B0BDDB1CE00806EE5 /* paramparser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = paramparser.cpp; path = parse/paramparser.cpp; sourceTree = "<group>"; };
+ 0C34965C0BDDB1CE00806EE5 /* paramparser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = paramparser.h; path = parse/paramparser.h; sourceTree = "<group>"; };
+ 0C34966C0BDDB20600806EE5 /* hierarchyparser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = hierarchyparser.cpp; path = parse/hierarchyparser.cpp; sourceTree = "<group>"; };
+ 0C34966D0BDDB20600806EE5 /* hierarchyparser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = hierarchyparser.h; path = parse/hierarchyparser.h; sourceTree = "<group>"; };
+ 0C3496780BDDB22F00806EE5 /* PathParseW.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PathParseW.cpp; path = parse/PathParseW.cpp; sourceTree = "<group>"; };
+ 0C34968F0BDDB2F800806EE5 /* depend.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = depend.cpp; sourceTree = "<group>"; };
+ 0C3496900BDDB2F800806EE5 /* depend.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = depend.h; sourceTree = "<group>"; };
+ 0C3496940BDDB30500806EE5 /* depview.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = depview.cpp; sourceTree = "<group>"; };
+ 0C3496950BDDB30500806EE5 /* depview.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = depview.h; sourceTree = "<group>"; };
+ 0C5425010C1398DE00F2D2CC /* string.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = string.cpp; path = string/string.cpp; sourceTree = "<group>"; };
+ 0C7926BD0BF7C65600EB510B /* wildcharsenum.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = wildcharsenum.cpp; path = file/wildcharsenum.cpp; sourceTree = "<group>"; };
+ 0C7926BE0BF7C65600EB510B /* wildcharsenum.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = wildcharsenum.h; path = file/wildcharsenum.h; sourceTree = "<group>"; };
+ 0C92FCA60BF41F6000D5B70C /* gradient.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = gradient.cpp; path = draw/gradient.cpp; sourceTree = "<group>"; };
+ 0C92FCA70BF41F6000D5B70C /* gradient.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = gradient.h; path = draw/gradient.h; sourceTree = "<group>"; };
+ 0CAAB8990BE5473700EDF43D /* playstring.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = playstring.cpp; path = string/playstring.cpp; sourceTree = "<group>"; };
+ 0CAAB89A0BE5473700EDF43D /* playstring.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = playstring.h; path = string/playstring.h; sourceTree = "<group>"; };
+ 0CAAB8BE0BE5482E00EDF43D /* filename.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = filename.h; path = file/filename.h; sourceTree = "<group>"; };
+ 0CAAB8BF0BE5482E00EDF43D /* filename.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = filename.cpp; path = file/filename.cpp; sourceTree = "<group>"; };
+ 0CAAB8F80BE5490C00EDF43D /* StringW.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StringW.cpp; path = string/StringW.cpp; sourceTree = "<group>"; };
+ 0CAAB8F90BE5490C00EDF43D /* StringW.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = StringW.h; path = string/StringW.h; sourceTree = "<group>"; };
+ 0CB242CC0BF7884E006C6DD0 /* assert.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = assert.cpp; sourceTree = "<group>"; };
+ 0CC1B69A0BEE870C0082991E /* std_file.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = std_file.h; sourceTree = "<group>"; };
+ 0CC1B6B00BEE877A0082991E /* std_file.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = std_file.cpp; sourceTree = "<group>"; };
+ 0CCF0E380C000D1100B207E8 /* nsguid.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = nsguid.h; sourceTree = "<group>"; };
+ 0CCF0E390C000D1100B207E8 /* nsguid.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = nsguid.cpp; sourceTree = "<group>"; };
+ 0CCF0E9C0C00129E00B207E8 /* url.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = url.h; path = string/url.h; sourceTree = "<group>"; };
+ 0CCF0E9D0C00129E00B207E8 /* url.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = url.cpp; path = string/url.cpp; sourceTree = "<group>"; };
+ 0CE6AE500BDD9EEC0077EB3C /* critsec.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = critsec.h; sourceTree = "<group>"; };
+ D2AAC06F0554671400DB518D /* libbfc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libbfc.a; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ D2AAC06D0554671400DB518D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D2AAC0700554677100DB518D /* Carbon.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DDFF38A45A11DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ D2AAC06F0554671400DB518D /* libbfc.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* bfc */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB77ACFE841707C02AAC07 /* Source */,
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
+ 034768DDFF38A45A11DB9C8B /* Products */,
+ );
+ name = bfc;
+ sourceTree = "<group>";
+ };
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB77AAFE841565C02AAC07 /* Carbon.framework */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 08FB77ACFE841707C02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 0CCF0DFC0C0006F100B207E8 /* file */,
+ 0CB242CC0BF7884E006C6DD0 /* assert.cpp */,
+ 0C2D19A80C0BE18400ED9158 /* critsec.cpp */,
+ 0CE6AE500BDD9EEC0077EB3C /* critsec.h */,
+ 0C34968F0BDDB2F800806EE5 /* depend.cpp */,
+ 0C3496900BDDB2F800806EE5 /* depend.h */,
+ 0C3496940BDDB30500806EE5 /* depview.cpp */,
+ 0C3496950BDDB30500806EE5 /* depview.h */,
+ 0C165B5A0BDDA30D00D223E0 /* foreach.cpp */,
+ 0C165B5B0BDDA30D00D223E0 /* foreach.h */,
+ 0C92FCA60BF41F6000D5B70C /* gradient.cpp */,
+ 0C92FCA70BF41F6000D5B70C /* gradient.h */,
+ 0C34966C0BDDB20600806EE5 /* hierarchyparser.cpp */,
+ 0C34966D0BDDB20600806EE5 /* hierarchyparser.h */,
+ 0C165BEA0BDDA54300D223E0 /* memblock.cpp */,
+ 0C165BEB0BDDA54300D223E0 /* memblock.h */,
+ 0C34965B0BDDB1CE00806EE5 /* paramparser.cpp */,
+ 0C34965C0BDDB1CE00806EE5 /* paramparser.h */,
+ 0C3496780BDDB22F00806EE5 /* PathParseW.cpp */,
+ 0CAAB8990BE5473700EDF43D /* playstring.cpp */,
+ 0CAAB89A0BE5473700EDF43D /* playstring.h */,
+ 0C165C0F0BDDA5EF00D223E0 /* ptrlist.cpp */,
+ 0C165C0E0BDDA5EF00D223E0 /* ptrlist.h */,
+ 0C165C200BDDA62500D223E0 /* stack.cpp */,
+ 0C165C210BDDA62500D223E0 /* stack.h */,
+ 0CCF0E380C000D1100B207E8 /* nsguid.h */,
+ 0CCF0E390C000D1100B207E8 /* nsguid.cpp */,
+ 0C7926BD0BF7C65600EB510B /* wildcharsenum.cpp */,
+ 0C7926BE0BF7C65600EB510B /* wildcharsenum.h */,
+ 0CC1B67D0BEE86590082991E /* Std */,
+ 0C3064600BEE9BB7006CF130 /* String */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 0C3064600BEE9BB7006CF130 /* String */ = {
+ isa = PBXGroup;
+ children = (
+ 0C5425010C1398DE00F2D2CC /* string.cpp */,
+ 0CCF0E9C0C00129E00B207E8 /* url.h */,
+ 0CCF0E9D0C00129E00B207E8 /* url.cpp */,
+ 0CAAB8F80BE5490C00EDF43D /* StringW.cpp */,
+ 0CAAB8F90BE5490C00EDF43D /* StringW.h */,
+ );
+ name = String;
+ sourceTree = "<group>";
+ };
+ 0CC1B67D0BEE86590082991E /* Std */ = {
+ isa = PBXGroup;
+ children = (
+ 0C165C130BDDA60100D223E0 /* std_string_osx.cpp */,
+ 0C165C250BDDA63900D223E0 /* std.cpp */,
+ 0CC1B6B00BEE877A0082991E /* std_file.cpp */,
+ 0CC1B69A0BEE870C0082991E /* std_file.h */,
+ 0C165C260BDDA63900D223E0 /* std.h */,
+ 0C165CA40BDDAA7D00D223E0 /* std_rect.cpp */,
+ 0C165CA50BDDAA7D00D223E0 /* std_rect.h */,
+ 0C165CAC0BDDAA9100D223E0 /* std_wnd.cpp */,
+ 0C165CAD0BDDAA9100D223E0 /* std_wnd.h */,
+ 0C1A569A0BE8380B004EB596 /* std_keyboard.h */,
+ 0C1A569B0BE8380B004EB596 /* std_keyboard.cpp */,
+ );
+ name = Std;
+ sourceTree = "<group>";
+ };
+ 0CCF0DFC0C0006F100B207E8 /* file */ = {
+ isa = PBXGroup;
+ children = (
+ 0CAAB8BF0BE5482E00EDF43D /* filename.cpp */,
+ 0CAAB8BE0BE5482E00EDF43D /* filename.h */,
+ );
+ name = file;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ D2AAC06B0554671400DB518D /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 0CE6AE520BDD9EEC0077EB3C /* critsec.h in Headers */,
+ 0C165B5D0BDDA30D00D223E0 /* foreach.h in Headers */,
+ 0C165BED0BDDA54300D223E0 /* memblock.h in Headers */,
+ 0C165C100BDDA5EF00D223E0 /* ptrlist.h in Headers */,
+ 0C165C230BDDA62500D223E0 /* stack.h in Headers */,
+ 0C165C280BDDA63900D223E0 /* std.h in Headers */,
+ 0C165CA70BDDAA7D00D223E0 /* std_rect.h in Headers */,
+ 0C165CAF0BDDAA9100D223E0 /* std_wnd.h in Headers */,
+ 0C34965E0BDDB1CE00806EE5 /* paramparser.h in Headers */,
+ 0C34966F0BDDB20600806EE5 /* hierarchyparser.h in Headers */,
+ 0C3496920BDDB2F800806EE5 /* depend.h in Headers */,
+ 0C3496970BDDB30500806EE5 /* depview.h in Headers */,
+ 0CAAB89C0BE5473700EDF43D /* playstring.h in Headers */,
+ 0CAAB8C00BE5482E00EDF43D /* filename.h in Headers */,
+ 0CAAB8FB0BE5490C00EDF43D /* StringW.h in Headers */,
+ 0C1A569C0BE8380B004EB596 /* std_keyboard.h in Headers */,
+ 0CC1B69B0BEE870C0082991E /* std_file.h in Headers */,
+ 0C92FCA90BF41F6000D5B70C /* gradient.h in Headers */,
+ 0C7926C00BF7C65600EB510B /* wildcharsenum.h in Headers */,
+ 0CCF0E3A0C000D1100B207E8 /* nsguid.h in Headers */,
+ 0CCF0E9E0C00129E00B207E8 /* url.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ D2AAC06E0554671400DB518D /* bfc */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB920108733DBB0010E9CD /* Build configuration list for PBXNativeTarget "bfc" */;
+ buildPhases = (
+ D2AAC06B0554671400DB518D /* Headers */,
+ D2AAC06C0554671400DB518D /* Sources */,
+ D2AAC06D0554671400DB518D /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = bfc;
+ productName = bfc;
+ productReference = D2AAC06F0554671400DB518D /* libbfc.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB920508733DBB0010E9CD /* Build configuration list for PBXProject "bfc" */;
+ compatibilityVersion = "Xcode 2.4";
+ hasScannedForEncodings = 1;
+ mainGroup = 0867D691FE84028FC02AAC07 /* bfc */;
+ productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ D2AAC06E0554671400DB518D /* bfc */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ D2AAC06C0554671400DB518D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 0C165B5C0BDDA30D00D223E0 /* foreach.cpp in Sources */,
+ 0C165BEC0BDDA54300D223E0 /* memblock.cpp in Sources */,
+ 0C165C110BDDA5EF00D223E0 /* ptrlist.cpp in Sources */,
+ 0C165C150BDDA60100D223E0 /* std_string_osx.cpp in Sources */,
+ 0C165C220BDDA62500D223E0 /* stack.cpp in Sources */,
+ 0C165C270BDDA63900D223E0 /* std.cpp in Sources */,
+ 0C165CA60BDDAA7D00D223E0 /* std_rect.cpp in Sources */,
+ 0C165CAE0BDDAA9100D223E0 /* std_wnd.cpp in Sources */,
+ 0C34965D0BDDB1CE00806EE5 /* paramparser.cpp in Sources */,
+ 0C34966E0BDDB20600806EE5 /* hierarchyparser.cpp in Sources */,
+ 0C3496790BDDB22F00806EE5 /* PathParseW.cpp in Sources */,
+ 0C3496910BDDB2F800806EE5 /* depend.cpp in Sources */,
+ 0C3496960BDDB30500806EE5 /* depview.cpp in Sources */,
+ 0CAAB89B0BE5473700EDF43D /* playstring.cpp in Sources */,
+ 0CAAB8C10BE5482E00EDF43D /* filename.cpp in Sources */,
+ 0CAAB8FA0BE5490C00EDF43D /* StringW.cpp in Sources */,
+ 0C1A569D0BE8380B004EB596 /* std_keyboard.cpp in Sources */,
+ 0CC1B6B10BEE877A0082991E /* std_file.cpp in Sources */,
+ 0C92FCA80BF41F6000D5B70C /* gradient.cpp in Sources */,
+ 0CB242CE0BF7884E006C6DD0 /* assert.cpp in Sources */,
+ 0C7926BF0BF7C65600EB510B /* wildcharsenum.cpp in Sources */,
+ 0CCF0E3B0C000D1100B207E8 /* nsguid.cpp in Sources */,
+ 0CCF0E9F0C00129E00B207E8 /* url.cpp in Sources */,
+ 0C2D19A90C0BE18400ED9158 /* critsec.cpp in Sources */,
+ 0C5425030C1398DE00F2D2CC /* string.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB920208733DBB0010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ GCC_PREFIX_HEADER = "";
+ INSTALL_PATH = /usr/local/lib;
+ OTHER_CPLUSPLUSFLAGS = "-fpermissive";
+ PRODUCT_NAME = bfc;
+ ZERO_LINK = YES;
+ };
+ name = Debug;
+ };
+ 1DEB920308733DBB0010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = (
+ ppc,
+ i386,
+ );
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "";
+ INSTALL_PATH = /usr/local/lib;
+ OTHER_CPLUSPLUSFLAGS = "-fpermissive";
+ PRODUCT_NAME = bfc;
+ };
+ name = Release;
+ };
+ 1DEB920608733DBB0010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ ..,
+ ../..,
+ );
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Debug;
+ };
+ 1DEB920708733DBB0010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ ..,
+ ../..,
+ );
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB920108733DBB0010E9CD /* Build configuration list for PBXNativeTarget "bfc" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB920208733DBB0010E9CD /* Debug */,
+ 1DEB920308733DBB0010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1DEB920508733DBB0010E9CD /* Build configuration list for PBXProject "bfc" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB920608733DBB0010E9CD /* Debug */,
+ 1DEB920708733DBB0010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/Src/Wasabi/bfc/bfc_assert.h b/Src/Wasabi/bfc/bfc_assert.h
new file mode 100644
index 00000000..d58bc7ff
--- /dev/null
+++ b/Src/Wasabi/bfc/bfc_assert.h
@@ -0,0 +1,39 @@
+#ifndef _ASSERT_H
+#define _ASSERT_H
+
+#include <bfc/wasabi_std.h>
+
+#ifdef CPLUSPLUS
+extern "C" {
+#endif
+
+COMEXP void _assert_handler(const char *reason, const char *file, int line);
+COMEXP void _assert_handler_str(const char *string, const char *reason, const char *file, int line);
+
+#ifdef CPLUSPLUS
+}
+#endif
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+// benski> added june 7 2007.. somewhat of a hack - don't want to enable assert's for final builds
+#include "../../Winamp/buildtype.h"
+
+#if defined(_DEBUG) /*|| defined(INTERNAL) */|| defined(BETA)
+#define ASSERTS_ENABLED
+#endif
+
+#ifdef ASSERTS_ENABLED
+
+ #define ASSERT(x) ((x) ? void() : _assert_handler(#x, __FILE__, __LINE__))
+ #define ASSERTPR(x, str) ((x) ? void() : _assert_handler_str((str), #x, __FILE__, __LINE__))
+ #define ASSERTALWAYS(str) _assert_handler_str((str), 0, __FILE__, __LINE__)
+#else
+ #define ASSERT(x) ;
+ #define ASSERTPR(x,y) ;
+ #define ASSERTALWAYS ;
+#endif
+
+#endif
diff --git a/Src/Wasabi/bfc/bitlist.h b/Src/Wasabi/bfc/bitlist.h
new file mode 100644
index 00000000..b73dcd19
--- /dev/null
+++ b/Src/Wasabi/bfc/bitlist.h
@@ -0,0 +1,41 @@
+#ifndef _BITLIST_H
+#define _BITLIST_H
+
+#include "memblock.h"
+
+class BitList {
+public:
+ BitList(unsigned int size=0) {
+ setSize(size);
+ }
+
+ int getitem(int n) const {
+ if (n < 0 || n >= m_size) return 0;
+ return (m_list[n>>3]>>(n&7))&1;
+ }
+ void setitem(int n, int v) {
+ if (n >= 0 && n < m_size) {
+ int lv=1<<(n&7);
+ if (v) m_list[n>>3]|=lv;
+ else m_list[n>>3]&=~lv;
+ }
+ }
+
+ int operator[](int n) const { return getitem(n); }
+
+ int getSize() const { // in bits
+ return m_size;
+ }
+ void setSize(unsigned int newsize) {
+ m_list.setSize((newsize+7)>>3);
+ m_size = newsize;
+ }
+
+ int getsize() const { return m_size; }
+
+private:
+ MemBlock< uint8_t> m_list;
+ int m_size;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/common.h b/Src/Wasabi/bfc/common.h
new file mode 100644
index 00000000..305241b8
--- /dev/null
+++ b/Src/Wasabi/bfc/common.h
@@ -0,0 +1,23 @@
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#ifdef WIN32
+// disable "dll-interface to be used by clients of class" warning message.
+#pragma warning(disable: 4251)
+#endif /* WIN32 */
+
+#ifdef COMEXP
+#undef COMEXP
+#endif
+#define COMEXP
+
+
+#ifndef __cplusplus
+#define EXTC extern
+#else
+#define EXTC extern "C"
+#endif
+
+#include <bfc/wasabi_std.h>
+
+#endif /* _COMMON_H */
diff --git a/Src/Wasabi/bfc/critsec.cpp b/Src/Wasabi/bfc/critsec.cpp
new file mode 100644
index 00000000..e7506371
--- /dev/null
+++ b/Src/Wasabi/bfc/critsec.cpp
@@ -0,0 +1,73 @@
+#include "precomp_wasabi_bfc.h"
+#include "critsec.h"
+// uncomment this if needed
+//#define CS_DEBUG
+
+CriticalSection::CriticalSection() {
+#ifdef WIN32
+ InitializeCriticalSection(&cs);
+#elif defined(__APPLE__)
+ MPCreateCriticalRegion(&cr);
+#elif defined(LINUX)
+ pthread_mutex_t recursive = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+ cs.mutex = recursive;
+#endif
+
+#ifdef ASSERTS_ENABLED
+#ifdef CS_DEBUG
+ within = 0;
+#endif
+#endif
+}
+
+CriticalSection::~CriticalSection() {
+#ifdef CS_DEBUG
+#ifdef ASSERTS_ENABLED
+ ASSERT(!within);
+#endif
+#endif
+#ifdef WIN32
+ DeleteCriticalSection(&cs);
+#elif defined(__APPLE__)
+ MPDeleteCriticalRegion(cr);
+#elif defined(LINUX)
+ pthread_mutex_destroy(&cs.mutex);
+#endif
+}
+
+void CriticalSection::enter() {
+#ifdef WIN32
+ EnterCriticalSection(&cs);
+#elif defined(__APPLE__)
+ MPEnterCriticalRegion(cr, kDurationForever);
+#elif defined(LINUX)
+ pthread_mutex_lock(&cs.mutex);
+#endif
+
+#ifdef CS_DEBUG
+#ifdef ASSERTS_ENABLED
+ ASSERT(!within);
+ within = 1;
+#endif
+#endif
+}
+
+void CriticalSection::leave() {
+#if defined(CS_DEBUG) && defined(ASSERTS_ENABLED)
+ ASSERT(within);
+ within = 0;
+#endif
+
+#ifdef WIN32
+ LeaveCriticalSection(&cs);
+#elif defined(__APPLE__)
+ MPExitCriticalRegion(cr);
+#elif defined(LINUX)
+ pthread_mutex_unlock(&cs.mutex);
+#endif
+}
+
+void CriticalSection::inout() {
+ enter();
+ leave();
+}
diff --git a/Src/Wasabi/bfc/critsec.h b/Src/Wasabi/bfc/critsec.h
new file mode 100644
index 00000000..e9951a9a
--- /dev/null
+++ b/Src/Wasabi/bfc/critsec.h
@@ -0,0 +1,96 @@
+#ifndef _CRITSEC_H
+#define _CRITSEC_H
+
+#ifdef _WIN32
+#include <windows.h>
+#elif defined(__APPLE__)
+#include <CoreServices/CoreServices.h>
+#endif
+
+#include <bfc/common.h>
+#include <bfc/bfc_assert.h>
+
+/**
+ CriticalSection is a portable object that implements a critical section,
+ which is to say, it ensures that no two threads can be in that same
+ section of code at the same time. Usually you make them a global object
+ or allocate them with new and pass them to both threads.
+
+ @short Critical section class.
+ @author Nullsoft
+ @ver 1.0
+ @see Thread
+ @see InCriticalSection
+*/
+
+class CriticalSection {
+public:
+ CriticalSection();
+ virtual ~CriticalSection();
+
+/**
+ Enters the critical section. If another thread is already in the critical
+ section, the calling thread will be blocked until the other thread calls
+ leave().
+ @see leave()
+*/
+ void enter();
+/**
+ Leaves the critical section. If another thread is currently blocked on
+ this critical section, it will be unblocked. If multiple threads are blocking
+ only one will be unblocked.
+ @see enter()
+*/
+ void leave();
+
+/**
+ Calls enter() and leave() in quick succession. Useful to make sure that no
+ other thread is in the critical section (although another thread could
+ immediately re-enter)
+ @see enter()
+ @see leave()
+*/
+ void inout();
+
+private:
+#ifdef ASSERTS_ENABLED
+ int within;
+#endif
+#ifdef _WIN32
+ CRITICAL_SECTION cs;
+#elif defined(__APPLE__)
+ MPCriticalRegionID cr;
+#endif
+
+};
+
+/**
+ This is a little helper class to ease the use of class CriticalSection.
+ When it is instantiated, it enters a given critical section. When it is
+ destroyed, it leaves the given critical section.
+ CriticalSection a_cs;
+ void blah() {
+ InCriticalSection cs(a_cs); // critical section protection begins
+ if (test) {
+ return 0; // critical section protection ends
+ }
+ // critical section protection still active!
+ doSomething();
+ return 1; // critical section protection ends
+ }
+
+ @author Nullsoft
+ @see CriticalSection
+*/
+class InCriticalSection {
+public:
+ InCriticalSection(CriticalSection *cs) : m_cs(cs) { m_cs->enter(); }
+ InCriticalSection(CriticalSection &cs) : m_cs(&cs) { m_cs->enter(); }
+ ~InCriticalSection() { m_cs->leave(); }
+private:
+ CriticalSection *m_cs;
+};
+
+#define _INCRITICALSECTION(id, x) InCriticalSection __I_C_S__##id(x)
+#define INCRITICALSECTION(x) _INCRITICALSECTION(__LINE__, x)
+#endif
diff --git a/Src/Wasabi/bfc/depend.cpp b/Src/Wasabi/bfc/depend.cpp
new file mode 100644
index 00000000..e9917002
--- /dev/null
+++ b/Src/Wasabi/bfc/depend.cpp
@@ -0,0 +1,211 @@
+#include "precomp_wasabi_bfc.h"
+#include "depend.h"
+#include "platform/guid.h"
+
+DependentViewerI::DependentViewerI() : viewed_items(NULL) { }
+
+DependentViewerI::DependentViewerI(const DependentViewerI &dep) :
+ viewed_items(NULL)
+{
+ // watch their items now
+ if (dep.viewed_items != NULL)
+ {
+ for (int i = 0; i < dep.viewed_items->getNumItems(); i++)
+ viewer_addViewItem(dep.viewed_items->enumItem(i));
+ }
+}
+
+DependentViewerI::~DependentViewerI()
+{
+ if (viewed_items != NULL)
+ {
+ // tell viewed items to detach from us
+ foreach(viewed_items)
+ viewed_items->getfor()->dependent_regViewer(this, FALSE);
+ endfor
+#if 0
+ for (int i = 0; i < viewed_items->getNumItems(); i++)
+ {
+ ifc_dependent *item = viewed_items->enumItem(i);
+ item->dependent_regViewer(this, FALSE);
+ }
+#endif
+ viewed_items->removeAll();
+ delete viewed_items;
+ }
+}
+
+DependentViewerI &DependentViewerI::operator =(const DependentViewerI &dep)
+{
+ if (this != &dep)
+ {
+ viewer_delAllItems();
+ // watch their items now
+ if (dep.viewed_items != NULL)
+ {
+ for (int i = 0; i < dep.viewed_items->getNumItems(); i++)
+ viewer_addViewItem(dep.viewed_items->enumItem(i));
+ }
+ }
+ return *this;
+}
+
+void DependentViewerI::viewer_addViewItem(ifc_dependent *item)
+{
+ ASSERT(item != NULL);
+ if (viewed_items == NULL) viewed_items = new DependentList(8);
+ if (viewed_items->haveItem(item)) return ;
+ viewed_items->addItem(item);
+ item->dependent_regViewer(this, TRUE);
+}
+
+void DependentViewerI::viewer_delViewItem(ifc_dependent *item)
+{
+ if (item == NULL) return ;
+ if (viewed_items == NULL || !viewed_items->haveItem(item)) return ;
+ item->dependent_regViewer(this, FALSE);
+ viewed_items->removeItem(item);
+ if (viewed_items->getNumItems() == 0)
+ {
+ delete viewed_items; viewed_items = NULL;
+ }
+}
+
+void DependentViewerI::viewer_delAllItems()
+{
+ while (viewed_items != NULL)
+ {
+ ifc_dependent *item = viewer_enumViewItem(0);
+ if (item == NULL) break;
+ viewer_delViewItem(item);
+ }
+ delete viewed_items;
+ viewed_items = NULL;
+}
+
+void DependentViewerI::viewer_delAllOfClass(const GUID *guid)
+{
+ if (viewed_items == NULL) return ;
+ foreach(viewed_items)
+ if (viewed_items->getfor()->dependent_getInterface(guid))
+ viewer_delViewItem(viewed_items->getfor());
+ endfor
+}
+
+ifc_dependent *DependentViewerI::viewer_enumViewItem(int which)
+{
+ if (viewed_items == NULL) return NULL;
+ return viewed_items->enumItem(which);
+}
+
+int DependentViewerI::viewer_getNumItems()
+{
+ if (viewed_items == NULL) return 0;
+ return viewed_items->getNumItems();
+}
+
+int DependentViewerI::viewer_haveItem(ifc_dependent *item)
+{
+ if (viewed_items == NULL) return 0;
+ return viewed_items->haveItem(item);
+}
+
+int DependentViewerI::dependentViewer_callback(ifc_dependent *item, const GUID *classguid, int cb, intptr_t param1, intptr_t param2, void *ptr, size_t ptrlen)
+{
+ if (viewed_items == NULL || !viewed_items->haveItem(item)) return 0;
+ switch (cb)
+ {
+ case DependentCB::DEPCB_NOP: return 1;
+
+ case DependentCB::DEPCB_DELETED:
+ viewed_items->removeItem(item);
+ return viewer_onItemDeleted(item);
+
+ case DependentCB::DEPCB_EVENT:
+ return viewer_onEvent(item, classguid, (int)param1, param2, ptr, ptrlen);
+ break;
+ }
+ return 0;
+}
+
+DependentI::DependentI(const GUID *classguid) : viewers(NULL), class_guid(classguid ? *classguid : INVALID_GUID)
+{}
+
+DependentI::DependentI(const DependentI &dep) : viewers(NULL), class_guid(dep.class_guid) { }
+
+DependentI::~DependentI()
+{
+ if (viewers != NULL)
+ {
+ foreach(viewers)
+ viewers->getfor()->dependentViewer_callback(this, &class_guid, DependentCB::DEPCB_DELETED);
+ endfor
+ delete viewers;
+ }
+}
+
+DependentI& DependentI::operator =(const ifc_dependent &dep)
+{
+ // placeholder code... nobody asked to watch us
+ if (this != &dep)
+ {
+ viewers = NULL;
+ }
+ return *this;
+}
+
+void DependentI::dependent_regViewer(api_dependentviewer *viewer, int add)
+{
+ if (viewer == NULL) return ;
+ if (add)
+ {
+ if (viewers == NULL) viewers = new ViewerList(8);
+ if (viewers->haveItem(viewer)) return ;
+ viewers->addItem(viewer);
+ viewer->dependentViewer_callback(this, &class_guid, DependentCB::DEPCB_NOP);
+ }
+ else
+ { // delete
+ if (viewers == NULL) return ;
+ viewers->removeItem(viewer);
+ if (viewers->getNumItems() == 0)
+ {
+ delete viewers; viewers = NULL;
+ }
+ }
+ dependent_onRegViewer(viewer, add);
+}
+
+void DependentI::dependent_sendEvent(const GUID *classguid, int event, intptr_t param, void *ptr, size_t ptrlen, api_dependentviewer *viewer)
+{
+ if (classguid == NULL) classguid = &class_guid; // use default
+ ASSERT(*classguid != INVALID_GUID);
+ sendViewerCallbacks(classguid, DependentCB::DEPCB_EVENT, event, param, ptr, ptrlen, viewer);
+}
+
+void DependentI::sendViewerCallbacks(const GUID *classguid, int msg, intptr_t param1, intptr_t param2, void *ptr, size_t ptrlen, api_dependentviewer *viewer)
+{
+ if (viewers == NULL) return ;
+ ASSERT(classguid != NULL);
+ foreach(viewers)
+ if (viewer == NULL || viewer == viewers->getfor())
+ viewers->getfor()->dependentViewer_callback(this, classguid, msg, param1, param2, ptr, ptrlen);
+ endfor
+}
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS DependentViewerI
+START_DISPATCH;
+CB(DEPENDENTVIEWER_CALLBACK, dependentViewer_callback);
+END_DISPATCH;
+#undef CBCLASS
+
+#define CBCLASS DependentI
+START_DISPATCH;
+VCB(API_DEPENDENT_REGVIEWER, dependent_regViewer);
+CB(API_DEPENDENT_GETINTERFACE, dependent_getInterface);
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/Wasabi/bfc/depend.h b/Src/Wasabi/bfc/depend.h
new file mode 100644
index 00000000..1dc1a7ea
--- /dev/null
+++ b/Src/Wasabi/bfc/depend.h
@@ -0,0 +1,152 @@
+#ifndef _DEPEND_H
+#define _DEPEND_H
+
+#include <bfc/platform/platform.h>
+#include <bfc/common.h>
+#include <bfc/ptrlist.h>
+
+// a pair of classes to implement data dependency. a viewer can register
+// a list of things it wants to know about
+
+// WARNING: this file is still under development. check back for changes
+// in subsequent SDK releases. over time it is going to become more generic
+
+
+class ifc_dependent;
+
+#include <api/dependency/api_dependentviewer.h>
+
+// inherit from this one
+class /*NOVTABLE */DependentViewerI : public api_dependentviewer
+{
+protected:
+ /**
+ @param classguid If set, incoming events are restricted to those in that GUID namespace. Can be NULL.
+ */
+ DependentViewerI();
+ DependentViewerI(const DependentViewerI &dep);
+ virtual ~DependentViewerI();
+ // copy
+ DependentViewerI &operator =(const DependentViewerI &dep);
+
+ // derived classes call this on themselves when they want to view a new item
+ // everything else gets handled automagically
+ void viewer_addViewItem(ifc_dependent *item);
+ void viewer_delViewItem(ifc_dependent *item);
+ void viewer_delAllItems();
+ void viewer_delAllOfClass(const GUID *guid); //only works if dependent has implemented dependent_getInterface() for the GUID
+
+ // call this whenever you need to know what you're looking at
+ ifc_dependent *viewer_enumViewItem(int which);
+ int viewer_getNumItems();
+ // returns TRUE if item is in our list
+ int viewer_haveItem(ifc_dependent *item);
+
+ // convenience callback methods
+
+ // item you were looking at is gone: WARNING: pointer no longer valid!
+ virtual int viewer_onItemDeleted(ifc_dependent *item) { return 1; }
+ // item you are looking at issuing an event
+ virtual int viewer_onEvent(ifc_dependent *item, const GUID *classguid, int event, intptr_t param, void *ptr, size_t ptrlen) { return 1; }
+
+private:
+ // don't override this; override the individual convenience callbacks
+ virtual int dependentViewer_callback(ifc_dependent *item, const GUID *classguid, int cb, intptr_t param1 = 0, intptr_t param2 = 0, void *ptr = NULL, size_t ptrlen = 0);
+ typedef PtrList <ifc_dependent> DependentList;
+ DependentList * viewed_items;
+protected:
+ RECVS_DISPATCH;
+};
+
+template <class VT>
+class NOVTABLE DependentViewerT : private DependentViewerI
+{
+protected:
+ DependentViewerT() { }
+ DependentViewerT(VT *first)
+ {
+ if (first) viewer_addViewItem(first);
+ }
+
+public:
+ using DependentViewerI::viewer_addViewItem;
+ using DependentViewerI::viewer_delViewItem;
+ using DependentViewerI::viewer_delAllItems;
+ VT *viewer_enumViewItem(int which)
+ {
+ return static_cast<VT*>(DependentViewerI::viewer_enumViewItem(which));
+ }
+ using DependentViewerI::viewer_getNumItems;
+ using DependentViewerI::viewer_haveItem;
+
+ // spiffy callbacks to override
+ // item you were looking at is gone: WARNING: pointer no longer valid!
+ virtual int viewer_onItemDeleted(VT *item) { return 1; }
+ // item you are looking at issuing an event (filtered by class guid of VT)
+ virtual int viewer_onEvent(VT *item, int event, intptr_t param2, void *ptr, size_t ptrlen) { return 1; }
+
+private:
+ virtual int viewer_onItemDeleted(ifc_dependent *item)
+ {
+ return viewer_onItemDeleted(static_cast<VT*>(item));
+ }
+ virtual int viewer_onEvent(ifc_dependent *item, const GUID *classguid, int event, intptr_t param, void *ptr, size_t ptrlen)
+ {
+ if (*classguid != *VT::depend_getClassGuid()) return 0; // filter namespace
+ return viewer_onEvent(static_cast<VT*>(item), event, param, ptr, ptrlen);
+ }
+};
+
+// ------------------------------------------------------------
+
+#include <api/dependency/api_dependent.h>
+
+class NOVTABLE DependentI : public ifc_dependent
+{
+protected:
+ DependentI(const GUID *class_guid = NULL);
+ DependentI(const DependentI &dep);
+ virtual ~DependentI();
+
+public:
+ // copy
+ DependentI& operator =(const ifc_dependent &dep);
+
+protected:
+ // override this to catch when viewers register and deregister
+ virtual void dependent_onRegViewer(api_dependentviewer *viewer, int add) {}
+ // override this to help people cast you to various classes
+ virtual void *dependent_getInterface(const GUID *classguid) { return NULL; }
+
+ // call this on yourself to send an event
+ void dependent_sendEvent(const GUID *classguid, int event, intptr_t param = 0, void *ptr = NULL, size_t ptrlen = 0, api_dependentviewer *viewer = NULL);
+
+private:
+ virtual void dependent_regViewer(api_dependentviewer *viewer, int add);
+ void sendViewerCallbacks(const GUID *classguid, int msg, intptr_t param1 = 0, intptr_t param2 = 0, void *ptr = NULL, size_t ptrlen = 0, api_dependentviewer *viewer = NULL);
+ typedef PtrList<api_dependentviewer> ViewerList;
+ ViewerList *viewers;
+ GUID class_guid;
+protected:
+ RECVS_DISPATCH;
+};
+
+
+// use like MyClass *myobj = dynamic_guid_cast<MyClass>(some_dependent_ptr);
+// MyClass::getClassGuid() must be defined
+// MyClass::dependent_getInterface() must be defined too
+template <class T>
+class dynamic_guid_cast
+{
+public:
+ dynamic_guid_cast(ifc_dependent *_dp, const GUID *_g) : dp(_dp), g(_g) { }
+ operator T*()
+ {
+ return (*g == *T::depend_getClassGuid()) ? static_cast<T*>(dp->dependent_getInterface(g)) : NULL;
+ }
+private:
+ ifc_dependent *dp;
+ const GUID *g;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/depview.cpp b/Src/Wasabi/bfc/depview.cpp
new file mode 100644
index 00000000..24ec0be8
--- /dev/null
+++ b/Src/Wasabi/bfc/depview.cpp
@@ -0,0 +1,2 @@
+#include "precomp_wasabi_bfc.h"
+#include "depview.h" \ No newline at end of file
diff --git a/Src/Wasabi/bfc/depview.h b/Src/Wasabi/bfc/depview.h
new file mode 100644
index 00000000..d743764c
--- /dev/null
+++ b/Src/Wasabi/bfc/depview.h
@@ -0,0 +1,103 @@
+#ifndef _DEPVIEW_H
+#define _DEPVIEW_H
+
+#include <bfc/depend.h>
+#include <map>
+
+// this handles classes that use the getDependencyPtr() method instead of a
+// public cast
+
+template <class VT>
+class NOVTABLE DependentViewerTPtr : private DependentViewerI
+{
+protected:
+ DependentViewerTPtr(VT *first = NULL)
+ {
+ _addViewItem(first);
+ }
+
+ void viewer_addViewItem(VT *item) { _addViewItem(item); }
+ void viewer_delViewItem(VT *item) { _delViewItem(item); }
+ using DependentViewerI::viewer_delAllItems;
+
+ VT *viewer_enumViewItem(int which)
+ {
+ return lookup(DependentViewerI::viewer_enumViewItem(which));
+ }
+ using DependentViewerI::viewer_getNumItems;
+ int viewer_haveItem(VT *item)
+ {
+ return DependentViewerI::viewer_haveItem(item->getDependencyPtr());
+ }
+
+ // item you were looking at is gone: WARNING: pointer no longer valid!
+ virtual int viewer_onItemDeleted(VT *item) { return 1; }
+ // item you are looking at issuing an event
+ virtual int viewer_onEvent(VT *item, int event, intptr_t param2, void *ptr, size_t ptrlen) { return 1; }
+
+protected:
+ virtual int viewer_onItemDeleted(ifc_dependent *item)
+ {
+ return viewer_onItemDeleted(lookup(item));
+ }
+ virtual int viewer_onEvent(ifc_dependent *item, const GUID *classguid, int event, intptr_t param, void *ptr, size_t ptrlen)
+ {
+ if (*classguid != *VT::depend_getClassGuid()) return 0; // filter namespace
+ return viewer_onEvent(lookup(item), event, param, ptr, ptrlen);
+ }
+
+private:
+ VT *lookup(ifc_dependent *d)
+ {
+ if (d == NULL)
+ return NULL;
+
+ VT *vt = NULL;
+ //int r = ptrmap.getItem(d, &vt);
+ auto it = ptrmap.find(d);
+ if (it != ptrmap.end())
+ {
+ vt = it->second;
+ }
+
+ //ASSERT(r);
+ ASSERT(vt->getDependencyPtr() == d);
+ return vt;
+ }
+ void _addViewItem(VT *item)
+ {
+ if (item == NULL)
+ return ;
+ ifc_dependent *d = item->getDependencyPtr();
+ if (d == NULL)
+ return ;
+
+ ptrmap.insert({ d, item });
+
+ DependentViewerI::viewer_addViewItem(d);
+ }
+ void _delViewItem(VT *item)
+ {
+ if (item == NULL) return ;
+ ifc_dependent *dep = NULL;
+
+ //ptrmap.reverseGetItem(item, &dep);
+ //int r = ptrmap.reverseDelItem(item);
+ for (auto &ptr : ptrmap)
+ {
+ if (ptr.second == item)
+ {
+ dep = ptr.first;
+ ptrmap.erase(dep);
+ break;
+ }
+ }
+
+ //ASSERT(r);
+ DependentViewerI::viewer_delViewItem(dep);
+ }
+
+ std::map<ifc_dependent *, VT *> ptrmap;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/dispatch.h b/Src/Wasabi/bfc/dispatch.h
new file mode 100644
index 00000000..541527c3
--- /dev/null
+++ b/Src/Wasabi/bfc/dispatch.h
@@ -0,0 +1,622 @@
+#pragma once
+//#include <bfc/platform/platform.h>
+#include "bfc/platform/types.h"
+#include "bfc/platform/guid.h"
+
+#ifdef WIN32
+#ifndef NOVTABLE
+#define NOVTABLE __declspec(novtable)
+#endif
+#else
+#define NOVTABLE
+#endif
+class DispatchableCallback;
+
+#pragma warning(disable: 4786)
+#pragma warning(disable: 4275)
+#pragma warning(disable: 4100)
+
+enum
+{
+ DISPATCH_SUCCESS = 0,
+ DISPATCH_FAILURE = 1,
+};
+
+
+class NOVTABLE Dispatchable
+{
+public:
+// // fake virtual destructor
+// void destruct() { _voidcall(DESTRUCT); }
+
+ // this is virtual so it is visible across modules
+ virtual int _dispatch( int msg, void *retval, void **params = 0, int nparam = 0 ) = 0;
+
+
+ /* added 22 May 2007. these aren't used yet. To be used in the future
+ in the meantime, don't use negative numbers for your msg values */
+ int AddRef();
+ int Release();
+ int QueryInterface( GUID interface_guid, void **object );
+ enum
+ {
+ ADDREF = -1,
+ RELEASE = -2,
+ QUERYINTERFACE = -3,
+ };
+protected:
+// // protected real destructor
+// ~Dispatchable() {}
+ // helper templates to implement client-side methods
+ int _voidcall( int msg )
+ {
+ return _dispatch( msg, 0 );
+ }
+
+ template<class PARAM1>
+ int _voidcall( int msg, PARAM1 param1 )
+ {
+ void *params[ 1 ] = { &param1 };
+ return _dispatch( msg, 0, params, 1 );
+ }
+
+ template<class PARAM1, class PARAM2>
+ int _voidcall( int msg, PARAM1 param1, PARAM2 param2 )
+ {
+ void *params[ 2 ] = { &param1, &param2 };
+ return _dispatch( msg, 0, params, 2 );
+ }
+
+ template<class PARAM1, class PARAM2, class PARAM3>
+ int _voidcall( int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3 )
+ {
+ void *params[ 3 ] = { &param1, &param2, &param3 };
+ return _dispatch( msg, 0, params, 3 );
+ }
+
+ template<class PARAM1, class PARAM2, class PARAM3, class PARAM4>
+ int _voidcall( int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4 )
+ {
+ void *params[ 4 ] = { &param1, &param2, &param3, &param4 };
+ return _dispatch( msg, 0, params, 4 );
+ }
+
+ template<class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5>
+ int _voidcall( int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5 )
+ {
+// void *params[4] = { &param1, &param2, &param3, &param4, &param5 }; // mig found another bug
+ void *params[ 5 ] = { &param1, &param2, &param3, &param4, &param5 };
+ return _dispatch( msg, 0, params, 5 );
+ }
+
+ template<class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6>
+ int _voidcall( int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6 )
+ {
+// void *params[4] = { &param1, &param2, &param3, &param4, &param5, &param6 }; // mig found another bug
+ void *params[ 6 ] = { &param1, &param2, &param3, &param4, &param5, &param6 };
+ return _dispatch( msg, 0, params, 6 );
+ }
+
+ template<class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7>
+ int _voidcall( int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7 )
+ {
+ void *params[ 7 ] = { &param1, &param2, &param3, &param4, &param5, &param6 , &param7 };
+ return _dispatch( msg, 0, params, 7 );
+ }
+
+ template<class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8>
+ int _voidcall( int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8 )
+ {
+ void *params[ 8 ] = { &param1, &param2, &param3, &param4, &param5, &param6 , &param7 , &param8 };
+ return _dispatch( msg, 0, params, 8 );
+ }
+
+ template<class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9>
+ int _voidcall( int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9 )
+ {
+ void *params[ 9 ] = { &param1, &param2, &param3, &param4, &param5, &param6 , &param7 , &param8 , &param9 };
+ return _dispatch( msg, 0, params, 9 );
+ }
+
+ template<class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10>
+ int _voidcall( int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9, PARAM10 param10 )
+ {
+ void *params[ 10 ] = { &param1, &param2, &param3, &param4, &param5, &param6 , &param7 , &param8 , &param9 , &param10 };
+ return _dispatch( msg, 0, params, 10 );
+ }
+
+ template<class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10, class PARAM11, class PARAM12, class PARAM13, class PARAM14>
+ int _voidcall( int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9, PARAM10 param10, PARAM11 param11, PARAM12 param12, PARAM13 param13, PARAM14 param14 )
+ {
+ void *params[ 14 ] = { &param1, &param2, &param3, &param4, &param5, &param6 , &param7 , &param8 , &param9 , &param10 , &param11 , &param12 , &param13 , &param14 };
+ return _dispatch( msg, 0, params, 14 );
+ }
+
+ template<class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10, class PARAM11, class PARAM12, class PARAM13, class PARAM14, class PARAM15, class PARAM16>
+ int _voidcall( int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9, PARAM10 param10, PARAM11 param11, PARAM12 param12, PARAM13 param13, PARAM14 param14, PARAM15 param15, PARAM16 param16 )
+ {
+ void *params[ 16 ] = { &param1, &param2, &param3, &param4, &param5, &param6 , &param7 , &param8 , &param9 , &param10 , &param11 , &param12 , &param13 , &param14 , &param15 , &param16 };
+ return _dispatch( msg, 0, params, 16 );
+ }
+
+ template<class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10, class PARAM11, class PARAM12, class PARAM13, class PARAM14, class PARAM15, class PARAM16, class PARAM17>
+ int _voidcall( int msg, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9, PARAM10 param10, PARAM11 param11, PARAM12 param12, PARAM13 param13, PARAM14 param14, PARAM15 param15, PARAM16 param16, PARAM17 param17 )
+ {
+ void *params[ 17 ] = { &param1, &param2, &param3, &param4, &param5, &param6 , &param7 , &param8 , &param9 , &param10 , &param11 , &param12 , &param13 , &param14 , &param15 , &param16 , &param17 };
+ return _dispatch( msg, 0, params, 17 );
+ }
+
+
+ template<class RETURN_TYPE>
+ RETURN_TYPE _call( int msg, RETURN_TYPE defval )
+ {
+ RETURN_TYPE retval;
+ if ( _dispatch( msg, &retval ) ) return retval;
+ return defval;
+ }
+
+ template<class RETURN_TYPE, class PARAM1>
+ RETURN_TYPE _call( int msg, RETURN_TYPE defval, PARAM1 param1 )
+ {
+ void *params[ 1 ] = { &param1 };
+ RETURN_TYPE retval;
+ if ( _dispatch( msg, &retval, params, 1 ) ) return retval;
+ return defval;
+ }
+
+ template<class RETURN_TYPE, class PARAM1, class PARAM2>
+ RETURN_TYPE _call( int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2 )
+ {
+ void *params[ 2 ] = { &param1, &param2 };
+ RETURN_TYPE retval;
+ if ( _dispatch( msg, &retval, params, 2 ) ) return retval;
+ return defval;
+ }
+
+ template<class RETURN_TYPE, class PARAM1, class PARAM2, class PARAM3>
+ RETURN_TYPE _call( int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3 )
+ {
+ void *params[ 3 ] = { &param1, &param2, &param3 };
+ RETURN_TYPE retval;
+ if ( _dispatch( msg, &retval, params, 3 ) ) return retval;
+ return defval;
+ }
+
+ template<class RETURN_TYPE, class PARAM1, class PARAM2, class PARAM3, class PARAM4>
+ RETURN_TYPE _call( int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4 )
+ {
+ void *params[ 4 ] = { &param1, &param2, &param3, &param4 };
+ RETURN_TYPE retval;
+ if ( _dispatch( msg, &retval, params, 4 ) ) return retval;
+ return defval;
+ }
+
+ template<class RETURN_TYPE, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5>
+ RETURN_TYPE _call( int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5 )
+ {
+ void *params[ 5 ] = { &param1, &param2, &param3, &param4, &param5 };
+ RETURN_TYPE retval;
+ if ( _dispatch( msg, &retval, params, 5 ) ) return retval;
+ return defval;
+ }
+
+ template<class RETURN_TYPE, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6>
+ RETURN_TYPE _call( int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6 )
+ {
+ void *params[ 6 ] = { &param1, &param2, &param3, &param4, &param5, &param6 };
+ RETURN_TYPE retval;
+ if ( _dispatch( msg, &retval, params, 6 ) ) return retval;
+ return defval;
+ }
+
+ template<class RETURN_TYPE, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7>
+ RETURN_TYPE _call( int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7 )
+ {
+ void *params[ 7 ] = { &param1, &param2, &param3, &param4, &param5, &param6, &param7 };
+ RETURN_TYPE retval;
+ if ( _dispatch( msg, &retval, params, 7 ) ) return retval;
+ return defval;
+ }
+
+ template<class RETURN_TYPE, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8>
+ RETURN_TYPE _call( int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8 )
+ {
+ void *params[ 8 ] = { &param1, &param2, &param3, &param4, &param5, &param6, &param7, &param8 };
+ RETURN_TYPE retval;
+ if ( _dispatch( msg, &retval, params, 8 ) ) return retval;
+ return defval;
+ }
+
+ template<class RETURN_TYPE, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9>
+ RETURN_TYPE _call( int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9 )
+ {
+ void *params[ 9 ] = { &param1, &param2, &param3, &param4, &param5, &param6, &param7, &param8, &param9 };
+ RETURN_TYPE retval;
+ if ( _dispatch( msg, &retval, params, 9 ) ) return retval;
+ return defval;
+ }
+
+ template<class RETURN_TYPE, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10>
+ RETURN_TYPE _call( int msg, RETURN_TYPE defval, PARAM1 param1, PARAM2 param2, PARAM3 param3, PARAM4 param4, PARAM5 param5, PARAM6 param6, PARAM7 param7, PARAM8 param8, PARAM9 param9, PARAM10 param10 )
+ {
+ void *params[ 10 ] = { &param1, &param2, &param3, &param4, &param5, &param6, &param7, &param8, &param9, &param10 };
+ RETURN_TYPE retval;
+ if ( _dispatch( msg, &retval, params, 10 ) ) return retval;
+ return defval;
+ }
+
+ template <class CASTNAME, class CLASSNAME, class RETVAL>
+ void cb( RETVAL( CLASSNAME:: *fn )( ), void *retval, void **params )
+ {
+ *static_cast<RETVAL *>( retval ) = ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( );
+ }
+
+ template <class CASTNAME, class CLASSNAME>
+ void vcb( void ( CLASSNAME:: *fn )( ), void *retval, void **params )
+ {
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( );
+ }
+
+ template <class CASTNAME, class CLASSNAME, class RETVAL, class PARAM1>
+ void cb( RETVAL( CLASSNAME:: *fn )( PARAM1 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ *static_cast<RETVAL *>( retval ) = ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1 );
+ }
+
+ template <class CASTNAME, class CLASSNAME, class PARAM1>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1 );
+ }
+
+ template <class CASTNAME, class CLASSNAME, class PARAM1, class PARAM2>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1, PARAM2 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2 );
+ }
+
+ template <class CASTNAME, class CLASSNAME, class RETVAL, class PARAM1, class PARAM2>
+ void cb( RETVAL( CLASSNAME:: *fn )( PARAM1, PARAM2 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ *static_cast<RETVAL *>( retval ) = ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2 );
+ }
+
+ // 3 params
+ template <class CASTNAME, class CLASSNAME, class PARAM1, class PARAM2, class PARAM3>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3 );
+ }
+
+ template <class CASTNAME, class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3>
+ void cb( RETVAL( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ *static_cast<RETVAL *>( retval ) = ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3 );
+ }
+
+ // 4 params
+ template <class CASTNAME, class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4 );
+ }
+
+ template <class CASTNAME, class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4>
+ void cb( RETVAL( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ *static_cast<RETVAL *>( retval ) = ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4 );
+ }
+
+ // 5 params
+ template <class CASTNAME, class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5 );
+ }
+
+ template <class CASTNAME, class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5>
+ void cb( RETVAL( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ *static_cast<RETVAL *>( retval ) = ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5 );
+ }
+
+ // 6 params
+ template <class CASTNAME, class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6 );
+ }
+
+ template <class CASTNAME, class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6>
+ void cb( RETVAL( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ *static_cast<RETVAL *>( retval ) = ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6 );
+ }
+
+ // 7 params
+ template <class CASTNAME, class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ PARAM7 *p7 = static_cast<PARAM7 *>( params[ 6 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6, *p7 );
+ }
+
+ template <class CASTNAME, class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7>
+ void cb( RETVAL( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ PARAM7 *p7 = static_cast<PARAM7 *>( params[ 6 ] );
+ *static_cast<RETVAL *>( retval ) = ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6, *p7 );
+ }
+
+ // 8 params
+ template <class CASTNAME, class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ PARAM7 *p7 = static_cast<PARAM7 *>( params[ 6 ] );
+ PARAM8 *p8 = static_cast<PARAM8 *>( params[ 7 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8 );
+ }
+
+ template <class CASTNAME, class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8>
+ void cb( RETVAL( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ PARAM7 *p7 = static_cast<PARAM7 *>( params[ 6 ] );
+ PARAM8 *p8 = static_cast<PARAM8 *>( params[ 7 ] );
+ *static_cast<RETVAL *>( retval ) = ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8 );
+ }
+
+ // 9 params
+ template <class CASTNAME, class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ PARAM7 *p7 = static_cast<PARAM7 *>( params[ 6 ] );
+ PARAM8 *p8 = static_cast<PARAM8 *>( params[ 7 ] );
+ PARAM9 *p9 = static_cast<PARAM9 *>( params[ 8 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9 );
+ }
+
+ template <class CASTNAME, class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9>
+ void cb( RETVAL( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ PARAM7 *p7 = static_cast<PARAM7 *>( params[ 6 ] );
+ PARAM8 *p8 = static_cast<PARAM8 *>( params[ 7 ] );
+ PARAM9 *p9 = static_cast<PARAM9 *>( params[ 8 ] );
+ *static_cast<RETVAL *>( retval ) = ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9 );
+ }
+
+ // 10 params
+ template <class CASTNAME, class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ PARAM7 *p7 = static_cast<PARAM7 *>( params[ 6 ] );
+ PARAM8 *p8 = static_cast<PARAM8 *>( params[ 7 ] );
+ PARAM9 *p9 = static_cast<PARAM9 *>( params[ 8 ] );
+ PARAM10 *p10 = static_cast<PARAM10 *>( params[ 9 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10 );
+ }
+
+ template <class CASTNAME, class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10>
+ void cb( RETVAL( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ PARAM7 *p7 = static_cast<PARAM7 *>( params[ 6 ] );
+ PARAM8 *p8 = static_cast<PARAM8 *>( params[ 7 ] );
+ PARAM9 *p9 = static_cast<PARAM9 *>( params[ 8 ] );
+ PARAM10 *p10 = static_cast<PARAM10 *>( params[ 9 ] );
+ *static_cast<RETVAL *>( retval ) = ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10 );
+ }
+
+ // 14 params
+ template <class CASTNAME, class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10, class PARAM11, class PARAM12, class PARAM13, class PARAM14>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10, PARAM11, PARAM12, PARAM13, PARAM14 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ PARAM7 *p7 = static_cast<PARAM7 *>( params[ 6 ] );
+ PARAM8 *p8 = static_cast<PARAM8 *>( params[ 7 ] );
+ PARAM9 *p9 = static_cast<PARAM9 *>( params[ 8 ] );
+ PARAM10 *p10 = static_cast<PARAM10 *>( params[ 9 ] );
+ PARAM11 *p11 = static_cast<PARAM11 *>( params[ 10 ] );
+ PARAM12 *p12 = static_cast<PARAM12 *>( params[ 11 ] );
+ PARAM13 *p13 = static_cast<PARAM13 *>( params[ 12 ] );
+ PARAM14 *p14 = static_cast<PARAM14 *>( params[ 13 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14 );
+ }
+
+ // 16 params
+ template <class CASTNAME, class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10, class PARAM11, class PARAM12, class PARAM13, class PARAM14, class PARAM15, class PARAM16>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10, PARAM11, PARAM12, PARAM13, PARAM14, PARAM15, PARAM16 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ PARAM7 *p7 = static_cast<PARAM7 *>( params[ 6 ] );
+ PARAM8 *p8 = static_cast<PARAM8 *>( params[ 7 ] );
+ PARAM9 *p9 = static_cast<PARAM9 *>( params[ 8 ] );
+ PARAM10 *p10 = static_cast<PARAM10 *>( params[ 9 ] );
+ PARAM11 *p11 = static_cast<PARAM11 *>( params[ 10 ] );
+ PARAM12 *p12 = static_cast<PARAM12 *>( params[ 11 ] );
+ PARAM13 *p13 = static_cast<PARAM13 *>( params[ 12 ] );
+ PARAM14 *p14 = static_cast<PARAM14 *>( params[ 13 ] );
+ PARAM15 *p15 = static_cast<PARAM15 *>( params[ 14 ] );
+ PARAM16 *p16 = static_cast<PARAM16 *>( params[ 15 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14, *p15, *p16 );
+ }
+
+ // 17 params
+ template <class CASTNAME, class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10, class PARAM11, class PARAM12, class PARAM13, class PARAM14, class PARAM15, class PARAM16, class PARAM17>
+ void vcb( void ( CLASSNAME:: *fn )( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10, PARAM11, PARAM12, PARAM13, PARAM14, PARAM15, PARAM16, PARAM17 ), void *retval, void **params )
+ {
+ PARAM1 *p1 = static_cast<PARAM1 *>( params[ 0 ] );
+ PARAM2 *p2 = static_cast<PARAM2 *>( params[ 1 ] );
+ PARAM3 *p3 = static_cast<PARAM3 *>( params[ 2 ] );
+ PARAM4 *p4 = static_cast<PARAM4 *>( params[ 3 ] );
+ PARAM5 *p5 = static_cast<PARAM5 *>( params[ 4 ] );
+ PARAM6 *p6 = static_cast<PARAM6 *>( params[ 5 ] );
+ PARAM7 *p7 = static_cast<PARAM7 *>( params[ 6 ] );
+ PARAM8 *p8 = static_cast<PARAM8 *>( params[ 7 ] );
+ PARAM9 *p9 = static_cast<PARAM9 *>( params[ 8 ] );
+ PARAM10 *p10 = static_cast<PARAM10 *>( params[ 9 ] );
+ PARAM11 *p11 = static_cast<PARAM11 *>( params[ 10 ] );
+ PARAM12 *p12 = static_cast<PARAM12 *>( params[ 11 ] );
+ PARAM13 *p13 = static_cast<PARAM13 *>( params[ 12 ] );
+ PARAM14 *p14 = static_cast<PARAM14 *>( params[ 13 ] );
+ PARAM15 *p15 = static_cast<PARAM15 *>( params[ 14 ] );
+ PARAM16 *p16 = static_cast<PARAM16 *>( params[ 15 ] );
+ PARAM17 *p17 = static_cast<PARAM17 *>( params[ 16 ] );
+ ( static_cast<CLASSNAME *>( static_cast<CASTNAME *>( this ) )->*fn )( *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14, *p15, *p16, *p17 );
+ }
+
+
+ enum
+ {
+ DESTRUCT = 0xffff
+ };
+};
+
+#define CB(x, y) case (x): cb<CBCLASS>(&CBCLASS::y, retval, params); break;
+#define CBT(x, y) case (x): cb<CBCLASST>(&CBCLASS::y, retval, params); break;
+#define VCB(x, y) case (x): vcb<CBCLASS>(&CBCLASS::y, retval, params); break;
+#define VCBT(x, y) case (x): vcb<CBCLASST>(&CBCLASS::y, retval, params); break;
+
+#define RECVS_DISPATCH virtual int _dispatch(int msg, void *retval, void **params=0, int nparam=0)
+
+#define START_DISPATCH \
+ int CBCLASS::_dispatch(int msg, void *retval, void **params, int nparam) { \
+ switch (msg) {
+#define START_DISPATCH_INLINE \
+ int _dispatch(int msg, void *retval, void **params, int nparam) { \
+ switch (msg) {
+
+//FINISH case DESTRUCT: delete this; return 1;
+#define END_DISPATCH \
+ default: return 0; \
+ } \
+ return 1; \
+ }
+#define FORWARD_DISPATCH(x) \
+ default: return x::_dispatch(msg, retval, params, nparam); \
+ } \
+ return 1; \
+ }
+
+#define DISPATCH_CODES enum
+
+inline int Dispatchable::AddRef()
+{
+ return _call( Dispatchable::ADDREF, 0 );
+}
+
+inline int Dispatchable::Release()
+{
+ return _call( Dispatchable::RELEASE, 0 );
+}
+
+inline int Dispatchable::QueryInterface( GUID interface_guid, void **object )
+{
+ return _call( Dispatchable::QUERYINTERFACE, 0, interface_guid, object );
+}
+
+#ifndef DECLARE_EXTERNAL_SERVICE
+#define DECLARE_EXTERNAL_SERVICE(_type, _name) extern _type *_name
+#endif
+
+#ifndef DEFINE_EXTERNAL_SERVICE
+#define DEFINE_EXTERNAL_SERVICE(_type, _name) _type *_name=0
+#endif
diff --git a/Src/Wasabi/bfc/draw/convolve.cpp b/Src/Wasabi/bfc/draw/convolve.cpp
new file mode 100644
index 00000000..2ac48930
--- /dev/null
+++ b/Src/Wasabi/bfc/draw/convolve.cpp
@@ -0,0 +1,60 @@
+#include <precomp.h>
+
+#include "convolve.h"
+
+#define RED(a) (((a)>>16)&0xff)
+#define GRN(a) (((a)>>8)&0xff)
+#define BLU(a) (((a)&0xff))
+#define ALP(a) (((a)>>24))
+
+Convolve3x3::Convolve3x3(ARGB32 *_bits, int _w, int _h) : bits(_bits), w(_w), h(_h) {
+ ZERO(vals);
+ multiplier = 0;
+}
+
+void Convolve3x3::setPos(int x, int y, float v) {
+ ASSERT(x >= -1 && x <= 1 && y >= -1 && y <= 1);
+ vals[y+1][x+1] = v;
+}
+
+void Convolve3x3::setMultiplier(int m) {
+ multiplier = m;
+}
+
+void Convolve3x3::convolve() {
+ if (bits == NULL || w <= 0 || h <= 0) return; // nothin'
+ MemMatrix<ARGB32> temp(w, h, bits); // make a copy
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ if (ALP(temp(x, y))<=1) continue;
+ float ra=0, rg=0, rb=0;
+ for (int a = -1; a <= 1; a++) {
+ for (int b = -1; b <= 1; b++) {
+ int px = x + a, py = y + b;
+ if (px < 0 || px >= w || py < 0 || py >= h) continue;
+ ARGB32 c = temp(px, py);
+ if (ALP(c) <= 1) continue;
+ ra += (float)RED(c) * vals[b][a] * multiplier;
+ rg += (float)GRN(c) * vals[b][a] * multiplier;
+ rb += (float)BLU(c) * vals[b][a] * multiplier;
+ }
+ }
+ unsigned int r = MINMAX((int)ra, 0, 255);
+ unsigned int g = MINMAX((int)rg, 0, 255);
+ unsigned int b = MINMAX((int)rb, 0, 255);
+ unsigned int lum = MAX(MAX(r, g), b);
+if (lum < 64) lum = 0;
+else if (lum > 192) lum = 255;
+ //bits[x+y*w] = (ALP(*temp.m(x, y))<<24)|(r<<16)|(g<<8)|(b);
+ bits[x+y*w] &= 0xffffff;
+ bits[x+y*w] |= (255-lum) << 24;
+//if (lum < 64) {
+// bits[x+y*w] &= 0xffff00ff;
+// bits[x+y*w] |= lum << 8;
+//} else {
+// bits[x+y*w] &= 0xff00ffff;
+// bits[x+y*w] |= lum << 16;
+//}
+ }
+ }
+}
diff --git a/Src/Wasabi/bfc/draw/convolve.h b/Src/Wasabi/bfc/draw/convolve.h
new file mode 100644
index 00000000..aac2e237
--- /dev/null
+++ b/Src/Wasabi/bfc/draw/convolve.h
@@ -0,0 +1,24 @@
+#ifndef _CONVOLVE_H
+#define _CONVOLVE_H
+
+#include "platform/types.h"
+// world's slowest crappiest convolve :P think it sucks? write a better one
+// and send it to me
+
+class Convolve3x3 {
+public:
+ Convolve3x3(ARGB32 *bits, int w, int h);
+
+ void setPos(int x, int y, float v);
+ void setMultiplier(int m);
+
+ void convolve();
+
+private:
+ ARGB32 *bits;
+ int w, h;
+ float vals[3][3];
+ float multiplier;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/draw/drawpoly.cpp b/Src/Wasabi/bfc/draw/drawpoly.cpp
new file mode 100644
index 00000000..02c84f33
--- /dev/null
+++ b/Src/Wasabi/bfc/draw/drawpoly.cpp
@@ -0,0 +1,458 @@
+#include <precomp.h>
+
+#include "drawpoly.h"
+#include <bfc/parse/pathparse.h>
+
+#define MAXPOINTS 32
+
+static ARGB32 *bits, color;
+static int w, h, across;
+struct Point2d {
+ int X, Y;
+};
+typedef struct Point2d Point2d; // bleh
+static Point2d points[MAXPOINTS];
+static int npoints;
+
+void Draw::beginPolygon(ARGB32 *bits, int w, int h, ARGB32 color) {
+ ::bits = bits;
+ ::w = w;
+ ::h = h;
+ ::color = color;
+ ::across = w;
+ npoints = 0;
+}
+
+void Draw::addPoint(int x, int y) {
+ if (npoints >= MAXPOINTS) return;
+ points[npoints].X = x;
+ points[npoints].Y = y;
+ npoints++;
+}
+
+static void premultiply(ARGB32 *m_pBits, int nwords) {
+ for (; nwords > 0; nwords--, m_pBits++) {
+ unsigned __int8 *pixel = (unsigned __int8 *)m_pBits;
+ unsigned int alpha = pixel[3];
+ if (alpha == 255) continue;
+ pixel[0] = (pixel[0] * alpha) >> 8; // blue
+ pixel[1] = (pixel[1] * alpha) >> 8; // green
+ pixel[2] = (pixel[2] * alpha) >> 8; // red
+ }
+}
+
+void Draw::drawPointList(ARGB32 *bits, int w, int h, const wchar_t *pointlist) {
+ if (pointlist == NULL || *pointlist == '\0') return;
+ PathParserW outer(pointlist, L"|");
+ const wchar_t *pl;
+ for (int i = 0; (pl = outer.enumString(i)) != NULL; i++)
+ {
+ PathParserW inner(pl, L"=");
+ ARGB32 color = WASABI_API_SKIN->parse(inner.enumStringSafe(1, L"255,255,255,255"), L"coloralpha");
+ int a = color & 0xff000000;
+ color = _byteswap_ulong(color<<8) | a;
+ premultiply(&color, 1);
+ beginPolygon(bits, w, h, color);
+ PathParserW eener(inner.enumStringSafe(0, L"0,0"), L";");
+ const wchar_t *cc;
+ for (int j = 0; (cc = eener.enumString(j)) != NULL; j++) {
+ PathParserW com(cc, L",");
+ const wchar_t *xs = com.enumStringSafe(0, L"0");
+ int x = wcschr(xs, '.') ? (int)floor(WTOF(xs) * w + .5f) : WTOI(xs);
+ const wchar_t *ys = com.enumStringSafe(1, L"0");
+ int y = wcschr(ys, '.') ? (int)floor(WTOF(ys) * h + .5f) : WTOI(ys);
+ addPoint(x, y);
+ }
+ endPolygon();
+ }
+}
+
+#define PIXEL ARGB32
+
+// this originally came from Michael Abrash's Zen of Graphics Programming
+// been modified a bit
+/* DRAWPOLY.H: Header file for polygon-filling code */
+
+/* Describes a single point (used for a single vertex) */
+
+//struct Point2d {
+// int X; /* X coordinate */
+// int Y; /* Y coordinate */
+//};
+
+//typedef struct Point2d Point2d;
+
+typedef struct {
+ int X, Y;
+} Point2dC;
+
+/* Describes a series of points (used to store a list of vertices that
+ describe a polygon; each vertex is assumed to connect to the two
+ adjacent vertices, and the last vertex is assumed to connect to the
+ first) */
+struct Point2dListHeader {
+ int Length; /* # of points */
+ struct Point2d *Point2dPtr; /* pointer to list of points */
+};
+
+typedef struct Point2dListHeader Point2dListHeader;
+
+/* Describes the beginning and ending X coordinates of a single
+ horizontal line */
+struct HLine {
+ int XStart; /* X coordinate of leftmost pixel in line */
+ int XEnd; /* X coordinate of rightmost pixel in line */
+};
+
+typedef struct {
+ int XStart, XEnd;
+} HLineColor;
+
+/* Describes a Length-long series of horizontal lines, all assumed to
+ be on contiguous scan lines starting at YStart and proceeding
+ downward (used to describe a scan-converted polygon to the
+ low-level hardware-dependent drawing code) */
+struct HLineList {
+ int Length; /* # of horizontal lines */
+ int YStart; /* Y coordinate of topmost line */
+ struct HLine * HLinePtr; /* pointer to list of horz lines */
+};
+
+static void DrawHorizontalLineList(struct HLineList * HLineListPtr, PIXEL *dest,
+ PIXEL Color) {
+ struct HLine *HLinePtr, *ptr;
+ int Length, Width, c;
+ PIXEL *ScreenPtr;
+
+ /* Point to the start of the first scan line on which to draw */
+ ScreenPtr = dest + HLineListPtr->YStart * across;
+ Length = HLineListPtr->Length;
+ /* Point to the XStart/XEnd descriptor for the first (top)
+ horizontal line */
+ HLinePtr = HLineListPtr->HLinePtr;
+
+ /* clip left/right */
+ for (ptr = HLinePtr, c = Length; c; c--) {
+ if (ptr->XStart < 0) ptr->XStart = 0;
+ if (ptr->XEnd >= w) ptr->XEnd = w - 1;
+ ptr++;
+ }
+ /* clip top */
+ if (HLineListPtr->YStart < 0) {
+ int skip = -HLineListPtr->YStart;
+ HLineListPtr->YStart = 0;
+ ScreenPtr += across * skip;
+ Length -= skip;
+ HLinePtr += skip;
+ }
+ /* clip bottom */
+ if (HLineListPtr->YStart + Length > h) {
+ Length -= (HLineListPtr->YStart + Length) - h;
+ }
+
+ /* Draw each horizontal line in turn, starting with the top one and
+ advancing one line each time */
+ while (Length-- > 0) {
+ /* Draw the whole horizontal line if it has a positive width */
+ if ((Width = HLinePtr->XEnd - HLinePtr->XStart + 1) > 0)
+// bmemsetw(ScreenPtr+HLinePtr->XStart, Color, Width);
+ MEMFILL<PIXEL>(ScreenPtr+HLinePtr->XStart, Color, Width);
+ HLinePtr++; /* point to next scan line X info */
+ ScreenPtr += across; /* point to next scan line start */
+ }
+}
+
+/* Scan converts an edge from (X1,Y1) to (X2,Y2), not including the
+ point at (X2,Y2). If SkipFirst == 1, the point at (X1,Y1) isn't
+ drawn; if SkipFirst == 0, it is. For each scan line, the pixel
+ closest to the scanned edge without being to the left of the
+ scanned edge is chosen. Uses an all-integer approach for speed and
+ precision
+
+ Link with L21-1.C, L21-3.C, and L22-1.C in Compact model.
+ Tested with Borland C++ 4.02 by Jim Mischel 12/16/94.
+*/
+
+static void ScanEdge(int X1, int Y1, int X2, int Y2, int SetXStart,
+ int SkipFirst, struct HLine **EdgePoint2dPtr) {
+ int DeltaX, Height, Width, AdvanceAmt, ErrorTerm, i;
+ int ErrorTermAdvance, XMajorAdvanceAmt;
+ struct HLine *WorkingEdgePoint2dPtr;
+
+ WorkingEdgePoint2dPtr = *EdgePoint2dPtr; /* avoid double dereference */
+ AdvanceAmt = ((DeltaX = X2 - X1) > 0) ? 1 : -1;
+ /* direction in which X moves (Y2 is
+ always > Y1, so Y always counts up) */
+
+ if ((Height = Y2 - Y1) <= 0) /* Y length of the edge */
+ return; /* guard against 0-length and horizontal edges */
+
+ /* Figure out whether the edge is vertical, diagonal, X-major
+ (mostly horizontal), or Y-major (mostly vertical) and handle
+ appropriately */
+ if ((Width = abs(DeltaX)) == 0) {
+ /* The edge is vertical; special-case by just storing the same
+ X coordinate for every scan line */
+ /* Scan the edge for each scan line in turn */
+ for (i = Height - SkipFirst; i-- > 0; WorkingEdgePoint2dPtr++) {
+ /* Store the X coordinate in the appropriate edge list */
+ if (SetXStart == 1)
+ WorkingEdgePoint2dPtr->XStart = X1;
+ else
+ WorkingEdgePoint2dPtr->XEnd = X1;
+ }
+ } else if (Width == Height) {
+ /* The edge is diagonal; special-case by advancing the X
+ coordinate 1 pixel for each scan line */
+ if (SkipFirst) /* skip the first point if so indicated */
+ X1 += AdvanceAmt; /* move 1 pixel to the left or right */
+ /* Scan the edge for each scan line in turn */
+ for (i = Height - SkipFirst; i-- > 0; WorkingEdgePoint2dPtr++) {
+ /* Store the X coordinate in the appropriate edge list */
+ if (SetXStart == 1)
+ WorkingEdgePoint2dPtr->XStart = X1;
+ else
+ WorkingEdgePoint2dPtr->XEnd = X1;
+ X1 += AdvanceAmt; /* move 1 pixel to the left or right */
+ }
+ } else if (Height > Width) {
+ /* Edge is closer to vertical than horizontal (Y-major) */
+ if (DeltaX >= 0)
+ ErrorTerm = 0; /* initial error term going left->right */
+ else
+ ErrorTerm = -Height + 1; /* going right->left */
+ if (SkipFirst) { /* skip the first point if so indicated */
+ /* Determine whether it's time for the X coord to advance */
+ if ((ErrorTerm += Width) > 0) {
+ X1 += AdvanceAmt; /* move 1 pixel to the left or right */
+ ErrorTerm -= Height; /* advance ErrorTerm to next point */
+ }
+ }
+ /* Scan the edge for each scan line in turn */
+ for (i = Height - SkipFirst; i-- > 0; WorkingEdgePoint2dPtr++) {
+ /* Store the X coordinate in the appropriate edge list */
+ if (SetXStart == 1)
+ WorkingEdgePoint2dPtr->XStart = X1;
+ else
+ WorkingEdgePoint2dPtr->XEnd = X1;
+ /* Determine whether it's time for the X coord to advance */
+ if ((ErrorTerm += Width) > 0) {
+ X1 += AdvanceAmt; /* move 1 pixel to the left or right */
+ ErrorTerm -= Height; /* advance ErrorTerm to correspond */
+ }
+ }
+ } else {
+ /* Edge is closer to horizontal than vertical (X-major) */
+ /* Minimum distance to advance X each time */
+ XMajorAdvanceAmt = (Width / Height) * AdvanceAmt;
+ /* Error term advance for deciding when to advance X 1 extra */
+ ErrorTermAdvance = Width % Height;
+ if (DeltaX >= 0)
+ ErrorTerm = 0; /* initial error term going left->right */
+ else
+ ErrorTerm = -Height + 1; /* going right->left */
+ if (SkipFirst) { /* skip the first point if so indicated */
+ X1 += XMajorAdvanceAmt; /* move X minimum distance */
+ /* Determine whether it's time for X to advance one extra */
+ if ((ErrorTerm += ErrorTermAdvance) > 0) {
+ X1 += AdvanceAmt; /* move X one more */
+ ErrorTerm -= Height; /* advance ErrorTerm to correspond */
+ }
+ }
+ /* Scan the edge for each scan line in turn */
+ for (i = Height - SkipFirst; i-- > 0; WorkingEdgePoint2dPtr++) {
+ /* Store the X coordinate in the appropriate edge list */
+ if (SetXStart == 1)
+ WorkingEdgePoint2dPtr->XStart = X1;
+ else
+ WorkingEdgePoint2dPtr->XEnd = X1;
+ X1 += XMajorAdvanceAmt; /* move X minimum distance */
+ /* Determine whether it's time for X to advance one extra */
+ if ((ErrorTerm += ErrorTermAdvance) > 0) {
+ X1 += AdvanceAmt; /* move X one more */
+ ErrorTerm -= Height; /* advance ErrorTerm to correspond */
+ }
+ }
+ }
+
+ *EdgePoint2dPtr = WorkingEdgePoint2dPtr; /* advance caller's ptr */
+}
+
+/* Color-fills a convex polygon. All vertices are offset by (XOffset,
+ YOffset). "Convex" means that every horizontal line drawn through
+ the polygon at any point would cross exactly two active edges
+ (neither horizontal lines nor zero-length edges count as active
+ edges; both are acceptable anywhere in the polygon), and that the
+ right & left edges never cross. (It's OK for them to touch, though,
+ so long as the right edge never crosses over to the left of the
+ left edge.) Nonconvex polygons won't be drawn properly. Returns 1
+ for success, 0 if memory allocation failed.
+
+ Compiled with Borland C++ 4.02. Link with L21-3.C.
+ Checked by Jim Mischel 11/30/94.
+ */
+
+/* Advances the index by one vertex forward through the vertex list,
+ wrapping at the end of the list */
+#define INDEX_FORWARD(Index) \
+ Index = (Index + 1) % VertexList->Length;
+
+/* Advances the index by one vertex backward through the vertex list,
+ wrapping at the start of the list */
+#define INDEX_BACKWARD(Index) \
+ Index = (Index - 1 + VertexList->Length) % VertexList->Length;
+
+/* Advances the index by one vertex either forward or backward through
+ the vertex list, wrapping at either end of the list */
+#define INDEX_MOVE(Index,Direction) \
+ if (Direction > 0) \
+ Index = (Index + 1) % VertexList->Length; \
+ else \
+ Index = (Index - 1 + VertexList->Length) % VertexList->Length;
+
+int FillConvexPolygon(struct Point2dListHeader *VertexList, PIXEL *dest,
+ PIXEL Color) {
+ int i, MinIndexL, MaxIndex, MinIndexR, SkipFirst, Temp;
+ int MinPoint2d_Y, MaxPoint2d_Y, TopIsFlat, LeftEdgeDir;
+ int NextIndex, CurrentIndex, PreviousIndex;
+ int DeltaXN, DeltaYN, DeltaXP, DeltaYP;
+ struct HLineList WorkingHLineList;
+ struct HLine *EdgePoint2dPtr;
+ struct Point2d *VertexPtr;
+
+ /* Point to the vertex list */
+ VertexPtr = VertexList->Point2dPtr;
+
+ /* Scan the list to find the top and bottom of the polygon */
+ if (VertexList->Length == 0)
+ return(1); /* reject null polygons */
+ MaxPoint2d_Y = MinPoint2d_Y = VertexPtr[MinIndexL = MaxIndex = 0].Y;
+ for (i = 1; i < VertexList->Length; i++) {
+ if (VertexPtr[i].Y < MinPoint2d_Y)
+ MinPoint2d_Y = VertexPtr[MinIndexL = i].Y; /* new top */
+ else if (VertexPtr[i].Y > MaxPoint2d_Y)
+ MaxPoint2d_Y = VertexPtr[MaxIndex = i].Y; /* new bottom */
+ }
+ if (MinPoint2d_Y == MaxPoint2d_Y)
+ return(1); /* polygon is 0-height; avoid infinite loop below */
+
+ /* Scan in ascending order to find the last top-edge point */
+ MinIndexR = MinIndexL;
+ while (VertexPtr[MinIndexR].Y == MinPoint2d_Y)
+ INDEX_FORWARD(MinIndexR);
+ INDEX_BACKWARD(MinIndexR); /* back up to last top-edge point */
+
+ /* Now scan in descending order to find the first top-edge point */
+ while (VertexPtr[MinIndexL].Y == MinPoint2d_Y)
+ INDEX_BACKWARD(MinIndexL);
+ INDEX_FORWARD(MinIndexL); /* back up to first top-edge point */
+
+ /* Figure out which direction through the vertex list from the top
+ vertex is the left edge and which is the right */
+ LeftEdgeDir = -1; /* assume left edge runs down thru vertex list */
+ if ((TopIsFlat = (VertexPtr[MinIndexL].X !=
+ VertexPtr[MinIndexR].X) ? 1 : 0) == 1) {
+ /* If the top is flat, just see which of the ends is leftmost */
+ if (VertexPtr[MinIndexL].X > VertexPtr[MinIndexR].X) {
+ LeftEdgeDir = 1; /* left edge runs up through vertex list */
+ Temp = MinIndexL; /* swap the indices so MinIndexL */
+ MinIndexL = MinIndexR; /* points to the start of the left */
+ MinIndexR = Temp; /* edge, similarly for MinIndexR */
+ }
+ } else {
+ /* Point to the downward end of the first line of each of the
+ two edges down from the top */
+ NextIndex = MinIndexR;
+ INDEX_FORWARD(NextIndex);
+ PreviousIndex = MinIndexL;
+ INDEX_BACKWARD(PreviousIndex);
+ /* Calculate X and Y lengths from the top vertex to the end of
+ the first line down each edge; use those to compare slopes
+ and see which line is leftmost */
+ DeltaXN = VertexPtr[NextIndex].X - VertexPtr[MinIndexL].X;
+ DeltaYN = VertexPtr[NextIndex].Y - VertexPtr[MinIndexL].Y;
+ DeltaXP = VertexPtr[PreviousIndex].X - VertexPtr[MinIndexL].X;
+ DeltaYP = VertexPtr[PreviousIndex].Y - VertexPtr[MinIndexL].Y;
+ if (((long)DeltaXN * DeltaYP - (long)DeltaYN * DeltaXP) < 0L) {
+ LeftEdgeDir = 1; /* left edge runs up through vertex list */
+ Temp = MinIndexL; /* swap the indices so MinIndexL */
+ MinIndexL = MinIndexR; /* points to the start of the left */
+ MinIndexR = Temp; /* edge, similarly for MinIndexR */
+ }
+ }
+
+ /* Set the # of scan lines in the polygon, skipping the bottom edge
+ and also skipping the top vertex if the top isn't flat because
+ in that case the top vertex has a right edge component, and set
+ the top scan line to draw, which is likewise the second line of
+ the polygon unless the top is flat */
+ if ((WorkingHLineList.Length =
+ MaxPoint2d_Y - MinPoint2d_Y - 1 + TopIsFlat) <= 0)
+ return(1); /* there's nothing to draw, so we're done */
+ //WorkingHLineList.YStart = YOffset + MinPoint2d_Y + 1 - TopIsFlat;
+ WorkingHLineList.YStart = MinPoint2d_Y + 1 - TopIsFlat;
+
+ /* Get memory in which to store the line list we generate */
+ if ((WorkingHLineList.HLinePtr =
+ (struct HLine *) (malloc(sizeof(struct HLine) *
+ WorkingHLineList.Length))) == NULL)
+ return(0); /* couldn't get memory for the line list */
+
+ /* Scan the left edge and store the boundary points in the list */
+ /* Initial pointer for storing scan converted left-edge coords */
+ EdgePoint2dPtr = WorkingHLineList.HLinePtr;
+ /* Start from the top of the left edge */
+ PreviousIndex = CurrentIndex = MinIndexL;
+ /* Skip the first point of the first line unless the top is flat;
+ if the top isn't flat, the top vertex is exactly on a right
+ edge and isn't drawn */
+ SkipFirst = TopIsFlat ? 0 : 1;
+ /* Scan convert each line in the left edge from top to bottom */
+ do {
+ INDEX_MOVE(CurrentIndex,LeftEdgeDir);
+ ScanEdge(VertexPtr[PreviousIndex].X,
+ VertexPtr[PreviousIndex].Y,
+ VertexPtr[CurrentIndex].X,
+ VertexPtr[CurrentIndex].Y, 1, SkipFirst, &EdgePoint2dPtr);
+ PreviousIndex = CurrentIndex;
+ SkipFirst = 0; /* scan convert the first point from now on */
+ } while (CurrentIndex != MaxIndex);
+
+ /* Scan the right edge and store the boundary points in the list */
+ EdgePoint2dPtr = WorkingHLineList.HLinePtr;
+ PreviousIndex = CurrentIndex = MinIndexR;
+ SkipFirst = TopIsFlat ? 0 : 1;
+ /* Scan convert the right edge, top to bottom. X coordinates are
+ adjusted 1 to the left, effectively causing scan conversion of
+ the nearest points to the left of but not exactly on the edge */
+ do {
+ INDEX_MOVE(CurrentIndex,-LeftEdgeDir);
+ //ScanEdge(VertexPtr[PreviousIndex].X + XOffset - 1,
+ ScanEdge(VertexPtr[PreviousIndex].X - 1,
+ VertexPtr[PreviousIndex].Y,
+ //VertexPtr[CurrentIndex].X + XOffset - 1,
+ VertexPtr[CurrentIndex].X - 1,
+ VertexPtr[CurrentIndex].Y, 0, SkipFirst, &EdgePoint2dPtr);
+ PreviousIndex = CurrentIndex;
+ SkipFirst = 0; /* scan convert the first point from now on */
+ } while (CurrentIndex != MaxIndex);
+
+ /* Draw the line list representing the scan converted polygon */
+ //CUT (*drawfn)(&WorkingHLineList, dest, Color, vc);
+ DrawHorizontalLineList(&WorkingHLineList, dest, Color);
+
+ /* Release the line list's memory and we're successfully done */
+ free(WorkingHLineList.HLinePtr);
+ return(1);
+}
+
+// done with abrashitude
+
+void Draw::endPolygon() {
+ if (npoints == 0) return;
+
+ struct Point2dListHeader head;
+ head.Length = npoints;
+ head.Point2dPtr = &points[0];
+ FillConvexPolygon(&head, bits, color);
+}
diff --git a/Src/Wasabi/bfc/draw/drawpoly.h b/Src/Wasabi/bfc/draw/drawpoly.h
new file mode 100644
index 00000000..c8bea56d
--- /dev/null
+++ b/Src/Wasabi/bfc/draw/drawpoly.h
@@ -0,0 +1,16 @@
+#ifndef _DRAWPOLY_H
+#define _DRAWPOLY_H
+
+#include <bfc/wasabi_std.h>
+
+class Draw {
+public:
+ static void beginPolygon(ARGB32 *bits, int w, int h, ARGB32 color);
+ static void addPoint(int x, int y);
+ static void endPolygon();
+ static void drawPointList(ARGB32 *bits, int w, int h, const wchar_t *pointlist);
+};
+
+// x,y;x,y;x,y;x,y=R,G,B|x,y;x,y;x,y;=R,G,B
+
+#endif
diff --git a/Src/Wasabi/bfc/draw/gradient.cpp b/Src/Wasabi/bfc/draw/gradient.cpp
new file mode 100644
index 00000000..b8468ee0
--- /dev/null
+++ b/Src/Wasabi/bfc/draw/gradient.cpp
@@ -0,0 +1,309 @@
+#include <precomp.h>
+
+#include "gradient.h"
+
+#include <math.h>//floor
+#include <bfc/ptrlist.h>
+#include <bfc/parse/pathparse.h>
+
+
+#define DEFAULT_GRAD_MODE L"linear"
+
+template<class T> inline void SWAP(T &a, T &b) {
+ T c = a;
+ a = b;
+ b = c;
+}
+
+
+
+
+inline unsigned int LERPu(unsigned int a, unsigned int b, double p) {
+// ASSERT(p >= 0);
+// ASSERT(p <= 1.f);
+ unsigned int ret = (unsigned int)((double)b * p + (double)a * (1. - p));
+ return ret;
+}
+
+inline float LERPf(double a, double b, float p) {
+// ASSERT(p >= 0);
+// ASSERT(p <= 1.f);
+ return (float)(b * p + a * (1. - p));
+}
+
+Gradient::Gradient() :
+ gammagroup(L"")
+{
+ gradient_x1 = 0.0f;
+ gradient_y1 = 0.0f;
+ gradient_x2 = 1.0f;
+ gradient_y2 = 1.0f;
+ reverse_colors = 0;
+ antialias = 0;
+ mode = DEFAULT_GRAD_MODE;
+ list.addItem(new GradientPoint(0.0f, 0xff00ff00));
+ list.addItem(new GradientPoint(.5, 0x000000ff));
+ list.addItem(new GradientPoint(1.0f, 0xffff0000));
+}
+
+Gradient::~Gradient() {
+ list.deleteAll();
+}
+
+void Gradient::setX1(float x1) {
+ gradient_x1 = x1;
+ onParamChange();
+}
+
+void Gradient::setY1(float y1) {
+ gradient_y1 = y1;
+ onParamChange();
+}
+
+void Gradient::setX2(float x2) {
+ gradient_x2 = x2;
+ onParamChange();
+}
+
+void Gradient::setY2(float y2) {
+ gradient_y2 = y2;
+ onParamChange();
+}
+
+void Gradient::clearPoints() {
+ list.deleteAll();
+ onParamChange();
+}
+
+void Gradient::addPoint(float pos, ARGB32 color)
+{
+ list.addItem(new GradientPoint(pos, color, gammagroup));
+ onParamChange();
+}
+
+void Gradient::setPoints(const wchar_t *pointlist)
+{
+ clearPoints();
+ if (pointlist == NULL || *pointlist == '\0') return;
+// 0.5=233,445,245,123;
+ PathParserW pp(pointlist, L";");
+ if (pp.getNumStrings() <= 0) return;
+ for (int i = 0; i < pp.getNumStrings(); i++)
+ {
+ PathParserW rp(pp.enumString(i), L"=");
+ if (rp.getNumStrings() != 2)
+ continue;
+ float pos = (float)WTOF(rp.enumString(0));
+ ARGB32 color = (ARGB32)WASABI_API_SKIN->parse(rp.enumString(1), L"coloralpha");
+ addPoint(pos, color);
+ }
+}
+
+void Gradient::setReverseColors(int c) {
+ reverse_colors = c;
+}
+
+void Gradient::setAntialias(int c) {
+ antialias = c;
+}
+
+void Gradient::setMode(const wchar_t *_mode) {
+ mode = _mode;
+ if (mode.isempty())
+ mode = DEFAULT_GRAD_MODE;
+}
+
+void Gradient::setGammaGroup(const wchar_t *group) {
+ gammagroup = group;
+ // reset our points
+ foreach(list)
+ list.getfor()->color.setColorGroup(group);
+ endfor
+}
+
+static inline ARGB32 colorLerp(ARGB32 color1, ARGB32 color2, double pos) {
+ unsigned int a1 = (color1>>24) & 0xff;
+ unsigned int a2 = (color2>>24) & 0xff;
+ unsigned int r1 = (color1>>16) & 0xff;
+ unsigned int r2 = (color2>>16) & 0xff;
+ unsigned int g1 = (color1>>8) & 0xff;
+ unsigned int g2 = (color2>>8) & 0xff;
+ unsigned int b1 = (color1) & 0xff;
+ unsigned int b2 = (color2) & 0xff;
+ return (LERPu(a1, a2, pos)<<24) | (LERPu(r1, r2, pos) << 16) | (LERPu(g1,g2,pos)<<8) | LERPu(b1, b2, pos);
+}
+
+void Gradient::renderGrad(ARGB32 *ptr, int len, int *positions) {
+
+ int npos = list.getNumItems();
+ ASSERT(npos >= 2);
+
+ ARGB32 color1, color2;
+ for (int i = 0; i < npos-1; i++) {
+ color1 = list.q(i)->color.getColor();
+ color2 = list.q(i+1)->color.getColor();
+
+ if (reverse_colors) {
+ color1 = BGRATOARGB(color1);
+ color2 = BGRATOARGB(color2);
+ }
+
+ int x1 = positions[i];
+ int x2 = positions[i+1];
+ if (x1 == x2) continue;
+ // hflip if need be
+ if (x1 > x2) {
+ SWAP(x1, x2);
+ SWAP(color1, color2);
+ }
+ float c = 0;
+ float segment_len = (float)((x2 - x1)+1);
+
+ if (x1 < 0) { // clip left
+ c += -x1;
+ x1 = 0;
+ }
+ for (int x = x1; x < x2; x++, c += 1.0f) {
+ if (x >= len) break; // clip right
+ ptr[x] = colorLerp(color1, color2, c / segment_len);
+ }
+ }
+#if 0//later
+ // fill in left if needed
+ if (positions[0] > 0) MEMFILL<ARGB32>(ptr, list.q(0)->color, positions[0]);
+
+ // and right if needed
+ int rpos = positions[npos-1];
+ if (rpos < len) MEMFILL<ARGB32>(ptr+rpos, list.getLast()->color, len-rpos);
+#endif
+}
+
+void Gradient::renderGradient(ARGB32 *bits, int w, int h, int pitch)
+{
+ if (pitch == 0)
+ pitch = w;
+
+ list.sort();
+
+ ARGB32 default_color = 0xffff00ff;
+ if (list.getNumItems() == 1) default_color = list.q(0)->color.getColor();
+ // blank it out to start
+ if (pitch == w)
+ MEMFILL<ARGB32>(bits, default_color, w * h);
+ else
+ {
+ for (int i=0;i<h;i++)
+ MEMFILL<ARGB32>(bits+i*pitch, default_color, w);
+ }
+
+ if (list.getNumItems() > 1) {
+ if (mode.iscaseequal(L"linear")) {
+//FUCKO: not if endcaps are filled
+
+ // force non-vertical lines
+ if (ABS(gradient_x1 - gradient_x2) < 0.0005f) gradient_x2 = gradient_x1+0.0005f;
+
+ double px1 = gradient_x1 * w, py1 = gradient_y1 * h;
+ double px2 = gradient_x2 * w, py2 = gradient_y2 * h;
+
+ // convert to y = mx + b
+ double m = (py2 - py1)/(px2 - px1);
+ m = -1.f/m; // invert the slope
+
+ int nitems = list.getNumItems();
+
+ // get the in-pixels x and y for points on the gradient
+ for (int i = 0; i < nitems; i++) {
+ GradientPoint *gp = list.q(i);
+ // need x and y given pos
+ gp->x = LERPf(px1, px2, gp->pos);
+ gp->y = LERPf(py1, py2, gp->pos);
+ }
+
+ MemBlock<int> positions(nitems);
+ for (int _y = 0; _y < h; _y++) {
+ // project all the color points onto this scanline
+ for (int i = 0; i < nitems; i++) {
+ GradientPoint *gp = list.q(i);
+// y = mx + b
+// b = y - mx;
+ double newb = gp->y - m * gp->x;
+// y = mx + newb
+// y - newb = mx
+// (y - newb)/m = x
+ double xxx = (_y - newb)/m;
+ positions[i] = (int)floor(xxx+0.5f);
+ }
+ renderGrad(bits+_y*pitch, w, positions);
+ }
+ } else if (mode.iscaseequal(L"circular")) {
+ double tot = SQRT(SQR(gradient_x1 - gradient_x2) + SQR(gradient_y1 - gradient_y2));
+ foreach(list)
+ GradientPoint *gp = list.getfor();
+ gp->dist = gp->pos * tot;
+ endfor
+
+ ARGB32 *dst = bits;
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ ARGB32 c;
+ if (antialias) {
+ double fx = (((double)x)-0.5f) / (double)w;
+ double fy = (((double)y)-0.5f) / (double)h;
+ ARGB32 ul = getPixelCirc(fx, fy);
+ fx = (((double)x)+0.5f) / (double)w;
+ fy = (((double)y)-0.5f) / (double)h;
+ ARGB32 ur = getPixelCirc(fx, fy);
+ fx = (((double)x)+0.5f) / (double)w;
+ fy = (((double)y)+0.5f) / (double)h;
+ ARGB32 lr = getPixelCirc(fx, fy);
+ fx = (((double)x)-0.5f) / (double)w;
+ fy = (((double)y)+0.5f) / (double)h;
+ ARGB32 ll = getPixelCirc(fx, fy);
+ c = colorLerp(colorLerp(ll, lr, 0.5f), colorLerp(ul, ur, 0.5f), 0.5);
+ } else {
+ double fy = (double)y / (double)h;
+ double fx = (double)x / (double)w;
+ c = getPixelCirc(fx, fy);
+ }
+ *dst++ = c;
+ }
+ dst += (pitch-w);
+ }
+ }
+ }//list.getNumItems()>1
+
+ if (pitch == w)
+ premultiplyARGB32(bits, w * h);
+ else
+ {
+ for (int i=0;i<h;i++)
+ premultiplyARGB32(bits+i*pitch, w);
+ }
+
+}
+
+ARGB32 Gradient::getPixelCirc(double fx, double fy) {
+ int nitems = list.getNumItems();
+ //double dist = SQR(fx - gradient_x1) + SQR(fy - gradient_y1);
+ double dist = SQRT(SQR(fx - gradient_x1) + SQR(fy - gradient_y1));
+ ARGB32 c = 0xff00ff00;
+ if (dist <= list.q(0)->dist)
+ c = list.q(0)->color.getColor();
+ else if (dist >= list.getLast()->dist)
+ c = list.getLast()->color.getColor();
+ else for (int i = 0; i < nitems-1; i++) {
+ if (list.q(i)->dist <= dist && list.q(i+1)->dist >= dist) {
+ double pdist = list.q(i+1)->dist - list.q(i)->dist;
+ double pp = dist - list.q(i)->dist;
+ pp /= pdist;
+ if (list.q(i)->color.getColor() == list.q(i+1)->color.getColor())
+ c = list.q(i)->color.getColor();
+ else
+ c = colorLerp(list.q(i)->color.getColor(), list.q(i+1)->color.getColor(), pp);
+ break;
+ }
+ }
+ if (reverse_colors) c = BGRATOARGB(c);
+ return c;
+}
diff --git a/Src/Wasabi/bfc/draw/gradient.h b/Src/Wasabi/bfc/draw/gradient.h
new file mode 100644
index 00000000..1e721ee9
--- /dev/null
+++ b/Src/Wasabi/bfc/draw/gradient.h
@@ -0,0 +1,67 @@
+#ifndef _GRADIENT_H
+#define _GRADIENT_H
+
+#include <bfc/wasabi_std.h>
+#include <bfc/string/StringW.h>
+#include <tataki/color/filteredcolor.h>
+
+class GradientPoint
+{
+public:
+ GradientPoint(float p, ARGB32 c, const wchar_t *group=L"") : pos(p), dist(0), color(c, group), x(0), y(0) { }
+ float pos;
+ double dist;
+ FilteredColor color;
+ float x, y;
+ static int compareItem(GradientPoint *p1, GradientPoint* p2) {
+ int r = CMP3(p1->pos, p2->pos);
+ if (r == 0) return CMP3(p1, p2);
+ else return r;
+ }
+};
+
+
+class Gradient
+{
+public:
+ Gradient();
+ virtual ~Gradient();
+
+ void setX1(float x1);
+ void setY1(float y1);
+ void setX2(float x2);
+ void setY2(float y2);
+
+ void clearPoints();
+ void addPoint(float pos, ARGB32 color);
+
+ // "pos=color;pos=color" "0.25=34,45,111"
+ void setPoints(const wchar_t *str);
+
+ void setReverseColors(int c);
+
+ void setAntialias(int c);
+
+ void setMode(const wchar_t *mode);
+
+ void setGammaGroup(const wchar_t *group);
+
+ // note: this will automatically premultiply against alpha
+ void renderGradient(ARGB32 *bits, int width, int height, int pitch=0);
+
+protected:
+ virtual void onParamChange() { }
+
+ ARGB32 getPixelCirc(double x, double y);
+
+private:
+ float gradient_x1, gradient_y1, gradient_x2, gradient_y2;
+ class GradientList : public PtrListQuickSorted<GradientPoint, GradientPoint> { };
+ GradientList list;
+ void renderGrad(ARGB32 *bits, int len, int *positions);
+ int reverse_colors;
+ int antialias;
+ StringW mode, gammagroup;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/draw/skinfilter.cpp b/Src/Wasabi/bfc/draw/skinfilter.cpp
new file mode 100644
index 00000000..4ebbb364
--- /dev/null
+++ b/Src/Wasabi/bfc/draw/skinfilter.cpp
@@ -0,0 +1,17 @@
+#include <precomp.h>
+
+#include "skinfilter.h"
+
+#include <studio/services/svc_skinfilter.h>
+
+void ApplySkinFilters::apply(const char *elementid, const char *forced_gammagroup, ARGB32 *bits, int w, int h, int bpp) {
+ if ((elementid == NULL && forced_gammagroup == NULL) || bits == NULL || w <= 0 || h <= 0) return;
+ SkinFilterEnum sfe;
+
+ while (1) {
+ svc_skinFilter *obj = sfe.getNext(FALSE);
+ if (!obj) break;
+ obj->filterBitmap((unsigned char *)bits, w, h, bpp, elementid, forced_gammagroup);
+ sfe.getLastFactory()->releaseInterface(obj);
+ }
+}
diff --git a/Src/Wasabi/bfc/draw/skinfilter.h b/Src/Wasabi/bfc/draw/skinfilter.h
new file mode 100644
index 00000000..5b1b417f
--- /dev/null
+++ b/Src/Wasabi/bfc/draw/skinfilter.h
@@ -0,0 +1,11 @@
+#ifndef _SKINFILTER_H
+#define _SKINFILTER_H
+
+#include <bfc/std.h>
+
+class ApplySkinFilters {
+public:
+ static void apply(const char *element_id, const char *forced_gammagroup, ARGB32 *bits, int w, int h, int bpp=32);
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/error.h b/Src/Wasabi/bfc/error.h
new file mode 100644
index 00000000..9c9f7a8e
--- /dev/null
+++ b/Src/Wasabi/bfc/error.h
@@ -0,0 +1,6 @@
+#pragma once
+#ifndef REPLICANT_INCLUDE
+#include "../../replicant/foundation/error.h"
+#else
+#include "foundation/error.h"
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/bfc/file/filename.cpp b/Src/Wasabi/bfc/file/filename.cpp
new file mode 100644
index 00000000..b3d24990
--- /dev/null
+++ b/Src/Wasabi/bfc/file/filename.cpp
@@ -0,0 +1,2 @@
+#include "precomp_wasabi_bfc.h"
+#include "filename.h"
diff --git a/Src/Wasabi/bfc/file/filename.h b/Src/Wasabi/bfc/file/filename.h
new file mode 100644
index 00000000..8442f1b8
--- /dev/null
+++ b/Src/Wasabi/bfc/file/filename.h
@@ -0,0 +1,26 @@
+#ifndef _FILENAME_H
+#define _FILENAME_H
+
+#include <bfc/string/StringW.h>
+#include <bfc/string/playstring.h>
+#include <bfc/dispatch.h>
+
+// a simple class to drag-and-drop filenames around
+
+#define DD_FILENAME L"DD_Filename v1"
+
+// another implementation that uses the central playstring table
+class FilenamePS : private Playstring
+{
+public:
+ FilenamePS(const wchar_t *str) : Playstring(str) {}
+ const wchar_t *getFilename() { return getValue(); }
+ operator const wchar_t *() { return getFilename(); }
+ static const wchar_t *dragitem_getDatatype() { return DD_FILENAME; }
+
+protected:
+ FilenamePS(const FilenamePS &fn) {}
+ FilenamePS& operator =(const FilenamePS &ps) { return *this; }
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/file/readdir.cpp b/Src/Wasabi/bfc/file/readdir.cpp
new file mode 100644
index 00000000..e3bc48ef
--- /dev/null
+++ b/Src/Wasabi/bfc/file/readdir.cpp
@@ -0,0 +1,129 @@
+#include "precomp_wasabi_bfc.h"
+#include "readdir.h"
+
+#ifdef _WIN32
+#include <shlwapi.h>
+#endif
+
+#if !defined(WIN32) && !defined(LINUX)
+#error port me
+#endif
+
+//PORT
+ReadDir::ReadDir( const wchar_t *_path, const wchar_t *_match, bool _skipdots ) : skipdots( _skipdots ), first( 1 ), path( _path ), match( _match )
+{
+ files = INVALID_HANDLE_VALUE;
+ if ( match.isempty() )
+ match = MATCHALLFILES;
+ ZERO( data );
+
+}
+
+ReadDir::~ReadDir()
+{
+ //PORT
+#ifdef WIN32
+ if ( files != INVALID_HANDLE_VALUE ) FindClose( files );
+#endif
+#ifdef LINUX
+ if ( d != NULL ) closedir( d );
+#endif
+}
+
+int ReadDir::next()
+{
+ //PORT
+#ifdef WIN32
+ for ( ;;)
+ {
+ if ( first )
+ {
+ wchar_t fullpath[ MAX_PATH ];
+ PathCombineW( fullpath, path.getValue(), match.getValue() );
+ files = FindFirstFileW( fullpath, &data );
+ }
+ if ( files == INVALID_HANDLE_VALUE ) return 0;
+ if ( first )
+ {
+ first = 0;
+ if ( skipdots && ( isDotDir() || isDotDotDir() ) ) continue;
+ return 1;
+ }
+ if ( !FindNextFileW( files, &data ) ) return 0;
+
+ if ( skipdots && ( isDotDir() || isDotDotDir() ) ) continue;
+ return 1;
+ }
+#endif//WIN32
+#ifdef LINUX
+
+ path.AddBackslash();
+ if ( first || d == NULL )
+ {
+ if ( !( d = opendir( path ) ) ) return 0;
+ first = 0;
+ }
+
+ while ( 1 )
+ {
+ de = readdir( d );
+ if ( !de )
+ {
+ closedir( d );
+ d = NULL;
+ return 0;
+ }
+
+ StringW full;
+ full.printf( L"%s%s", path.v(), de->d_name );
+
+ if ( stat( full, &st ) == -1 )
+ continue;
+
+ if ( skipdots && ( isDotDir() || isDotDotDir() ) ) continue;
+
+ if ( !Std::match( match, de->d_name ) ) continue;
+
+ return 1;
+ }
+
+#endif
+}
+
+const wchar_t *ReadDir::getFilename()
+{
+ if ( first ) if ( !next() ) return NULL;
+ //PORT
+ return data.cFileName;
+
+}
+
+int ReadDir::isDir()
+{
+ //PORT
+ if ( files == INVALID_HANDLE_VALUE ) return 0;
+ return !!( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY );
+}
+
+int ReadDir::isReadonly()
+{
+ //PORT
+ if ( files == INVALID_HANDLE_VALUE ) return 0;
+ return !!( data.dwFileAttributes & FILE_ATTRIBUTE_READONLY );
+
+}
+
+int ReadDir::isDotDir()
+{
+ //PORT
+ if ( files == INVALID_HANDLE_VALUE ) return 0;
+ return ( data.cFileName[ 0 ] == '.' && data.cFileName[ 1 ] == 0 );
+}
+
+int ReadDir::isDotDotDir()
+{
+ //PORT
+
+ if ( files == INVALID_HANDLE_VALUE ) return 0;
+ return ( data.cFileName[ 0 ] == '.' && data.cFileName[ 1 ] == '.' && data.cFileName[ 2 ] == 0 );
+}
diff --git a/Src/Wasabi/bfc/file/readdir.h b/Src/Wasabi/bfc/file/readdir.h
new file mode 100644
index 00000000..edfc9d87
--- /dev/null
+++ b/Src/Wasabi/bfc/file/readdir.h
@@ -0,0 +1,48 @@
+#ifndef _READDIR_H
+#define _READDIR_H
+
+
+
+#include <bfc/common.h>
+#include <bfc/string/StringW.h>
+
+/* intended use:
+ ReadDir dir(path);
+ while (dir.next()) {
+ const char *fn = dir.getFilename();
+ }
+*/
+
+class ReadDir
+{
+public:
+ ReadDir(const wchar_t *path, const wchar_t *match=NULL, bool skipdots=true);
+ ~ReadDir();
+
+ int next(); // done when returns 0
+ const wchar_t *getFilename();
+ int isDir(); // if current file is a dir
+ int isReadonly(); // if current file is readonly
+
+ int isDotDir(); // if given dir iteself is being enumerated (usually ".")
+ int isDotDotDir(); // if parent dir of cur dir is showing (usually "..")
+
+ const wchar_t *getPath() { return path; }
+
+private:
+ StringW path, match;
+ int skipdots, first;
+//PORT
+#ifdef WIN32
+ HANDLE files;
+ WIN32_FIND_DATAW data; // (shrug) so we have two? so what?
+ //StringW filename;
+#endif
+#ifdef LINUX
+ DIR *d;
+ struct dirent *de;
+ struct stat st;
+#endif
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/file/recursedir.cpp b/Src/Wasabi/bfc/file/recursedir.cpp
new file mode 100644
index 00000000..ca836a28
--- /dev/null
+++ b/Src/Wasabi/bfc/file/recursedir.cpp
@@ -0,0 +1,67 @@
+#include "precomp_wasabi_bfc.h"
+#include "recursedir.h"
+
+RecurseDir::RecurseDir( const wchar_t *_path, const wchar_t *_match ) :
+ path( _path ), match( _match )
+{
+ if ( match.isempty() ) match = Wasabi::Std::matchAllFiles();
+
+ curdir = new ReadDir( path, match );
+}
+
+RecurseDir::~RecurseDir()
+{
+ dirstack.deleteAll();
+}
+
+int RecurseDir::next()
+{
+ for ( ;;)
+ {
+ if ( curdir == NULL )
+ { // pop one off the stack
+ curdir = dirstack.getLast();
+ if ( curdir == NULL ) return 0; // done
+ dirstack.removeLastItem();
+ }
+ int r = curdir->next();
+ if ( r <= 0 )
+ {
+ delete curdir; curdir = NULL;
+ continue; // get another one
+ }
+
+ // ok, we have a file to look at
+ if ( curdir->isDir() )
+ { // descend into it
+ StringW newpath = curdir->getPath();
+ newpath.AppendPath( curdir->getFilename() );
+
+ dirstack.addItem( curdir ); // push the old one
+ curdir = new ReadDir( newpath, match ); // start new one
+
+ continue;
+ }
+
+ return r;
+ }
+}
+
+const wchar_t *RecurseDir::getPath()
+{
+ if ( curdir == NULL )
+ return NULL;
+ return curdir->getPath();
+}
+
+const wchar_t *RecurseDir::getFilename()
+{
+ if ( curdir == NULL )
+ return NULL;
+ return curdir->getFilename();
+}
+
+const wchar_t *RecurseDir::getOriginalPath()
+{
+ return path;
+}
diff --git a/Src/Wasabi/bfc/file/recursedir.h b/Src/Wasabi/bfc/file/recursedir.h
new file mode 100644
index 00000000..2c40c7ac
--- /dev/null
+++ b/Src/Wasabi/bfc/file/recursedir.h
@@ -0,0 +1,73 @@
+#ifndef _RECURSEDIR_H
+#define _RECURSEDIR_H
+
+#include <bfc/wasabi_std.h>
+#include <bfc/ptrlist.h>
+#include <bfc/common.h>
+#include <bfc/file/readdir.h>
+
+class ReadDir;
+
+/**
+ Read the contents of a directory, recursively.
+ Also possible to use search match patterns.
+
+ @short Recursive directory reading.
+ @author Nullsoft
+ @ver 1.0
+ @see ReadDir
+*/
+class RecurseDir {
+public:
+ /**
+ Sets the directory to read and the match pattern.
+ If no match pattern is set, it will match against
+ all files.
+
+ @param path The path of the directory to read.
+ @param match The match pattern to use.
+ */
+ RecurseDir(const wchar_t *path, const wchar_t *match=NULL);
+
+ /**
+ Deletes the directory stack.
+ */
+ ~RecurseDir();
+
+ /**
+ Advance to the next file.
+
+ @ret 0, No more files to read; > 0, Files left to read.
+ */
+ int next();
+
+ /**
+ Restart from the top of the directory tree.
+
+ @ret 0
+ */
+ int restart();
+
+ /**
+ Get the current directory path.
+
+ @ret The path.
+ */
+ const wchar_t *getPath();
+
+ /**
+ Get the filename for the current file.
+
+ @ret The filename.
+ */
+ const wchar_t *getFilename();
+
+ const wchar_t *getOriginalPath();
+
+private:
+ StringW path, match;
+ ReadDir *curdir;
+ PtrList<ReadDir> dirstack;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/file/splitpath.c b/Src/Wasabi/bfc/file/splitpath.c
new file mode 100644
index 00000000..d9c3fbc5
--- /dev/null
+++ b/Src/Wasabi/bfc/file/splitpath.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2000 Martin Fuchs
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+// 03/29/2004, f. gastellu : added _makepath and _wmakepath
+
+#include "splitpath.h"
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WANT_UNICODE
+
+void _wsplitpath(const WCHAR* path, WCHAR* drv, WCHAR* dir, WCHAR* name, WCHAR* ext)
+{
+ const WCHAR* end; /* end of processed string */
+ const WCHAR* p; /* search pointer */
+ const WCHAR* s; /* copy pointer */
+
+ /* extract drive name */
+ if (path[0] && path[1]==':') {
+ if (drv) {
+ *drv++ = *path++;
+ *drv++ = *path++;
+ *drv = L'\0';
+ }
+ } else if (drv)
+ *drv = L'\0';
+
+ /* search for end of string or stream separator */
+ for(end=path; *end && *end!=L':'; )
+ end++;
+
+ /* search for begin of file extension */
+ for(p=end; p>path && *--p!=L'\\' && *p!=L'/'; )
+ if (*p == L'.') {
+ end = p;
+ break;
+ }
+
+ if (ext)
+ for(s=end; *ext=*s++; )
+ ext++;
+
+ /* search for end of directory name */
+ for(p=end; p>path; )
+ if (*--p=='\\' || *p=='/') {
+ p++;
+ break;
+ }
+
+ if (name) {
+ for(s=p; s<end; )
+ *name++ = *s++;
+
+ *name = L'\0';
+ }
+
+ if (dir) {
+ for(s=path; s<p; )
+ *dir++ = *s++;
+
+ *dir = L'\0';
+ }
+}
+
+#endif
+
+#ifdef WANT_ACP
+
+void _splitpath(const char* path, char* drv, char* dir, char* name, char* ext)
+{
+ const char* end; /* end of processed string */
+ const char* p; /* search pointer */
+ const char* s; /* copy pointer */
+
+ /* extract drive name */
+ if (path[0] && path[1]==':') {
+ if (drv) {
+ *drv++ = *path++;
+ *drv++ = *path++;
+ *drv = '\0';
+ }
+ } else if (drv)
+ *drv = '\0';
+
+ /* search for end of string or stream separator */
+ for(end=path; *end && *end!=':'; )
+ end++;
+
+ /* search for begin of file extension */
+ for(p=end; p>path && *--p!='\\' && *p!='/'; )
+ if (*p == '.') {
+ end = p;
+ break;
+ }
+
+ if (ext)
+ for(s=end; (*ext=*s++); )
+ ext++;
+
+ /* search for end of directory name */
+ for(p=end; p>path; )
+ if (*--p=='\\' || *p=='/') {
+ p++;
+ break;
+ }
+
+ if (name) {
+ for(s=p; s<end; )
+ *name++ = *s++;
+
+ *name = '\0';
+ }
+
+ if (dir) {
+ for(s=path; s<p; )
+ *dir++ = *s++;
+
+ *dir = '\0';
+ }
+}
+
+#endif
+
+#ifdef WANT_UNICODE
+
+void _wmakepath( WCHAR *path, const WCHAR *drive, const WCHAR *dir, const WCHAR *fname, const WCHAR *ext ) {
+ if (!path) return;
+ *path = 0;
+ if (drive) {
+ *path++ = *drive;
+ *path++ = ':';
+ }
+ if (dir) {
+ strcat(path, dir);
+ if (dir[strlen(dir)-1] != '\\' && dir[strlen(dir)-1] != '/')
+ strcat(path, "/");
+ path += strlen(path);
+ }
+ if (fname) strcat(path, fname);
+ if (ext) {
+ if (*ext != '.') strcat(path++, ".");
+ strcat(path, ext);
+ }
+}
+
+#endif
+
+#ifdef WANT_ACP
+
+void _makepath( char *path, const char *drive, const char *dir, const char *fname, const char *ext ) {
+ if (!path) return;
+ *path = 0;
+ if (drive) {
+ *path++ = *drive;
+ *path++ = ':';
+ }
+ if (dir) {
+ strcat(path, dir);
+ if (dir[strlen(dir)-1] != '\\' && dir[strlen(dir)-1] != '/')
+ strcat(path, "/");
+ path += strlen(path);
+ }
+ if (fname) strcat(path, fname);
+ if (ext) {
+ if (*ext != '.') strcat(path++, ".");
+ strcat(path, ext);
+ }
+}
+
+#endif
+
+
+/*
+void main() // test splipath()
+{
+ TCHAR drv[_MAX_DRIVE+1], dir[_MAX_DIR], name[_MAX_FNAME], ext[_MAX_EXT];
+
+ _tsplitpath(L"x\\y", drv, dir, name, ext);
+ _tsplitpath(L"x\\", drv, dir, name, ext);
+ _tsplitpath(L"\\x", drv, dir, name, ext);
+ _tsplitpath(L"x", drv, dir, name, ext);
+ _tsplitpath(L"", drv, dir, name, ext);
+ _tsplitpath(L".x", drv, dir, name, ext);
+ _tsplitpath(L":x", drv, dir, name, ext);
+ _tsplitpath(L"a:x", drv, dir, name, ext);
+ _tsplitpath(L"a.b:x", drv, dir, name, ext);
+ _tsplitpath(L"W:\\/\\abc/Z:~", drv, dir, name, ext);
+ _tsplitpath(L"abc.EFGH:12345", drv, dir, name, ext);
+ _tsplitpath(L"C:/dos/command.com", drv, dir, name, ext);
+}
+*/
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/bfc/file/splitpath.h b/Src/Wasabi/bfc/file/splitpath.h
new file mode 100644
index 00000000..bbea3c96
--- /dev/null
+++ b/Src/Wasabi/bfc/file/splitpath.h
@@ -0,0 +1,26 @@
+#ifndef _SPLITPATH_H
+#define _SPLITPATH_H
+
+#ifndef _WIN32
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#define WANT_UNICODE
+#define WANT_ACP
+
+#ifdef WANT_UNICODE
+void _wsplitpath(const WCHAR* path, WCHAR* drv, WCHAR* dir, WCHAR* name, WCHAR* ext);
+void _wmakepath( WCHAR *path, const WCHAR *drive, const WCHAR *dir, const WCHAR *fname, const WCHAR *ext );
+#endif
+
+#ifdef WANT_ACP
+void _splitpath(const char* path, char* drv, char* dir, char* name, char* ext);
+void _makepath( char *path, const char *drive, const char *dir, const char *fname, const char *ext);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+#endif
diff --git a/Src/Wasabi/bfc/file/tmpnamestr.h b/Src/Wasabi/bfc/file/tmpnamestr.h
new file mode 100644
index 00000000..c18e5832
--- /dev/null
+++ b/Src/Wasabi/bfc/file/tmpnamestr.h
@@ -0,0 +1,18 @@
+#ifndef _TMPNAMESTR_H
+#define _TMPNAMESTR_H
+
+#include <bfc/string/StringW.h>
+
+class TmpNameStrW : public StringW
+{
+public:
+ TmpNameStrW()
+ {
+ wchar_t tmp[WA_MAX_PATH]=L"";
+ TMPNAM(tmp);
+ setValue(tmp);
+ }
+};
+
+
+#endif
diff --git a/Src/Wasabi/bfc/file/wildcharsenum.cpp b/Src/Wasabi/bfc/file/wildcharsenum.cpp
new file mode 100644
index 00000000..ae3e24e2
--- /dev/null
+++ b/Src/Wasabi/bfc/file/wildcharsenum.cpp
@@ -0,0 +1,64 @@
+// NONPORTABLE NONPORTABLE NONPORTABLE
+#include "precomp_wasabi_bfc.h"
+#ifdef WIN32
+#include <windows.h>
+#endif
+#include "wildcharsenum.h"
+#include <bfc/parse/pathparse.h>
+#include <bfc/parse/paramparser.h>
+#include <bfc/file/readdir.h>
+
+WildcharsEnumerator::WildcharsEnumerator(const wchar_t *_selection) : selection(_selection)
+{
+ // Then scan.
+ rescan();
+}
+
+WildcharsEnumerator::~WildcharsEnumerator() {
+ finddatalist.deleteAll();
+}
+
+int WildcharsEnumerator::getNumFiles()
+{
+ return finddatalist.getNumItems();
+}
+
+const wchar_t *WildcharsEnumerator::enumFile(int n) {
+ StringW path = finddatalist.enumItem(n)->path;
+ if (!path.isempty())
+ {
+ enumFileString = StringPathCombine(path.getValue(), finddatalist.enumItem(n)->filename.getValue());
+ return enumFileString;
+ }
+ return finddatalist.enumItem(n)->filename;
+}
+
+void WildcharsEnumerator::rescan()
+{
+ finddatalist.removeAll();
+ ParamParser pp(selection, L";");
+ for (int is = 0; is < pp.getNumItems(); is++)
+ {
+ StringW _selection = pp.enumItem(is);
+
+ PathParserW parse(_selection);
+ StringW path = L"";
+ StringW mask = L"";
+
+ for (int i=0;i<parse.getNumStrings()-1;i++)
+ path.AppendFolder(parse.enumString(i));
+
+ mask = parse.getLastString();
+
+ // enum files and store a list
+ ReadDir rd(path, mask, true);
+ while (rd.next()) {
+ finddatalist.addItem(new find_entry(rd.getPath(), rd.getFilename()));
+ }
+ }
+}
+
+int WildcharsEnumerator::isWildchars(const wchar_t *filename)
+{
+ return (wcschr(filename, '*') || wcschr(filename, '?'));
+}
diff --git a/Src/Wasabi/bfc/file/wildcharsenum.h b/Src/Wasabi/bfc/file/wildcharsenum.h
new file mode 100644
index 00000000..10972132
--- /dev/null
+++ b/Src/Wasabi/bfc/file/wildcharsenum.h
@@ -0,0 +1,34 @@
+#ifndef __WILDCHARSENUM_H
+#define __WILDCHARSENUM_H
+
+#include <bfc/ptrlist.h>
+#include <bfc/string/StringW.h>
+
+class find_entry {
+public:
+ find_entry(const wchar_t *_path, const wchar_t *_filename) : path(_path), filename(_filename) {}
+ ~find_entry() {}
+ StringW path;
+ StringW filename;
+};
+
+class WildcharsEnumerator
+{
+public:
+ WildcharsEnumerator(const wchar_t *_selection);
+ virtual ~WildcharsEnumerator();
+
+ int getNumFiles();
+ const wchar_t *enumFile(int n);
+ void rescan();
+
+ static int isWildchars(const wchar_t *filename);
+
+private:
+ StringW selection;
+ PtrList <find_entry> finddatalist;
+ StringW singfiledup;
+ StringW enumFileString;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/foreach.cpp b/Src/Wasabi/bfc/foreach.cpp
new file mode 100644
index 00000000..022eadd5
--- /dev/null
+++ b/Src/Wasabi/bfc/foreach.cpp
@@ -0,0 +1,22 @@
+#include "foreach.h"
+
+__foreach::__foreach(const PtrListRoot &ptrlist, int reverse) :
+ list(ptrlist.getNumItems(), ptrlist.getItemList()), pos(0)
+{
+ if (reverse) list.reverse();
+}
+
+__foreach::__foreach(const PtrListRoot *ptrlist, int reverse) :
+ list(ptrlist->getNumItems(), ptrlist->getItemList()), pos(0) {
+ if (reverse) list.reverse();
+}
+
+int __foreach::done() const { return (pos >= list.getSize()); }
+
+void *__foreach::next(int advance) { if (advance) pos++; return getPtr(); }
+
+void *__foreach::getPtr() const { return (pos < list.getSize()) ? list[pos] : NULL; }
+
+int __foreach::getPos() const { return pos; }
+
+
diff --git a/Src/Wasabi/bfc/foreach.h b/Src/Wasabi/bfc/foreach.h
new file mode 100644
index 00000000..1ba53801
--- /dev/null
+++ b/Src/Wasabi/bfc/foreach.h
@@ -0,0 +1,55 @@
+#ifndef _FOREACH_H
+#define _FOREACH_H
+
+#include "memblock.h"
+#include "ptrlist.h"
+
+
+// foreach stuff
+/* use like this:
+ PtrList<blah> list;
+ foreach(list)
+ list.getfor()->booga();
+ something(list.getfor());
+ endfor
+*/
+
+// foreach stuff
+class __foreach
+{
+public:
+ __foreach(const PtrListRoot &ptrlist, int reverse=FALSE);
+ __foreach(const PtrListRoot *ptrlist, int reverse=FALSE);
+
+ int done() const;
+ void *next(int advance = TRUE);
+ void *getPtr() const;
+
+ int getPos() const;
+
+private:
+ MemBlock<void *> list;
+ int pos;
+};
+
+#define foreach(x) \
+{ \
+ void *__fe_void; \
+ __foreach ___f(x); \
+ for (__fe_void = ___f.getPtr(); !___f.done(); __fe_void = ___f.next()) {
+#define getfor() castFor(__fe_void)
+#define endfor \
+ } \
+}
+#define foreach_reverse(x) \
+{ \
+ void *__fe_void; \
+ __foreach ___f(x, TRUE); \
+ for (__fe_void = ___f.getPtr(); !___f.done(); __fe_void = ___f.next()) {
+#define getfor() castFor(__fe_void)
+#define endfor \
+ } \
+}
+#define foreach_index (___f.getPos())
+
+#endif
diff --git a/Src/Wasabi/bfc/freelist.cpp b/Src/Wasabi/bfc/freelist.cpp
new file mode 100644
index 00000000..06a9218d
--- /dev/null
+++ b/Src/Wasabi/bfc/freelist.cpp
@@ -0,0 +1,81 @@
+#include "precomp_wasabi_bfc.h"
+
+#include "freelist.h"
+
+// define this to turn off freelist behavior
+//#define FREELIST_FUCT
+
+FreelistPriv::FreelistPriv() {
+ total_allocated = 0;
+}
+
+FreelistPriv::~FreelistPriv() {
+#ifdef ASSERTS_ENABLED
+// ASSERTPR(total_allocated == 0, "didn't free entire freelist!(1)");
+// ASSERTPR(blocks.getNumItems() == 0, "didn't free entire freelist!(2)");
+ if (total_allocated != 0) DebugStringW(L"didn't free entire freelist!(1)\n");
+ if (blocks.getNumItems() != 0) DebugStringW(L"didn't free entire freelist!(2)\n");
+#endif
+}
+
+void *FreelistPriv::getRecord(int typesize, int blocksize, int initialblocksize) {
+#ifdef FREELIST_FUCT
+ return MALLOC(typesize);
+#else
+ ASSERT(typesize >= sizeof(void *));
+ FLMemBlock *mem = NULL;
+ for (int i = 0; i < blocks.getNumItems(); i++) {
+ mem = blocks[i];
+ if (mem->freelist != NULL) break;
+ mem = NULL;
+ }
+ if (mem == NULL) {
+ // figure record count for this new block
+ int siz = (blocks.getNumItems() ? blocksize : initialblocksize);
+ // allocate another block of memory
+ mem = new FLMemBlock(siz*typesize);
+ // prelink it into a freelist
+ char *record = static_cast<char *>(mem->freelist);
+ void **ptr;
+ for (int i = 0; i < siz-1; i++) {
+ ptr = reinterpret_cast<void **>(record);
+ record += typesize;
+ *ptr = static_cast<void *>(record);
+ }
+ // terminate newly made freelist
+ ptr = reinterpret_cast<void **>(record);
+ *ptr = NULL;
+ blocks.addItem(mem);
+ }
+ // get first free record
+ void *ret = mem->freelist;
+ // advance freelist *
+ mem->freelist = *(static_cast<void **>(mem->freelist));
+ mem->nallocated++;
+ total_allocated++;
+ return ret;
+#endif
+}
+
+void FreelistPriv::freeRecord(void *record) {
+#ifdef FREELIST_FUCT
+ FREE(record);
+#else
+ FLMemBlock *mem=NULL;
+ for (int i = 0; i < blocks.getNumItems(); i++) {
+ mem = blocks[i];
+ if (mem->isMine(reinterpret_cast<MBT*>(record))) break;
+ mem = NULL;
+ }
+ ASSERTPR(mem != NULL, "attempted to free record with no block");
+ // stash it back on the block's freelist
+ *reinterpret_cast<void **>(record) = mem->freelist;
+ mem->freelist = record;
+ ASSERT(mem->nallocated > 0);
+ mem->nallocated--;
+ if (mem->nallocated == 0) {
+ blocks.delItem(mem);
+ }
+ total_allocated--;
+#endif
+}
diff --git a/Src/Wasabi/bfc/freelist.h b/Src/Wasabi/bfc/freelist.h
new file mode 100644
index 00000000..dba7e46e
--- /dev/null
+++ b/Src/Wasabi/bfc/freelist.h
@@ -0,0 +1,93 @@
+#ifndef _FREELIST_H
+#define _FREELIST_H
+
+#include <bfc/wasabi_std.h>
+#include <bfc/memblock.h>
+#include <bfc/ptrlist.h>
+
+// actual implementation
+class FreelistPriv {
+protected:
+ FreelistPriv();
+ ~FreelistPriv();
+
+ void *getRecord(int typesize, int blocksize, int initialblocksize);
+ void freeRecord(void *rec);
+
+private:
+ int total_allocated;
+ typedef uint8_t MBT;
+ class FLMemBlock : public MemBlock<MBT> {
+ public:
+ FLMemBlock(int siz) : MemBlock<MBT>(siz) {
+ freelist = getMemory();
+ nallocated = 0;
+ }
+ void *freelist;
+ int nallocated; // # of records assigned from block
+ };
+ PtrList< FLMemBlock > blocks; // the blocks of mem we alloc from
+};
+
+// type-safe template
+static const int DEF_BLOCKSIZE=250;
+template
+<class T, int BLOCKSIZE=DEF_BLOCKSIZE, int INITIALBLOCKSIZE=DEF_BLOCKSIZE, int ALIGNMENT=4>
+class Freelist : private FreelistPriv {
+public:
+ // just returns the memory, you have to call constructor manually
+ T *getRecord() {
+ return static_cast<T *>(FreelistPriv::getRecord(itemsize(), BLOCKSIZE, INITIALBLOCKSIZE));
+ }
+
+ // creates object via default constructor
+ T *newRecord() {
+ T *ret = getRecord();
+#ifdef FORTIFY
+#undef new
+#endif
+ new(ret) T;
+#ifdef FORTIFY
+#define new ZFortify_New
+#endif
+ return ret;
+ }
+
+ // creates object via 1-parameter constructor
+ template<class P1>
+ T *newRecord(P1 p1) {
+ T *ret = getRecord();
+#ifdef FORTIFY
+#undef new
+#endif
+ new(ret) T(p1);
+#ifdef FORTIFY
+#define new ZFortify_New
+#endif
+ return ret;
+ }
+
+ // just frees it, you have to call destructor manually
+ void freeRecord(T *record) { FreelistPriv::freeRecord(record); }
+
+ // calls delete for you, and frees it
+ void deleteRecord(T *record) {
+ if (record != NULL) {
+ record->~T();
+ freeRecord(record);
+ }
+ }
+
+ void deletePtrList(PtrList<T> *list) {
+ ASSERT(list != NULL);
+ for (int i = 0; i < list->getNumItems(); i++) {
+ deleteRecord(list->enumItem(i));
+ }
+ list->removeAll();
+ }
+
+protected:
+ int itemsize() { return (sizeof(T) + (ALIGNMENT-1)) - (sizeof(T) % ALIGNMENT); }
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/loadlib.cpp b/Src/Wasabi/bfc/loadlib.cpp
new file mode 100644
index 00000000..8682cd29
--- /dev/null
+++ b/Src/Wasabi/bfc/loadlib.cpp
@@ -0,0 +1,85 @@
+#include "precomp_wasabi_bfc.h"
+
+#include "loadlib.h"
+
+#if !defined(WIN32) && !defined(LINUX)
+#error port me
+#endif
+
+Library::Library(const wchar_t *filename) : NamedW(filename)
+{
+ lib = NULL;
+}
+
+Library::~Library()
+{
+ unload();
+}
+
+int Library::load(const wchar_t *newname)
+{
+ if (lib != NULL && newname == NULL)
+ return 1;
+ unload();
+ if (newname != NULL)
+ setName(newname);
+
+ const wchar_t *n = getName();
+ ASSERT(n != NULL);
+#ifdef WIN32
+ __try {
+ lib = LoadLibraryW(n);
+ } __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ // stupid DLL
+ lib = NULL;
+ OutputDebugString(L"exception while loading dll");
+ OutputDebugStringW(newname);
+ OutputDebugString(L"\n");
+ }
+#elif defined(LINUX)
+ // Not using string to try to not use common/wasabi in Studio.exe
+ char *conv = _strdup( getName() );
+ int len = strlen( conv );
+ if ( ! strcasecmp( conv + len - 4, ".dll" ) )
+ {
+ strcpy( conv + len - 4, ".so" );
+ }
+
+ lib = dlopen(conv, RTLD_LAZY);
+
+ free( conv );
+#else
+#error port me!
+#endif
+ if (lib == NULL) return 0;
+ return 1;
+}
+
+void Library::unload()
+{
+ if (lib != NULL)
+ {
+#ifdef WIN32
+ FreeLibrary(lib);
+#elif defined(LINUX)
+ dlclose(lib);
+#else
+#error port me!
+#endif
+
+ }
+ lib = NULL;
+}
+
+void *Library::getProcAddress(const char *procname)
+{
+ ASSERT(procname != NULL);
+#if defined(WIN32)
+ return GetProcAddress(lib, procname);
+#elif defined(LINUX)
+ return dlsym(lib, procname);
+#else
+#error port me!
+#endif
+}
diff --git a/Src/Wasabi/bfc/loadlib.h b/Src/Wasabi/bfc/loadlib.h
new file mode 100644
index 00000000..6729700c
--- /dev/null
+++ b/Src/Wasabi/bfc/loadlib.h
@@ -0,0 +1,35 @@
+#ifndef _LOADLIB_H
+#define _LOADLIB_H
+
+#include <bfc/wasabi_std.h>
+#include <bfc/named.h>
+
+class Library : public NamedW
+{
+public:
+ Library(const wchar_t *filename=NULL);
+ Library(const Library &l) {
+ lib = NULL; // FG> overrides default constructor, so we need to init this too...
+ load(l.getName());
+ }
+ ~Library();
+
+ Library& operator =(const Library &l) {
+ if (this != &l) {
+ unload();
+ load(l.getName());
+ }
+ return *this;
+ }
+
+ int load(const wchar_t *filename=NULL);
+ void unload();
+
+ void *getProcAddress(const char *procname);
+ OSMODULEHANDLE getHandle() const { return lib; }
+
+private:
+ OSMODULEHANDLE lib;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/memblock.cpp b/Src/Wasabi/bfc/memblock.cpp
new file mode 100644
index 00000000..668e1ccd
--- /dev/null
+++ b/Src/Wasabi/bfc/memblock.cpp
@@ -0,0 +1,66 @@
+#include "memblock.h"
+#include <bfc/bfc_assert.h>
+
+#ifdef _DEBUG
+int memblocks_totalsize=0;
+#endif
+
+VoidMemBlock::VoidMemBlock(int _size, const void *data) {
+ mem = NULL;
+ size = 0;
+ setSize(_size);
+ if (data != NULL && size > 0) MEMCPY(mem, data, size);
+}
+
+VoidMemBlock::~VoidMemBlock() {
+#ifdef _DEBUG
+ memblocks_totalsize -= size;
+#endif
+ FREE(mem);
+}
+
+void *VoidMemBlock::setSize(int newsize) {
+#ifdef _DEBUG
+ memblocks_totalsize -= size;
+#endif
+ ASSERT(newsize >= 0);
+ if (newsize < 0) newsize = 0;
+ if (newsize == 0) {
+ FREE(mem);
+ mem = NULL;
+ } else if (size != newsize) {
+ mem = REALLOC(mem, newsize);
+ }
+ size = newsize;
+#ifdef _DEBUG
+ memblocks_totalsize += size;
+#endif
+ return getMemory();
+}
+
+void *VoidMemBlock::setMinimumSize(int newminsize, int increment) {
+ if (newminsize > size) setSize(newminsize+increment);
+ return getMemory();
+}
+
+void VoidMemBlock::setMemory(const void *data, int datalen, int offsetby) {
+ if (datalen <= 0) return;
+ ASSERT(mem != NULL);
+ ASSERT(offsetby >= 0);
+ char *ptr = reinterpret_cast<char *>(mem);
+ ASSERT(ptr + offsetby + datalen <= ptr + size);
+ MEMCPY(ptr + offsetby, data, datalen);
+}
+
+int VoidMemBlock::getSize() const {
+ return size;
+}
+
+int VoidMemBlock::isMine(void *ptr) {
+ return (ptr >= mem && ptr < (char*)mem + size);
+}
+
+void VoidMemBlock::zeroMemory() {
+ if (mem == NULL || size < 1) return;
+ MEMZERO(mem, size);
+}
diff --git a/Src/Wasabi/bfc/memblock.h b/Src/Wasabi/bfc/memblock.h
new file mode 100644
index 00000000..8fdec08d
--- /dev/null
+++ b/Src/Wasabi/bfc/memblock.h
@@ -0,0 +1,101 @@
+#ifndef _MEMBLOCK_H
+#define _MEMBLOCK_H
+
+//#include <bfc/wasabi_std.h>
+#include <bfc/std_mem.h>
+//#include <wasabicfg.h>
+
+#ifdef _DEBUG
+extern int memblocks_totalsize;
+#endif
+
+class VoidMemBlock {
+protected:
+ VoidMemBlock(int size=0, const void *data=0);
+ ~VoidMemBlock();
+
+ void *setSize(int newsize);
+ void *setMinimumSize(int newminsize, int increment=0);
+ void *getMemory() const { return mem; }
+ void setMemory(const void *data, int datalen, int offsetby=0);
+ int getSize() const;
+
+ int isMine(void *ptr);
+
+ void zeroMemory();
+
+private:
+ void *mem;
+ int size;
+};
+
+// just a convenient resizeable block of memory wrapper
+// doesn't handle constructors or anything, meant for int, char, etc.
+template <class T>
+class MemBlock : private VoidMemBlock {
+public:
+ MemBlock(int _size = 0, const T *data = NULL) : VoidMemBlock(_size*sizeof(T), data) {}
+ MemBlock(const MemBlock<T> &source) : VoidMemBlock(source.getSizeInBytes(), source.getMemory()) {}
+ MemBlock(const MemBlock<T> *source) : VoidMemBlock(source->getSizeInBytes(), source->getMemory()) {}
+
+ T *setSize(int newsize) {
+ return static_cast<T*>(VoidMemBlock::setSize(newsize * sizeof(T)));
+ }
+ T *setMinimumSize(int newminsize, int increment = 0) {
+ return static_cast<T*>(VoidMemBlock::setMinimumSize(newminsize * sizeof(T), increment*sizeof(T)));
+ }
+
+ T *getMemory() const { return static_cast<T *>(VoidMemBlock::getMemory()); }
+ T *getMemory(int offset) const { return static_cast<T *>(VoidMemBlock::getMemory())+offset; } // note pointer arithmetic
+ T *m() const { return getMemory(); }
+ T *m(int offset) const { return getMemory(offset); }
+ operator T *() const { return getMemory(); }
+ T& operator() (unsigned int ofs) { return getMemory()[ofs]; }
+ const T& operator() (unsigned int ofs) const { return getMemory()[ofs]; }
+
+ void copyTo(T *dest) { MEMCPY(getMemory(), dest, getSizeInBytes()); }
+
+ int getSize() const { return VoidMemBlock::getSize()/sizeof(T); }// # of T's
+ int getSizeInBytes() const { return VoidMemBlock::getSize(); }
+
+ int isMine(T *ptr) { return VoidMemBlock::isMine(ptr); }
+
+ void setMemory(const T *data, int datalen, int offsetby = 0) { VoidMemBlock::setMemory(data, datalen*sizeof(T), offsetby*sizeof(T)); } // # of T's
+ void zeroMemory() { VoidMemBlock::zeroMemory(); }
+
+ void reverse() {
+ const int nitems = getSize();
+ if (nitems <= 1) return;
+ MemBlock<T> nm(this);
+ T *mymem = getMemory(), *revmem = nm.getMemory();
+ for (int i = 0, j = nitems-1; j >= 0; i++, j--) {
+ MEMCPY(mymem+i, revmem+j, sizeof(T));
+ }
+ }
+};
+
+// just a convenience class for a 2d MemBlock<>
+template <class T>
+class MemMatrix : public MemBlock<T> {
+public:
+ MemMatrix(int _width, int height, const T *data = NULL) : MemBlock<T>(_width * height, data), width(_width) {}
+
+ T *setSize(int _width, int height) {
+ MemBlock<T>::setSize(width * height);
+ width = _width;
+ }
+
+ // () access i.e. obj(x,y)
+ T& operator() (unsigned int x, unsigned int y) {
+ return *MemBlock<T>::m(x + y * width);
+ }
+ const T& operator() (unsigned int x, unsigned int y) const {
+ return *MemBlock<T>::m(x + y * width);
+ }
+
+private:
+ int width;
+};
+
+
+#endif
diff --git a/Src/Wasabi/bfc/multipatch.h b/Src/Wasabi/bfc/multipatch.h
new file mode 100644
index 00000000..242737b4
--- /dev/null
+++ b/Src/Wasabi/bfc/multipatch.h
@@ -0,0 +1,412 @@
+#ifndef _WASABI_MULTIPATCH_H
+#define _WASABI_MULTIPATCH_H
+// (c) 2005 Nullsoft, Inc.
+
+#include "dispatch.h"
+/*
+Author: Ben Allison <benski@nullsoft.com>
+
+The purpose of the MultiPatch class is to allow a class to have multiple Dispatchable interfaces.
+
+It is an alternative to the method of using a stub class with virtual functions.
+(you see these classes all over Wasabi, either ending in I or X, depending on age)
+Since each vtable entry costs 4 bytes per object (8 on 64bit), using this method adds some code size
+(and, in some multiple-inheritance situations, memory per object for vtable overrides)
+
+Of course, MultiPatch's dispatching function adds code size, too. But the function shouldn't be any
+larger or slower than the dispatching in the api_X class anyway.
+
+Using MultiPatch, each method call goes through this chain:
+ dispatch->multipatch->your class method
+
+ as opposed to:
+ dispatch->your class method (single inheritance)
+
+ or:
+ dispatch->virtual function->your class method (api_X method)
+
+A clever compiler might be able to optimize away the _multipatch function call by
+pushing "patch" on the top of the parameter stack and jmp'ing.
+
+For an example on usage, scroll down to the bottom of the page.
+*/
+
+template <int patch_t, class base_t>
+class MultiPatch : public base_t
+{
+protected:
+ virtual int _multipatch(int patch, int msg, void *retval, void **params=0, int nparam=0) = 0;
+
+private:
+ int _dispatch(int msg, void *retval, void **params=0, int nparam=0)
+ {
+ return _multipatch(patch_t, msg, retval, params, nparam);
+ }
+
+public:
+ /* these helper functions are a direct copy from Dispatchable...
+ * They need to be duplicated, because the compiler gets confused when trying to cast
+ * from Dispatchable to the child class (since that class has multiple Dispatchable parents)
+ *
+ * They could potentially be eliminated by modifying Dispatchable's versions, but the risk of breakage
+ * isn't worth it.
+ */
+ template <class CLASSNAME, class RETVAL>
+ void cb(RETVAL (CLASSNAME::*fn)(), void *retval, void **params) {
+ *static_cast<RETVAL*>(retval) = (static_cast<CLASSNAME *>(this)->*fn)();
+ }
+
+ template <class CLASSNAME>
+ void vcb(void (CLASSNAME::*fn)(), void *retval, void **params) {
+ (static_cast<CLASSNAME *>(this)->*fn)();
+ }
+
+ template <class CLASSNAME, class RETVAL, class PARAM1>
+ void cb(RETVAL (CLASSNAME::*fn)(PARAM1), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ *static_cast<RETVAL*>(retval) = (static_cast<CLASSNAME *>(this)->*fn)(*p1);
+ }
+
+ template <class CLASSNAME, class PARAM1>
+ void vcb(void (CLASSNAME::*fn)(PARAM1), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1);
+ }
+
+ template <class CLASSNAME, class PARAM1, class PARAM2>
+ void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2);
+ }
+
+ template <class CLASSNAME, class RETVAL, class PARAM1, class PARAM2>
+ void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ *static_cast<RETVAL*>(retval) = (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2);
+ }
+
+ // 3 params
+ template <class CLASSNAME, class PARAM1, class PARAM2, class PARAM3>
+ void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3);
+ }
+
+ template <class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3>
+ void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ *static_cast<RETVAL*>(retval) = (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3);
+ }
+
+ // 4 params
+ template <class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4>
+ void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4);
+ }
+
+ template <class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4>
+ void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ *static_cast<RETVAL*>(retval) = (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4);
+ }
+
+ // 5 params
+ template <class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5>
+ void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5);
+ }
+
+ template <class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5>
+ void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ *static_cast<RETVAL*>(retval) = (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5);
+ }
+
+ // 6 params
+ template <class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6>
+ void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6);
+ }
+
+ template <class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6>
+ void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ *static_cast<RETVAL*>(retval) = (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6);
+ }
+
+ // 7 params
+ template <class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7>
+ void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ PARAM7 *p7 = static_cast<PARAM7*>(params[6]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7);
+ }
+
+ template <class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7>
+ void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ PARAM7 *p7 = static_cast<PARAM7*>(params[6]);
+ *static_cast<RETVAL*>(retval) = (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7);
+ }
+
+ // 8 params
+ template <class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8>
+ void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ PARAM7 *p7 = static_cast<PARAM7*>(params[6]);
+ PARAM8 *p8 = static_cast<PARAM8*>(params[7]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8);
+ }
+
+ template <class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8>
+ void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ PARAM7 *p7 = static_cast<PARAM7*>(params[6]);
+ PARAM8 *p8 = static_cast<PARAM8*>(params[7]);
+ *static_cast<RETVAL*>(retval) = (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8);
+ }
+
+ // 9 params
+ template <class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9>
+ void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ PARAM7 *p7 = static_cast<PARAM7*>(params[6]);
+ PARAM8 *p8 = static_cast<PARAM8*>(params[7]);
+ PARAM9 *p9 = static_cast<PARAM9*>(params[8]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9);
+ }
+
+ template <class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9>
+ void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ PARAM7 *p7 = static_cast<PARAM7*>(params[6]);
+ PARAM8 *p8 = static_cast<PARAM8*>(params[7]);
+ PARAM9 *p9 = static_cast<PARAM9*>(params[8]);
+ *static_cast<RETVAL*>(retval) = (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9);
+ }
+
+ // 10 params
+ template <class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10>
+ void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ PARAM7 *p7 = static_cast<PARAM7*>(params[6]);
+ PARAM8 *p8 = static_cast<PARAM8*>(params[7]);
+ PARAM9 *p9 = static_cast<PARAM9*>(params[8]);
+ PARAM10 *p10 = static_cast<PARAM10*>(params[9]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10);
+ }
+
+ template <class CLASSNAME, class RETVAL, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10>
+ void cb(RETVAL (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ PARAM7 *p7 = static_cast<PARAM7*>(params[6]);
+ PARAM8 *p8 = static_cast<PARAM8*>(params[7]);
+ PARAM9 *p9 = static_cast<PARAM9*>(params[8]);
+ PARAM10 *p10 = static_cast<PARAM10*>(params[9]);
+ *static_cast<RETVAL*>(retval) = (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10);
+ }
+
+ // 14 params
+ template <class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10, class PARAM11, class PARAM12, class PARAM13, class PARAM14>
+ void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10, PARAM11, PARAM12, PARAM13, PARAM14), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ PARAM7 *p7 = static_cast<PARAM7*>(params[6]);
+ PARAM8 *p8 = static_cast<PARAM8*>(params[7]);
+ PARAM9 *p9 = static_cast<PARAM9*>(params[8]);
+ PARAM10 *p10 = static_cast<PARAM10*>(params[9]);
+ PARAM11 *p11 = static_cast<PARAM11*>(params[10]);
+ PARAM12 *p12 = static_cast<PARAM12*>(params[11]);
+ PARAM13 *p13 = static_cast<PARAM13*>(params[12]);
+ PARAM14 *p14 = static_cast<PARAM14*>(params[13]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14);
+ }
+
+ // 16 params
+ template <class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10, class PARAM11, class PARAM12, class PARAM13, class PARAM14, class PARAM15, class PARAM16>
+ void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10, PARAM11, PARAM12, PARAM13, PARAM14, PARAM15, PARAM16), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ PARAM7 *p7 = static_cast<PARAM7*>(params[6]);
+ PARAM8 *p8 = static_cast<PARAM8*>(params[7]);
+ PARAM9 *p9 = static_cast<PARAM9*>(params[8]);
+ PARAM10 *p10 = static_cast<PARAM10*>(params[9]);
+ PARAM11 *p11 = static_cast<PARAM11*>(params[10]);
+ PARAM12 *p12 = static_cast<PARAM12*>(params[11]);
+ PARAM13 *p13 = static_cast<PARAM13*>(params[12]);
+ PARAM14 *p14 = static_cast<PARAM14*>(params[13]);
+ PARAM15 *p15 = static_cast<PARAM15*>(params[14]);
+ PARAM16 *p16 = static_cast<PARAM16*>(params[15]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14, *p15, *p16);
+ }
+
+ // 17 params
+ template <class CLASSNAME, class PARAM1, class PARAM2, class PARAM3, class PARAM4, class PARAM5, class PARAM6, class PARAM7, class PARAM8, class PARAM9, class PARAM10, class PARAM11, class PARAM12, class PARAM13, class PARAM14, class PARAM15, class PARAM16, class PARAM17>
+ void vcb(void (CLASSNAME::*fn)(PARAM1, PARAM2, PARAM3, PARAM4, PARAM5, PARAM6, PARAM7, PARAM8, PARAM9, PARAM10, PARAM11, PARAM12, PARAM13, PARAM14, PARAM15, PARAM16, PARAM17), void *retval, void **params) {
+ PARAM1 *p1 = static_cast<PARAM1*>(params[0]);
+ PARAM2 *p2 = static_cast<PARAM2*>(params[1]);
+ PARAM3 *p3 = static_cast<PARAM3*>(params[2]);
+ PARAM4 *p4 = static_cast<PARAM4*>(params[3]);
+ PARAM5 *p5 = static_cast<PARAM5*>(params[4]);
+ PARAM6 *p6 = static_cast<PARAM6*>(params[5]);
+ PARAM7 *p7 = static_cast<PARAM7*>(params[6]);
+ PARAM8 *p8 = static_cast<PARAM8*>(params[7]);
+ PARAM9 *p9 = static_cast<PARAM9*>(params[8]);
+ PARAM10 *p10 = static_cast<PARAM10*>(params[9]);
+ PARAM11 *p11 = static_cast<PARAM11*>(params[10]);
+ PARAM12 *p12 = static_cast<PARAM12*>(params[11]);
+ PARAM13 *p13 = static_cast<PARAM13*>(params[12]);
+ PARAM14 *p14 = static_cast<PARAM14*>(params[13]);
+ PARAM15 *p15 = static_cast<PARAM15*>(params[14]);
+ PARAM16 *p16 = static_cast<PARAM16*>(params[15]);
+ PARAM17 *p17 = static_cast<PARAM17*>(params[16]);
+ (static_cast<CLASSNAME *>(this)->*fn)(*p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11, *p12, *p13, *p14, *p15, *p16, *p17);
+ }
+
+};
+
+
+#define RECVS_MULTIPATCH int _multipatch(int patch, int msg, void *retval, void **params=0, int nparam=0)
+#define START_MULTIPATCH \
+ int CBCLASS::_multipatch(int patch, int msg, void *retval, void **params, int nparam) { \
+ switch (patch) {
+//FINISH case DESTRUCT: delete this; return 1;
+#define END_MULTIPATCH \
+ default: return 0; \
+ } \
+ return 1; \
+ }
+#define FORWARD_MULTIPATCH(x) \
+ default: return x::_multipatch(patch, msg, retval, params, nparam); \
+ } \
+ return 1; \
+ }
+
+#define START_PATCH(x) case x: switch(msg) {
+#define END_PATCH default: return 0; } break;
+#define NEXT_PATCH(x) END_PATCH START_PATCH(x)
+
+#define M_CB(p, c, x, y) case (x): MultiPatch<p,c>::cb(&CBCLASS::y, retval, params); break;
+#define M_VCB(p, c, x, y) case (x): MultiPatch<p,c>::vcb(&CBCLASS::y, retval, params); break;
+
+
+#define MULTIPATCH_CODES enum
+#endif
+
+
+/* use example:
+
+enum
+{
+ Test_Patch1 = 10,
+ Test_Patch2 = 20,
+};
+
+class Test : public MultiPatch<Test_Patch1, api_class1>,
+ public MultiPatch<Test_Patch2, api_class2>
+{
+public:
+ int TestFunc1();
+ void TestFunc2();
+ void TestFunc3();
+protected:
+ RECVS_MULTIPATCH;
+};
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS Test
+START_MULTIPATCH;
+ START_PATCH(Test_Patch1)
+ M_CB(Test_Patch1, api_class1, API_CLASS1_FUNC1, TestFunc1);
+ NEXT_PATCH(Test_Patch2)
+ M_VCB(Test_Patch2, api_class2, API_CLASS1_FUNC1, TestFunc2);
+ M_VCB(Test_Patch2, api_class2, API_CLASS1_FUNC2, TestFunc3);
+ END_PATCH
+END_MULTIPATCH;
+#undef CBCLASS
+
+*/ \ No newline at end of file
diff --git a/Src/Wasabi/bfc/named.h b/Src/Wasabi/bfc/named.h
new file mode 100644
index 00000000..6aa64d94
--- /dev/null
+++ b/Src/Wasabi/bfc/named.h
@@ -0,0 +1,25 @@
+#ifndef _NAMED_H
+#define _NAMED_H
+
+#include <bfc/common.h>
+#include <bfc/string/StringW.h>
+
+class NOVTABLE NamedW
+{
+public:
+ NamedW(const wchar_t *initial_name=NULL) : name(initial_name) {}
+ virtual ~NamedW() {} // placeholder to ensure name is destructed properly
+ const wchar_t *getName() const { return name; }
+ const wchar_t *getNameSafe(const wchar_t *defval=NULL) const {
+ const wchar_t *str = name;
+ return str ? str : (defval ? defval : L"(null)");
+ }
+ void setName(const wchar_t *newname) { if (name.isequal(newname)) return; name = newname; onSetName(); }
+ // override this to catch name settings
+ virtual void onSetName() {}
+
+private:
+ StringW name;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/node.cpp b/Src/Wasabi/bfc/node.cpp
new file mode 100644
index 00000000..b80be157
--- /dev/null
+++ b/Src/Wasabi/bfc/node.cpp
@@ -0,0 +1,8 @@
+#include "precomp_wasabi_bfc.h"
+#include "node.h"
+
+// In debug mode, the node baseclass will keep track of the count
+// of all nodes created, to help detect leakage of nodes.
+#ifdef _DEBUG
+int Node::count = 0;
+#endif//_DEBUG
diff --git a/Src/Wasabi/bfc/node.h b/Src/Wasabi/bfc/node.h
new file mode 100644
index 00000000..72850cbd
--- /dev/null
+++ b/Src/Wasabi/bfc/node.h
@@ -0,0 +1,118 @@
+#ifndef _NODE_H
+#define _NODE_H
+
+#include "ptrlist.h"
+
+//
+// node.h
+//
+// Some node classes.
+//
+
+
+
+// ==========================================================================
+//
+// class Node
+//
+// A generic "node" object from which one may subclass and create a set of
+// disparate objects that may be assembled into a hierarchical tree.
+//
+class Node {
+private:
+ PtrList<Node> childlist;
+ Node * parent;
+
+protected:
+
+#ifdef _DEBUG
+ static int count;
+#endif//_DEBUG
+
+public:
+
+ Node(Node * myParent = NULL) : childlist(), parent(myParent) {
+#ifdef _DEBUG
+ count++;
+#endif//_DEBUG
+ }
+
+ Node(const Node & a) : childlist(a.childlist), parent(a.parent) {
+#ifdef _DEBUG
+ count++;
+#endif//_DEBUG
+ }
+
+ virtual ~Node() {
+#ifdef _DEBUG
+ count--;
+#endif//_DEBUG
+ };
+
+ int nodeCount() {
+#ifdef _DEBUG
+ return count;
+#else //_DEBUG
+ return -1;
+#endif//_DEBUG
+ }
+
+ //
+ // Const Data Accessor Methods
+ int getNumChildren() const {
+ return childlist.getNumItems();
+ }
+
+ Node * enumChild(int index) const {
+ return childlist[index];
+ }
+
+ Node * getParent() const {
+ return parent;
+ }
+
+ //
+ // Nonconst Data Manipulator Methods
+ Node * addChild(Node * child) {
+ child->setParent(this);
+ return childlist.addItem(child);
+ }
+
+ Node * setParent(Node * myParent) {
+ return parent = myParent;
+ }
+
+ PtrList< Node > & ChildList() {
+ return childlist;
+ }
+};
+
+// ==========================================================================
+//
+// class NodeC< TPayload >
+//
+// If you would rather use Node as a container class than as a base class,
+// this object will allow you to contain a payload instance and be accessed
+// as if it were the payload instance using a reference operator and an
+// implicit cast operator.
+//
+template < class TPayload >
+class NodeC : public Node {
+protected:
+ TPayload payload;
+public:
+ NodeC( const TPayload & myPayload, NodeC * myParent = NULL ) : Node( myParent ), payload( myPayload ) {}
+ NodeC( const NodeC & a ) : Node( a ), payload( a.payload ) {}
+
+ //
+ // In addition to being able to call all of the Node methods, you can also
+ // simply treat the node objects themselves as if they were the payload
+ // instantiation through these simple methods:
+
+ // Explicit reference operator - for lvalues and force rvalues.
+ TPayload & operator () ( void ) { return payload; }
+ // Implicit cast operator - for rvalues that can accept a TPayload &
+ operator TPayload & ( void ) { return payload; }
+};
+
+#endif//_NODE_H
diff --git a/Src/Wasabi/bfc/nsguid.cpp b/Src/Wasabi/bfc/nsguid.cpp
new file mode 100644
index 00000000..acedf0a7
--- /dev/null
+++ b/Src/Wasabi/bfc/nsguid.cpp
@@ -0,0 +1,174 @@
+#include "nsguid.h"
+#include <bfc/wasabi_std.h>
+#ifdef LINUX
+#include <uuid/uuid.h>
+#endif
+
+char *nsGUID::toChar(const GUID &guid, char *target)
+{
+ // {1B3CA60C-DA98-4826-B4A9-D79748A5FD73}
+ SPRINTF( target, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+ (int)guid.Data1, (int)guid.Data2, (int)guid.Data3,
+ (int)guid.Data4[0], (int)guid.Data4[1],
+ (int)guid.Data4[2], (int)guid.Data4[3],
+ (int)guid.Data4[4], (int)guid.Data4[5],
+ (int)guid.Data4[6], (int)guid.Data4[7] );
+
+ return target;
+}
+
+char *nsGUID::toCode(const GUID &guid, char *target)
+{
+ //{ 0x1b3ca60c, 0xda98, 0x4826, { 0xb4, 0xa9, 0xd7, 0x97, 0x48, 0xa5, 0xfd, 0x73 } };
+ SPRINTF( target, "{ 0x%08x, 0x%04x, 0x%04x, { 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x } };",
+ (int)guid.Data1, (int)guid.Data2, (int)guid.Data3,
+ (int)guid.Data4[0], (int)guid.Data4[1],
+ (int)guid.Data4[2], (int)guid.Data4[3],
+ (int)guid.Data4[4], (int)guid.Data4[5],
+ (int)guid.Data4[6], (int)guid.Data4[7] );
+
+ return target;
+}
+
+GUID nsGUID::fromCode(const char *source) {
+
+ GUID guid = GUID_NULL;
+ int Data1, Data2, Data3;
+ int Data4[8] = {0};
+
+ //{ 0x1b3ca60c, 0xda98, 0x4826, { 0xb4, 0xa9, 0xd7, 0x97, 0x48, 0xa5, 0xfd, 0x73 } };
+ SSCANF( source, " { 0x%08x, 0x%04x, 0x%04x, { 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x } } ; ",
+ &Data1, &Data2, &Data3, Data4 + 0, Data4 + 1,
+ Data4 + 2, Data4 + 3, Data4 + 4, Data4 + 5, Data4 + 6, Data4 + 7 );
+
+ // Cross assign all the values
+ guid.Data1 = Data1;
+ guid.Data2 = Data2;
+ guid.Data3 = Data3;
+ guid.Data4[0] = Data4[0];
+ guid.Data4[1] = Data4[1];
+ guid.Data4[2] = Data4[2];
+ guid.Data4[3] = Data4[3];
+ guid.Data4[4] = Data4[4];
+ guid.Data4[5] = Data4[5];
+ guid.Data4[6] = Data4[6];
+ guid.Data4[7] = Data4[7];
+
+ return guid;
+}
+
+int nsGUID::compare(const GUID &a, const GUID &b) {
+ int delta1 = a.Data1 - b.Data1;
+ if (delta1 == 0) {
+ int delta2 = a.Data2 - b.Data2;
+ if (delta2 == 0) {
+ int delta3 = a.Data3 - b.Data3;
+ if (delta3 == 0) {
+ int i;
+ for (i = 0; i < 8; i++ ) {
+ int delta4 = a.Data4[i] - b.Data4[i];
+ if (delta4 == 0) {
+ continue; // :)
+ } else {
+ return delta4;
+ }
+ }
+ } else {
+ return delta3;
+ }
+ } else {
+ return delta2;
+ }
+ } else {
+ return delta1;
+ }
+ return 0;
+}
+
+#ifdef WASABI_COMPILE_CREATEGUID
+void nsGUID::createGuid(GUID *g) {
+#ifdef WIN32
+ CoCreateGuid(g);
+#else
+ uuid_t uid;
+ uuid_generate(uid);
+ MEMCPY(g, &uid, MIN((int)sizeof(GUID), (int)sizeof(uuid_t)));
+#endif
+}
+#endif
+
+
+
+wchar_t *nsGUID::toCharW(const GUID &guid, wchar_t *target)
+{
+ // {1B3CA60C-DA98-4826-B4A9-D79748A5FD73}
+ WCSNPRINTF(target, 39, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+ (int)guid.Data1, (int)guid.Data2, (int)guid.Data3,
+ (int)guid.Data4[0], (int)guid.Data4[1],
+ (int)guid.Data4[2], (int)guid.Data4[3],
+ (int)guid.Data4[4], (int)guid.Data4[5],
+ (int)guid.Data4[6], (int)guid.Data4[7] );
+
+ return target;
+}
+
+GUID nsGUID::fromCharW(const wchar_t *source)
+{
+
+ if (source == NULL) return INVALID_GUID;
+
+ if (!WCSICMP(source, L"@all@"))
+ {
+ static GUID g={ 0xFFFFFFFF, 0xFFFF, 0xFFFF, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } };
+ return g;
+ }
+ if (WCSNICMP(source, L"guid:{", 6)==0)
+ {
+ source+=5;
+ }
+ if(WCSICMP(source, L"guid:avs")==0) {
+ static GUID g={ 10, 12, 16, { 255, 123, 1, 1, 66, 99, 69, 12 } };
+ return g;
+ }
+ if (WCSICMP(source, L"guid:pl")==0 || WCSICMP(source, L"guid:playlist")==0) {
+ static GUID g={ 0x45f3f7c1, 0xa6f3, 0x4ee6, { 0xa1, 0x5e, 0x12, 0x5e, 0x92, 0xfc, 0x3f, 0x8d } };
+ return g;
+ }
+ if (WCSICMP(source, L"guid:ml")==0 || WCSICMP(source, L"guid:musiclibrary")==0 || WCSICMP(source, L"guid:library")==0) {
+ static GUID g={ 0x6b0edf80, 0xc9a5, 0x11d3, { 0x9f, 0x26, 0x00, 0xc0, 0x4f, 0x39, 0xff, 0xc6 } };
+ return g;
+ }
+ if (WCSICMP(source, L"guid:default")==0) {
+ static GUID g={ 0xFFFFFFFF, 0xFFFF, 0xFFFF, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } };
+ return g;
+ }
+
+ if (!wcschr(source, '{') || !wcschr(source, '}'))
+ return INVALID_GUID;
+
+ GUID guid = GUID_NULL;
+ int Data1, Data2, Data3;
+ int Data4[8] = {0};
+
+ // {1B3CA60C-DA98-4826-B4A9-D79748A5FD73}
+ int n = swscanf( source, L" { %08x - %04x - %04x - %02x%02x - %02x%02x%02x%02x%02x%02x } ",
+ &Data1, &Data2, &Data3, Data4 + 0, Data4 + 1,
+ Data4 + 2, Data4 + 3, Data4 + 4, Data4 + 5, Data4 + 6, Data4 + 7 );
+
+ if (n != 11) return INVALID_GUID;
+
+ // Cross assign all the values
+ guid.Data1 = Data1;
+ guid.Data2 = Data2;
+ guid.Data3 = Data3;
+ guid.Data4[0] = Data4[0];
+ guid.Data4[1] = Data4[1];
+ guid.Data4[2] = Data4[2];
+ guid.Data4[3] = Data4[3];
+ guid.Data4[4] = Data4[4];
+ guid.Data4[5] = Data4[5];
+ guid.Data4[6] = Data4[6];
+ guid.Data4[7] = Data4[7];
+
+ return guid;
+}
diff --git a/Src/Wasabi/bfc/nsguid.h b/Src/Wasabi/bfc/nsguid.h
new file mode 100644
index 00000000..97db9a46
--- /dev/null
+++ b/Src/Wasabi/bfc/nsguid.h
@@ -0,0 +1,33 @@
+#ifndef _NSGUID_H
+#define _NSGUID_H
+#include "../../replicant/foundation/guid.h"
+#include <bfc/platform/guid.h>
+//#include <bfc/common.h>
+
+// Some conversion functions to allow
+// us to have GUIDs translatable to and from other data types.
+class nsGUID {
+public:
+ // To the "Human Readable" character format.
+ // {1B3CA60C-DA98-4826-B4A9-D79748A5FD73}
+ static char *toChar(const GUID &guid, char *target);
+ static wchar_t *toCharW(const GUID &guid, wchar_t *target);
+ static GUID fromCharW(const wchar_t *source);
+ // To the "C Structure" character format.
+ // { 0x1b3ca60c, 0xda98, 0x4826, { 0xb4, 0xa9, 0xd7, 0x97, 0x48, 0xa5, 0xfd, 0x73 } };
+ static char *toCode(const GUID &guid, char *target);
+ static GUID fromCode(const char *source);
+
+ // Compare function, returns -1, 0, 1
+ static int compare(const GUID &a, const GUID &b);
+
+ // strlen("{xx xxx xxx-xxxx-xxxx-xxxx-xxx xxx xxx xxx}"
+ enum { GUID_STRLEN = 38 };
+
+#ifdef WASABI_COMPILE_CREATEGUID
+ static void createGuid(GUID *g);
+#endif
+};
+
+
+#endif //_NSGUID_H
diff --git a/Src/Wasabi/bfc/pair.h b/Src/Wasabi/bfc/pair.h
new file mode 100644
index 00000000..2e9eaf0f
--- /dev/null
+++ b/Src/Wasabi/bfc/pair.h
@@ -0,0 +1,14 @@
+#ifndef _PAIR_H
+#define _PAIR_H
+
+template <class A, class B>
+class Pair {
+public:
+ Pair() {}
+ Pair(A _a, B _b) : a(_a), b(_b) {}
+
+ A a;
+ B b;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/parse/Makefile.am b/Src/Wasabi/bfc/parse/Makefile.am
new file mode 100644
index 00000000..ba35f4f9
--- /dev/null
+++ b/Src/Wasabi/bfc/parse/Makefile.am
@@ -0,0 +1,4 @@
+INCLUDES = -I$(top_srcdir)/src $(all_includes)
+METASOURCES = AUTO
+noinst_HEADERS = hierarchyparser.h paramparser.h pathparse.h
+
diff --git a/Src/Wasabi/bfc/parse/Makefile.in b/Src/Wasabi/bfc/parse/Makefile.in
new file mode 100644
index 00000000..09b532c0
--- /dev/null
+++ b/Src/Wasabi/bfc/parse/Makefile.in
@@ -0,0 +1,372 @@
+# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AR = @AR@
+AS = @AS@
+CC = @CC@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+GCJ = @GCJ@
+GCJFLAGS = @GCJFLAGS@
+HAVE_LIB = @HAVE_LIB@
+LIB = @LIB@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIB = @LTLIB@
+MAKEINFO = @MAKEINFO@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RC = @RC@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+INCLUDES = -I$(top_srcdir)/src $(all_includes)
+METASOURCES = AUTO
+noinst_LTLIBRARIES = libbfc_parse.la
+libbfc_parse_la_SOURCES = hierarchyparser.cpp paramparser.cpp pathparse.cpp
+noinst_HEADERS = hierarchyparser.h paramparser.h pathparse.h
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../../../config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I../../..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libbfc_parse_la_LDFLAGS =
+libbfc_parse_la_LIBADD =
+libbfc_parse_la_OBJECTS = hierarchyparser.lo paramparser.lo \
+pathparse.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+DEP_FILES = .deps/hierarchyparser.P .deps/paramparser.P \
+.deps/pathparse.P
+SOURCES = $(libbfc_parse_la_SOURCES)
+OBJECTS = $(libbfc_parse_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cpp .lo .o .obj .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu src/bfc/parse/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLTLIBRARIES:
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+
+distclean-noinstLTLIBRARIES:
+
+maintainer-clean-noinstLTLIBRARIES:
+
+# FIXME: We should only use cygpath when building on Windows,
+# and only if it is available.
+.c.obj:
+ $(COMPILE) -c `cygpath -w $<`
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+ -rm -f *.$(OBJEXT)
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libbfc_parse.la: $(libbfc_parse_la_OBJECTS) $(libbfc_parse_la_DEPENDENCIES)
+ $(CXXLINK) $(libbfc_parse_la_LDFLAGS) $(libbfc_parse_la_OBJECTS) $(libbfc_parse_la_LIBADD) $(LIBS)
+.cpp.o:
+ $(CXXCOMPILE) -c $<
+.cpp.obj:
+ $(CXXCOMPILE) -c `cygpath -w $<`
+.cpp.lo:
+ $(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags -o $$here/TAGS $(ETAGS_ARGS) $$tags $$unique $(LISP))
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = src/bfc/parse
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/bfc/parse/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+
+%.o: %.cpp
+ @echo '$(CXXCOMPILE) -c $<'; \
+ $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.cpp
+ @echo '$(LTCXXCOMPILE) -c $<'; \
+ $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLTLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLTLIBRARIES clean-compile clean-libtool \
+ clean-tags clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLTLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLTLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLTLIBRARIES distclean-noinstLTLIBRARIES \
+clean-noinstLTLIBRARIES maintainer-clean-noinstLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/Src/Wasabi/bfc/parse/PathParseW.cpp b/Src/Wasabi/bfc/parse/PathParseW.cpp
new file mode 100644
index 00000000..e60f422a
--- /dev/null
+++ b/Src/Wasabi/bfc/parse/PathParseW.cpp
@@ -0,0 +1,55 @@
+#include <bfc/bfc_assert.h>
+#include "pathparse.h"
+
+PathParserW::PathParserW(const wchar_t *_str, const wchar_t *sep, int uniquestrs) :
+ processed(FALSE), str(_str ? _str : L""), separators(sep), uniques(uniquestrs)
+{
+ ASSERT(sep != NULL);
+}
+
+int PathParserW::getNumStrings() {
+ process();
+ return strings.getNumItems();
+}
+
+wchar_t *PathParserW::enumString(int i) {
+ process();
+ return strings[i];
+}
+
+wchar_t *PathParserW::enumStringSafe(int i, wchar_t *def_val) {
+ wchar_t *ret = enumString(i);
+ if (ret == NULL) ret = def_val;
+ return ret;
+}
+
+void PathParserW::process() {
+ if (processed) return;
+ processed = 1;
+ preProcess(str);
+ wchar_t *nonconst = str.getNonConstVal();
+ wchar_t *context=0;
+
+ wchar_t *pt = WCSTOK(nonconst, separators, &context);
+ if (pt == NULL) return;
+ postProcess(pt);
+ strings.addItem(pt);
+ for (;;) {
+ wchar_t *pt = WCSTOK(NULL, separators, &context);
+ if (pt == NULL) break;
+ postProcess(pt);
+ if (uniques) {
+ int exists = 0;
+ foreach(strings)
+ if (!WCSICMP(strings.getfor(), pt))
+ {
+ exists=1;
+ break;
+ }
+ endfor;
+ if (exists) continue;
+ }
+ strings.addItem(pt);
+ }
+}
+
diff --git a/Src/Wasabi/bfc/parse/hierarchyparser.cpp b/Src/Wasabi/bfc/parse/hierarchyparser.cpp
new file mode 100644
index 00000000..8d07ed82
--- /dev/null
+++ b/Src/Wasabi/bfc/parse/hierarchyparser.cpp
@@ -0,0 +1,99 @@
+#include "precomp_wasabi_bfc.h"
+#include "hierarchyparser.h"
+#include <bfc/nsguid.h>
+#include <wchar.h>
+// This uses an AMAZINGLY inefficient algorithm! woo hoo!
+
+HierarchyParser::HierarchyParser(const wchar_t *str, const wchar_t *_sibling, const wchar_t *_escape, const wchar_t *_parent_open, const wchar_t *_parent_close) {
+ // Create a new rootnode.
+ rootnode = new HPNode(str);
+ // Parse the rootnode's contents into the rootnode's children.
+ HierarchyParser downparse(rootnode, _sibling, _escape, _parent_open, _parent_close);
+ // Set the actual name of the rootnode ("")
+ (*rootnode)() = L"";
+ // Mark that this was our allocation
+ myalloc = 1;
+}
+
+HierarchyParser::~HierarchyParser() {
+ // If we alloc, we must delete.
+ if (myalloc) {
+ delete rootnode;
+ }
+}
+
+HPNode *HierarchyParser::findGuid(GUID g) {
+ return NULL;
+}
+
+HPNode *HierarchyParser::findString(const wchar_t *str) {
+ return NULL;
+}
+
+HierarchyParser::HierarchyParser(HPNode *_rootnode, const wchar_t *_sibling, const wchar_t *_escape, const wchar_t *_parent_open, const wchar_t *_parent_close) {
+ // We did not alloc, we should not delete.
+ rootnode = _rootnode;
+ sibling = _sibling;
+ escape = _escape;
+ parent_open = _parent_open;
+ parent_close = _parent_close;
+
+ myalloc = 0;
+
+ const wchar_t *parsestr = (*rootnode)();
+
+ size_t i, length = wcslen(parsestr), depth = 0;
+
+ StringW curr_sibling;
+
+ for (i = 0; i < length; i++ ) {
+ wchar_t c = parsestr[i];
+
+ if (isEscape(c)) {
+ // always add the next character
+ curr_sibling += parsestr[++i];
+ } else if (isSibling(c)) {
+ // if we're not inside someone else,
+ if (!depth) {
+ // okay, we're done with the current sibling. ship him off.
+ processSibling(curr_sibling);
+ // on to the next sibling!
+ curr_sibling = L"";
+ } else {
+ curr_sibling += c;
+ }
+ } else if (isParentOpen(c)) {
+ // increment depth
+ curr_sibling += c;
+ depth++;
+ } else if (isParentClose(c)) {
+ // decrement depth
+ curr_sibling += c;
+ depth--;
+ } else {
+ curr_sibling += c;
+ }
+ }
+
+ // If there is anything left over, process it as a sibling.
+ if (curr_sibling.len()) {
+ processSibling(curr_sibling);
+ }
+}
+
+void HierarchyParser::processSibling(const wchar_t *sibstr) {
+ StringW curr_sibling = sibstr;
+ // slice the name out of the front of the string.
+ StringW sibling_name = curr_sibling.lSpliceChar(parent_open);
+ // curr_sibling will contain the children of this sibling (or nothing).
+ curr_sibling.rSpliceChar(parent_close);
+ // create a new child for our root node to contain the sibling's child info
+ HPNode *child = new HPNode(curr_sibling, rootnode);
+ // parse the child hierarchically for its children
+ HierarchyParser childparser(child, sibling, escape, parent_open, parent_close);
+ // once parsed. set its name to be this sibling
+ (*child)() = sibling_name;
+ // and lastly add him as a child to the root node.
+ rootnode->addChild(child);
+}
+
diff --git a/Src/Wasabi/bfc/parse/hierarchyparser.h b/Src/Wasabi/bfc/parse/hierarchyparser.h
new file mode 100644
index 00000000..286b3706
--- /dev/null
+++ b/Src/Wasabi/bfc/parse/hierarchyparser.h
@@ -0,0 +1,55 @@
+#ifndef __PARAMPARSE_H
+#define __PARAMPARSE_H
+
+#include <bfc/parse/pathparse.h>
+#include <bfc/node.h>
+#include <bfc/string/StringW.h>
+
+
+// typedef NodeC<String> HPNode // OH YAH, YOU CAN'T FWD REF TYPEDEFS. STOOOOOOPID.
+class HPNode : public NodeC<StringW> {
+public:
+ HPNode( const StringW & myPayload, NodeC<StringW> * myParent = NULL ) : NodeC<StringW>(myPayload, myParent) {}
+};
+
+class HierarchyParser {
+public:
+ HierarchyParser(const wchar_t *str = NULL, const wchar_t *_sibling=L";", const wchar_t *_escape=L"\\", const wchar_t *_parent_open=L"(", const wchar_t *_parent_close=L")") ;
+ ~HierarchyParser();
+
+ HPNode *findGuid(GUID g);
+ HPNode *findString(const wchar_t *str);
+
+ int hasGuid(GUID g) { return findGuid(g) != NULL; }
+ int hasString(const wchar_t *str) { return findString(str) != NULL; }
+
+ HPNode *rootNode() { return rootnode; }
+
+private:
+ HPNode *rootnode;
+ int myalloc;
+
+ StringW sibling;
+ StringW escape;
+ StringW parent_open;
+ StringW parent_close;
+
+ HierarchyParser(HPNode *_rootnode, const wchar_t *_sibling=L";", const wchar_t *_escape=L"\\", const wchar_t *_parent_open=L"(", const wchar_t *_parent_close=L")");
+ void processSibling(const wchar_t *sibling);
+
+
+ inline int isSibling(wchar_t c) {
+ return sibling.lFindChar(c) != -1;
+ }
+ inline int isEscape(wchar_t c) {
+ return escape.lFindChar(c) != -1;
+ }
+ inline int isParentOpen(wchar_t c) {
+ return parent_open.lFindChar(c) != -1;
+ }
+ inline int isParentClose(wchar_t c) {
+ return parent_close.lFindChar(c) != -1;
+ }
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/parse/paramparser.cpp b/Src/Wasabi/bfc/parse/paramparser.cpp
new file mode 100644
index 00000000..c68bbbe2
--- /dev/null
+++ b/Src/Wasabi/bfc/parse/paramparser.cpp
@@ -0,0 +1,20 @@
+#include "precomp_wasabi_bfc.h"
+#include "paramparser.h"
+#include <bfc/nsguid.h>
+#include <bfc/wasabi_std.h>
+
+int ParamParser::findGuid(GUID g) {
+ for (int i=0;i<getNumItems();i++) {
+ const wchar_t *e = enumItem(i);
+ GUID eguid = nsGUID::fromCharW(e);
+ if (g == eguid) return i;
+ }
+ return -1;
+}
+
+int ParamParser::findString(const wchar_t *str) {
+ for (int i=0;i<getNumItems();i++) {
+ if (!WCSICMP(str, enumItem(i))) return i;
+ }
+ return -1;
+} \ No newline at end of file
diff --git a/Src/Wasabi/bfc/parse/paramparser.h b/Src/Wasabi/bfc/parse/paramparser.h
new file mode 100644
index 00000000..69573bdc
--- /dev/null
+++ b/Src/Wasabi/bfc/parse/paramparser.h
@@ -0,0 +1,23 @@
+#ifndef __PARAMPARSE_H
+#define __PARAMPARSE_H
+
+#include <bfc/parse/pathparse.h>
+
+class ParamParser : private PathParserW
+{
+ public:
+
+ ParamParser(const wchar_t *str, const wchar_t *sep=L";", int unique=0) : PathParserW(str, sep, unique) {}
+
+ int findGuid(GUID g);
+ int findString(const wchar_t *str);
+
+ int hasGuid(GUID g) { return findGuid(g) >= 0; }
+ int hasString(const wchar_t *str) { return findString(str) >= 0; }
+
+ const wchar_t *enumItem(int element) { return enumString(element); }
+ int getNumItems() { return getNumStrings(); }
+ const wchar_t *getLastItem() { return getLastString(); }
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/parse/pathparse.cpp b/Src/Wasabi/bfc/parse/pathparse.cpp
new file mode 100644
index 00000000..a6653d5d
--- /dev/null
+++ b/Src/Wasabi/bfc/parse/pathparse.cpp
@@ -0,0 +1,54 @@
+#include "precomp_wasabi_bfc.h"
+#include <bfc/wasabi_std.h>
+#include "pathparse.h"
+
+PathParser::PathParser(const char *_str, const char *sep, int uniquestrs) :
+ processed(FALSE), str(_str ? _str : ""), separators(sep), uniques(uniquestrs)
+{
+ ASSERT(sep != NULL);
+}
+
+int PathParser::getNumStrings() {
+ process();
+ return strings.getNumItems();
+}
+
+char *PathParser::enumString(int i) {
+ process();
+ return strings[i];
+}
+
+char *PathParser::enumStringSafe(int i, char *def_val) {
+ char *ret = enumString(i);
+ if (ret == NULL) ret = def_val;
+ return ret;
+}
+
+void PathParser::process() {
+ if (processed) return;
+ processed = 1;
+ preProcess(str);
+ char *nonconst = str.getNonConstVal();
+
+ char *pt = strtok(nonconst, separators);
+ if (pt == NULL) return;
+ postProcess(pt);
+ strings.addItem(pt);
+ for (;;) {
+ char *pt = strtok(NULL, separators);
+ if (pt == NULL) break;
+ postProcess(pt);
+ if (uniques) {
+ int exists = 0;
+ foreach(strings)
+ if (STRCASEEQL(strings.getfor(), pt)) {
+ exists=1;
+ break;
+ }
+ endfor;
+ if (exists) continue;
+ }
+ strings.addItem(pt);
+ }
+}
+
diff --git a/Src/Wasabi/bfc/parse/pathparse.h b/Src/Wasabi/bfc/parse/pathparse.h
new file mode 100644
index 00000000..67a22ffe
--- /dev/null
+++ b/Src/Wasabi/bfc/parse/pathparse.h
@@ -0,0 +1,152 @@
+#ifndef _PATHPARSE_H
+#define _PATHPARSE_H
+
+#include <bfc/ptrlist.h>
+#include <bfc/string/bfcstring.h>
+#include <bfc/string/StringW.h>
+
+/**
+ PathParser is a class that parses a DOS/Windows (example: C:\DOS)
+ style path as well as a UNIX style path (example: /usr/local/bin/).
+
+ @short Path parser for Windows and UNIX style paths.
+ @author Nullsoft
+ @ver 1.0
+*/
+class PathParser
+{
+public:
+ /**
+ When PathParser is instantiated, the contructor takes the path to
+ parse and the separators to use to parse the path. It will then
+ parse the path using the separators and make the parsed elements
+ available. If no separators are given \ and / are used.
+
+ @param str The path to parse.
+ @param separators String that contains the separators to use. Single character separators only.
+ No delimiters between separators in the string.
+ */
+ PathParser(const char *_str, const char *sep = "\\/", int uniquestrs = 0);
+
+ void setString(const char *string, const char *separators = "\\/");
+
+ /**
+ Gets the number of path elements found in the path.
+
+ @ret The number of path elements found.
+ */
+ int getNumStrings();
+
+ /**
+ Gets the number of path elements found in the path.
+
+ @ret The number of path elements found.
+ */
+ char *enumString(int i);
+
+ char *enumStringSafe(int i, char *def_val="");
+
+ /**
+ Gets the last path element from the parsed path.
+
+ @ret The last path element from the parsed path.
+ */
+ char *getLastString() { return enumString(getNumStrings()-1); }
+
+protected:
+ /**
+ Override available for pre-processing of the
+ string before it's split. This is done at the start
+ of the process() call.
+
+ @param str A reference to the string to pre-process.
+ */
+ virtual void preProcess(String &str) { }
+
+ /**
+ Override available for post-processing of the pieces
+ of the command line that are obtained after it's
+ been split.
+
+ @param str The command line piece to post-process.
+ */
+ virtual void postProcess(char *str) { }
+
+private:
+ void process();
+ int processed;
+ String str;
+ String separators;
+ PtrList<char> strings;
+ int uniques;
+};
+
+class PathParserW
+{
+public:
+ /**
+ When PathParser is instantiated, the contructor takes the path to
+ parse and the separators to use to parse the path. It will then
+ parse the path using the separators and make the parsed elements
+ available. If no separators are given \ and / are used.
+
+ @param str The path to parse.
+ @param separators String that contains the separators to use. Single character separators only.
+ No delimiters between separators in the string.
+ */
+ PathParserW(const wchar_t *_str, const wchar_t *sep = L"\\/", int uniquestrs = 0);
+
+ void setString(const wchar_t *string, const wchar_t *separators = L"\\/");
+
+ /**
+ Gets the number of path elements found in the path.
+
+ @ret The number of path elements found.
+ */
+ int getNumStrings();
+
+ /**
+ Gets the number of path elements found in the path.
+
+ @ret The number of path elements found.
+ */
+ wchar_t *enumString(int i);
+
+ wchar_t *enumStringSafe(int i, wchar_t *def_val=L"");
+
+ /**
+ Gets the last path element from the parsed path.
+
+ @ret The last path element from the parsed path.
+ */
+ wchar_t *getLastString() { return enumString(getNumStrings()-1); }
+
+protected:
+ /**
+ Override available for pre-processing of the
+ string before it's split. This is done at the start
+ of the process() call.
+
+ @param str A reference to the string to pre-process.
+ */
+ virtual void preProcess(StringW &str) { }
+
+ /**
+ Override available for post-processing of the pieces
+ of the command line that are obtained after it's
+ been split.
+
+ @param str The command line piece to post-process.
+ */
+ virtual void postProcess(wchar_t *str) { }
+
+private:
+ void process();
+ int processed;
+ StringW str;
+ StringW separators;
+ PtrList<wchar_t> strings;
+ int uniques;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/platform/Makefile.am b/Src/Wasabi/bfc/platform/Makefile.am
new file mode 100644
index 00000000..aa27d337
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/Makefile.am
@@ -0,0 +1,6 @@
+INCLUDES = -I$(top_srcdir)/src $(all_includes)
+METASOURCES = AUTO
+noinst_LIBRARIES = libbfc_platform.a
+libbfc_platform_a_SOURCES = guid.h linux.h platform.h platform.cpp
+
+libbfc_platform_a_LIBADD = $(top_builddir)/src/bfc/platform/linux/libbfc_platform_linux.a
diff --git a/Src/Wasabi/bfc/platform/Makefile.in b/Src/Wasabi/bfc/platform/Makefile.in
new file mode 100644
index 00000000..3ccf8a57
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/Makefile.in
@@ -0,0 +1,376 @@
+# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AR = @AR@
+AS = @AS@
+CC = @CC@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+GCJ = @GCJ@
+GCJFLAGS = @GCJFLAGS@
+HAVE_LIB = @HAVE_LIB@
+LIB = @LIB@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIB = @LTLIB@
+MAKEINFO = @MAKEINFO@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RC = @RC@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+INCLUDES = -I$(top_srcdir)/src $(all_includes)
+METASOURCES = AUTO
+noinst_LIBRARIES = libbfc_platform.a
+libbfc_platform_a_SOURCES = guid.h linux.h platform.h platform.cpp
+
+libbfc_platform_a_LIBADD = $(top_builddir)/src/bfc/platform/linux/libbfc_platform_linux.a
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../../../config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I../../..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libbfc_platform_a_DEPENDENCIES = \
+$(top_builddir)/src/bfc/platform/linux/libbfc_platform_linux.a
+libbfc_platform_a_OBJECTS = platform.$(OBJEXT)
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+DEP_FILES = .deps/platform.P
+SOURCES = $(libbfc_platform_a_SOURCES)
+OBJECTS = $(libbfc_platform_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cpp .lo .o .obj .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu src/bfc/platform/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+# FIXME: We should only use cygpath when building on Windows,
+# and only if it is available.
+.c.obj:
+ $(COMPILE) -c `cygpath -w $<`
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+ -rm -f *.$(OBJEXT)
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libbfc_platform.a: $(libbfc_platform_a_OBJECTS) $(libbfc_platform_a_DEPENDENCIES)
+ -rm -f libbfc_platform.a
+ $(AR) cru libbfc_platform.a $(libbfc_platform_a_OBJECTS) $(libbfc_platform_a_LIBADD)
+ $(RANLIB) libbfc_platform.a
+.cpp.o:
+ $(CXXCOMPILE) -c $<
+.cpp.obj:
+ $(CXXCOMPILE) -c `cygpath -w $<`
+.cpp.lo:
+ $(LTCXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags -o $$here/TAGS $(ETAGS_ARGS) $$tags $$unique $(LISP))
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = src/bfc/platform
+
+distdir: $(DISTFILES)
+ here=`cd $(top_builddir) && pwd`; \
+ top_distdir=`cd $(top_distdir) && pwd`; \
+ distdir=`cd $(distdir) && pwd`; \
+ cd $(top_srcdir) \
+ && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/bfc/platform/Makefile
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+ -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+ @echo '$(COMPILE) -c $<'; \
+ $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.c
+ @echo '$(LTCOMPILE) -c $<'; \
+ $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+
+%.o: %.cpp
+ @echo '$(CXXCOMPILE) -c $<'; \
+ $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-cp .deps/$(*F).pp .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm .deps/$(*F).pp
+
+%.lo: %.cpp
+ @echo '$(LTCXXCOMPILE) -c $<'; \
+ $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
+ < .deps/$(*F).pp > .deps/$(*F).P; \
+ tr ' ' '\012' < .deps/$(*F).pp \
+ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ >> .deps/$(*F).P; \
+ rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLIBRARIES clean-compile clean-libtool clean-tags \
+ clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLIBRARIES distclean-compile \
+ distclean-libtool distclean-tags distclean-depend \
+ distclean-generic clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLIBRARIES \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-depend \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir \
+mostlyclean-depend distclean-depend clean-depend \
+maintainer-clean-depend info-am info dvi-am dvi check check-am \
+installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/Src/Wasabi/bfc/platform/export.h b/Src/Wasabi/bfc/platform/export.h
new file mode 100644
index 00000000..68e6e3c9
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/export.h
@@ -0,0 +1,20 @@
+#ifndef NULLSOFT_BFC_EXPORT_H
+#define NULLSOFT_BFC_EXPORT_H
+
+#ifdef _MSC_VER
+#define DLLEXPORT __declspec(dllexport)
+#elif defined(__GNUC__)
+#define DLLEXPORT __attribute__ ((visibility("default")))
+#else
+#error port me!
+#endif
+
+#ifdef _MSC_VER
+#define DLLIMPORT __declspec(dllimport)
+#elif defined(__GNUC__)
+#define DLLIMPORT
+#else
+#error port me!
+#endif
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/bfc/platform/guid.h b/Src/Wasabi/bfc/platform/guid.h
new file mode 100644
index 00000000..3724f6e1
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/guid.h
@@ -0,0 +1 @@
+#include "../../../replicant/foundation/guid.h"
diff --git a/Src/Wasabi/bfc/platform/linux.h b/Src/Wasabi/bfc/platform/linux.h
new file mode 100644
index 00000000..b57ec3f0
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/linux.h
@@ -0,0 +1,437 @@
+#ifndef __LINUX_H_WASABI
+#define __LINUX_H_WASABI
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/timeb.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <errno.h>
+#include <math.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/shm.h>
+
+#ifndef NOVTABLE
+#define NOVTABLE
+#endif
+
+#ifndef __USE_GNU
+#define __USE_GNU
+#include <pthread.h>
+#undef __USE_GNU
+#else
+#include <pthread.h>
+#endif
+
+#ifdef WASABI_COMPILE_WND
+
+// Fucking api_region and Font namespace conflicts
+#define _XRegion _XRegion
+#define api_region HRGN
+#define Font HFONT
+#define Cursor _Cursor
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/extensions/shape.h>
+#include <X11/extensions/XShm.h>
+#include <X11/Xos.h>
+#include <X11/Xatom.h>
+#include <X11/xpm.h>
+#include <X11/keysym.h>
+#include <X11/cursorfont.h>
+#undef _XRegion
+#undef api_region
+#undef Font
+#undef Cursor
+
+#ifdef WASABI_COMPILE_FONTS
+
+#ifdef __INCLUDE_FREETYPE
+#include <freetype/freetype.h>
+#include <freetype/ftglyph.h>
+
+#endif // freetype
+
+//typedef FT_Face HFONT;
+#endif // fonts
+
+#ifdef __INCLUDE_GTK
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#endif // gtk
+
+typedef Window HWND;
+
+#else // wnd
+typedef void * HWND;
+#endif // wnd
+
+// I know about XRectangle, but it's easier to recreate this than it is
+// to merge it with the rest of the code
+typedef struct { int left, top, right, bottom; } RECT;
+
+typedef unsigned long COLORREF;
+typedef struct {
+ char rgbBlue;
+ char rgbGreen;
+ char rgbRed;
+ char filler;
+} RGBQUAD;
+#define RGB( r, g, b ) ((((r)&0xFF)<<16)|(((g)&0xFF)<<8)|((b)&0xFF))
+#define min( a, b ) ((a>b)?b:a)
+#define max( a, b ) ((a>b)?a:b)
+#define CLR_NONE 0
+
+#ifdef __cplusplus
+#ifndef XMD_H
+typedef int BOOL; // It's int not bool because of some inheritance conflicts
+#endif
+#ifndef TRUE
+#define TRUE true
+#endif
+#ifndef FALSE
+#define FALSE false
+#endif
+#else
+#ifndef XMD_H
+typedef int BOOL;
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#endif
+typedef BOOL BOOLEAN;
+typedef struct { int x, y; } POINT;
+
+#ifdef WASABI_COMPILE_WND
+
+typedef void *HPEN;
+
+// The HDC knows what it's drawing on
+typedef struct hdc_typ {
+ GC gc;
+ Drawable d;
+ HRGN clip;
+} *HDC;
+
+// Pixmaps don't have associated width and height, at least not that I know of
+typedef struct {
+ Pixmap p;
+ int bmWidth;
+ int bmHeight;
+ XShmSegmentInfo *shmseginfo;
+
+} BITMAP, HBITMAP;
+
+typedef Pixmap HICON;
+
+#endif // wnd
+
+typedef int LRESULT;
+typedef int LPARAM;
+typedef int WPARAM;
+typedef int RPARAM;
+typedef unsigned int TCHAR;
+typedef long long __int64;
+typedef long long LARGE_INTEGER;
+typedef unsigned long long ULARGE_INTEGER;
+#define OSPIPE int
+#define OSPROCESSID int
+#define LOWORD(a) ((a)&0xffff)
+#define HIWORD(a) (((a)>>16)&0xffff)
+
+#define MAX_PATH 8192
+
+#define COMEXP
+#define EXTC extern "C"
+#define __cdecl
+#define CALLBACK
+#define WINAPI
+#define HRESULT void*
+#define WINUSERAPI
+#define APIENTRY
+#define __declspec(a)
+typedef char * LPSTR;
+typedef unsigned long DWORD;
+typedef short int WORD;
+#ifndef XMD_H
+typedef unsigned char BYTE;
+#endif
+typedef void* LPVOID;
+typedef struct {
+ long cx, cy;
+} SIZE;
+typedef long LONG;
+#define VOID void
+
+#ifdef WASABI_COMPILE_WND
+// Fix this for canvas
+typedef void * PAINTSTRUCT;
+#endif
+
+#ifndef WASABI_COMPILE_WND
+#ifndef None
+#define None (HWND)0
+#endif
+#endif
+
+typedef void* THREAD_RET;
+
+#ifdef WASABI_COMPILE_WND
+// Fix this with editwnd!
+typedef void * WNDPROC;
+typedef void * DRAWITEMSTRUCT;
+
+#define VK_MENU (XK_Alt_L | (XK_Alt_R << 16))
+#define VK_MBUTTON (XK_Meta_L | (XK_Meta_R << 16))
+#define VK_SHIFT (XK_Shift_L | (XK_Shift_R << 16))
+#define MK_RBUTTON ((XK_VoidSymbol << 16) | 1)
+#define MK_LBUTTON ((XK_VoidSymbol << 16) | 2)
+#define VK_CONTROL (XK_Control_L | (XK_Control_R << 16))
+#define VK_DELETE (XK_Delete | (XK_KP_Delete << 16))
+#define VK_RETURN (XK_Return)
+#define VK_ESCAPE (XK_Escape)
+#define VK_DOWN (XK_Down)
+#define VK_UP (XK_Up)
+#define VK_LEFT (XK_Left)
+#define VK_RIGHT (XK_Right)
+#define VK_HOME (XK_Home)
+#define VK_END (XK_End)
+#define VK_PRIOR (XK_Prior)
+#define VK_NEXT (XK_Next)
+#define VK_BACK (XK_BackSpace)
+#define VK_F1 (XK_F1)
+#define VK_SPACE (XK_space)
+
+#define INVALID_HANDLE_VALUE NULL
+#endif
+
+// Come back here later
+typedef struct {
+ pthread_mutex_t mutex;
+ pthread_t id;
+ int count;
+} CRITICAL_SECTION;
+typedef pthread_t HANDLE;
+
+typedef char OLECHAR;
+
+//#define NO_MMX
+//CUT? #define NULLREGION 0
+
+#define MAIN_MINX 0
+#define MAIN_MINY 0
+
+typedef void (*TIMERPROC)(HWND, UINT, UINT, DWORD);
+
+typedef struct {
+ HWND hwnd;
+ UINT message;
+ WPARAM wParam;
+ LPARAM lParam;
+ DWORD time;
+ POINT pt;
+} MSG;
+
+#ifdef __cplusplus
+
+#define _TRY try
+#define _EXCEPT(x) catch(...)
+
+#include <new>
+
+#ifdef WASABI_COMPILE_WND
+
+#define NULLREGION 1
+#define SIMPLEREGION 2
+#define COMPLEXREGION 3
+
+#endif
+
+// some of these are used even without wnd support
+
+enum {
+ WM_CREATE, // MULL
+ WM_CLOSE, // NULL
+ WM_PAINT, // NULL
+ WM_NCPAINT, // NULL
+ WM_SYNCPAINT, // NULL
+ WM_SETCURSOR, // NULL
+ WM_TIMER, // timerid
+ WM_SETFOCUS, // NULL
+ WM_KILLFOCUS, // NULL
+ WM_LBUTTONDOWN, // xPos | yPos << 16
+ WM_RBUTTONDOWN, // "
+ WM_MOUSEMOVE, // "
+ WM_LBUTTONUP, // "
+ WM_RBUTTONUP, // "
+ WM_CONTEXTMENU, // "
+ WM_ERASEBKGND, // NULL
+ WM_MOUSEWHEEL, // a << 16 | t (l=a/120)
+ WM_CHAR, // char
+ WM_KEYDOWN, // keypress
+ WM_KEYUP, // "
+ WM_SYSKEYDOWN, // look at OnSysKeyDown
+ WM_SYSKEYUP, // "
+ WM_SYSCOMMAND, // Hunh?
+ WM_MOUSEACTIVATE, // Hunh?
+ WM_ACTIVATEAPP, // Hunh?
+ WM_ACTIVATE, // WA_ACTIVE || WA_CLICKACTIVE
+ WM_NCACTIVATE, // NULL
+ WM_WINDOWPOSCHANGED, // NULL, WINDOWPOS *
+ WM_DROPFILES, // HDROP
+ WM_CAPTURECHANGED, // NULL
+ WM_COMMAND, // Commands?..
+ WM_SETTINGCHANGE,
+ WM_QUIT,
+ WM_DESTROY,
+ WM_USER = 1000, // wParam, lParam -> make sure this is last
+};
+
+#define PM_NOREMOVE 0x0000
+#define PM_REMOVE 0x0001
+#define PM_NOYIELD 0x0002 // ignored
+
+#ifdef WASABI_COMPILE_WND
+
+enum {
+ WA_ACTIVE, WA_CLICKACTIVE,
+};
+
+enum {
+ SC_CLOSE,
+};
+
+enum {
+ DT_LEFT,
+ DT_CENTER,
+ DT_RIGHT,
+ DT_VCENTER,
+ DT_WORDBREAK,
+ DT_SINGLELINE,
+ DT_NOPREFIX,
+ DT_PATH_ELLIPSIS,
+ DT_END_ELLIPSIS,
+ DT_MODIFYSTRING,
+ DT_CALCRECT,
+
+};
+
+#define ALL_EVENTS ExposureMask | StructureNotifyMask | \
+ KeyPressMask | KeyReleaseMask | \
+ ButtonPressMask | ButtonReleaseMask | \
+ PointerMotionMask | FocusChangeMask | \
+ EnterWindowMask | LeaveWindowMask
+
+
+#define NO_INPUT_EVENTS ExposureMask | StructureNotifyMask | \
+ PointerMotionMask | FocusChangeMask | \
+ EnterWindowMask | LeaveWindowMask
+
+class Linux {
+ private:
+ static Display *display;
+ static XContext context;
+
+ public:
+ static Display *getDisplay();
+ static int getScreenNum();
+ static Window RootWin();
+ static Visual *DefaultVis();
+
+ static int convertEvent( MSG *, XEvent * );
+ static void initContextData( HWND h );
+ static void nukeContextData( HWND h );
+ static XContext getContext();
+ static void setCursor( HWND h, int cursor );
+};
+
+#endif
+
+#endif
+
+typedef void* HINSTANCE; // Useless, just a placeholder
+typedef void* HMONITOR;
+typedef void* WIN32_FIND_DATA;
+typedef void* WIN32_FIND_DATAW;
+typedef void* BLENDFUNCTION;
+typedef void* ATOM;
+typedef void* HGLOBAL;
+typedef void* HKEY;
+typedef char* LPTSTR;
+typedef char* LPCTSTR;
+typedef DWORD* LPDWORD;
+
+#if defined(WASABI_API_TIMER) || defined(WASABI_API_WND)
+int GetMessage( MSG *, HWND, UINT, UINT );
+int PeekMessage( MSG *, HWND, UINT, UINT, UINT );
+int DispatchMessage( MSG * );
+int SendMessage( HWND, UINT, WPARAM, LPARAM );
+int SetTimer( HWND, int id, int ms, TIMERPROC );
+void KillTimer( HWND, int id );
+#endif
+
+#ifdef WASABI_COMPILE_WND
+
+void TranslateMessage( MSG * );
+void PostMessage( HWND, UINT, WPARAM, LPARAM );
+void PostQuitMessage( int );
+
+enum contextdata {
+ GWL_HINSTANCE = 0,
+ GWL_USERDATA,
+ GWL_INVALIDREGION,
+ GWL_RECT_LEFT,
+ GWL_RECT_TOP,
+ GWL_RECT_RIGHT,
+ GWL_RECT_BOTTOM,
+ GWL_HWND,
+ GWL_PARENT,
+
+ GWL_ENUM_SIZE
+};
+void MoveWindowRect( HWND, int, int );
+void SetWindowRect( HWND, RECT * );
+int GetWindowRect( HWND, RECT * );
+void SetWindowLong( HWND, enum contextdata, LONG );
+LONG GetWindowLong( HWND, enum contextdata );
+int GetUpdateRect( HWND, RECT *, BOOL );
+void GetUpdateRgn( HWND, HRGN, BOOL );
+void InvalidateRgn( HWND, HRGN, BOOL );
+void InvalidateRect( HWND, const RECT *, BOOL );
+void ValidateRgn( HWND, HRGN );
+void ValidateRect( HWND, const RECT * );
+HWND GetActiveWindow();
+HWND WindowFromPoint( POINT p );
+#endif
+
+void OutputDebugString( const char *s );
+int MulDiv( int m1, int m2, int d );
+DWORD GetTickCount();
+void Sleep( int ms );
+int IntersectRect(RECT *, const RECT *, const RECT *);
+void ExitProcess( int ret );
+DWORD GetModuleFileName(void *pid, const char *filename, int bufsize);
+const char *CharPrev(const char *lpszStart, const char *lpszCurrent);
+
+int SubtractRect( RECT *out, RECT *in1, RECT *in2 );
+int EqualRect( RECT *a, RECT *b );
+
+
+void CopyFile( const char *f1, const char *f2, BOOL b );
+
+#endif
+
diff --git a/Src/Wasabi/bfc/platform/linux/linux.cpp b/Src/Wasabi/bfc/platform/linux/linux.cpp
new file mode 100644
index 00000000..67471d4a
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/linux/linux.cpp
@@ -0,0 +1,961 @@
+#include <precomp.h>
+
+#include <api/api.h>
+ #include <api/linux/api_linux.h>
+
+#include <bfc/ptrlist.h>
+#include <bfc/string/string.h>
+#include <bfc/critsec.h>
+#include <bfc/thread.h>
+#include <api/application/ipcs.h>
+
+#ifdef WASABI_COMPILE_WND
+Display *Linux::display = NULL;
+
+int linux_atoms_loaded = 0;
+
+Atom winamp_msg;
+Atom dnd_enter, dnd_position, dnd_status, dnd_leave, dnd_drop, dnd_finished;
+Atom dnd_selection, dnd_wa3drop, dnd_private, dnd_typelist;
+Atom dnd_urilist, dnd_textplain, dnd_mozurl;
+#endif
+
+#ifndef _NOSTUDIO
+
+#ifdef WASABI_COMPILE_WND
+void LoadAtoms() {
+ if ( !linux_atoms_loaded ) {
+ linux_atoms_loaded = 1;
+ winamp_msg = XInternAtom( Linux::getDisplay(), "Winamp3", False );
+ dnd_wa3drop = XInternAtom( Linux::getDisplay(), "Winamp3_drop", False );
+ dnd_enter = XInternAtom( Linux::getDisplay(), "XdndEnter", True );
+ dnd_position = XInternAtom( Linux::getDisplay(), "XdndPosition", True );
+ dnd_status = XInternAtom( Linux::getDisplay(), "XdndStatus", True );
+ dnd_leave = XInternAtom( Linux::getDisplay(), "XdndLeave", True );
+ dnd_drop = XInternAtom( Linux::getDisplay(), "XdndDrop", True );
+ dnd_finished = XInternAtom( Linux::getDisplay(), "XdndFinished", True );
+ dnd_selection = XInternAtom( Linux::getDisplay(), "XdndSelection", True );
+ dnd_private = XInternAtom( Linux::getDisplay(), "XdndActionPrivate", True );
+ dnd_typelist = XInternAtom( Linux::getDisplay(), "XdndTypeList", True );
+ dnd_urilist = XInternAtom( Linux::getDisplay(), "text/uri-list", True );
+ dnd_textplain = XInternAtom( Linux::getDisplay(), "text/plain", True );
+ dnd_mozurl = XInternAtom( Linux::getDisplay(), "text/x-moz-url", True );
+ }
+}
+#endif
+
+#endif
+
+void OutputDebugString( const char *s ) {
+#ifdef _DEBUG
+ fprintf( stderr, "%s", s );
+#endif
+ char *file = getenv( "WASABI_LOG_FILE" );
+ if ( file ) {
+ if ( !STRCMP( file, "-" ) ) {
+ fprintf( stdout, "%s", s );
+ } else {
+ FILE *f = fopen( file, "a" );
+ if ( f ) {
+ fprintf( f, "%s", s );
+ fclose( f );
+ }
+ }
+ }
+}
+
+DWORD GetTickCount() {
+ static int starttime = -1;
+
+ if ( starttime == -1 )
+ starttime = time( NULL );
+
+ struct timeb tb;
+ ftime( &tb );
+ tb.time -= starttime;
+ return tb.time * 1000 + tb.millitm;
+}
+void Sleep( int ms ) {
+ if ( ms != 0 ) {
+ struct timespec ts = { 0, 0 };
+ ts.tv_sec = ms / 1000;
+ ts.tv_nsec = (ms % 1000) * 1000000;
+ nanosleep( &ts, NULL);
+ // usleep(ms * 1000);
+ }
+}
+
+#ifndef _NOSTUDIO
+
+#ifdef WASABI_COMPILE_WND
+
+Display *Linux::getDisplay() {
+ if ( ! display )
+ display = WASABI_API_LINUX->linux_getDisplay();
+
+ return display;
+}
+
+XContext Linux::getContext() {
+ static XContext context = 0;
+
+ if ( context == 0 )
+ context = WASABI_API_LINUX->linux_getContext();
+
+ return context;
+}
+
+int Linux::getScreenNum() { return DefaultScreen( getDisplay() ); }
+
+Window Linux::RootWin() {
+ return RootWindow( getDisplay(), getScreenNum() );
+}
+Visual *Linux::DefaultVis() {
+ return DefaultVisual( getDisplay(), getScreenNum() );
+}
+
+void Linux::setCursor( HWND h, int cursor ) {
+ Cursor c = XCreateFontCursor( Linux::getDisplay(), cursor );
+
+ if ( cursor == None )
+ XUndefineCursor( Linux::getDisplay(), h );
+ else
+ XDefineCursor( Linux::getDisplay(), h, c );
+
+ XFreeCursor( Linux::getDisplay(), c );
+}
+
+int Linux::convertEvent( MSG *m, XEvent *e ) {
+ m->hwnd = e->xany.window;
+
+ if ( m->hwnd ) {
+ api_window *rw =(api_window *)GetWindowLong( m->hwnd, GWL_USERDATA );
+ if ( !rw ) {
+ // This is to fix messages for dead windows...
+ return 0;
+ }
+ }
+
+ switch ( e->type ) {
+ case ButtonPress:
+ switch( e->xbutton.button ) {
+ case 1:
+ m->message = WM_LBUTTONDOWN;
+ m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
+ break;
+
+ case 2:
+
+ case 3:
+ m->message = WM_RBUTTONDOWN;
+ m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
+ break;
+
+ case 4:
+ m->message = WM_MOUSEWHEEL;
+ m->wParam = 120 << 16 | 0; // 1 tick, no modifiers
+ m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
+ break;
+
+ case 5:
+ m->message = WM_MOUSEWHEEL;
+ m->wParam = (-120) << 16 | 0; // 1 tick, no modifiers
+ m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
+ break;
+ }
+ break;
+ case ButtonRelease:
+ switch( e->xbutton.button ) {
+ case 1:
+ m->message = WM_LBUTTONUP;
+ m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
+ break;
+
+ case 2:
+
+ case 3:
+ m->message = WM_RBUTTONUP;
+ m->lParam = (e->xbutton.x & 0xffff) | (e->xbutton.y << 16);
+ break;
+ }
+ break;
+ case MotionNotify:
+ {
+ m->message = WM_MOUSEMOVE;
+ do {
+ // Spin...
+ } while( XCheckTypedWindowEvent( Linux::getDisplay(), m->hwnd, MotionNotify, e ) );
+
+ RECT r;
+ POINT offset = {0, 0};
+ HWND hwnd = m->hwnd;
+
+ GetWindowRect( hwnd, &r );
+
+ m->lParam = ((e->xmotion.x_root - r.left) & 0xffff) |
+ ((e->xmotion.y_root - r.top) << 16);
+
+ if ( ! (e->xmotion.state & ( Button1Mask | Button2Mask | Button3Mask )) )
+ PostMessage( m->hwnd, WM_SETCURSOR, m->hwnd, 0 );
+ }
+ break;
+
+ case KeyPress:
+ m->message = WM_KEYDOWN;
+ m->wParam = e->xkey.keycode;
+ break;
+
+ case KeyRelease:
+ m->message = WM_KEYUP;
+ m->wParam = e->xkey.keycode;
+ break;
+
+ case Expose:
+ {
+ RECT r;
+ m->message = WM_PAINT;
+ do {
+ r.left = e->xexpose.x;
+ r.top = e->xexpose.y;
+ r.right = r.left + e->xexpose.width;
+ r.bottom = r.top + e->xexpose.height;
+ InvalidateRect( m->hwnd, &r, FALSE );
+ } while( XCheckTypedWindowEvent( Linux::getDisplay(), m->hwnd, Expose, e ) );
+ }
+ break;
+
+ case ClientMessage: {
+ static int coord = -1;
+ static Atom supported = None;
+ XClientMessageEvent cme;
+
+ LoadAtoms();
+
+ int message = e->xclient.message_type;
+ if ( message == dnd_enter ) {
+ if ( e->xclient.data.l[1] & 1 ) {
+ Atom actual;
+ int format;
+ long unsigned int nitems, bytes;
+ unsigned char *data = NULL;
+
+ XGetWindowProperty( Linux::getDisplay(), e->xclient.data.l[0],
+ dnd_typelist, 0, 65536, True, XA_ATOM,
+ &actual, &format, &nitems, &bytes, &data );
+
+ Atom *atomdata = (Atom *)data;
+
+ supported = None;
+ for( int i = 0; i < nitems; i++ ) {
+ if ( atomdata[i] == dnd_urilist ) {
+ supported = dnd_urilist;
+ }
+ }
+ if ( supported == None ) {
+ for( int i = 0; i < nitems; i++ ) {
+ if ( atomdata[i] == dnd_textplain ) {
+ OutputDebugString( "text/plain found\n" );
+ supported = dnd_textplain;
+ }
+ }
+ }
+ if ( supported == None ) {
+ for( int i = 0; i < nitems; i++ ) {
+ if ( atomdata[i] == dnd_mozurl ) {
+ supported = dnd_mozurl;
+ }
+ }
+ }
+
+ XFree( data );
+ } else {
+ if ( e->xclient.data.l[2] == dnd_urilist ||
+ e->xclient.data.l[3] == dnd_urilist ||
+ e->xclient.data.l[4] == dnd_urilist ) {
+ supported = dnd_urilist;
+ } else if ( e->xclient.data.l[2] == dnd_mozurl ||
+ e->xclient.data.l[3] == dnd_mozurl ||
+ e->xclient.data.l[4] == dnd_mozurl ) {
+ supported = dnd_mozurl;
+ }
+ }
+
+
+ // DnD Enter
+ return 0;
+
+ } else if ( message == dnd_position ) {
+ // DnD Position Notify
+
+ cme.type = ClientMessage;
+ cme.message_type = dnd_status;
+ cme.format = 32;
+ cme.window = e->xclient.data.l[0];
+ cme.data.l[0] = e->xclient.window;
+ cme.data.l[1] = 1; // Can Accept
+ cme.data.l[2] = cme.data.l[3] = 0; // Empty rectangle - give us moves
+ cme.data.l[4] = dnd_private; // We're doing our own thing
+
+ if ( coord == -1 && supported != None ) {
+ XConvertSelection( Linux::getDisplay(), dnd_selection, supported,
+ dnd_wa3drop, cme.window, CurrentTime );
+ }
+
+ coord = e->xclient.data.l[2];
+
+ XSendEvent( Linux::getDisplay(), e->xclient.data.l[0], False,
+ NoEventMask, (XEvent *)&cme );
+
+ return 0;
+
+ } else if ( message == dnd_leave ) {
+ // DnD Leave
+ coord = -1;
+ supported = None;
+
+ return 0;
+
+ } else if ( message == dnd_drop ) {
+ // DnD Drop
+
+ Window win = e->xclient.data.l[0];
+
+ cme.type = ClientMessage;
+ cme.message_type = dnd_finished;
+ cme.format = 32;
+ cme.window = e->xclient.data.l[0];
+ cme.data.l[0] = e->xclient.window;
+ cme.data.l[1] = cme.data.l[2] = cme.data.l[3] = cme.data.l[4] = 0;
+
+ XSendEvent( Linux::getDisplay(), e->xclient.data.l[0], False,
+ NoEventMask, (XEvent *)&cme );
+
+ if ( supported != None ) {
+ Atom actual;
+ int format;
+ long unsigned int nitems, bytes;
+ unsigned char *data = NULL;
+
+ XGetWindowProperty( Linux::getDisplay(), cme.window, dnd_wa3drop,
+ 0, 65536, True, supported, &actual,
+ &format, &nitems, &bytes,
+ &data );
+
+ OutputDebugString( StringPrintf( "Drop data (%d):\n%s\n", nitems, data ) );
+
+ m->message = WM_DROPFILES;
+ m->wParam = coord;
+ m->lParam = (LPARAM)data;
+
+ coord = -1;
+ supported = None;
+
+ } else {
+ coord = -1;
+ supported = None;
+ return 0;
+ }
+
+ break;
+
+ } else if ( message == winamp_msg ) {
+ // Internal Message ...
+
+ m->message = e->xclient.data.l[0];
+ m->wParam = e->xclient.data.l[1];
+ m->lParam = e->xclient.data.l[2];
+ break;
+
+ } else {
+ return 0;
+ }
+ break;
+ }
+
+ case LeaveNotify:
+ case EnterNotify:
+ m->message = WM_MOUSEMOVE;
+ m->lParam = (e->xcrossing.x & 0xffff) | (e->xcrossing.y << 16);
+
+ if ( ! (e->xcrossing.state & ( Button1Mask | Button2Mask | Button3Mask )) )
+ PostMessage( m->hwnd, WM_SETCURSOR, m->hwnd, 0 );
+ break;
+
+ case FocusIn:
+ m->message = WM_SETFOCUS;
+ break;
+
+ case FocusOut:
+ m->message = WM_KILLFOCUS;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static HWND activeWindow;
+
+HWND GetActiveWindow() {
+ return activeWindow;
+}
+
+int IntersectRect( RECT *out, const RECT *i1, const RECT *i2 ) {
+ return Std::rectIntersect(i1, i2, out);
+}
+
+void TranslateMessage( MSG *m ) {
+ if ( m->message != WM_CHAR && m->message != WM_KEYDOWN &&
+ m->message != WM_KEYUP )
+ return;
+
+ int index = !!( Std::keyDown( VK_SHIFT ));
+
+ m->wParam = XKeycodeToKeysym( Linux::getDisplay(), m->wParam, index );
+}
+
+void PostMessage( HWND win, UINT msg, WPARAM wParam, LPARAM lParam ) {
+ XEvent e;
+
+ LoadAtoms();
+
+ e.type = ClientMessage;
+ e.xclient.window = win;
+ e.xclient.message_type = winamp_msg;
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = msg;
+ e.xclient.data.l[1] = wParam;
+ e.xclient.data.l[2] = lParam;
+
+ XSendEvent( Linux::getDisplay(), win, FALSE, NoEventMask, &e );
+}
+
+void PostQuitMessage( int i ) {
+ PostMessage( None, WM_QUIT, i, 0 );
+}
+
+#endif // wnd
+
+#if defined(WASABI_API_TIMER) | defined(WASABI_API_WND)
+
+struct TimerElem {
+ HWND win;
+ int id;
+ int nexttime;
+ int delta;
+ TIMERPROC tproc;
+
+ TimerElem( HWND _win, int _id, int ms, TIMERPROC _tproc ) {
+ win = _win;
+ id = _id;
+ delta = ms;
+ tproc = _tproc;
+ nexttime = Std::getTickCount() + delta;
+ }
+};
+
+int timer_id = 0;
+CriticalSection timer_cs;
+PtrList<TimerElem> timer_elems;
+
+int SetTimer( HWND win, int id, int ms, TIMERPROC tproc ) {
+ KillTimer(win, id);
+
+ if ( win == (HWND)0 ) {
+ id = timer_id++;
+ }
+
+ TimerElem *te = new TimerElem( win, id, ms, tproc );
+ timer_cs.enter();
+ timer_elems.addItem( te, PTRLIST_POS_LAST );
+ timer_cs.leave();
+
+ return id;
+}
+
+void KillTimer( HWND win, int id ) {
+ timer_cs.enter();
+ for( int i = 0; i < timer_elems.getNumItems(); i++ )
+ if ( timer_elems[i]->win == win && timer_elems[i]->id == id ) {
+ delete timer_elems[i];
+ timer_elems.delByPos( i );
+ i--;
+ }
+ timer_cs.leave();
+}
+
+CriticalSection send_cs;
+MSG *send_msg;
+int sending = 0;
+int send_ret;
+pthread_t message_thread = (pthread_t)-1;
+
+int _GetMessage( MSG *m, HWND, UINT, UINT, int block=1) {
+ MEMSET( m, 0, sizeof( MSG ) );
+
+ message_thread = pthread_self();
+
+#ifdef WASABI_COMPILE_WND
+ XEvent e;
+#endif // wnd
+ int curtime;
+ int done = 0;
+ int first = 1;
+ static wa_msgbuf ipcm;
+ static int qid = -1;
+ int size;
+
+ if ( qid == -1 ) { qid = WASABI_API_LINUX->linux_getIPCId(); }
+
+ if ( sending ) {
+ *m = *send_msg;
+ done = 1;
+ }
+
+ while( !done && (block || first)) {
+ if ( qid != -1 ) {
+ if ( (size = msgrcv( qid, &ipcm, IPC_MSGMAX , 0, IPC_NOWAIT )) != -1 ) {
+ m->hwnd = None;
+ m->message = WM_WA_IPC;
+ m->wParam = (WPARAM)&ipcm;
+ break;
+ }
+ }
+
+ curtime = GetTickCount();
+
+ timer_cs.enter();
+ for( int i = 0; i < timer_elems.getNumItems(); i++ ) {
+ if ( timer_elems[i]->nexttime < curtime ) {
+ if (block)
+ while( timer_elems[i]->nexttime < curtime )
+ timer_elems[i]->nexttime += timer_elems[i]->delta;
+
+ m->hwnd = timer_elems[i]->win;
+ m->message = WM_TIMER;
+ m->wParam = (WPARAM)timer_elems[i]->id;
+ m->lParam = (LPARAM)timer_elems[i]->tproc;
+
+ done = 1;
+ }
+ }
+ timer_cs.leave();
+
+ if ( !done && ! first )
+ Sleep( 1 );
+ else
+ first = 0;
+
+#ifdef WASABI_API_WND
+ if ( !done && XPending( Linux::getDisplay() ) ) {
+ int n = XEventsQueued( Linux::getDisplay(), QueuedAlready );
+
+ for ( int i = 0; !done && i < n; i++ ) {
+ XNextEvent( Linux::getDisplay(), &e );
+ if ( Linux::convertEvent( m, &e ) )
+ done = 1;
+ }
+ if ( done )
+ break;
+ }
+#endif // wnd
+ }
+
+#ifdef WASABI_API_WND
+ activeWindow = m->hwnd;
+#endif // wnd
+
+ return m->message != WM_QUIT;
+}
+
+int GetMessage( MSG *m, HWND w, UINT f, UINT l) {
+ return _GetMessage(m, w, f, l, 1);
+}
+
+// on linux, we don't really simply peek when PM_NOREMOVE is used,
+// we just don't block, which is the only thing we want to accomplish here
+int PeekMessage( MSG *m, HWND w, UINT f, UINT l, UINT remove) {
+ if (remove == PM_NOREMOVE) return _GetMessage(m, w, f, l, 0);
+ else _GetMessage(m, w, f, l, 1);
+}
+
+
+int DispatchMessage( MSG *m ) {
+ if ( m->message == WM_TIMER && m->hwnd == None ) {
+ TIMERPROC tproc = (TIMERPROC)m->lParam;
+ tproc( m->hwnd, m->message, m->wParam, 0 );
+ return 1;
+ }
+
+ int ret = 0;
+
+#ifdef WASABI_COMPILE_WND
+ api_window *rootwnd = (api_window *)GetWindowLong( m->hwnd, GWL_USERDATA );
+
+ if ( rootwnd ) {
+ ret = rootwnd->wndProc( m->hwnd, m->message, m->wParam, m->lParam );
+ rootwnd->performBatchProcesses();
+ }
+#endif // wnd
+
+ if ( sending ) {
+ send_ret = ret;
+ sending = 0;
+ }
+
+ return ret;
+}
+
+int SendMessage( HWND win, UINT msg, WPARAM wParam, LPARAM lParam ) {
+ MSG m;
+ m.hwnd = win;
+ m.message = msg;
+ m.wParam = wParam;
+ m.lParam = lParam;
+
+ int ret;
+
+ if ( pthread_equal( message_thread, pthread_self() ) ) {
+ return DispatchMessage( &m );
+
+ } else {
+ send_cs.enter();
+ sending = 1;
+ send_msg = &m;
+ while( sending ) { Sleep( 1 ); }
+ ret = send_ret;
+ send_cs.leave();
+
+ return ret;
+ }
+}
+
+#endif // timer | wnd
+
+int MulDiv( int m1, int m2, int d ) {
+ __asm__ volatile (
+ "mov %0, %%eax\n"
+ "mov %1, %%ebx\n"
+ "mov %2, %%ecx\n"
+ "mul %%ebx\n"
+ "div %%ecx\n"
+ : : "m" (m1), "m" (m2), "m" (d)
+ : "%eax", "%ebx", "%ecx", "%edx" );
+}
+
+void ExitProcess( int ret ) {
+ exit( ret );
+}
+
+#ifdef WASABI_COMPILE_WND
+
+void Linux::initContextData( HWND h ) {
+ int *data;
+ XPointer xp;
+
+ ASSERT( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ));
+
+ data = (int *)MALLOC( GWL_ENUM_SIZE * sizeof( int ) );
+
+ data[GWL_HWND] = h;
+
+ XSaveContext( Linux::getDisplay(), h, Linux::getContext(), (char *)data );
+}
+
+void Linux::nukeContextData( HWND h ) {
+ int *data;
+ XPointer xp;
+
+ if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
+ return;
+
+ data = (int *)xp;
+
+ ASSERT( data[GWL_HWND] == h );
+
+ if ( data[GWL_INVALIDREGION] ) {
+ XDestroyRegion( (HRGN)data[GWL_INVALIDREGION] );
+ }
+
+ XDeleteContext( Linux::getDisplay(), h, Linux::getContext() );
+
+ FREE( data );
+}
+
+void SetWindowLong( HWND h, contextdata type, LONG value ) {
+ XPointer data;
+
+ if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &data ) )
+ return;
+
+ ASSERT( ((int *)data)[GWL_HWND] == h );
+
+ ((int*)data)[type] = value;
+}
+
+LONG GetWindowLong( HWND h, contextdata type ) {
+ XPointer data;
+
+ if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &data ) )
+ return 0;
+
+ ASSERT( ((int *)data)[GWL_HWND] == h );
+
+ return ((int*)data)[type];
+}
+
+void MoveWindowRect( HWND h, int x, int y ) {
+ XPointer xp;
+ int *data;
+
+ if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
+ return;
+
+ data = (int *)xp;
+
+ ASSERT( data[GWL_HWND] == h );
+
+ data[GWL_RECT_RIGHT] -= data[GWL_RECT_LEFT] - x;
+ data[GWL_RECT_BOTTOM] -= data[GWL_RECT_TOP] - y;
+ data[GWL_RECT_LEFT] = x;
+ data[GWL_RECT_TOP] = y;
+}
+
+void SetWindowRect( HWND h, RECT *r ) {
+ int *data;
+ XPointer xp;
+
+ if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
+ return;
+
+ data = (int *)xp;
+
+ ASSERT( data[GWL_HWND] == h );
+
+ data[GWL_RECT_LEFT] = r->left;
+ data[GWL_RECT_TOP] = r->top;
+ data[GWL_RECT_RIGHT] = r->right;
+ data[GWL_RECT_BOTTOM] = r->bottom;
+}
+
+int GetWindowRect( HWND h, RECT *r ) {
+ int *data;
+ XPointer xp;
+
+ if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
+ return 0;
+
+ data = (int *)xp;
+
+ ASSERT( data[GWL_HWND] == h );
+
+ r->left = data[GWL_RECT_LEFT];
+ r->top = data[GWL_RECT_TOP];
+ r->right = data[GWL_RECT_RIGHT];
+ r->bottom = data[GWL_RECT_BOTTOM];
+
+ POINT offset = { 0, 0};
+ while( (h = data[GWL_PARENT]) != Linux::RootWin() ) {
+ if ( XFindContext( Linux::getDisplay(), h, Linux::getContext(), &xp ) )
+ return 0;
+
+ data = (int *)xp;
+
+ ASSERT( data[GWL_HWND] == h );
+
+ offset.x += data[GWL_RECT_LEFT];
+ offset.y += data[GWL_RECT_TOP];
+ }
+ r->left += offset.x;
+ r->top += offset.y;
+ r->right += offset.x;
+ r->bottom += offset.y;
+
+ return 1;
+}
+
+int GetUpdateRect( HWND h, RECT *ret, BOOL ) {
+ HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
+ if ( ! invalid || XEmptyRegion( invalid ) )
+ return 0;
+
+ XRectangle xr;
+ XClipBox( invalid, &xr );
+ ret->left = xr.x;
+ ret->top = xr.y;
+ ret->right = xr.x + xr.width;
+ ret->bottom = xr.y + xr.height;
+
+ return 1;
+}
+
+void GetUpdateRgn( HWND h, HRGN r, BOOL ) {
+ XSubtractRegion( r, r, r );
+
+ HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
+ if ( ! invalid ) return;
+
+
+ XUnionRegion( r, invalid, r );
+
+ XRectangle xr;
+
+ RECT rct;
+ GetWindowRect( h, &rct );
+ xr.x = 0;
+ xr.y = 0;
+ xr.width = rct.right - rct.left;
+ xr.height = rct.bottom - rct.top;
+
+ HRGN tmp = XCreateRegion();
+
+ XUnionRectWithRegion( &xr, tmp, tmp );
+ XIntersectRegion( r, tmp, r );
+ XDestroyRegion( tmp );
+}
+
+void InvalidateRect( HWND h, const RECT *r, BOOL ) {
+ HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
+ if ( ! invalid ) {
+ invalid = XCreateRegion();
+ SetWindowLong( h, GWL_INVALIDREGION, (LONG)invalid );
+ }
+
+ XRectangle xr;
+ if ( r == NULL ) {
+ RECT rct;
+ GetWindowRect( h, &rct );
+ xr.x = 0;
+ xr.y = 0;
+ xr.width = rct.right - rct.left;
+ xr.height = rct.bottom - rct.top;
+ } else {
+ xr.x = r->left;
+ xr.y = r->top;
+ xr.width = r->right - r->left;
+ xr.height = r->bottom - r->top;
+ }
+
+ XUnionRectWithRegion( &xr, invalid, invalid );
+
+ PostMessage( h, WM_PAINT, 0, 0 );
+}
+
+void InvalidateRgn( HWND h, HRGN r, BOOL ) {
+ HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
+
+ if ( ! invalid ) {
+ invalid = XCreateRegion();
+ SetWindowLong( h, GWL_INVALIDREGION, (LONG)invalid );
+ }
+
+ ASSERT( r != invalid );
+ XUnionRegion( invalid, r, invalid );
+
+ PostMessage( h, WM_PAINT, 0, 0 );
+}
+
+void ValidateRect( HWND h, const RECT *r ) {
+ HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
+ if ( ! invalid ) return;
+
+ XRectangle xr;
+ if ( r == NULL ) {
+ XDestroyRegion( invalid );
+ SetWindowLong( h, GWL_INVALIDREGION, 0 );
+ return;
+ }
+
+ xr.x = r->left;
+ xr.y = r->top;
+ xr.width = r->right - r->left;
+ xr.height = r->bottom - r->top;
+
+ HRGN tmp = XCreateRegion();
+ XUnionRectWithRegion( &xr, tmp, tmp );
+ XSubtractRegion( invalid, tmp, invalid );
+ XDestroyRegion( tmp );
+}
+
+void ValidateRgn( HWND h, HRGN r ) {
+ HRGN invalid = (HRGN)GetWindowLong( h, GWL_INVALIDREGION );
+ if ( ! invalid ) return;
+
+ ASSERT( r != invalid );
+ XSubtractRegion( invalid, r, invalid );
+}
+#endif // wnd
+
+int SubtractRect( RECT *out, RECT *in1, RECT *in2 ) {
+ int ret;
+ if ( in1->left >= in2->left && in1->right <= in2->right ) {
+ out->left = in1->left; out->right = in1->right;
+
+ if ( in1->top >= in2->top && in2->bottom >= in2->top && in2->bottom <= in2->bottom ) {
+ out->top = in1->bottom; out->bottom = in2->bottom;
+
+ ret = 1;
+ } else if ( in1->top <= in2->top && in1->bottom >= in2->top && in1->bottom <= in2->bottom ) {
+ out->top = in1->top; out->bottom = in2->top;
+
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+
+ } else if ( in1->top >= in2->top && in1->bottom <= in2->bottom ) {
+ out->top = in1->top; out->bottom = in1->bottom;
+
+ if ( in1->left >= in2->left && in2->right >= in2->left && in2->right <= in2->right ) {
+ out->left = in1->right; out->right = in2->right;
+
+ ret = 1;
+ } else if ( in1->left <= in2->left && in1->right >= in2->left && in1->right <= in2->right ) {
+ out->left = in1->left; out->right = in2->left;
+
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+
+
+ } else {
+ ret = 0;
+ }
+ return ret;
+}
+
+int EqualRect( RECT *a, RECT *b ) {
+ return ( a->top == b->top && a->bottom == b->bottom &&
+ a->left == b->left && a->right == b->right );
+}
+
+#ifdef WASABI_COMPILE_WND
+
+HWND WindowFromPoint( POINT p ) {
+ int x, y;
+ Window child;
+
+ XTranslateCoordinates( Linux::getDisplay(), Linux::RootWin(), Linux::RootWin(), p.x, p.y, &x, &y, &child );
+ return child;
+}
+#endif // wnd
+
+void CopyFile( const char *f1, const char *f2, BOOL b ) {
+ COPYFILE( f1, f2 );
+}
+
+DWORD GetModuleFileName(void *pid, const char *filename, int bufsize) {
+ char procbuffer[512];
+ sprintf(procbuffer, "/proc/%d/exe", (int)pid);
+ return readlink(procbuffer, (char *)filename, bufsize);
+}
+
+const char *CharPrev(const char *lpszStart, const char *lpszCurrent) {
+ if (lpszCurrent-1 >= lpszStart) return lpszCurrent-1;
+ return lpszStart;
+}
+
+#endif
diff --git a/Src/Wasabi/bfc/platform/minmax.h b/Src/Wasabi/bfc/platform/minmax.h
new file mode 100644
index 00000000..ccc37e96
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/minmax.h
@@ -0,0 +1,19 @@
+#ifndef NULLSOFT_BFC_PLATFORM_MINMAX_H
+#define NULLSOFT_BFC_PLATFORM_MINMAX_H
+
+#if defined(_WIN32) && !defined(MIN)
+#define MIN( a, b ) ((a>b)?b:a)
+#define MAX( a, b ) ((a>b)?a:b)
+#endif
+
+#if defined(__APPLE__) && !defined(MIN)
+#define MIN( a, b ) ((a>b)?b:a)
+#define MAX( a, b ) ((a>b)?a:b)
+#endif
+
+#if defined(__linux__) && !defined(MIN)
+#define MIN( a, b ) ((a>b)?b:a)
+#define MAX( a, b ) ((a>b)?a:b)
+#endif
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/bfc/platform/platform.cpp b/Src/Wasabi/bfc/platform/platform.cpp
new file mode 100644
index 00000000..bd9ece7b
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/platform.cpp
@@ -0,0 +1,6 @@
+#include "precomp_wasabi_bfc.h"
+#include "platform.h"
+
+void link_platform() {
+ OutputDebugString(L"dummy");
+} \ No newline at end of file
diff --git a/Src/Wasabi/bfc/platform/platform.h b/Src/Wasabi/bfc/platform/platform.h
new file mode 100644
index 00000000..6a14967a
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/platform.h
@@ -0,0 +1,498 @@
+#pragma once
+
+#include <bfc/platform/types.h>
+#include <bfc/std_mkncc.h> // for MKnCC
+
+#ifdef WIN32
+# include <bfc/platform/win32.h>
+
+#define OSMODULEHANDLE HINSTANCE
+#define INVALIDOSMODULEHANDLE ((OSMODULEHANDLE)0)
+#define OSWINDOWHANDLE HWND
+#define INVALIDOSWINDOWHANDLE ((OSWINDOWHANDLE)0)
+#define OSICONHANDLE HICON
+#define INVALIDOSICONHANDLE ((OSICONHANDLE)0)
+#define OSCURSORHANDLE HICON
+#define INVALIDOSCURSORHANDLE ((OSCURSORHANDLE)0)
+#define OSTHREADHANDLE HANDLE
+#define INVALIDOSTHREADHANDLE ((OSTHREADHANDLE)0)
+#define OSREGIONHANDLE HRGN
+#define INVALIDOSREGIONHANDLE ((OSREGIONHANDLE)0)
+typedef HMENU OSMENUHANDLE;
+
+#define RGBA(r,g,b,a) ((ARGB32)((uint8_t)(r) | ((uint8_t)(g) << 8) | ((uint8_t)(b) << 16) | ((uint8_t)(a) << 24)))
+
+#ifndef PATH_MAX
+#define PATH_MAX MAX_PATH
+#endif
+
+#elif defined(LINUX)
+# include <bfc/platform/linux.h>
+#elif defined(__APPLE__)
+#include <Carbon/Carbon.h>
+
+typedef HIShapeRef OSREGIONHANDLE;
+typedef int OSCURSOR; // TODO: find a good one for this
+typedef int OSCURSORHANDLE; // TODO: find a good one for this
+typedef HIWindowRef OSWINDOWHANDLE;
+typedef void *OSMODULEHANDLE; // TODO:
+typedef CGContextRef HDC; // TODO: find a better name
+typedef MenuRef OSMENUHANDLE;
+typedef CGImageRef OSICONHANDLE;
+
+#ifdef __LITTLE_ENDIAN__
+#define RGBA(r,g,b,a) ((ARGB32)((uint8_t)(r) | ((uint8_t)(g) << 8) | ((uint8_t)(b) << 16) | ((uint8_t)(a) << 24)))
+#elif defined(__BIG_ENDIAN__)
+#define RGBA(r,g,b,a) ((ARGB32)((uint8_t)(a) | ((uint8_t)(r) << 8) | ((uint8_t)(g) << 16) | ((uint8_t)(b) << 24)))
+#else
+#error endian preprocessor symbol not defined
+#endif
+
+#define RGB(r,g,b) RGBA(r,g,b,0xFF)
+
+static const HIWindowRef INVALIDOSWINDOWHANDLE = 0; // TODO: maybe there's an apple-defined name for this
+#define INVALIDOSMODULEHANDLE 0
+#define INVALIDOSCURSORHANDLE 0
+
+typedef char OSFNCHAR;
+typedef char *OSFNSTR;
+
+typedef const char OSFNCCHAR;
+typedef const char *OSFNCSTR;
+
+#define FNT(x) x
+
+typedef struct tagRECT
+{
+ int left;
+ int top;
+ int right;
+ int bottom;
+}
+RECT;
+typedef RECT * LPRECT;
+
+inline RECT RECTFromHIRect(const HIRect *r)
+{
+ RECT rect;
+ rect.left = r->origin.x;
+ rect.right = r->origin.x + r->size.width;
+ rect.top = r->origin.y;
+ rect.bottom = r->origin.y + r->size.height;
+ return rect;
+}
+
+inline HIRect HIRectFromRECT(const RECT *r)
+{
+ HIRect rect;
+ rect.origin.x = r->left;
+ rect.origin.y = r->top;
+ rect.size.width = r->right - r->left;
+ rect.size.height = r->bottom - r->top;
+ return rect;
+}
+
+typedef struct tagPOINT
+{
+ int x;
+ int y;
+}
+POINT;
+typedef struct tagPOINT * LPPOINT;
+
+inline HIPoint HIPointFromPOINT(const POINT *pt)
+{
+ HIPoint p;
+ p.x = pt->x;
+ p.y = pt->y;
+ return p;
+}
+
+inline int MulDiv(int a, int b, int c)
+{
+ int s;
+ int v;
+
+ s = 0;
+ if (a < 0)
+ {
+ s = !s;
+ a = -a;
+ }
+ if (b < 0)
+ {
+ s = !s;
+ b = -b;
+ }
+ if (c < 0)
+ {
+ s = !s;
+ c = -c;
+ }
+ double d;
+ d = ((double)a * (double)b) / (double)c;
+ if (d >= 4294967296.)
+ return -1;
+ v = d;
+ if (s)
+ v = -v;
+ return v;
+}
+
+#else
+#error port me
+// Windows API dependant definitions for non-windows platforms
+
+#define __cdecl
+#define __stdcall
+#define WINAPI
+#define WINBASEAPI
+#define WINUSERAPI
+#define WINGDIAPI
+#define WINOLEAPI
+#define CALLBACK
+#define FARPROC void *
+
+#define FALSE 0
+#define TRUE 1
+
+#define ERROR 0
+
+#define CONST const
+#define VOID void
+
+typedef unsigned long DWORD;
+typedef unsigned short WORD;
+typedef unsigned char BYTE;
+typedef long LONG;
+typedef int INT;
+typedef int BOOL;
+typedef short SHORT;
+typedef void * PVOID;
+typedef void * LPVOID;
+
+typedef char CHAR;
+typedef unsigned short WCHAR;
+typedef char * LPSTR;
+typedef WCHAR * LPWSTR;
+typedef const char * LPCSTR;
+typedef const WCHAR * LPCWSTR;
+typedef LPWSTR PTSTR, LPTSTR;
+typedef LPCWSTR LPCTSTR;
+typedef char TCHAR;
+typedef WCHAR OLECHAR;
+
+typedef void * HANDLE;
+typedef void * HWND;
+typedef void * HDC;
+typedef void * HFONT;
+typedef void * HBITMAP;
+typedef void * HINSTANCE;
+typedef void * HICON;
+typedef void * HRGN;
+typedef void * HPEN;
+typedef void * HBRUSH;
+typedef void * HRSRC;
+typedef void * HGLOBAL;
+typedef void * HACCEL;
+typedef void * HMODULE;
+typedef void * HMENU;
+typedef void * HGDIOBJ;
+
+typedef void * ATOM;
+typedef void * CRITICAL_SECTION;
+typedef void * LPCRITICAL_SECTION;
+
+typedef UINT WPARAM;
+typedef UINT LPARAM;
+typedef LONG LRESULT;
+typedef UINT COLORREF;
+
+typedef LRESULT(*WNDPROC)(HWND, UINT, WPARAM, LPARAM);
+typedef BOOL CALLBACK WNDENUMPROC(HWND, LPARAM);
+typedef VOID CALLBACK *TIMERPROC(HWND, UINT, UINT, DWORD);
+
+typedef struct tagPOINT
+{
+ LONG x;
+ LONG y;
+}
+POINT;
+typedef struct tagPOINT * LPPOINT;
+
+typedef struct tagSIZE
+{
+ LONG cx;
+ LONG cy;
+}
+SIZE;
+
+
+typedef struct tagRECT
+{
+ LONG left;
+ LONG top;
+ LONG right;
+ LONG bottom;
+}
+RECT;
+typedef RECT * LPRECT;
+
+typedef struct _COORD
+{
+ SHORT X;
+ SHORT Y;
+}
+COORD, *PCOORD;
+
+typedef struct tagPAINTSTRUCT
+{
+ HDC hdc;
+ BOOL fErase;
+ RECT rcPaint;
+ BOOL fRestore;
+ BOOL fIncUpdate;
+ BYTE rgbReserved[32];
+}
+PAINTSTRUCT;
+
+typedef struct tagBITMAP
+{ /* bm */
+ int bmType;
+ int bmWidth;
+ int bmHeight;
+ int bmWidthBytes;
+ BYTE bmPlanes;
+ BYTE bmBitsPixel;
+ LPVOID bmBits;
+}
+BITMAP;
+
+typedef struct tagRGBQUAD
+{
+ BYTE rgbRed;
+ BYTE rgbGreen;
+ BYTE rgbBlue;
+ BYTE rgbReserved;
+}
+RGBQUAD;
+
+typedef struct tagBITMAPINFOHEADER
+{
+ DWORD biSize;
+ LONG biWidth;
+ LONG biHeight;
+ WORD biPlanes;
+ WORD biBitCount;
+ DWORD biCompression;
+ DWORD biSizeImage;
+ LONG biXPelsPerMeter;
+ LONG biYPelsPerMeter;
+ DWORD biClrUsed;
+ DWORD biClrImportant;
+}
+BITMAPINFOHEADER;
+
+typedef struct tagBITMAPINFO
+{
+ BITMAPINFOHEADER bmiHeader;
+ RGBQUAD bmiColors[1];
+}
+BITMAPINFO, *LPBITMAPINFO;
+
+typedef struct tagMSG
+{
+ HWND hwnd;
+ UINT message;
+ WPARAM wParam;
+ LPARAM lParam;
+ DWORD time;
+ POINT pt;
+}
+MSG;
+
+typedef MSG * LPMSG;
+
+typedef struct _RGNDATAHEADER
+{
+ DWORD dwSize;
+ DWORD iType;
+ DWORD nCount;
+ DWORD nRgnSize;
+ RECT rcBound;
+}
+RGNDATAHEADER, *PRGNDATAHEADER;
+
+typedef struct _RGNDATA
+{
+ RGNDATAHEADER rdh;
+ char Buffer[1];
+}
+RGNDATA, *PRGNDATA;
+
+// Windows messages
+
+#define WM_SYSCOMMAND 0x112
+#define WM_LBUTTONDOWN 0x201
+#define WM_LBUTTONUP 0x202
+#define WM_RBUTTONDOWN 0x204
+#define WM_RBUTTONUP 0x205
+
+#define WM_USER 0x400
+
+#define WS_EX_TOOLWINDOW 0x00000080L
+
+#define WS_OVERLAPPED 0x00000000L
+#define WS_MAXIMIZEBOX 0x00010000L
+#define WS_MINIMIZEBOX 0x00020000L
+#define WS_SYSMENU 0x00080000L
+#define WS_CAPTION 0x00C00000L
+#define WS_CLIPCHILDREN 0x02000000L
+#define WS_CLIPSIBLINGS 0x04000000L
+#define WS_VISIBLE 0x10000000L
+#define WS_CHILD 0x40000000L
+#define WS_POPUP 0x80000000L
+
+#define HWND_TOP ((HWND)0)
+#define HWND_TOPMOST ((HWND)-1)
+#define HWND_NOTOPMOST ((HWND)-2)
+
+#define GWL_STYLE (-16)
+
+#define GW_HWNDFIRST 0
+#define GW_HWNDNEXT 2
+
+#define SWP_NOMOVE 0x0002
+#define SWP_NOSIZE 0x0001
+#define SWP_SHOWWINDOW 0x0040
+#define SWP_DEFERERASE 0x2000
+#define SWP_NOZORDER 0x0004
+#define SWP_NOACTIVATE 0x0010
+
+#define SW_SHOW 5
+
+#define SC_MINIMIZE 0xF020
+#define SC_MAXIMIZE 0xF030
+#define SC_RESTORE 0xF120
+
+#define GCL_HICONSM (-34)
+#define GCL_HICON (-14)
+
+#define MB_OK 0
+#define MB_OKCANCEL 1
+#define MB_TASKMODAL 0x2000L
+
+#define IDOK 1
+#define IDCANCEL 2
+
+#define VK_SHIFT 0x10
+#define VK_CONTROL 0x11
+#define VK_MENU 0x12
+
+#define RT_RCDATA 10
+
+#define IMAGE_BITMAP 0
+
+#define LR_LOADFROMFILE 0x0010
+
+#define DIB_RGB_COLORS 0
+
+#define MAX_PATH 1024
+#define _MAX_PATH MAX_PATH
+#define _MAX_DRIVE 3
+#define _MAX_DIR 256
+#define _MAX_FNAME 256
+#define _MAX_EXT 256
+
+#define GMEM_FIXED 0x0
+#define GMEM_ZEROINIT 0x40
+#define GPTR (GMEM_FIXED | GMEM_ZEROINIT)
+
+#define SPI_GETWORKAREA 48
+
+#define SM_CXDOUBLECLK 36
+#define SM_CYDOUBLECLK 37
+
+#define COLORONCOLOR 3
+
+#define SRCCOPY (DWORD)0x00CC0020
+
+#define BI_RGB 0L
+
+#define NULLREGION 1
+
+#define DT_LEFT 0x00000000
+#define DT_CENTER 0x00000001
+#define DT_RIGHT 0x00000002
+#define DT_VCENTER 0x00000004
+#define DT_WORDBREAK 0x00000010
+#define DT_SINGLELINE 0x00000020
+#define DT_CALCRECT 0x00000400
+#define DT_NOPREFIX 0x00000800
+#define DT_PATH_ELLIPSIS 0x00004000
+#define DT_END_ELLIPSIS 0x00008000
+#define DT_MODIFYSTRING 0x00010000
+
+#define FW_NORMAL 400
+#define FW_BOLD 700
+
+#define FF_DONTCARE (0<<4)
+
+#define BLACK_BRUSH 4
+#define NULL_BRUSH 5
+
+#define PS_SOLID 0
+#define PS_DOT 2
+
+#define TRANSPARENT 1
+#define OPAQUE 2
+
+#define ANSI_CHARSET 0
+#define ANSI_VAR_FONT 12
+
+#define OUT_DEFAULT_PRECIS 0
+#define CLIP_DEFAULT_PRECIS 0
+
+#define PROOF_QUALITY 2
+
+#define VARIABLE_PITCH 2
+
+#define RGN_AND 1
+#define RGN_OR 2
+#define RGN_DIFF 4
+#define RGN_COPY 5
+
+#define RDH_RECTANGLES 1
+
+#define MAXLONG 0x7fffffff
+
+// define GUID
+#include <bfc/platform/guid.h>
+
+#endif /* not WIN32 */
+
+#include <stdio.h>
+#include <stdlib.h>
+//#ifdef __cplusplus
+//#include <new>
+//#else
+//#include <new.h>
+//#endif
+#include <limits.h>
+
+
+#ifdef WIN32
+#define OSPIPE HANDLE
+#define OSPROCESSID int
+#endif
+
+// Ode macro keyworkds
+#define DISPATCH_ // makes a method dispatchable, automatically assigns a free ID (requires Interface)
+#define DISPATCH(x) // makes a method dispatchable and specifies its ID (not duplicate check, requires Interface)
+#define NODISPATCH // prevents a method from being dispatched if the class is marked for dispatching by default
+#define EVENT // marks a method as being an event to which other classes can connect to receive notification (used by Script and DependentItem helpers)
+#define SCRIPT // exposes a method to script interfaces (requires Script helper)
+#define IN // Input parameter
+#define OUT // Output parameter
+#define INOUT // Input/Output parameter
+
diff --git a/Src/Wasabi/bfc/platform/std_string_osx.cpp b/Src/Wasabi/bfc/platform/std_string_osx.cpp
new file mode 100644
index 00000000..ecfb16db
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/std_string_osx.cpp
@@ -0,0 +1,246 @@
+#include <bfc/std.h>
+
+// not perfect but it should work
+int WCSICMP(const wchar_t *str1, const wchar_t *str2)
+{
+ while (*str1 && *str2)
+ {
+ if (towlower(*str1) < towlower(*str2))
+ return -1;
+ if (towlower(*str2) < towlower(*str1))
+ return 1;
+ str1++;
+ str2++;
+ }
+
+ if (!*str1 && !*str2) return 0;
+ if (*str1) return 1;
+ if (*str2) return -1;
+
+ return -1; // shouldn't get here but we'll make the compiler shut up
+}
+
+int WCSNICMP(const wchar_t *str1, const wchar_t *str2, size_t len)
+{
+ while (*str1 && *str2 && len)
+ {
+ if (towlower(*str1) < towlower(*str2))
+ return -1;
+ if (towlower(*str2) < towlower(*str1))
+ return 1;
+ str1++;
+ str2++;
+ len--;
+ }
+
+ if (!len) return 0;
+ if (!*str1 && !*str2) return 0;
+ if (*str1) return 1;
+ if (*str2) return -1;
+
+ return -1; // shouldn't get here but we'll make the compiler shut up
+}
+
+
+/* these are super slow because of memory allocation, but will tide us over until apple adds wcscasecmp and family to their BSD API */
+
+#if 0 // remember this if we ever decide to use -fshort-wchar
+int WCSICMP(const wchar_t *str1, const wchar_t *str2)
+{
+ CFStringRef cfstr1 = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str1, wcslen(str1)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
+ CFStringRef cfstr2 = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str2, wcslen(str2)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
+ int result = CFStringCompare(cfstr1, cfstr2, kCFCompareCaseInsensitive);
+ CFRelease(cfstr1);
+ CFRelease(cfstr2);
+ return result;
+}
+
+int WCSNICMP(const wchar_t *str1, const wchar_t *str2, size_t len)
+{
+ CFStringRef cfstr1 = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str1, wcslen(str1)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
+ CFStringRef cfstr2 = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str2, wcslen(str2)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
+ int result = CFStringCompareWithOptions(cfstr1, cfstr2, CFRangeMake(0, len), kCFCompareCaseInsensitive);
+ CFRelease(cfstr1);
+ CFRelease(cfstr2);
+ return result;
+}
+#endif
+
+int WCSICOLL(const wchar_t *str1, const wchar_t *str2)
+{
+ CFStringRef cfstr1 = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str1, wcslen(str1)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
+ CFStringRef cfstr2 = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str2, wcslen(str2)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
+ int result = CFStringCompare(cfstr1, cfstr2, kCFCompareCaseInsensitive|kCFCompareNonliteral);
+ CFRelease(cfstr1);
+ CFRelease(cfstr2);
+ return result;
+}
+
+bool WCSIPREFIX(const wchar_t *str1, const wchar_t *prefix)
+{
+ CFStringRef cfstr1 = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)str1, wcslen(str1)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
+ CFStringRef cfstr2 = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)prefix, wcslen(prefix)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
+ bool result = CFStringHasPrefix(cfstr1, cfstr2);
+ CFRelease(cfstr1);
+ CFRelease(cfstr2);
+ return result;
+}
+
+wchar_t *DO_WCSDUP(const wchar_t *ptr EXTRA_INFO)
+{
+ if (ptr == NULL) return NULL;
+ int size = wcslen(ptr);
+ wchar_t *ret = (wchar_t *)MALLOC((size + 1) * sizeof(wchar_t));
+ if (ret != NULL)
+ {
+ WCSCPYN(ret, ptr, size+1);
+ }
+ return ret;
+}
+
+void WCSCPYN(wchar_t *dest, const wchar_t *src, int maxchar)
+{
+ ASSERT(dest != NULL);
+ ASSERT(src != NULL);
+ wcsncpy(dest, src, maxchar-1); // TODO: switch to a less brain dead function
+ dest[maxchar-1]=0;
+}
+
+void STRTOUPPER(char *str)
+{
+if (str)
+{
+ while (*str)
+ {
+ *str = toupper(*str);
+ }
+}
+}
+void STRTOLOWER(char *str)
+{
+ if (str)
+ {
+ while (*str)
+ {
+ *str = towlower(*str);
+ }
+ }
+}
+
+COMEXP void WCSTOUPPER(wchar_t *str)
+{
+ if (str)
+ {
+ while (*str)
+ {
+ *str = towupper(*str);
+ }
+ }
+}
+
+COMEXP void WCSTOLOWER(wchar_t *str)
+{
+ if (str)
+ {
+ while (*str)
+ {
+ *str = towlower(*str);
+ }
+ }
+}
+
+int WCSICMPSAFE(const wchar_t *str1, const wchar_t *str2, const wchar_t *defval1, const wchar_t *defval2)
+{
+ if (str1 == NULL) str1 = defval1;
+ if (str2 == NULL) str2 = defval2;
+ return WCSICMP(str1, str2);
+}
+
+wchar_t *WCSTOK(wchar_t *str, const wchar_t *sep, wchar_t **last)
+{
+ return wcstok(str, sep, last);
+}
+
+int WCSCASEEQLSAFE(const wchar_t *str1, const wchar_t *str2, const wchar_t *defval1, const wchar_t *defval2)
+{
+ return !WCSICMPSAFE(str1, str2, defval1, defval2);
+}
+
+int STRLEN(const char *str)
+{
+ ASSERT(str != NULL);
+ return strlen(str);
+}
+
+bool ISALPHA(wchar_t alpha)
+{
+ return iswalpha(alpha);
+}
+
+bool ISDIGIT(wchar_t digit)
+{
+ return iswdigit(digit);
+}
+
+bool ISSPACE(wchar_t space)
+{
+ return iswspace(space);
+}
+
+bool ISPUNCT(wchar_t punct)
+{
+ return iswpunct(punct);
+}
+
+int STRCMP(const char *str1, const char *str2)
+{
+ ASSERT(str1!=NULL);
+ ASSERT(str2!=NULL);
+ return strcmp(str1, str2);
+}
+
+int STRCMPSAFE(const char *str1, const char *str2, const char *defval1, const char *defval2)
+{
+ if (str1 == NULL) str1 = defval1;
+ if (str2 == NULL) str2 = defval2;
+ return STRCMP(str1, str2);
+}
+
+void STRNCPY(char *dest, const char *src, int maxchar)
+{
+ ASSERT(dest != NULL);
+ ASSERT(src != NULL);
+ strncpy(dest, src, maxchar);
+ //INLINE
+}
+
+int STRICMPSAFE(const char *str1, const char *str2, const char *defval1, const char *defval2)
+{
+ if (str1 == NULL) str1 = defval1;
+ if (str2 == NULL) str2 = defval2;
+ return STRICMP(str1, str2);
+}
+
+int STRICMP(const char *str1, const char *str2)
+{
+ ASSERT(str1!=NULL);
+ ASSERT(str2!=NULL);
+ return strcasecmp(str1, str2);
+}
+
+void STRCPY(char *dest, const char *src)
+{
+ ASSERT(dest != NULL);
+ ASSERT(src != NULL);
+ ASSERT(dest != src);
+ strcpy(dest, src);
+ //INLINE
+}
+
+char *STRSTR(const char *str1, const char *str2)
+{
+ ASSERT(str1!=NULL);
+ ASSERT(str2!=NULL);
+ ASSERT(str1 != str2);
+ return strstr(str1, str2);
+}
diff --git a/Src/Wasabi/bfc/platform/strcmp.h b/Src/Wasabi/bfc/platform/strcmp.h
new file mode 100644
index 00000000..f76d47af
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/strcmp.h
@@ -0,0 +1,15 @@
+#ifndef NULLSOFT_BFC_STRCMP_H
+#define NULLSOFT_BFC_STRCMP_H
+
+#ifdef _WIN32
+#include <shlwapi.h>
+#define strcasestr StrStrIA
+#endif
+
+#ifdef __APPLE__
+#include <string.h>
+#define _strnicmp strncasecmp
+#define _stricmp strcasecmp
+#endif
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/bfc/platform/types.h b/Src/Wasabi/bfc/platform/types.h
new file mode 100644
index 00000000..ff83ce04
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/types.h
@@ -0,0 +1,2 @@
+#include <bfc/platform/platform.h>
+#include "../replicant/foundation/types.h" \ No newline at end of file
diff --git a/Src/Wasabi/bfc/platform/win32.h b/Src/Wasabi/bfc/platform/win32.h
new file mode 100644
index 00000000..73d8872e
--- /dev/null
+++ b/Src/Wasabi/bfc/platform/win32.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <stdio.h>
+
+#ifndef WIN32
+#error this file is only for win32
+#endif
+
+
+// this should be the *only* place windows.h gets included!
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#ifndef _WIN32_WCE
+#include <io.h>
+#endif
+
+#if defined(_MSC_VER) // msvc
+# define WASABIDLLEXPORT __declspec(dllexport)
+# if _MSC_VER >= 1100
+# define NOVTABLE __declspec(novtable)
+# endif
+#endif
+
+
+
+#define OSPIPE HANDLE
+
+
+typedef WCHAR OSFNCHAR;
+typedef LPWSTR OSFNSTR;
+typedef LPCWSTR OSFNCSTR;
+
diff --git a/Src/Wasabi/bfc/precomp_wasabi_bfc.cpp b/Src/Wasabi/bfc/precomp_wasabi_bfc.cpp
new file mode 100644
index 00000000..e9fd2651
--- /dev/null
+++ b/Src/Wasabi/bfc/precomp_wasabi_bfc.cpp
@@ -0,0 +1 @@
+#include "precomp_wasabi_bfc.h"
diff --git a/Src/Wasabi/bfc/precomp_wasabi_bfc.h b/Src/Wasabi/bfc/precomp_wasabi_bfc.h
new file mode 100644
index 00000000..57b10887
--- /dev/null
+++ b/Src/Wasabi/bfc/precomp_wasabi_bfc.h
@@ -0,0 +1,22 @@
+#ifndef NULLSOFT_BFC_PRECOMP_H
+#define NULLSOFT_BFC_PRECOMP_H
+
+// Platform
+#include <bfc/platform/platform.h>
+
+// Std
+#include "wasabi_std.h"
+#include "std_mem.h"
+#include "wasabi_std_wnd.h"
+#include "std_math.h"
+#include "std_string.h"
+
+// Containers
+#include "memblock.h"
+#include "tlist.h"
+#include "stack.h"
+#include "ptrlist.h"
+
+#include "file/splitpath.h"
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/bfc/ptrlist.cpp b/Src/Wasabi/bfc/ptrlist.cpp
new file mode 100644
index 00000000..32015dcb
--- /dev/null
+++ b/Src/Wasabi/bfc/ptrlist.cpp
@@ -0,0 +1,330 @@
+#include "ptrlist.h"
+#include <bfc/bfc_assert.h>
+
+// if this symbol is enabled, do sanity checking in a bunch of methods
+//#define DO_VERIFY_PTRLIST
+
+#if defined(ASSERTS_ENABLED) && defined(DO_VERIFY_PTRLIST)
+#define VERIFY_PTRLIST verify()
+#else
+#define VERIFY_PTRLIST
+#endif
+
+#ifdef _DEBUG
+int ptrlist_totalnitems = 0;
+#endif
+
+PtrListRoot::PtrListRoot( int initial_size )
+{
+ nitems = nslots = 0;
+ items = NULL;
+ //FG>why? we might as well save initial_size*4 bytes if nobody inserts anything in the list, no?
+ //BU No. initial_size defaults to 0 and therefore no memory is actually
+ //allocated in a typical construction. But, sometimes you want to start with
+ //a specific size, generally when you know the exact size you want,
+ //so that you can avoid REALLOCs when you initially populate the list.
+ //FG>Ah, makes sense.
+ setMinimumSize( initial_size );
+}
+
+PtrListRoot::PtrListRoot( const PtrListRoot *from )
+{
+ nitems = nslots = 0;
+ items = NULL;
+ copyFrom( from );
+}
+
+PtrListRoot::~PtrListRoot()
+{
+ removeAll();
+}
+
+void PtrListRoot::copyFrom( const PtrListRoot *from )
+{
+ ASSERT( from != NULL );
+
+ removeAll();
+ appendFrom( from );
+ VERIFY_PTRLIST;
+}
+
+void PtrListRoot::appendFrom( const PtrListRoot *from )
+{
+ ASSERT( from != NULL );
+
+ int n = from->getNumItems();
+
+ if ( n <= 0 )
+ return;
+
+ void **mem = from->getItemList();
+
+ ASSERT( mem != NULL ); // can't be NULL if getNumItems() >= 1
+
+ setMinimumSize( getNumItems() + n );
+ MEMCPY( items + getNumItems(), from->getItemList(), sizeof( void * ) * n );
+ nitems += n;
+#ifdef _DEBUG
+ ptrlist_totalnitems += n;
+#endif
+ VERIFY_PTRLIST;
+}
+
+void PtrListRoot::setMinimumSize( int _nslots )
+{
+ ASSERT( _nslots >= 0 );
+#ifdef DECREASE_PTRLISTS_SIZE
+ if ( _nslots + 2 * DEF_PTRLIST_INCREMENT < nslots )
+ {
+ nslots = ( ( _nslots / DEF_PTRLIST_INCREMENT ) + 2 ) * DEF_PTRLIST_INCREMENT;
+ items = (void **) REALLOC( items, sizeof( void * ) * nslots );
+ }
+#endif
+ if ( _nslots == 0 || _nslots <= nslots )
+ return;
+
+ nslots = _nslots;
+
+ if ( items )
+ items = (void **) REALLOC( items, sizeof( void * ) * nslots );
+ else
+ items = (void **) MALLOC( sizeof( void * ) * nslots );
+
+ VERIFY_PTRLIST;
+}
+
+int PtrListRoot::getNumItems() const
+{
+ return nitems;
+}
+
+void *PtrListRoot::enumItem( int n ) const
+{
+ if ( items == NULL || n < 0 || n >= nitems )
+ return NULL;
+
+ return items[ n ];
+}
+
+void *PtrListRoot::addItem( void *item, int pos, int increment )
+{
+ ASSERT( increment > 0 );
+ ASSERTPR( item != NULL, "can't put NULLs into ptrlists" );
+ ASSERT( nitems <= nslots );
+
+#ifdef DECREASE_PTRLISTS_SIZE
+ // expand or shrink as necessary
+ if ( items == NULL || nslots == nitems )
+ setMinimumSize( nslots + increment );
+ else
+ setMinimumSize( nitems );
+#else
+ // expand if necessary
+ if ( items == NULL || nslots == nitems )
+ setMinimumSize( nslots + increment );
+#endif
+
+ items[ nitems++ ] = item;
+
+ if ( pos != PTRLIST_POS_LAST )
+ moveItem( nitems - 1, pos );
+
+ VERIFY_PTRLIST;
+
+#ifdef _DEBUG
+ ptrlist_totalnitems++;
+#endif
+
+ return item;
+}
+
+// replace what's in the slot with the new value
+void *PtrListRoot::setItem( void *item, int pos )
+{
+ ASSERT( nitems >= pos );
+ items[ pos ] = item;
+ VERIFY_PTRLIST;
+ return item;
+}
+
+void PtrListRoot::reverse()
+{
+ if ( nitems <= 1 )
+ return;
+
+ MemBlock<void *> block( nitems, items );
+ void **blockmem = block.getMemory();
+
+ for ( int i = 0, j = nitems - 1; j >= 0; i++, j-- )
+ {
+ items[ i ] = blockmem[ j ];
+ }
+}
+
+void PtrListRoot::moveItem( int from, int to )
+{
+ if ( from == to )
+ return;
+
+ void *ptr = items[ from ];
+
+ if ( nitems > from + 1 ) // if moving from the end, there is nothing to shift behind our src position
+ {
+ //IMPORTANT note for future ports: This assumes MEMCPY accepts overlapping segments.
+ MEMCPY( &items[ from ], &items[ from + 1 ], ( nitems - from ) * sizeof( void * ) );
+ }
+
+ if ( to > from )
+ to--;
+
+ if ( nitems > to ) // if moving to the end, there is nothing to shift behind our target position
+ MEMCPY( &items[ to + 1 ], &items[ to ], ( nitems - to - 1 ) * sizeof( void * ) );
+
+ items[ to ] = ptr;
+ VERIFY_PTRLIST;
+}
+
+int PtrListRoot::removeItem( void *item )
+{
+ int c = 0;
+
+ if ( item == NULL || items == NULL || nitems <= 0 )
+ return 0;
+
+ // count occurences of item in items, remember the first one
+ void **p = items;
+ int first = -1;
+
+ for ( int i = 0; i < nitems; i++, p++ )
+ {
+ if ( *p == item )
+ {
+ if ( c++ == 0 )
+ first = i;
+ }
+ }
+
+ // if we found one, remove it
+ if ( c > 0 )
+ {
+ removeByPos( first ); // delByPos is faaast
+ c--; // decrease count
+ }
+
+ VERIFY_PTRLIST;
+
+ return c; // returns how many occurences of this item left
+}
+
+void PtrListRoot::removeEveryItem( void *item )
+{
+ while ( removeItem( item ) );
+ VERIFY_PTRLIST;
+}
+
+void PtrListRoot::removeByPos( int pos )
+{
+ if ( pos < 0 || pos >= nitems )
+ return; //JC
+
+ --nitems;
+#ifdef _DEBUG
+ ptrlist_totalnitems--;
+#endif
+
+ if ( pos == nitems )
+ return; // last one? nothing to copy over
+
+ MEMCPY( items + pos, items + ( pos + 1 ), sizeof( void * ) * ( nitems - pos ) ); // CT:not (nitems-(pos+1)) as nitems has been decremented earlier
+#ifdef DECREASE_PTRLISTS_SIZE
+ // shrink if necessary
+ setMinimumSize( nitems );
+#endif
+ VERIFY_PTRLIST;
+}
+
+void PtrListRoot::removeLastItem()
+{
+ if ( nitems == 0 || items == NULL ) return;
+ nitems--; // hee hee
+#ifdef _DEBUG
+ ptrlist_totalnitems--;
+#endif
+#ifdef DECREASE_PTRLISTS_SIZE
+ // shrink if necessary
+ setMinimumSize( nitems );
+#endif
+ VERIFY_PTRLIST;
+}
+
+void PtrListRoot::removeAll()
+{
+ FREE( items ); items = NULL;
+#ifdef _DEBUG
+ ptrlist_totalnitems -= nitems;
+#endif
+#ifdef DECREASE_PTRLISTS_SIZE
+ // shrink if necessary
+ setMinimumSize( nitems );
+#endif
+ nitems = 0;
+ nslots = 0;
+ VERIFY_PTRLIST;
+}
+
+void PtrListRoot::freeAll()
+{
+ for ( int i = 0; i < nitems; i++ ) //JC
+ if ( items ) FREE( items[ i ] );
+
+ removeAll();
+ VERIFY_PTRLIST;
+}
+
+int PtrListRoot::searchItem( void *item ) const
+{
+ for ( int i = 0; i < nitems; i++ )
+ if ( items[ i ] == item )
+ return i;
+ return -1;
+}
+
+void PtrListRoot::verify()
+{
+#ifdef DO_VERIFY_PTRLIST
+ ASSERT( nitems >= 0 );
+ ASSERT( nslots >= 0 );
+ ASSERT( nitems <= nslots );
+#endif
+}
+
+#if 0
+int PtrListRoot::bsearchItem( void *item ) const
+{
+ // do binary search
+ if ( nitems == 0 || items == NULL ) return -1;
+
+ int bot = 0, top = nitems - 1, mid;
+
+ for ( int c = 0; c < nitems + 16; c++ )
+ {
+ if ( bot > top ) return -1;
+ mid = ( bot + top ) / 2;
+ if ( item == items[ mid ] ) return mid;
+ if ( item < items[ mid ] ) top = mid - 1;
+ else bot = mid + 1;
+ }
+ ASSERTPR( 0, "binary search fucked up" );
+ return -1;
+}
+#endif
+
+void PtrListRoot::purge()
+{
+ ASSERT( nitems == 0 );
+ if ( items != NULL )
+ {
+ FREE( items );
+ items = NULL;
+ }
+}
diff --git a/Src/Wasabi/bfc/ptrlist.h b/Src/Wasabi/bfc/ptrlist.h
new file mode 100644
index 00000000..9d8d310d
--- /dev/null
+++ b/Src/Wasabi/bfc/ptrlist.h
@@ -0,0 +1,777 @@
+#ifndef _PTRLIST_H
+#define _PTRLIST_H
+
+#include <bfc/std_math.h>
+//#include <bfc/memblock.h>
+#include <bfc/bfc_assert.h>
+
+#include <bfc/platform/platform.h>
+
+//#include <wasabicfg.h>
+
+#ifdef _DEBUG
+extern int ptrlist_totalnitems;
+#endif
+
+// Disable the "identifier was truncated to '255' characters..." warning.
+#pragma warning( disable : 4786 )
+
+/*
+
+a generic pointer list template. only takes up 12 bytes when empty. auto-grows
+the array as necessary, NEVER shrinks it unless you removeAll() or equivalent
+
+Use, PtrList<typename>, never PtrListRoot
+
+*/
+
+// yes, this really should be an enum or something
+#define PTRLIST_POS_LAST -1
+
+// 4k each, leaving 16 bytes for MALLOC overhead
+//#define DEF_PTRLIST_INCREMENT (4096/sizeof(void*)-16)
+
+// in average, 4k doubles the VM working set of a skin, 128bytes (32 elements) seems most optimal
+#define DEF_PTRLIST_INCREMENT (128)
+
+class __foreach;
+
+// base class, to share as much code as possible
+class NOVTABLE PtrListRoot
+{
+ friend class __foreach;
+protected:
+ PtrListRoot(int initial_size = 0);
+ PtrListRoot(const PtrListRoot *from);
+ virtual ~PtrListRoot();
+
+ void copyFrom(const PtrListRoot *from);
+ void appendFrom(const PtrListRoot *from);
+
+ void setMinimumSize(int nslots); // expand to at least this many slots
+ int getNumItems() const;
+ int size() const { return nitems; }
+ bool empty() { return nitems == 0; }
+
+ void *enumItem(int n) const;
+
+ void moveItem(int from, int to);
+
+ int removeItem(void *item);
+ void removeEveryItem(void *item);
+ void removeByPos(int pos);
+ void removeLastItem();
+ void removeAll();
+ void freeAll();
+ void purge();
+
+ // gross-ass linear search to find index of item
+ // note that PtrListSorted provides a binary search version
+ int searchItem(void *item) const;
+
+#if 0//fuct
+ // speedy binary search. although it'll be fuct if it's not sorted right
+ int bsearchItem(void *item) const;
+#endif
+
+ void *addItem(void *item, int pos, int inc);
+ void *setItem(void *item, int pos); // replace what's in the slot with the new value
+
+ void reverse();
+
+ void **getItemList() const { return items; } // try to avoid! this is inline to make q() fast
+
+private:
+#undef verify // for Mac
+ void verify();
+
+ int nitems, nslots;
+ void **items;
+};
+
+// now we add the methods that refer specifically to the pointer type
+template <class T>
+class PtrList : public PtrListRoot
+{
+ friend class __foreach;
+public:
+ PtrList(int initial_size = 0) {}
+ PtrList(const PtrList<T> &r) { copyFrom(&r); }
+ PtrList(const PtrList<T> *r) { copyFrom(r); }
+ ~PtrList() {}
+
+ // copy another PtrList
+ // deletes previous contents
+ void copyFrom(const PtrList<T> *from) { PtrListRoot::copyFrom(from); }
+
+ // append contents of another PtrList to the end of this one
+ // preserves previous contents
+ void appendFrom(const PtrList<T> *from) { PtrListRoot::appendFrom(from); }
+
+ // adding
+
+ // expand freelist to at least this many slots, even if 0 items in list
+ void setMinimumSize(int nslots) { PtrListRoot::setMinimumSize(nslots); }
+
+ // provide a public addItem for the pointer type
+ T *addItem(const T *item, int pos = PTRLIST_POS_LAST, int inc = DEF_PTRLIST_INCREMENT)
+ {
+ return static_cast<T *>(PtrListRoot::addItem(const_cast<T*>(item), pos, inc));
+ }
+
+ void push_back(const T* item) { return addItem(item); }
+
+ // replace what's in the slot with the new value
+ T *setItem(const T *item, int pos) { return static_cast<T *>(PtrListRoot::setItem(const_cast<T*>(item), pos)); }
+
+ // reverse the order of the list in place
+ void reverse() { PtrListRoot::reverse(); }
+
+ // enumerating
+
+ // returns # of items in list
+ int getNumItems() const { return PtrListRoot::getNumItems(); }
+
+ // basic list enumerator. returns NULL for out of bounds
+ T *enumItem(int n) const { return static_cast<T *>(PtrListRoot::enumItem(n)); }
+ T *operator[](int n) const { return enumItem(n); }
+
+ // this will safely return NULL if 0 items due to enumItems's boundscheck
+ T *getFirst() const { return enumItem(0); }
+ T *getLast() const { return enumItem(getNumItems() - 1); }
+
+ // this is a NON-BOUNDS-CHECKING lookup
+ T *q(int n) { return static_cast<T*>(getItemList()[n]); }
+
+ // gross-ass linear search to find index of item
+ // note that PtrListSorted provides a binary search version
+ int searchItem(T *item) const { return PtrListRoot::searchItem(item); }
+ int haveItem(T *item) const { return searchItem(item) >= 0; }
+
+ // deleteing
+
+ // removes first instance of a pointer in list, returns how many are left
+ int removeItem(T *item) { return PtrListRoot::removeItem(item); }
+
+ //DEPRECATED
+ int delItem(T *item) { return removeItem(item); }
+
+ // removes all instances of this pointer
+ void removeEveryItem(const T *item) { PtrListRoot::removeEveryItem(const_cast<T*>(item)); }
+ // removes pointer at specified position regardless of value
+ void removeByPos(int pos) { PtrListRoot::removeByPos(pos); }
+ // DEPRECATED
+ void delByPos(int pos) { removeByPos(pos); }
+ // removes last item
+ void removeLastItem() { PtrListRoot::removeLastItem(); }
+ // removes all entries, also deletes memory space
+ void removeAll() { PtrListRoot::removeAll(); }
+ // removes all entries, calling FREE on the pointers
+ void freeAll() { PtrListRoot::freeAll(); }
+ // removes all entries, calling delete on the pointers
+ void deleteAll()
+ {
+ int i, nitems = getNumItems();
+ for (i = 0; i < nitems; i++)
+ delete enumItem(i);
+ removeAll();
+ }
+ // removes all entries, calling delete on the pointers
+ // FG>this version removes each entry as it deletes it so if
+ // one of the object uses this list in its destructor, it will
+ // still work. It is MUCH slower than deleteAll tho.
+ void deleteAllSafe()
+ {
+ //CUT ASSERT(!(nitems != 0 && items == NULL));
+ while (getNumItems())
+ {
+ T *i = enumItem(0);
+ delete i;
+ removeItem(i);
+ }
+ }
+ void deleteItem(int item)
+ {
+ if (item < getNumItems())
+ {
+ deleteItem(enumItem(item));
+ }
+ }
+ void deleteItem(T *item)
+ {
+ delete item;
+ removeItem(item);
+ }
+
+ void moveItem(int from, int to) { PtrListRoot::moveItem(from, to); }
+
+ static T *castFor(void *ptr) { return static_cast<T*>(ptr); }
+
+ using PtrListRoot::purge;
+
+protected:
+ T **getItemList()
+ {
+ return reinterpret_cast<T **>(PtrListRoot::getItemList());
+ }
+};
+
+class NotSorted
+{
+public:
+ // comparator for searching -- override
+ static int compareAttrib(const wchar_t *attrib, void *item) { return 0; }
+ // comparator for sorting -- override , -1 p1 < p2, 0 eq, 1 p1 > p2
+ static int compareItem(void *p1, void* p2) { return CMP3(p1, p2); }
+};
+
+//template <class T, class C> class NoSort {
+// static void _sort(T **, int) {}
+//};
+
+// a base class to sort the pointers
+// you must implement the comparisons (C) and the sort algorithm (S)
+template < class T, class C, class S >
+class PtrListSorted : public PtrList<T>
+{
+public:
+ PtrListSorted(int initial_size = 0) : PtrList<T>(initial_size)
+ {
+ need_sorting = 0;
+ auto_sort = true;
+ dups_low = dups_hi = dups_pos = 0;
+ }
+
+ void copyFrom(const PtrList<T> *from)
+ {
+ PtrList<T>::copyFrom(from);
+ need_sorting = 1;
+ if (auto_sort) sort();
+ }
+
+ T *addItem(T *item, int pos = PTRLIST_POS_LAST, int inc = DEF_PTRLIST_INCREMENT)
+ {
+#if 1
+ // check for appending in sorted order
+ if (pos == PTRLIST_POS_LAST && !need_sorting && auto_sort)
+ {
+ int n = PtrList<T>::getNumItems();
+ if (n > 0 && C::compareItem(item, q(n - 1)) < 0) need_sorting = 1;
+ }
+ else
+#endif
+ need_sorting = 1;
+ return PtrList<T>::addItem(item, pos, inc);
+ }
+
+ void sort(bool force_sort = false)
+ {
+ if (need_sorting || force_sort)
+ S::_sort(PtrList<T>::getItemList(), PtrList<T>::getNumItems());
+ need_sorting = 0;
+ }
+
+ T *enumItem(int n)
+ { // NOT const since we might call sort()
+ if (auto_sort) sort();
+ return PtrList<T>::enumItem(n);
+ }
+T *operator[](int n) { return PtrListSorted<T, C, S>::enumItem(n); }
+
+ T *q(int n)
+ {
+ if (auto_sort) sort();
+ return static_cast<T*>(PtrList<T>::getItemList()[n]);
+ }
+
+ T *findItem(const wchar_t *attrib, int *pos = NULL)
+ {
+ ASSERTPR(!(!auto_sort && need_sorting), "must call sort() first if auto-sorting is disabled");
+ sort();
+#if 1 // do binary search
+ if (PtrList<T>::getNumItems() == 0) return NULL;
+
+ int bot = 0, top = PtrList<T>::getNumItems() - 1, mid;
+
+ for (int c = 0; c < PtrList<T>::getNumItems() + 1; c++)
+ {
+ if (bot > top) return NULL;
+ mid = (bot + top) / 2;
+ int r = C::compareAttrib(attrib, PtrList<T>::getItemList()[mid]);
+ if (r == 0)
+ {
+ if (pos != NULL) *pos = mid;
+ return PtrList<T>::getItemList()[mid];
+ }
+ if (r < 0)
+ {
+ top = mid - 1;
+ }
+ else
+ {
+ bot = mid + 1;
+ }
+ }
+ ASSERTPR(0, "binary search fucked up");
+#else
+ // re-enable this in case of fuckup
+ for (int i = 0; i < nitems; i++)
+ {
+ if (C::compareAttrib(attrib, static_cast<T *>(items[i])) == 0)
+ return static_cast<T *>items[i];
+ }
+#endif
+ return NULL;
+ }
+
+ T *findItem(T *attrib, int *pos = NULL)
+ {
+ return findItem((const wchar_t *)attrib, pos);
+ }
+
+ int beginEnumDups(const char *attrib)
+ {
+ int pos;
+ findItem(attrib, &pos);
+
+ if (pos < 0)
+ return -1;
+
+ dups_hi = pos;
+ dups_low = pos;
+
+ int i;
+ for (i = pos - 1;i >= 0;i--)
+ {
+ if (C::compareAttrib(attrib, static_cast<T *>(enumItem(i))) == 0)
+ break;
+
+ dups_low = i;
+ }
+
+ for (i = pos + 1;i < PtrList<T>::getNumItems();i++)
+ {
+ if (C::compareAttrib(attrib, static_cast<T *>(enumItem(i))) == 0)
+ break;
+
+ dups_hi = i;
+ }
+
+ dups_pos = dups_low;
+
+ return dups_pos;
+ }
+
+ int getNextDup()
+ { // returns -1 when done
+ if (dups_pos >= dups_hi)
+ return -1;
+
+ return ++dups_pos;
+ }
+
+#if 0
+ // replace search with binary search
+ int searchItem(T *item) const
+ {
+ ASSERTPR(!(!auto_sort && need_sorting), "must call sort() first if auto-sorting is disabled");
+ sort();
+ return bsearchItem(item);
+ }
+#endif
+
+ void setAutoSort(bool as) { auto_sort = as; }
+ bool getAutoSort() const { return auto_sort; }
+
+ void removeDups()
+ {
+ ASSERTPR(!(!auto_sort && need_sorting), "must call sort() first if auto-sorting is disabled");
+ sort();
+ for (int i = 1; i < PtrList<T>::getNumItems(); i++)
+ {
+ if (C::compareItem(enumItem(i - 1), enumItem(i)) == 0)
+ {
+ PtrList<T>::delByPos(i);
+ i--;
+ }
+ }
+ }
+
+private:
+ int need_sorting;
+ bool auto_sort;
+ int dups_low, dups_hi, dups_pos;
+};
+
+// quicksort -- you still need to override the compare fns
+template <class T, class C>
+class QuickSorted
+{
+public:
+ static void _sort(T **items, int nitems)
+ {
+ if (items == NULL || nitems <= 1)
+ return ;
+
+ Qsort(items, 0, nitems - 1);
+ }
+
+private:
+ static void swapItem(T **items, int a, int b)
+ { // no bounds checking!
+ T *tmp = items[a];
+ items[a] = items[b];
+ items[b] = tmp;
+ }
+
+ static void Qsort(T **items, int lo0, int hi0)
+ {
+ int lo = lo0, hi = hi0;
+ if (hi0 > lo0)
+ {
+ T *mid = items[(lo0 + hi0) / 2];
+ while (lo <= hi)
+ {
+ while ((lo < hi0) && (C::compareItem(items[lo], mid) < 0))
+ lo++;
+
+ while ((hi > lo0) && (C::compareItem(items[hi], mid) > 0))
+ hi--;
+
+ if (lo <= hi)
+ {
+ swapItem(items, lo, hi);
+ lo++;
+ hi--;
+ }
+ }
+
+ if (lo0 < hi)
+ Qsort(items, lo0, hi);
+
+ if (lo < hi0)
+ Qsort(items, lo, hi0);
+ }
+ }
+};
+
+// easy way to specify quicksorting, just data type and comparison class
+template <class T, class C> class PtrListQuickSorted : public PtrListSorted<T, C, QuickSorted<T, C> >
+{
+public:
+ PtrListQuickSorted(int initial_size = 0) : PtrListSorted<T, C, QuickSorted<T, C> >(initial_size) {}
+};
+
+
+// easy way to get a list sorted by pointer val
+class SortByPtrVal
+{
+public:
+ static int compareItem(void *p1, void *p2) { return CMP3(p1, p2); }
+ static int compareAttrib(const wchar_t *attrib, void *item) { return CMP3((void *)attrib, item); }
+};
+
+template <class T> class PtrListQuickSortedByPtrVal : public PtrListQuickSorted<T, SortByPtrVal > {};
+
+
+// this class automatically inserts at the correct position, so
+// the binary searches are very fast if you need to insert and search often (no need to sort)
+template < class T, class C >
+class PtrListInsertSorted : public PtrList<T>
+{
+public:
+ PtrListInsertSorted() : last_insert_pos(0) { disable_sort = 0; }
+
+ T *addItem(T *item)
+ {
+ int numItems = PtrList<T>::getNumItems();
+ if (numItems == 0)
+ {
+ last_insert_pos = 0;
+
+ return PtrList<T>::addItem(item);
+ }
+
+ int insertpoint = -1;
+ if (!disable_sort)
+ {
+ int bot = 0, top = numItems - 1, mid;
+ // benski>
+ // optimization based on profiler info. Too many string compares!
+ // Most of the use of this comes from GuiObjectWnd's constructor (and derived classes)
+ // so I've changed GuiObjectWnd to add things in alphabetical order.
+ // Before we start the binary search, we'll check the new item against the LAST item inserted
+ // Most of the time, we'll finish the insert in O(1)
+ // Even if we fail, we mitigate the loss somewhat by limiting the binary search
+
+ if (last_insert_pos >= numItems) // the list may have shrunk since last time
+ last_insert_pos = numItems - 1;
+
+ int quickTest = C::compareItem(item, PtrList<T>::getItemList()[last_insert_pos]);
+
+ if (quickTest == 0) // right on the money.. we'll go ahead and insert ourselves next
+ return PtrList<T>::addItem(item, last_insert_pos);
+
+ if (quickTest > 0) // ok we go after the last inserted item (good), but we need to make sure we go before the next one
+ {
+ last_insert_pos++;
+
+ if (last_insert_pos == numItems) // we're at the end? cool...
+ return PtrList<T>::addItem(item, PTRLIST_POS_LAST);
+
+ quickTest = C::compareItem(item, PtrList<T>::getItemList()[last_insert_pos]); // test against the next item
+
+ if (quickTest <= 0) // and we're not bigger than the next one... perfect!
+ return PtrList<T>::addItem(item, last_insert_pos);
+ else // too bad
+ bot = last_insert_pos; // help out the binary search ... We're at least bigger than everything before last_insert_pos
+ }
+ else // ok our optimization failed, but we can still help out the binary search
+ top = last_insert_pos - 1; // we're at least smaller than everything before last_insert_pos
+
+ // end optimization code
+
+
+ for (int c = 0; c < numItems + 1; c++)
+ {
+ if (bot > top)
+ {
+ // insert here
+ insertpoint = bot;
+ break;
+ }
+ mid = (bot + top) / 2;
+ int r = C::compareItem(item, PtrList<T>::getItemList()[mid]);
+
+ if (r == 0)
+ {
+ // insert here
+ insertpoint = mid;
+ break;
+ }
+
+ if (r < 0)
+ {
+ top = mid - 1;
+ }
+ else
+ {
+ bot = mid + 1;
+ }
+ }
+ last_insert_pos = insertpoint;
+ ASSERTPR(insertpoint != -1, "insertsort/binary search fucked up");
+ }
+ else // no sorting
+ {
+ last_insert_pos = numItems;
+ insertpoint = PTRLIST_POS_LAST;
+ }
+
+ return PtrList<T>::addItem(item, insertpoint);
+ }
+ T *getInsertionPoint(T *item, int *pos)
+ {
+ if (PtrList<T>::getNumItems() == 0)
+ {
+ if (pos)
+ *pos = 0;
+
+ return NULL;
+ }
+
+ int bot = 0, top = PtrList<T>::getNumItems() - 1, mid;
+
+ int insertpoint = -1;
+ if (!disable_sort )
+ {
+ for (int c = 0; c < PtrList<T>::getNumItems() + 1; c++)
+ {
+ if (bot > top)
+ {
+ // insert here
+ insertpoint = bot;
+ break;
+ }
+ mid = (bot + top) / 2;
+ int r = C::compareItem(item, PtrList<T>::getItemList()[mid]);
+
+ if (r == 0)
+ {
+ // insert here
+ insertpoint = mid;
+ break;
+ }
+
+ if (r < 0)
+ {
+ top = mid - 1;
+ }
+ else
+ {
+ bot = mid + 1;
+ }
+ }
+
+ ASSERTPR(insertpoint != -1, "insertsort/binary search fucked up");
+ }
+ else
+ insertpoint = PTRLIST_POS_LAST;
+
+ if (pos)
+ *pos = insertpoint;
+
+ return PtrList<T>::enumItem(insertpoint);
+ }
+ T *findItem(const wchar_t *attrib, int *pos = NULL)
+ {
+ if (isSorted())
+ {
+ // binary search
+ if (PtrList<T>::getNumItems() == 0)
+ return NULL;
+
+ int bot = 0, top = PtrList<T>::getNumItems() - 1, mid;
+
+ for (int c = 0; c < PtrList<T>::getNumItems() + 1; c++)
+ {
+ if (bot > top)
+ return NULL;
+
+ mid = (bot + top) / 2;
+ int r = C::compareAttrib(attrib, PtrList<T>::getItemList()[mid]);
+
+ if (r == 0)
+ {
+ if (pos != NULL)
+ *pos = mid;
+
+ return PtrList<T>::getItemList()[mid];
+ }
+
+ if (r < 0)
+ {
+ top = mid - 1;
+ }
+ else
+ {
+ bot = mid + 1;
+ }
+ }
+ ASSERTPR(0, "binary search fucked up");
+ }
+ else
+ {
+ // linear search
+ for (int i = 0; i < PtrList<T>::getNumItems(); i++)
+ {
+ int r = C::compareAttrib(attrib, PtrList<T>::getItemList()[i]);
+ if (r == 0)
+ {
+ if (pos != NULL)
+ *pos = i;
+
+ return PtrList<T>::getItemList()[i];
+ }
+ }
+ }
+
+ return NULL;
+ }
+ T *findItem(T *attrib, int *pos = NULL) { return findItem((const wchar_t *)attrib, pos); }
+ void setSorted(int dosort) { disable_sort = !dosort; }
+ int isSorted() { return !disable_sort; }
+ int disable_sort;
+
+ int last_insert_pos;
+};
+
+// this list allows you to have multiple items with same attrib and adds findLastItem so you can
+// sort on more than just one item. this can be used to make autosorting lists of overriding items
+// which you can add and remove at will.
+template <class T, class C> class PtrListQuickMultiSorted : public PtrListQuickSorted<T, C>
+{
+public:
+ PtrListQuickMultiSorted(int initial_size = 0) : PtrListQuickSorted<T, C>(initial_size) {}
+ T *findLastItem(const wchar_t *attrib, int *pos = NULL)
+ {
+ PtrListQuickSorted<T, C>::sort();
+ int p = 0;
+ int fp = 0;
+ T *item = PtrListQuickSorted<T, C>::findItem(attrib, &fp);
+
+ if (!item)
+ return NULL;
+
+ p = fp;
+
+ for(;;)
+ {
+ p++;
+
+ if (p >= PtrListQuickSorted<T, C>::getNumItems())
+ break;
+
+ T* i = PtrListQuickSorted<T, C>::enumItem(p);
+
+ if (!C::compareAttrib(attrib, i))
+ {
+ fp = p;
+ item = i;
+ }
+ else
+ break;
+ }
+
+ if (pos != NULL)
+ *pos = fp;
+
+ return item;
+ }
+};
+//same thing but Insert sorted. use this one if you insert and search items often (no need to sort on findItem)
+template <class T, class C> class PtrListInsertMultiSorted : public PtrListInsertSorted<T, C>
+{
+public:
+ PtrListInsertMultiSorted() : PtrListInsertSorted<T, C>() {}
+ T *findLastItem(const wchar_t *attrib, int *pos = NULL)
+ {
+ //sort();
+ int p = 0;
+ int fp = 0;
+ T *item = PtrListInsertSorted<T, C>::findItem(attrib, &fp);
+
+ if (!item)
+ return NULL;
+
+ p = fp;
+
+ for (;;)
+ {
+ p++;
+
+ if (p >= PtrListInsertSorted<T, C>::getNumItems())
+ break;
+
+ T* i = PtrListInsertSorted<T, C>::enumItem(p);
+
+ if (!C::compareAttrib(attrib, i))
+ {
+ fp = p;
+ item = i;
+ }
+ else
+ break;
+ }
+
+ if (pos != NULL)
+ *pos = fp;
+
+ return item;
+ }
+};
+
+
+#include <bfc/foreach.h>
+
+#endif
diff --git a/Src/Wasabi/bfc/reentryfilter.h b/Src/Wasabi/bfc/reentryfilter.h
new file mode 100644
index 00000000..1e1da68d
--- /dev/null
+++ b/Src/Wasabi/bfc/reentryfilter.h
@@ -0,0 +1,78 @@
+#ifndef __REENTRYFILTER_H
+#define __REENTRYFILTER_H
+
+#include <bfc/tlist.h>
+
+class ReentryFilterObject {
+ public:
+
+ ReentryFilterObject() {}
+ virtual ~ReentryFilterObject() {}
+
+ void enterScope(int scope) {
+ scopes.addItem(scope);
+ }
+
+ int isInScope(int scope) {
+ for (int i=0;i<scopes.getNumItems();i++)
+ if (scopes.enumItem(i) == scope) return 1;
+ return 0;
+ }
+
+ void leaveScope(int scope) {
+ for (int i=0;i<scopes.getNumItems();i++)
+ if (scopes.enumItem(i) == scope) {
+ scopes.delByPos(i);
+ return;
+ }
+ }
+
+ private:
+
+ TList<int> scopes;
+};
+
+class ReentryFilter {
+ public:
+
+ ReentryFilter() : reentering(0), thisscope(-1), filter(NULL) {} // call setFilterObject, enterScope and leaveScope manually
+
+ ReentryFilter(ReentryFilterObject *filterobj, intptr_t scope) {
+ setFilterObject(filterobj);
+ enterScope(scope);
+ }
+
+ void setFilterObject(ReentryFilterObject *filterobj) {
+ filter = filterobj;
+ }
+
+ void enterScope(intptr_t scope) {
+ ASSERT(filter != NULL);
+ if (filter->isInScope(scope)) {
+ reentering = 1;
+ } else {
+ filter->enterScope(scope);
+ reentering = 0;
+ }
+ thisscope = scope;
+ }
+
+ void leaveScope() {
+ ASSERT(filter != NULL);
+ filter->leaveScope(thisscope);
+ }
+
+ virtual ~ReentryFilter() {
+ if (reentering) return;
+ leaveScope();
+ }
+
+ int mustLeave() { return reentering; }
+
+ private:
+ intptr_t thisscope;
+ int reentering;
+ ReentryFilterObject *filter;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/bfc/stack.cpp b/Src/Wasabi/bfc/stack.cpp
new file mode 100644
index 00000000..98199463
--- /dev/null
+++ b/Src/Wasabi/bfc/stack.cpp
@@ -0,0 +1,77 @@
+#include "precomp_wasabi_bfc.h"
+#include "stack.h"
+
+//#define STACK_SIZE_INCREMENT 250
+
+// going from 250 to 32 decreases size of VM working set by several megabytes
+#define STACK_SIZE_INCREMENT 32
+
+StackBase::StackBase()
+{
+ nslots = 0;
+ cur = 0;
+ stack = NULL;
+}
+
+StackBase::~StackBase()
+{
+ if (stack != NULL) FREE(stack);
+}
+
+int StackBase::push(void *item, int sizeofT, int increment)
+{
+ if (increment <= 0) increment = STACK_SIZE_INCREMENT;
+ if (stack == NULL) {
+ nslots = increment;
+ stack = (char*)MALLOC(sizeofT * nslots);
+ } else if (cur >= nslots) {
+ int newnslots = nslots + increment;
+ stack = (char*)REALLOC(stack, sizeofT*newnslots);
+ nslots = newnslots;
+ }
+ MEMCPY(stack + cur*sizeofT, item, sizeofT);
+ cur++;
+ return cur;
+}
+
+int StackBase::peek() {
+ return cur;
+}
+
+int StackBase::peekAt(void *ptr, int n, int sizeofT) {
+ if (ptr != NULL) MEMCPY(ptr, stack + (cur-1-n)*sizeofT, sizeofT);
+ return cur;
+}
+
+int StackBase::getRef(void **ptr, int n, int sizeofT) {
+ if (ptr != NULL) *ptr = stack + (cur-1-n)*sizeofT;
+ return cur;
+}
+
+void *StackBase::top(int sizeofT) {
+ ASSERT(cur >= 0);
+ if (cur == 0) return NULL;
+ return stack + (cur-1)*sizeofT;
+}
+
+int StackBase::pop(void *ptr, int sizeofT) {
+ ASSERT(cur >= 0);
+ if (cur == 0) return 0;
+ ASSERT(stack != NULL);
+ --cur;
+ if (ptr != NULL) MEMCPY(ptr, stack + cur*sizeofT, sizeofT);
+ return 1;
+}
+
+int StackBase::isempty() {
+ return cur == 0;
+}
+
+void StackBase::purge() {
+ ASSERT(isempty());
+ if (stack != NULL) {
+ FREE(stack);
+ stack = NULL;
+ }
+}
+
diff --git a/Src/Wasabi/bfc/stack.h b/Src/Wasabi/bfc/stack.h
new file mode 100644
index 00000000..39ed50a0
--- /dev/null
+++ b/Src/Wasabi/bfc/stack.h
@@ -0,0 +1,42 @@
+//PORTABLE
+#ifndef _STACK_H
+#define _STACK_H
+
+#include <bfc/common.h>
+#include <bfc/wasabi_std.h>
+
+// a self-growing stack. note that it never shrinks (for now)
+
+class StackBase {
+protected:
+ StackBase();
+ ~StackBase();
+
+ int push(void *item, int sizeofT, int increment);
+ int peek();
+ int peekAt(void *ptr, int n, int sizeofT);
+ int getRef(void **ptr, int n, int sizeofT);
+ void *top(int sizeofT);
+ int pop(void *ptr, int sizeofT);
+ int isempty();
+ void purge();
+
+private:
+ int nslots, cur;
+ char *stack;
+};
+
+template<class T>
+class Stack : public StackBase {
+public:
+ int push(T item, int increment=-1) { return StackBase::push(&item, sizeof(T), increment); }
+ using StackBase::peek;
+ T top() { return *static_cast<T*>(StackBase::top(sizeof(T))); }
+ int peekAt(T *ptr = NULL, int n = 0) { return StackBase::peekAt(ptr, n, sizeof(T)); }
+ int getRef(T **ptr = NULL, int n = 0) { if (!ptr) return peek(); return StackBase::getRef((void **)&(*ptr), n, sizeof(T)); }
+ int pop(T *ptr = NULL) { return StackBase::pop(ptr, sizeof(T)); }
+ using StackBase::isempty;
+ using StackBase::purge;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/std_file.cpp b/Src/Wasabi/bfc/std_file.cpp
new file mode 100644
index 00000000..a1c7267a
--- /dev/null
+++ b/Src/Wasabi/bfc/std_file.cpp
@@ -0,0 +1,428 @@
+#include "precomp_wasabi_bfc.h"
+
+#include "std_file.h"
+#include <bfc/file/readdir.h>
+#include <bfc/platform/strcmp.h>
+
+#ifdef WIN32
+#include <shellapi.h> // for ShellExecute
+#endif
+
+#ifdef __APPLE__
+#include <unistd.h>
+#endif
+
+#define TMPNAME_PREFIX L"WTF"
+
+#ifndef _NOSTUDIO
+#include <bfc/parse/pathparse.h>
+
+#undef fopen
+#undef fclose
+#undef fseek
+#undef ftell
+#undef fread
+#undef fwrite
+#undef fgets
+#undef fprintf
+#undef unlink
+#undef access
+
+#ifdef WASABI_COMPILE_FILEREADER
+static PtrList<void> fileReaders;
+
+OSFILETYPE FileReaderOpen(const wchar_t *filename, OSFNCSTR mode)
+{
+ OSFILETYPE ret = NULL;
+
+ const wchar_t *rFilename = filename;
+ wchar_t str[WA_MAX_PATH] = L"";
+
+ if (wcsstr(filename, L".."))
+ {
+ PathParserW pp(filename);
+ for (int i = 0;i < pp.getNumStrings();i++)
+ {
+ if (!wcscmp(pp.enumString(i), L".."))
+ {
+ PathParserW pp2(str);
+ if (pp2.getNumStrings() <= 0)
+ return NULL;
+ ASSERTPR(pp2.getNumStrings() > 0, "we don't handle this right, and I'm not sure how to fix it because I'm not sure what the code should do with a leading .. --BU");
+ int l = (int)wcslen(pp2.enumString(pp2.getNumStrings() - 1));
+ str[wcslen(str) - l - 1] = 0;
+ continue;
+ }
+ if (!wcscmp(pp.enumString(i), L"."))
+ continue;
+ wcscat(str, pp.enumString(i));
+ wcscat(str, L"/");
+ }
+ str[wcslen(str) - 1] = 0;
+ rFilename = str;
+ }
+
+ if (WASABI_API_FILE && (ret = (OSFILETYPE )WASABI_API_FILE->fileOpen(rFilename, mode)))
+ {
+ fileReaders.addItem((void *)ret);
+ return ret;
+ }
+ return 0;
+}
+#endif
+
+static DWORD mode_to_access(const wchar_t *mode)
+{
+ DWORD access_flags=0;
+ if (mode)
+ {
+ if (mode[0]=='r')
+ access_flags|=GENERIC_READ;
+
+ if (mode[0]=='w' || mode[0] == 'a')
+ {
+ access_flags|=GENERIC_WRITE;
+ if (mode[1] == '+')
+ access_flags|=GENERIC_READ;
+ }
+ }
+ return access_flags;
+}
+
+static DWORD mode_to_create(const wchar_t *mode)
+{
+ if (mode[0]=='r')
+return OPEN_EXISTING;
+ if (mode[0] == 'w')
+ return CREATE_ALWAYS;
+ if (mode[0] == 'a')
+ return OPEN_ALWAYS;
+
+ return OPEN_ALWAYS;
+}
+
+OSFILETYPE WFOPEN(const wchar_t *filename, OSFNCSTR mode, bool useFileReaders)
+{
+ if (!filename || !*filename)
+ return OPEN_FAILED;
+
+ if (!mode)
+ mode = WF_WRITE_BINARY;
+
+ OSFILETYPE ret = OPEN_FAILED;
+
+ if (!WCSNICMP(filename, L"file:", 5))
+ filename += 5;
+
+#ifdef _WIN32
+ ret = CreateFileW(filename, mode_to_access(mode), FILE_SHARE_READ, 0, mode_to_create(mode), FILE_FLAG_SEQUENTIAL_SCAN, 0);
+ if (ret != OPEN_FAILED && mode[0]=='a')
+ SetFilePointer(ret, 0, 0, FILE_END);
+#elif defined(__APPLE__)
+ // this is kind of slow, but hopefully this function isn't called enough for a major performance impact
+ // maybe it'd be faster if we did -fshort-wchar and used CFStringCreateWithCharactersNoCopy
+ CFStringRef cfstr = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)filename, wcslen(filename)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
+ if (cfstr)
+ {
+ size_t len = CFStringGetMaximumSizeOfFileSystemRepresentation(cfstr);
+ if (len)
+ {
+ char *tmpfn = alloca(len);
+ if (tmpfn)
+ {
+ if (CFStringGetFileSystemRepresentation(cfstr, tmpfn, len))
+ ret = fopen(tmpfn, mode);
+ }
+ }
+ CFRelease(cfstr);
+ }
+#else
+#error port me
+#endif
+
+ if (ret != OPEN_FAILED)
+ return ret;
+
+ // File not found... try to open it with the file readers
+ // but before that, resolve ".." in path so zip can find it
+#ifdef WASABI_COMPILE_FILEREADER
+ if (useFileReaders)
+ {
+ if (ret = FileReaderOpen(filename, mode))
+ return ret;
+ else
+ return OPEN_FAILED;
+ }
+#endif
+ // File still not found ...
+
+ return OPEN_FAILED;
+}
+
+int FCLOSE(OSFILETYPE stream)
+{
+#ifdef WASABI_COMPILE_FILEREADER
+ if (fileReaders.searchItem((void *)stream) != -1)
+ {
+ fileReaders.removeItem((void *)stream);
+ WASABI_API_FILE->fileClose((void *)stream);
+ return 0;
+ }
+#endif
+ return !CloseHandle(stream);
+}
+
+static __int64 Seek64(HANDLE hf, __int64 distance, DWORD MoveMethod)
+{
+ LARGE_INTEGER li;
+
+ li.QuadPart = distance;
+
+ li.LowPart = SetFilePointer (hf, li.LowPart, &li.HighPart, MoveMethod);
+
+ if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
+ {
+ li.QuadPart = -1;
+ }
+
+ return li.QuadPart;
+}
+
+int FSEEK(OSFILETYPE stream, long offset, int origin)
+{
+#ifdef WASABI_COMPILE_FILEREADER
+ if (fileReaders.searchItem((void *)stream) != -1)
+ return WASABI_API_FILE->fileSeek(offset, origin, (void *)stream);
+#endif
+ return (int)Seek64(stream, offset, origin);
+}
+
+uint64_t FTELL(OSFILETYPE stream)
+{
+#ifdef WASABI_COMPILE_FILEREADER
+ if (fileReaders.searchItem((void *)stream) != -1)
+ return WASABI_API_FILE->fileTell((void *)stream);
+#endif
+ return Seek64(stream, 0, FILE_CURRENT);
+}
+
+size_t FREAD(void *buffer, size_t size, size_t count, OSFILETYPE stream)
+{
+#ifdef WASABI_COMPILE_FILEREADER
+ if (fileReaders.searchItem((void *)stream) != -1)
+ return WASABI_API_FILE->fileRead(buffer, size*count, (void *)stream);
+#endif
+ DWORD bytesRead=0;
+ ReadFile(stream, buffer, (DWORD)(size*count), &bytesRead, NULL);
+ return bytesRead;
+}
+
+size_t FWRITE(const void *buffer, size_t size, size_t count, OSFILETYPE stream)
+{
+#ifdef WASABI_COMPILE_FILEREADER
+ if (fileReaders.searchItem((void *)stream) != -1)
+ return WASABI_API_FILE->fileWrite(buffer, (int)(size*count), (void *)stream);
+#endif
+
+ DWORD bytesWritten=0;
+ WriteFile(stream, buffer, (DWORD)(size*count), &bytesWritten, NULL);
+ return bytesWritten;
+}
+
+uint64_t FGETSIZE(OSFILETYPE stream)
+{
+#ifdef WASABI_COMPILE_FILEREADER
+ if (fileReaders.searchItem((void *)stream) != -1)
+ return WASABI_API_FILE->fileGetFileSize((void *)stream);
+#endif
+ LARGE_INTEGER position;
+ position.QuadPart=0;
+ position.LowPart = GetFileSize(stream, (LPDWORD)&position.HighPart);
+
+ if (position.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
+ return INVALID_FILE_SIZE;
+ else
+ return position.QuadPart;
+}
+/*
+char *FGETS(char *string, int n, OSFILETYPE stream)
+{
+#ifdef WASABI_COMPILE_FILEREADER
+ if (fileReaders.searchItem((void *)stream) != -1)
+ {
+ char c;
+ char *p = string;
+ for (int i = 0;i < (n - 1);i++)
+ {
+ if (!WASABI_API_FILE->fileRead(&c, 1, stream))
+ {
+ if (!i) return NULL;
+ break;
+ }
+ if (c == 0x0d) continue;
+ if (c == 0x0a) break;
+ *p++ = c;
+ }
+ *p = 0;
+ return string;
+ }
+#endif
+ return fgets(string, n, stream);
+}
+*/
+/*
+int FPRINTF(OSFILETYPE stream, const char *format , ...)
+{
+ int ret;
+ va_list args;
+ va_start (args, format);
+#ifdef WASABI_COMPILE_FILEREADER
+ if (fileReaders.searchItem((void *)stream) != -1)
+ {
+ String p;
+ ret = p.vsprintf(format, args);
+ FWRITE(p.v(), p.len(), 1, stream);
+ }
+ else
+#endif
+ ret = vfprintf(stream, format, args); //real stdio
+ va_end (args);
+ return ret;
+}*/
+
+OSFNCSTR TMPNAM2(OSFNSTR str, int val)
+{
+#ifdef WIN32
+ wchar_t tempPath[MAX_PATH-14] = {0};
+ static wchar_t tempName[MAX_PATH];
+ GetTempPathW(MAX_PATH-14, tempPath);
+ GetTempFileNameW(tempPath, TMPNAME_PREFIX, val, tempName);
+
+ if (str)
+ {
+ wcsncpy(str, tempName, MAX_PATH);
+ return str;
+ }
+ else
+ {
+ return tempName;
+ }
+#elif defined(LINUX) || defined(__APPLE__)
+ mkstemp(StringPrintf("%sXXXXXX", str).getNonConstVal());
+ return (const char *)str;
+#endif
+}
+
+OSFNCSTR TMPNAM(OSFNSTR string)
+{
+ return TMPNAM2(string, 0);
+}
+
+int UNLINK(OSFNCSTR filename)
+{
+#ifdef WASABI_COMPILE_FILEREADER
+ return FDELETE(filename);
+#elif defined(_WIN32)
+ return _wunlink(filename);
+#else
+ return unlink(filename); // this has been undefed at the top of this file
+#endif
+}
+
+int ACCESS(const char *filename, int mode)
+{
+#ifdef WIN32
+ return _access(filename, mode);
+#else
+ return access(filename, mode); // this has been undefed at the top of this file
+#endif
+}
+
+int WACCESS(OSFNCSTR filename, int mode)
+{
+#ifdef WIN32
+ return _waccess(filename, mode);
+#elif defined(__APPLE__)
+ return access(filename, mode); // this has been undefed at the top of this file
+#endif
+}
+
+int FDELETE(const wchar_t *filename, int permanently)
+{
+#ifdef WASABI_COMPILE_FILEREADER
+ if (permanently)
+ return WASABI_API_FILE->fileRemove(filename);
+ else
+ return WASABI_API_FILE->fileRemoveUndoable(filename);
+#else
+ return UNLINK(filename);
+#endif
+}
+
+int MOVEFILE(const wchar_t * filename, const wchar_t *destfilename)
+{
+#ifdef WASABI_COMPILE_FILEREADER
+ return WASABI_API_FILE->fileMove(filename, destfilename);
+#elif defined(_WIN32)
+ return MoveFileW(filename, destfilename);
+#else
+ return rename(filename, destfilename);
+#endif
+}
+
+#ifdef WIN32
+#include <shlobj.h>
+#include <shellapi.h>
+
+static HRESULT ResolveShortCut(LPCWSTR pszShortcutFile, LPWSTR pszPath, int maxbuf)
+{
+ HRESULT hres;
+ IShellLinkW* psl;
+ wchar_t szGotPath[MAX_PATH] = {0};
+ WIN32_FIND_DATAW wfd;
+
+ *pszPath = 0; // assume failure
+
+ hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ IID_IShellLinkW, (void **) & psl);
+ if (SUCCEEDED(hres))
+ {
+ IPersistFile* ppf;
+
+ hres = psl->QueryInterface(IID_IPersistFile, (void **) & ppf); // OLE 2! Yay! --YO
+ if (SUCCEEDED(hres))
+ {
+ hres = ppf->Load(pszShortcutFile, STGM_READ);
+ if (SUCCEEDED(hres))
+ {
+ hres = psl->Resolve(HWND_DESKTOP, SLR_ANY_MATCH);
+ if (SUCCEEDED(hres))
+ {
+ wcsncpy(szGotPath, pszShortcutFile, MAX_PATH);
+ hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATAW *) & wfd,
+ SLGP_SHORTPATH );
+ wcsncpy(pszPath, szGotPath, maxbuf);
+ if (maxbuf) pszPath[maxbuf] = 0;
+ }
+ }
+ ppf->Release();
+ }
+ psl->Release();
+ }
+ return SUCCEEDED(hres);
+}
+#endif
+
+// ommitting a maxbuf param was just asking for trouble...
+int StdFile::resolveShortcut(OSFNCSTR filename, OSFNSTR destfilename, int maxbuf)
+{
+#ifdef WIN32
+ return ResolveShortCut(filename, destfilename, maxbuf);
+#elif defined(LINUX) || defined(__APPLE__)
+ return readlink(filename, destfilename, maxbuf);
+#else
+#error port me
+#endif
+}
+
+#endif // ndef _NOSTUDIO \ No newline at end of file
diff --git a/Src/Wasabi/bfc/std_file.h b/Src/Wasabi/bfc/std_file.h
new file mode 100644
index 00000000..1c1a0d3d
--- /dev/null
+++ b/Src/Wasabi/bfc/std_file.h
@@ -0,0 +1,101 @@
+#ifndef _STD_FILE_H
+#define _STD_FILE_H
+
+#include <bfc/platform/platform.h>
+#include "wasabi_std.h"
+#include <stdio.h>
+
+/* TODO:
+ FEOF
+ FFLUSH
+ FGETPOS - maybe implement as just FTELL?
+ FSETPOS - maybe implement as just FSEEK?
+ FPUTS - no problems, look at FPRINTF implementation
+ FSTAT (in conjunction with FILENO), only fill in _stat::st_size for now (via getFileSize)
+*/
+
+#ifndef _NOSTUDIO
+// EXTC is used here as some .c files will use these functions
+
+#define NO_FILEREADERS false
+
+#ifdef _WIN32
+#define WF_READONLY_BINARY L"rb"
+#define WF_WRITE_TEXT L"wt"
+#define WF_WRITE_BINARY L"wb"
+#define WF_APPEND L"a"
+#define WF_APPEND_RW L"a+"
+#define OPEN_FAILED INVALID_HANDLE_VALUE
+#elif defined(__APPLE__)
+#define WF_READONLY_BINARY "r"
+#define WF_WRITE_TEXT "w"
+#define WF_WRITE_BINARY "w"
+#define WF_APPEND "a"
+#define WF_APPEND_RW "a+"
+#define OPEN_FAILED 0
+#endif
+
+#ifdef _WIN32
+typedef HANDLE OSFILETYPE;
+#else
+#error port me
+#endif
+
+OSFILETYPE WFOPEN(const wchar_t *filename, OSFNCSTR mode, bool useFileReaders = true);
+
+int FCLOSE(OSFILETYPE stream);
+int FSEEK(OSFILETYPE stream, long offset, int origin);
+uint64_t FTELL(OSFILETYPE stream);
+#undef FREAD // defined on Mac for some reason
+size_t FREAD(void *buffer, size_t size, size_t count, OSFILETYPE stream);
+#undef FWRITE // defined on Mac for some reason
+size_t FWRITE(const void *buffer, size_t size, size_t count, OSFILETYPE stream);
+//char *FGETS( char *string, int n, OSFILETYPE stream);
+//int FPRINTF(OSFILETYPE stream, const char *format , ...);
+uint64_t FGETSIZE(OSFILETYPE stream);
+const wchar_t *TMPNAM(wchar_t *string);
+OSFNCSTR TMPNAM2(wchar_t *string, int val);
+int FEXISTS(const char *filename); // return 1 if true, 0 if not, -1 if unknown
+int UNLINK(const wchar_t *filename); // return 1 on success, 0 on error
+int WACCESS(const wchar_t *filename, int mode);
+#ifdef __cplusplus
+// returns 1 on success, 0 on error, -1 if undoable deletes aren't supported
+int FDELETE(OSFNCSTR filename, int permanently=TRUE);
+#else
+int FDELETE(OSFNCSTR filename, int permanently);
+#endif
+
+// 1 on success, 0 on fail
+// can't move directories between volumes on win32
+int MOVEFILE(OSFNCSTR filename, OSFNCSTR destfilename);
+
+
+#ifdef __cplusplus
+namespace StdFile {
+#endif
+ int resolveShortcut(OSFNCSTR filename, OSFNSTR destfilename, int maxbuf);
+#ifdef __cplusplus
+};
+#endif
+
+#ifdef WASABI_COMPILE_FILEREADER
+
+#ifndef REAL_STDIO
+#ifndef __APPLE__
+//#define fopen FOPEN
+//#define fclose FCLOSE
+//#define fseek FSEEK
+//#define ftell FTELL
+//#define fread FREAD
+//#define fwrite FWRITE
+//#define fgets FGETS
+//#define fprintf FPRINTF
+//#define unlink UNLINK
+//#define access ACCESS
+#endif
+#endif //real_stdio
+
+#endif //WASABI_COMPILE_FILEREADER
+#endif //_nostudio
+
+#endif
diff --git a/Src/Wasabi/bfc/std_keyboard.cpp b/Src/Wasabi/bfc/std_keyboard.cpp
new file mode 100644
index 00000000..aa5707dc
--- /dev/null
+++ b/Src/Wasabi/bfc/std_keyboard.cpp
@@ -0,0 +1,51 @@
+#include "precomp_wasabi_bfc.h"
+#include "std_keyboard.h"
+
+int Std::keyDown(int code)
+{
+#ifdef WIN32
+ return !!(GetKeyState(code) & 0x8000);
+#elif defined(LINUX)
+ if ( code == MK_RBUTTON || code == MK_LBUTTON ) {
+ Window t1, t2;
+ int rx, ry, wx, wy;
+ unsigned int buttons;
+
+ XQueryPointer( Linux::getDisplay(), Linux::RootWin(), &t1, &t2,
+ &rx, &ry, &wx, &wy, &buttons );
+
+ if ( code == MK_RBUTTON )
+ return buttons & Button3Mask;
+ else
+ return buttons & Button1Mask;
+ }
+
+ int code1 = XKeysymToKeycode( Linux::getDisplay(), code & 0xFFFF );
+ int code2 = XKeysymToKeycode( Linux::getDisplay(), (code>>16) & 0xFFFF );
+
+ char keys_return[32] = {0};
+ XQueryKeymap( Linux::getDisplay(), keys_return );
+
+ if ( code1 && code2 )
+ return (keys_return[ (code1 >> 3) & 31 ] & (1 << (code1 & 7))) ||
+ (keys_return[ (code2 >> 3) & 31 ] & (1 << (code2 & 7)));
+
+ return (keys_return[ (code1 >> 3) & 31 ] & (1 << (code1 & 7)));
+#else
+ return 0;
+#warning port me!
+#endif
+}
+
+// TODO: add async flag to be able to choose between GetKeyState/GetAsyncKeyState (win32) GetCurrentKeyModifiers/GetCurrentEventkeyModifiers (mac)
+bool Std::keyModifier(int code)
+{
+#ifdef WIN32
+ return !!(GetKeyState(code) & 0x8000);
+#elif defined(__APPLE__)
+ return GetCurrentKeyModifiers() & code;
+#elif defined(LINUX)
+#error port me
+#endif
+}
+
diff --git a/Src/Wasabi/bfc/std_keyboard.h b/Src/Wasabi/bfc/std_keyboard.h
new file mode 100644
index 00000000..eb21c6f4
--- /dev/null
+++ b/Src/Wasabi/bfc/std_keyboard.h
@@ -0,0 +1,46 @@
+#ifndef NULLSOFT_WASABI_STD_KEYBOARD_H
+#define NULLSOFT_WASABI_STD_KEYBOARD_H
+
+#ifdef _WIN32
+#include <windows.h>
+enum
+{
+ STDKEY_SHIFT = VK_SHIFT,
+ STDKEY_ALT = VK_MENU,
+ STDKEY_CONTROL = VK_CONTROL,
+
+ STDKEY_UP = VK_UP,
+ STDKEY_DOWN = VK_DOWN,
+ STDKEY_LEFT = VK_LEFT,
+ STDKEY_RIGHT = VK_RIGHT,
+
+ STDKEY_HOME = VK_HOME,
+ STDKEY_END = VK_END,
+};
+
+#elif defined(__APPLE__)
+#include <Carbon/Carbon.h>
+enum
+{
+ STDKEY_SHIFT = shiftKey,
+ STDKEY_ALT = cmdKey, // yes, I know the option call has "alt" written on it, but Mac programs use Apple key like windows Alt key
+ STDKEY_CONTROL = controlKey,
+
+ STDKEY_UP = kUpArrowCharCode,
+ STDKEY_DOWN = kDownArrowCharCode,
+ STDKEY_LEFT = kLeftArrowCharCode,
+ STDKEY_RIGHT = kRightArrowCharCode,
+
+ STDKEY_HOME = kHomeCharCode,
+ STDKEY_END = kEndCharCode,
+};
+
+#else
+#error port me
+#endif
+namespace Std
+{
+ int keyDown(int code);
+ bool keyModifier(int code);
+}
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/bfc/std_math.cpp b/Src/Wasabi/bfc/std_math.cpp
new file mode 100644
index 00000000..9bbfe112
--- /dev/null
+++ b/Src/Wasabi/bfc/std_math.cpp
@@ -0,0 +1,18 @@
+#include "precomp_wasabi_bfc.h"
+
+#include "std_math.h"
+
+
+void premultiplyARGB32(ARGB32 *words, int nwords)
+{
+ for (; nwords > 0; nwords--, words++)
+ {
+ unsigned char *pixel = (unsigned char *)words;
+ unsigned int alpha = pixel[3];
+ if (alpha == 255) continue;
+ pixel[0] = (pixel[0] * alpha) >> 8; // blue
+ pixel[1] = (pixel[1] * alpha) >> 8; // green
+ pixel[2] = (pixel[2] * alpha) >> 8; // red
+ }
+}
+
diff --git a/Src/Wasabi/bfc/std_math.h b/Src/Wasabi/bfc/std_math.h
new file mode 100644
index 00000000..9b6a8966
--- /dev/null
+++ b/Src/Wasabi/bfc/std_math.h
@@ -0,0 +1,48 @@
+#ifndef _STD_MATH_H
+#define _STD_MATH_H
+
+// FG> doesn't work for me without this include (error C2039: 'sin' : is not a member of '`global namespace'')
+#include <math.h>
+#include <bfc/platform/types.h>
+#ifdef __cplusplus
+static inline double SIN(double a) { return ::sin(a); }
+static inline double COS(double a) { return ::cos(a); }
+static inline double SQRT(double a) { return ::sqrt(a); }
+
+#else
+#define SIN(a) sin(a)
+#define COS(a) sin(a)
+#define SQRT(a) sqrt(a)
+unsigned long COMEXP BSWAP_C(unsigned long input);
+#endif
+
+#ifdef __cplusplus
+// neat trick from C++ book, p. 161
+template<class T> inline T MAX(T a, T b) { return a > b ? a : b; }
+template<class T> inline T MIN(T a, T b) { return a > b ? b : a; }
+template<class T> inline T MINMAX(T a, T minval, T maxval) {
+ return (a < minval) ? minval : ( (a > maxval) ? maxval : a );
+}
+
+// and a couple of my own neat tricks :) BU
+template<class T> inline T ABS(T a) { return a < 0 ? -a : a; }
+template<class T> inline T SQR(T a) { return a * a; }
+template<class T> inline int CMP3(T a, T b) {
+ if (a < b) return -1;
+ if (a == b) return 0;
+ return 1;
+}
+
+static inline RGB24 RGBTOBGR(RGB24 col) {
+ return ((col & 0xFF00FF00) | ((col & 0xFF0000) >> 16) | ((col & 0xFF) << 16));
+}
+static inline RGB24 BGRTORGB(RGB24 col) { return RGBTOBGR(col); }
+static inline ARGB32 BGRATOARGB(ARGB32 col) { return RGBTOBGR(col); }
+
+void premultiplyARGB32(ARGB32 *words, int nwords=1);
+
+#else // not __cplusplus
+void COMEXP premultiplyARGB32(ARGB32 *words, int nwords);
+#endif
+
+#endif
diff --git a/Src/Wasabi/bfc/std_mem.h b/Src/Wasabi/bfc/std_mem.h
new file mode 100644
index 00000000..db1d9312
--- /dev/null
+++ b/Src/Wasabi/bfc/std_mem.h
@@ -0,0 +1,71 @@
+#ifndef _STD_MEM_H
+#define _STD_MEM_H
+
+#include <bfc/platform/platform.h>
+#include <string.h>
+
+wchar_t *WMALLOC(size_t size);
+void *MALLOC(size_t size);
+void *CALLOC(size_t records, size_t recordsize);
+void *REALLOC(void *ptr, size_t size);
+void FREE(void *ptr);
+
+void *MEMDUP(const void *src, size_t n);
+void MEMCPY(void *dest, const void *src, size_t n);
+void MEMCPY_(void *dest, const void *src, size_t n);
+void MEMCPY32(void *dest, const void *src, size_t words);
+
+#ifdef __cplusplus
+static __inline int MEMCMP(const void *buf1, const void *buf2, size_t count) {
+ return memcmp(buf1, buf2, count);
+}
+static __inline void MEMSET(void *dest, int c, size_t n) {
+ memset(dest, c, n);
+}
+static __inline void MEMZERO(void *dest, size_t nbytes) {
+ memset(dest, 0, nbytes);
+}
+#else
+#define MEMCMP memcmp
+#define MEMSET memset
+#define MEMZERO(dest, nbytes) memset(dest, 0, nbytes)
+#endif
+
+#ifdef __cplusplus
+
+// these are for structs and basic classes only
+static __inline void ZERO(int &obj) { obj = 0; }
+template<class T>
+inline void ZERO(T &obj) { MEMZERO(&obj, sizeof(T)); }
+
+// generic version that should work for all types
+template<class T>
+inline void MEMFILL(T *ptr, T val, unsigned int n) {
+ for (int i = 0; i < n; i++) ptr[i] = val;
+}
+
+// asm 32-bits version
+void MEMFILL32(void *ptr, unsigned long val, unsigned int n);
+
+// helpers that call the asm version
+template<>
+inline void MEMFILL<unsigned long>(unsigned long *ptr, unsigned long val, unsigned int n) { MEMFILL32(ptr, val, n); }
+
+template<>
+void MEMFILL<unsigned short>(unsigned short *ptr, unsigned short val, unsigned int n);
+
+// int
+template<>
+inline void MEMFILL<int>(int *ptr, int val, unsigned int n) {
+ MEMFILL32(ptr, *reinterpret_cast<unsigned long *>(&val), n);
+}
+
+// float
+template<>
+inline void MEMFILL<float>(float *ptr, float val, unsigned int n) {
+ MEMFILL32(ptr, *reinterpret_cast<unsigned long *>(&val), n);
+}
+
+#endif // __cplusplus defined
+
+#endif
diff --git a/Src/Wasabi/bfc/std_mkncc.h b/Src/Wasabi/bfc/std_mkncc.h
new file mode 100644
index 00000000..113e464d
--- /dev/null
+++ b/Src/Wasabi/bfc/std_mkncc.h
@@ -0,0 +1,11 @@
+#ifndef _STD_MKNCC
+#define _STD_MKNCC
+
+// note: this is endian-incompatible with win32's MAKEFOURCC
+// otoh, it shows up nicely in a debug register ;)
+
+#define MK4CC(a, b, c, d) ( (((unsigned long)a)<<24)|(((unsigned long)b)<<16)|(((unsigned long)c)<<8)|((unsigned long)d) )
+#define MK3CC(b, c, d) ( (((unsigned long)b)<<16)|(((unsigned long)c)<<8)|((unsigned long)d) )
+#define MK2CC(c, d) ( (((unsigned long)c)<<8)|((unsigned long)d) )
+
+#endif
diff --git a/Src/Wasabi/bfc/std_string.cpp b/Src/Wasabi/bfc/std_string.cpp
new file mode 100644
index 00000000..aef1402c
--- /dev/null
+++ b/Src/Wasabi/bfc/std_string.cpp
@@ -0,0 +1,254 @@
+#include "std_string.h"
+#include <bfc/assert.h>
+
+int WCSICOLL(const wchar_t *str1, const wchar_t *str2)
+{
+ return lstrcmpiW(str1, str2);
+}
+
+int WCSICMP(const wchar_t *str1, const wchar_t *str2)
+{
+ // WCSICMP is supposed to be used for string-lookup kinds of code, so we need to make sure it's done in a non-locale-aware way
+ return CompareStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, str1, -1, str2, -1)-2;
+ //return _wcsicmp(str1, str2);
+}
+
+int WCSNICMP(const wchar_t *str1, const wchar_t *str2, size_t len)
+{
+ return _wcsnicmp(str1, str2, len);
+}
+
+wchar_t *WCSTOK(wchar_t *str, const wchar_t *sep, wchar_t **last)
+{
+ return wcstok(str, sep);
+}
+
+bool ISALPHA(wchar_t alpha)
+{
+ return IsCharAlphaW(alpha)==TRUE;
+}
+
+bool ISDIGIT(wchar_t digit)
+{
+ WORD type=0;
+ GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, &digit, 1, &type);
+ return !!(type&C1_DIGIT);
+}
+
+bool ISSPACE(wchar_t space)
+{
+ WORD type=0;
+ GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, &space, 1, &type);
+ return !!(type&C1_SPACE);
+}
+
+bool ISPUNCT(wchar_t punct)
+{
+ WORD type=0;
+ GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, &punct, 1, &type);
+ return !!(type&C1_PUNCT);
+}
+
+char *STRSTR(const char *str1, const char *str2) {
+ ASSERT(str1!=NULL);
+ ASSERT(str2!=NULL);
+ ASSERT(str1 != str2);
+ return const_cast<char *>(strstr(str1, str2));
+}
+
+wchar_t *WCSCASESTR(const wchar_t *str1, const wchar_t *str2)
+{
+ ASSERT(str1!=NULL);
+ ASSERT(str2!=NULL);
+ wchar_t *p;
+ size_t len = wcslen(str2);
+ for (p = (wchar_t *)str1; *p; p++)
+ {
+ if (!_wcsnicmp(p, str2, len))
+ return p;
+ }
+ return NULL;
+}
+
+void STRCPY(char *dest, const char *src) {
+ ASSERT(dest != NULL);
+ ASSERT(src != NULL);
+ ASSERT(dest != src);
+ strcpy(dest, src);
+//INLINE
+}
+
+void STRNCPY(char *dest, const char *src, int maxchar) {
+ ASSERT(dest != NULL);
+ ASSERT(src != NULL);
+ strncpy(dest, src, maxchar);
+//INLINE
+}
+
+void WCSCPYN(wchar_t *dest, const wchar_t *src, size_t maxchar)
+{
+ ASSERT(dest != NULL);
+ ASSERT(src != NULL);
+ StringCchCopyW(dest, maxchar, src);
+}
+
+char *STRCHR(const char *str, int c) {
+ ASSERT(str != NULL);
+ return const_cast<char *>(strchr(str, c));
+//INLINE
+}
+
+void STRCAT(char *dest, const char *append) {
+ ASSERT(dest != NULL);
+ ASSERT(append != NULL);
+ ASSERT(dest != append);
+ strcat(dest, append);
+}
+
+unsigned long STRTOUL(const char *s, char **p, int rx) {
+ ASSERT(s != NULL);
+ ASSERT(p != NULL);
+ return strtoul(s,p,rx);
+}
+
+wchar_t *WCSDUP(const wchar_t *ptr)
+{
+ if (ptr == NULL) return NULL;
+ size_t size = wcslen(ptr);
+ wchar_t *ret = (wchar_t *)MALLOC((size + 1) * sizeof(wchar_t));
+ if (ret != NULL)
+ {
+ WCSCPYN(ret, ptr, size+1);
+ }
+ return ret;
+}
+
+int STRLEN(const char *str) {
+ ASSERT(str != NULL);
+ return (int)strlen(str);
+}
+
+int STRCMP(const char *str1, const char *str2) {
+ ASSERT(str1!=NULL);
+ ASSERT(str2!=NULL);
+ return strcmp(str1, str2);
+}
+
+int STRCMPSAFE(const char *str1, const char *str2, const char *defval1, const char *defval2) {
+ if (str1 == NULL) str1 = defval1;
+ if (str2 == NULL) str2 = defval2;
+ return STRCMP(str1, str2);
+}
+
+int WCSCMPSAFE(const wchar_t *str1, const wchar_t *str2, const wchar_t *defval1, const wchar_t *defval2) {
+ if (str1 == NULL) str1 = defval1;
+ if (str2 == NULL) str2 = defval2;
+ return wcscmp(str1, str2);
+}
+int STRICMP(const char *str1, const char *str2) {
+ ASSERT(str1!=NULL);
+ ASSERT(str2!=NULL);
+#if defined(WIN32)
+ return _stricmp(str1, str2);
+#elif defined(LINUX)
+ return strcasecmp(str1, str2);
+#endif
+}
+
+int STRICMPSAFE(const char *str1, const char *str2, const char *defval1, const char *defval2) {
+ if (str1 == NULL) str1 = defval1;
+ if (str2 == NULL) str2 = defval2;
+ return STRICMP(str1, str2);
+}
+
+int WCSICMPSAFE(const wchar_t *str1, const wchar_t *str2, const wchar_t *defval1, const wchar_t *defval2)
+{
+ if (str1 == NULL) str1 = defval1;
+ if (str2 == NULL) str2 = defval2;
+ return WCSICMP(str1, str2);
+}
+
+
+int WCSEQLSAFE(const wchar_t *str1, const wchar_t *str2, const wchar_t *defval1, const wchar_t *defval2) {
+ return !WCSCMPSAFE(str1, str2, defval1, defval2);
+}
+
+int STRCASEEQLSAFE(const char *str1, const char *str2, const char *defval1, const char *defval2) {
+ return !STRICMPSAFE(str1, str2, defval1, defval2);
+}
+
+int WCSCASEEQLSAFE(const wchar_t *str1, const wchar_t *str2, const wchar_t *defval1, const wchar_t *defval2)
+{
+ return !WCSICMPSAFE(str1, str2, defval1, defval2);
+}
+
+
+
+//FG> sorry brennan, this need to not be a const :)
+void STRTOUPPER(char *p)
+{
+ CharUpperA(p);
+}
+
+void STRTOLOWER(char *p)
+{
+ CharLowerA(p);
+}
+
+void WCSTOUPPER(wchar_t *p)
+{
+ CharUpperW(p);
+}
+
+void KEYWORDUPPER(wchar_t *p)
+{/*
+ if (p)
+ {
+ while (p && *p)
+ {
+ *p = towupper(*p);
+ p++;
+ }
+ }*/
+ int l = (int)wcslen(p);
+ // from MSDN - If LCMAP_UPPERCASE or LCMAP_LOWERCASE is set, the lpSrcStr and lpDestStr pointers can be the same.
+ LCMapStringW(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), LCMAP_UPPERCASE, p, l, p, l);
+}
+
+void WCSTOLOWER(wchar_t *p)
+{
+ CharLowerW(p);
+}
+
+int STRNICMP(const char *str1, const char *str2, int l) {
+ ASSERT(str1!=NULL);
+ ASSERT(str2!=NULL);
+
+ ASSERT(l>=0);
+ while (TOUPPER(*str1) == TOUPPER(*str2) && *str1 != 0 && *str2 != 0 && l--)
+ str1++, str2++;
+ if (l == 0) return 0;
+ return (*str2 - *str1);
+}
+
+int STRNCASEEQL(const char *str1, const char *str2, int l) {
+ ASSERT(str1!=NULL);
+ ASSERT(str2!=NULL);
+ return STRNICMP(str1, str2, l) == 0;
+}
+
+int STREQL(const char *str1, const char *str2) {
+ ASSERT(str1!=NULL);
+ ASSERT(str2!=NULL);
+ return (strcmp(str1, str2) == 0);
+}
+
+int STRCASEEQL(const char *str1, const char *str2) {
+ ASSERT(str1!=NULL);
+ ASSERT(str2!=NULL);
+#ifdef WIN32
+ return (_stricmp(str1, str2)==0);
+#else
+ return (strcasecmp(str1, str2)==0);
+#endif
+} \ No newline at end of file
diff --git a/Src/Wasabi/bfc/std_string.h b/Src/Wasabi/bfc/std_string.h
new file mode 100644
index 00000000..fa86ee43
--- /dev/null
+++ b/Src/Wasabi/bfc/std_string.h
@@ -0,0 +1,11 @@
+#ifndef _STD_STRING_H
+#define _STD_STRING_H
+
+#include <bfc/platform/platform.h>
+#ifdef __cplusplus
+bool ISALPHA(wchar_t alpha);
+bool ISDIGIT(wchar_t digit);
+bool ISSPACE(wchar_t space);
+bool ISPUNCT(wchar_t punct);
+#endif
+#endif
diff --git a/Src/Wasabi/bfc/std_wnd.cpp b/Src/Wasabi/bfc/std_wnd.cpp
new file mode 100644
index 00000000..3ad69fc1
--- /dev/null
+++ b/Src/Wasabi/bfc/std_wnd.cpp
@@ -0,0 +1,1098 @@
+#include "precomp_wasabi_bfc.h"
+
+#include "wasabi_std_wnd.h"
+#include "api.h"
+#include <api/wnd/api_window.h>
+#include <api/wnd/wndevent.h>
+#include <api/wnd/wndevent.h>
+#include <shobjidl.h>
+#include "../winamp/wa_ipc.h"
+
+#ifndef AC_SRC_ALPHA
+const int AC_SRC_ALPHA = 1;
+#endif
+
+#ifndef THBN_CLICKED
+#define THBN_CLICKED 0x1800
+#endif
+
+static int nreal = 0;
+
+#ifdef __APPLE__
+OSStatus MyWindowEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData);
+OSStatus MyControlEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData);
+#endif
+
+#ifdef _WIN32
+static HINSTANCE gdi32instance = NULL;
+
+static int(WINAPI *getRandomRgn)(HDC dc, HRGN rgn, int i) = NULL;
+
+static int grrfailed = 0;
+
+static void register_wndClass(HINSTANCE hInstance);
+
+static int versionChecked = 0;
+static int isNT = 0;
+
+static int IsNT()
+{
+ if (versionChecked)
+ return isNT;
+
+ if (GetVersion() < 0x80000000)
+ isNT = 1;
+
+ versionChecked = 1;
+ return isNT;
+}
+
+int Wasabi::Std::Wnd::alphaStretchBlit(HDC destHDC, int dstx, int dsty, int dstw, int dsth, HDC sourceHDC, int srcx, int srcy, int srcw, int srch)
+{
+ if (IsNT())
+ {
+ SetStretchBltMode(destHDC, HALFTONE);
+ StretchBlt(destHDC, dstx, dsty, dstw, dsth, sourceHDC, srcx , srcy, srcw, srch, SRCCOPY);
+ return 1;
+ }
+ else
+ return 0;
+}
+#endif
+
+#ifdef __APPLE__
+enum
+{
+ kWasabi = 'WASA'
+};
+
+const ControlID kWasabiID = { kWasabi, 0 };
+
+void GetWasabiHIView(WindowRef window, HIViewRef *control)
+{
+ GetControlByID(window, &kWasabiID, control);
+}
+
+
+OSStatus CreateHIView ( WindowRef inWindow, const Rect* inBounds,
+ ControlRef* outControl )
+{
+ OSStatus err;
+ ControlRef root;
+ EventRef event;
+
+
+ // Make an initialization event
+ err = CreateEvent( NULL, kEventClassHIObject, kEventHIObjectInitialize,
+ GetCurrentEventTime(), 0, &event );
+ require_noerr( err, CantCreateEvent );
+
+ // If bounds were specified, push the them into the initialization event
+ // so that they can be used in the initialization handler.
+ if ( inBounds != NULL )
+ {
+ err = SetEventParameter( event, 'boun', typeQDRectangle,
+ sizeof( Rect ), inBounds );
+ require_noerr( err, CantSetParameter );
+ }
+
+ err = HIObjectCreate( kHIViewClassID, event, (HIObjectRef*)
+ outControl );
+ require_noerr( err, CantCreate );
+
+
+ // If a parent window was specified, place the new view into the
+ // parent window.
+ if ( inWindow != NULL )
+ {
+ err = GetRootControl( inWindow, &root );
+ require_noerr( err, CantGetRootControl );
+
+
+ err = HIViewAddSubview( root, *outControl );
+ SetControlID( *outControl, &kWasabiID );
+ HIViewSetVisible(*outControl, true);
+ }
+
+
+CantCreate:
+CantGetRootControl:
+CantSetParameter:
+CantCreateEvent:
+ ReleaseEvent( event );
+
+
+CantRegister:
+ return err;
+}
+#endif
+
+OSWINDOWHANDLE Wasabi::Std::Wnd::createWnd(RECT *r, int nochild, int acceptdrops, OSWINDOWHANDLE parent, OSMODULEHANDLE module, ifc_window *rw)
+{
+#ifdef _WIN32
+ register_wndClass(module);
+
+ int style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+ int exstyle=0;
+
+ if (parent == NULL) {
+ exstyle |= WS_EX_TOOLWINDOW;
+ style |= WS_POPUP;
+ } else
+ style |= WS_CHILD;
+
+ if (nochild) style=WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+
+ if (acceptdrops) exstyle |= WS_EX_ACCEPTFILES;
+
+ HWND ret = CreateWindowExW(exstyle, BASEWNDCLASSNAME, NULL, style,
+ r->left, r->top, r->right - r->left, r->bottom - r->top, parent, NULL, module, (LPVOID)rw);
+ if (ret != INVALIDOSWINDOWHANDLE)
+ {
+ nreal++;
+ if(NULL != WASABI_API_APP && 0 != (WS_POPUP & style))
+ WASABI_API_APP->app_registerGlobalWindow(ret);
+ }
+ return ret;
+#elif defined(__APPLE__)
+ Rect wndRect;
+ SetRect(&wndRect, r->left, r->top, r->right, r->bottom);
+ WindowRef newWnd;
+ CreateNewWindow(kOverlayWindowClass, kWindowCompositingAttribute, &wndRect, &newWnd);
+ SetWindowGroup(newWnd, GetWindowGroupOfClass(kDocumentWindowClass));
+ // install a window event handler
+ const EventTypeSpec windowEventList[] =
+ {
+ {
+ kEventClassCommand, kEventProcessCommand
+ },
+// { kEventClassWindow, kEventWindowBoundsChanging },
+ { kEventClassWindow, kEventWindowBoundsChanged },
+// { kEventClassWindow, kEventWindowInit },
+
+ {kEventClassMouse, kEventMouseDown},
+ {kEventClassMouse, kEventMouseUp},
+ {kEventClassMouse, kEventMouseMoved},
+ {kEventClassMouse, kEventMouseDragged},
+ //{kEventClassMouse, kEventMouseEntered},
+ //{kEventClassMouse, kEventMouseExited},
+ //{kEventClassMouse, kEventMouseWheelMoved},
+
+ {kEventClassKeyboard, kEventRawKeyDown},
+ {kEventClassKeyboard, kEventRawKeyUp},
+
+ };
+ InstallWindowEventHandler(newWnd, MyWindowEventHandler, GetEventTypeCount(windowEventList), windowEventList, rw, NULL);
+
+ // create the content view
+ HIViewRef myHIView;
+ CreateHIView(newWnd,&wndRect,(ControlRef*)&myHIView);
+ const EventTypeSpec controlEventList[] =
+ {
+ { kEventClassControl, kEventControlDraw},
+ { kEventClassControl, kEventControlApplyBackground},
+ };
+
+ InstallEventHandler(GetControlEventTarget(myHIView), MyControlEventHandler, GetEventTypeCount(controlEventList), controlEventList, rw, NULL);
+
+ return newWnd;
+#endif
+}
+
+void Wasabi::Std::Wnd::destroyWnd(OSWINDOWHANDLE wnd)
+{
+#ifdef _WIN32
+
+ if(NULL != WASABI_API_APP && 0 != (WS_POPUP & GetWindowLongPtr(wnd, GWL_STYLE)))
+ WASABI_API_APP->app_unregisterGlobalWindow(wnd);
+
+ DestroyWindow(wnd);
+ nreal--;
+ if (nreal == 0)
+ {
+ if (gdi32instance) FreeLibrary(gdi32instance);
+
+ gdi32instance = NULL;
+ getRandomRgn = NULL;
+ }
+#elif defined(__APPLE__)
+ DisposeWindow(wnd);
+#endif
+}
+
+int Wasabi::Std::Wnd::isValidWnd(OSWINDOWHANDLE wnd)
+{
+#ifdef _WIN32
+ return IsWindow(wnd);
+#elif defined(__APPLE__)
+ // TODO: docs suggest that this function is slow
+ if (!wnd)
+ return 0;
+ return IsValidWindowPtr(wnd);
+#endif
+}
+
+#ifdef _WIN32
+void Wasabi::Std::Wnd::setLayeredWnd(OSWINDOWHANDLE wnd, int layered)
+{
+ if (layered)
+ {
+ // have to clear and reset, can't just set
+ SetWindowLong(wnd, GWL_EXSTYLE, GetWindowLong(wnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
+ SetWindowLong(wnd, GWL_EXSTYLE, GetWindowLong(wnd, GWL_EXSTYLE) | WS_EX_LAYERED);
+ }
+ else
+ {
+ SetWindowLong(wnd, GWL_EXSTYLE, GetWindowLong(wnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
+ }
+}
+
+int Wasabi::Std::Wnd::isLayeredWnd(OSWINDOWHANDLE wnd)
+{
+ DWORD dwLong = GetWindowLong(wnd, GWL_EXSTYLE);
+ return !!(dwLong & WS_EX_LAYERED);
+}
+
+
+
+void Wasabi::Std::Wnd::setLayeredAlpha(OSWINDOWHANDLE wnd, int amount)
+{
+ if (!isDesktopAlphaAvailable()) return;
+ SetLayeredWindowAttributes(wnd, RGB(0, 0, 0), amount, LWA_ALPHA);
+}
+
+
+void Wasabi::Std::Wnd::updateLayeredWnd(OSWINDOWHANDLE wnd, int x, int y, int w, int h, HDC surfdc, int alpha)
+{
+ if (!isDesktopAlphaAvailable()) return;
+ BLENDFUNCTION blend = {AC_SRC_OVER, 0, (BYTE)alpha, AC_SRC_ALPHA };
+ POINT sp = {x, y}, pt = {0, 0};
+ SIZE ss = { w, h };
+ //HDC sysdc = GetDC(NULL);
+ UpdateLayeredWindow(wnd, NULL/*sysdc*/, &sp, &ss, surfdc, &pt, 0, &blend, ULW_ALPHA);
+ //ReleaseDC(NULL, sysdc);
+}
+#endif
+
+void Wasabi::Std::Wnd::setWndPos(OSWINDOWHANDLE wnd, OSWINDOWHANDLE zorder, int x, int y, int w, int h,
+ int nozorder, int noactive, int nocopybits, int nomove, int noresize)
+{
+#ifdef _WIN32
+ SetWindowPos(wnd, zorder, x, y, w, h,
+ SWP_DEFERERASE | // we ignore WM_SYNCPAINT anyway
+ (nozorder ? SWP_NOZORDER : 0) |
+ (noactive ? SWP_NOACTIVATE : 0) |
+ (nocopybits ? SWP_NOCOPYBITS : 0) |
+ (nomove ? SWP_NOMOVE : 0) |
+ (noresize ? SWP_NOSIZE : 0));
+#elif defined(__APPLE__)
+ if (!nomove)
+ {
+ MoveWindow(wnd, x, y, false);
+ }
+ if (!noresize)
+ {
+ Rect newRect;
+ newRect.left = x;
+ newRect.right=x+w;
+ newRect.top = y;
+ newRect.bottom = y+h;
+// SetWindowBounds(wnd, kWindowStructureRgn, &newRect);
+ SizeWindow(wnd, w, h, false);
+ }
+ if (!noactive)
+ SelectWindow(wnd);
+ if (!nocopybits)
+ Wasabi::Std::Wnd::invalidateRect(wnd, 0);
+
+#endif
+}
+
+void Wasabi::Std::Wnd::bringToFront(OSWINDOWHANDLE wnd)
+{
+#ifdef _WIN32
+ SetWindowPos(wnd, HWND_TOP, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_DEFERERASE | SWP_NOOWNERZORDER);
+#elif defined(__APPLE__)
+ BringToFront(wnd);
+#endif
+}
+
+void Wasabi::Std::Wnd::sendToBack(OSWINDOWHANDLE wnd)
+{
+#ifdef _WIN32
+ SetWindowPos(wnd, HWND_BOTTOM, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_DEFERERASE | SWP_NOOWNERZORDER);
+#elif defined(__APPLE__)
+ SendBehind(wnd, 0);
+#endif
+}
+
+OSWINDOWHANDLE Wasabi::Std::Wnd::getWindowFromPoint(POINT pt)
+{
+#ifdef _WIN32
+ return ::WindowFromPoint(pt);
+#else
+#warning port me
+return 0;
+#endif
+}
+
+int Wasabi::Std::Wnd::isWndVisible(OSWINDOWHANDLE wnd)
+{
+ return IsWindowVisible(wnd);
+}
+
+void Wasabi::Std::Wnd::showWnd(OSWINDOWHANDLE wnd, int noactivate)
+{
+#ifdef _WIN32
+ ShowWindow(wnd, noactivate ? SW_SHOWNA : SW_SHOWNORMAL);
+#elif defined(__APPLE__)
+ ShowWindow(wnd);
+ if (!noactivate)
+ ActivateWindow(wnd, 1);
+#endif
+}
+
+void Wasabi::Std::Wnd::hideWnd(OSWINDOWHANDLE wnd)
+{
+#ifdef _WIN32
+ ShowWindow(wnd, SW_HIDE);
+#elif defined(__APPLE__)
+ HideWindow(wnd);
+#endif
+}
+
+int Wasabi::Std::Wnd::isPopup(OSWINDOWHANDLE wnd)
+{
+#ifdef _WIN32
+ return !!(GetWindowLong(wnd, GWL_STYLE) & WS_POPUP);
+#elif defined(__APPLE__)
+ return 0; // TODO: maybe use window class or window group to determine
+#endif
+}
+
+#ifdef _WIN32
+void Wasabi::Std::Wnd::setEnabled(OSWINDOWHANDLE wnd, int enabled)
+{
+ EnableWindow(wnd, enabled);
+}
+#endif
+
+void Wasabi::Std::Wnd::setFocus(OSWINDOWHANDLE wnd)
+{
+#ifdef _WIN32
+ SetFocus(wnd);
+#elif defined(__APPLE__)
+ SetUserFocusWindow(wnd);
+#endif
+}
+
+OSWINDOWHANDLE Wasabi::Std::Wnd::getFocus()
+{
+#ifdef _WIN32
+ return GetFocus();
+#elif defined(__APPLE__)
+ return GetUserFocusWindow();
+#endif
+}
+
+#ifdef _WIN32
+void Wasabi::Std::Wnd::setTopmost(OSWINDOWHANDLE wnd, int topmost)
+{
+ SetWindowPos(wnd, topmost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
+}
+#endif
+
+void Wasabi::Std::Wnd::invalidateRect(OSWINDOWHANDLE wnd, RECT *r)
+{
+#ifdef _WIN32
+ OSREGIONHANDLE reg = NULL;
+ if (r == NULL)
+ {
+ RECT cr;
+ if (!IsWindow(wnd))
+ return;
+
+ GetClientRect(wnd, &cr);
+ reg = CreateRectRgnIndirect(&cr);
+ }
+ else
+ reg = CreateRectRgnIndirect(r);
+ invalidateRegion(wnd, reg);
+ DeleteObject(reg);
+#elif defined(__APPLE__)
+ HIViewRef view;
+ GetWasabiHIView(wnd, &view);
+ if (r == 0)
+ {
+ HIViewSetNeedsDisplay(view, true);
+ }
+ else
+ {
+ HIRect rect = CGRectMake(r->left, r->top, r->right-r->left, r->bottom - r->top);
+ HIViewSetNeedsDisplayInRect(view, &rect, true);
+ }
+#endif
+}
+
+
+void Wasabi::Std::Wnd::invalidateRegion(OSWINDOWHANDLE wnd, OSREGIONHANDLE region)
+{
+#ifdef _WIN32
+ clipOSChildren(wnd, region);
+ InvalidateRgn(wnd, region, FALSE);
+#elif defined(__APPLE__)
+ HIViewRef view;
+ GetWasabiHIView(wnd, &view);
+ HIViewSetNeedsDisplayInShape(view, region, true);
+#endif
+}
+
+void Wasabi::Std::Wnd::validateRect(OSWINDOWHANDLE wnd, RECT *r)
+{
+#ifdef _WIN32
+ ValidateRect(wnd, r);
+#elif defined(__APPLE__)
+ HIViewRef view;
+ GetWasabiHIView(wnd, &view);
+ if (r == 0)
+ {
+ HIViewSetNeedsDisplay(view, false);
+ }
+ else
+ {
+ HIRect rect = CGRectMake(r->left, r->top, r->right-r->left, r->bottom - r->top);
+ HIViewSetNeedsDisplayInRect(view, &rect, false);
+ }
+#endif
+}
+
+void Wasabi::Std::Wnd::validateRegion(OSWINDOWHANDLE wnd, OSREGIONHANDLE region)
+{
+#ifdef _WIN32
+ ValidateRgn(wnd, region);
+#elif defined(__APPLE__)
+ HIViewRef view;
+ GetWasabiHIView(wnd, &view);
+ HIViewSetNeedsDisplayInShape(view, region, false);
+#endif
+}
+
+void Wasabi::Std::Wnd::update(OSWINDOWHANDLE wnd)
+{
+#ifdef _WIN32
+ if (wnd != NULL)
+ UpdateWindow(wnd);
+#elif defined(__APPLE__)
+ if (wnd)
+ {
+ HIViewRef view;
+ GetWasabiHIView(wnd, &view);
+ HIViewRender(view);
+ }
+#endif
+}
+
+
+int Wasabi::Std::Wnd::getUpdateRect(OSWINDOWHANDLE wnd, RECT *r)
+{
+#ifdef _WIN32
+ return GetUpdateRect(wnd, r, FALSE);
+#else
+ Rect updateRect;
+ GetWindowBounds(wnd, kWindowUpdateRgn, &updateRect);
+ r->left=updateRect.left;
+ r->right = updateRect.right;
+ r->top = updateRect.top;
+ r->bottom = updateRect.bottom;
+#endif
+}
+
+#ifdef _WIN32
+void Wasabi::Std::Wnd::getUpdateRegion(OSWINDOWHANDLE wnd, OSREGIONHANDLE region)
+{
+ GetUpdateRgn(wnd, region, FALSE);
+}
+#elif defined(__APPLE__)
+// TODO: GetWindowRegion(wnd, kWindowUpdateRgn, region);
+#endif
+
+#ifdef _WIN32
+int Wasabi::Std::Wnd::haveGetRandomRegion()
+{
+ // I assume linux will just return FALSE
+ if (gdi32instance == NULL && !grrfailed)
+ {
+ gdi32instance = LoadLibrary(L"GDI32.dll");
+ if (gdi32instance != NULL)
+ {
+ getRandomRgn = (int(WINAPI *)(HDC, HRGN, int)) GetProcAddress(gdi32instance, "GetRandomRgn");
+ if (getRandomRgn == NULL)
+ {
+ grrfailed = 1;
+ FreeLibrary(gdi32instance);
+ gdi32instance = NULL;
+ }
+ }
+ else
+ {
+ grrfailed = 1;
+ }
+ }
+ return (getRandomRgn != NULL);
+}
+
+void Wasabi::Std::Wnd::getRandomRegion(HDC hdc, OSREGIONHANDLE region)
+{
+ if (!haveGetRandomRegion()) return;
+ (*getRandomRgn)(hdc, region, SYSRGN);
+}
+#endif
+void Wasabi::Std::Wnd::setWndRegion(OSWINDOWHANDLE wnd, OSREGIONHANDLE region, int redraw)
+{
+#ifdef _WIN32
+ SetWindowRgn(wnd, region, !!redraw);
+#elif defined(__APPLE__)
+#warning port me?
+#endif
+}
+#ifdef _WIN32
+int Wasabi::Std::Wnd::isDesktopAlphaAvailable()
+{
+ return 1; // we're only targetting windows 2000 and up, so it's always available
+}
+#endif
+int Wasabi::Std::Wnd::isTransparencyAvailable()
+{
+#ifdef _WIN32
+ // there is no win32 implementation that supports setLayeredWindowAttributes but not updateLayeredWindow
+ return Wasabi::Std::Wnd::isDesktopAlphaAvailable();
+#elif defined(__APPLE__)
+ return 1;
+#else
+#error port me
+#endif
+}
+
+void Wasabi::Std::Wnd::getClientRect(OSWINDOWHANDLE wnd, RECT *r)
+{
+#ifdef _WIN32
+ GetClientRect(wnd, r);
+#elif defined(__APPLE__)
+ Rect temp;
+ GetWindowBounds(wnd, kWindowContentRgn, &temp);
+ r->left = 0;
+ r->top = 0;
+ r->right = temp.right-temp.left;
+ r->bottom = temp.bottom-temp.top;
+#endif
+}
+
+void Wasabi::Std::Wnd::getWindowRect(OSWINDOWHANDLE wnd, RECT *r)
+{
+#ifdef _WIN32
+ GetWindowRect(wnd, r);
+#elif defined(__APPLE__)
+ Rect temp;
+ GetWindowBounds(wnd, kWindowGlobalPortRgn, &temp);
+ r->left = temp.left;
+ r->top = temp.top;
+ r->right = temp.right;
+ r->bottom = temp.bottom;
+#endif
+}
+
+void Wasabi::Std::Wnd::clientToScreen(OSWINDOWHANDLE wnd, int *x, int *y)
+{
+#ifdef _WIN32
+ POINT p = { x ? *x : 0, y ? *y : 0 };
+ ClientToScreen(wnd, &p);
+ if (x) *x = p.x;
+ if (y) *y = p.y;
+#elif defined(__APPLE__)
+ Point pt;
+ pt.h = x?*x:0;
+ pt.v = y?*y:0;
+ QDLocalToGlobalPoint(GetWindowPort(wnd) , &pt);
+ if (x) *x = pt.h;
+ if (y) *y = pt.v;
+#endif
+}
+
+void Wasabi::Std::Wnd::screenToClient(OSWINDOWHANDLE wnd, int *x, int *y)
+{
+#ifdef _WIN32
+ POINT p = { x ? *x : 0, y ? *y : 0 };
+ ScreenToClient(wnd, &p);
+ if (x) *x = p.x;
+ if (y) *y = p.y;
+#elif defined(__APPLE__)
+ Point pt;
+ pt.h = x?*x:0;
+ pt.v = y?*y:0;
+ QDGlobalToLocalPoint(GetWindowPort(wnd) , &pt);
+ if (x) *x = pt.h;
+ if (y) *y = pt.v;
+#endif
+}
+
+#ifdef _WIN32
+void Wasabi::Std::Wnd::setParent(OSWINDOWHANDLE child, OSWINDOWHANDLE newparent)
+{
+ SetParent(child, newparent);
+}
+#endif
+
+OSWINDOWHANDLE Wasabi::Std::Wnd::getParent(OSWINDOWHANDLE wnd)
+{
+#ifdef _WIN32
+ return GetParent(wnd);
+#else
+ return 0;
+#endif
+}
+
+#ifdef _WIN32
+OSWINDOWHANDLE Wasabi::Std::Wnd::getTopmostChild(OSWINDOWHANDLE wnd)
+{
+ return GetWindow(wnd, GW_CHILD);
+}
+
+void Wasabi::Std::Wnd::setCapture(OSWINDOWHANDLE wnd)
+{
+ SetCapture(wnd);
+}
+
+void Wasabi::Std::Wnd::releaseCapture()
+{
+ ReleaseCapture();
+}
+
+OSWINDOWHANDLE Wasabi::Std::Wnd::getCapture()
+{
+ return GetCapture();
+}
+
+void Wasabi::Std::Wnd::revokeDragNDrop(OSWINDOWHANDLE wnd)
+{
+ if (wnd == NULL) return;
+ RevokeDragDrop(wnd);
+}
+#endif
+void Wasabi::Std::Wnd::setWndName(OSWINDOWHANDLE wnd, const wchar_t *name)
+{
+#ifdef _WIN32
+ SetWindowTextW(wnd, name);
+#elif defined(__APPLE__)
+ // TODO:
+ //SetWindowTitleWithCFString(wnd,
+#endif
+}
+
+
+void Wasabi::Std::Wnd::getWndName(OSWINDOWHANDLE wnd, wchar_t *name, int maxlen)
+{
+ #ifdef _WIN32
+ GetWindowTextW(wnd, name, maxlen);
+#else
+ name[0]=0;
+#warning port me
+#endif
+}
+
+void Wasabi::Std::Wnd::setIcon(OSWINDOWHANDLE wnd, OSICONHANDLE icon, int large)
+{
+#ifdef _WIN32
+ SendMessageW(wnd, WM_SETICON, !large ? ICON_SMALL : ICON_BIG, (LPARAM)icon);
+#else
+#warning port me
+#endif
+}
+
+OSWINDOWHANDLE Wasabi::Std::Wnd::getActiveWindow()
+{
+#ifdef _WIN32
+ return GetActiveWindow();
+#elif defined(__APPLE__)
+ return ActiveNonFloatingWindow();
+#endif
+}
+
+void Wasabi::Std::Wnd::setActiveWindow(OSWINDOWHANDLE wnd)
+{
+#ifdef _WIN32
+ SetActiveWindow(wnd);
+#elif defined(__APPLE__)
+ SelectWindow(wnd);
+#endif
+}
+
+#ifdef _WIN32
+// clip oswindow children off the invalidation region
+void Wasabi::Std::Wnd::clipOSChildren(OSWINDOWHANDLE wnd, OSREGIONHANDLE reg)
+{
+ HWND w = GetWindow(wnd, GW_CHILD);
+ while (w != NULL)
+ {
+ if (IsWindowVisible(w))
+ {
+ RECT r;
+ GetClientRect(w, &r);
+ POINT p = {r.left, r.top};
+ ClientToScreen(w, &p);
+ ScreenToClient(wnd, &p);
+ OffsetRect(&r, p.x, p.y);
+ OSREGIONHANDLE cr = CreateRectRgnIndirect(&r);
+ OSREGIONHANDLE or = CreateRectRgn(0, 0, 0, 0);
+ CombineRgn(or, reg, 0, RGN_COPY);
+ CombineRgn(reg, or, cr, RGN_DIFF);
+ DeleteObject(cr);
+ DeleteObject(or);
+ }
+ w = GetWindow(w, GW_HWNDNEXT);
+ }
+}
+
+//////////////////////////
+
+static LRESULT CALLBACK wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ // fetch out the api_window *
+ if (uMsg == WM_CREATE)
+ {
+ CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
+ ASSERT(cs->lpCreateParams != NULL);
+ // stash pointer to self
+ SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)cs->lpCreateParams);
+ }
+
+ // pass the messages into the BaseWnd
+ ifc_window *rootwnd = (ifc_window*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ if (rootwnd == NULL || rootwnd->getOsWindowHandle() != hWnd)
+ {
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+ }
+ else
+ {
+ LRESULT r = 0;
+ switch (uMsg)
+ {
+ case WM_CLOSE:
+ PostMessage(GetParent(hWnd), WM_CLOSE, wParam, lParam);
+ return 0;
+ case WM_NCPAINT: return 0;
+ case WM_SYNCPAINT: return 0;
+ // case WM_SETFOCUS: r = rootwnd->windowEvent(WndEvent::SETFOCUS);
+ // case WM_KILLFOCUS: r = rootwnd->windowEvent(WndEvent::KILLFOCUS);
+ case WM_ACTIVATE:
+ if ( (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) && IsIconic(GetParent(hWnd)) )
+ {
+ ShowWindow(GetParent(hWnd), SW_RESTORE);
+ }
+ r = rootwnd->wndProc(hWnd, uMsg, wParam, lParam);
+ break;
+ case WM_COMMAND:
+ if (HIWORD(wParam) == THBN_CLICKED)
+ {
+ HWND parentWnd = GetParent(hWnd);
+ if (parentWnd == NULL)
+ parentWnd = hWnd;
+
+ switch (LOWORD(wParam))
+ {
+ case 0: //previous
+ {
+ SendMessage(parentWnd, WM_COMMAND, 40044, 0);
+ }
+ break;
+ case 1: //play
+ {
+ SendMessage(parentWnd, WM_COMMAND, 40045, 0);
+ }
+ break;
+ case 2: //pause
+ {
+ SendMessage(parentWnd, WM_COMMAND, 40046, 0);
+ }
+ break;
+ case 3: //stop
+ {
+ SendMessage(parentWnd, WM_COMMAND, 40047, 0);
+ }
+ break;
+ case 4: //next
+ {
+ SendMessage(parentWnd, WM_COMMAND, 40048, 0);
+ }
+ break;
+ }
+ }
+ default:
+ r = rootwnd->wndProc(hWnd, uMsg, wParam, lParam);
+ }
+ if (IsWindow(hWnd)) // wndProc may have switched skin and killed this window
+ rootwnd->performBatchProcesses();
+ return r;
+ }
+}
+
+static void register_wndClass(HINSTANCE hInstance)
+{
+ WNDCLASSW wc;
+ if (GetClassInfoW(hInstance, BASEWNDCLASSNAME, &wc)) return;
+
+ // regiszter pane class
+ wc.style = 0;
+ wc.lpfnWndProc = (WNDPROC)wndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInstance;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = BASEWNDCLASSNAME;
+
+ int r = RegisterClassW(&wc);
+ if (r == 0)
+ {
+ int res = GetLastError();
+ if (res != ERROR_CLASS_ALREADY_EXISTS)
+ {
+ char florp[WA_MAX_PATH] = {0};
+ SPRINTF(florp, "Failed to register class, err %d", res);
+ ASSERTPR(0, florp);
+ }
+ }
+}
+#endif
+
+#ifdef __APPLE__
+
+// TODO: call into BaseWnd and take this out of here
+#include <tataki/canvas/canvas.h>
+#include <tataki/region/region.h>
+#include <api/wnd/basewnd.h>
+
+OSStatus MyWindowEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
+{
+ HICommand hiCommand;
+ OSStatus err = eventNotHandledErr;
+ UInt32 eventClass = GetEventClass(inEvent);
+ UInt32 eventKind = GetEventKind(inEvent);
+ ifc_window *wasabiWnd = (ifc_window *)inUserData;
+ WindowRef window = wasabiWnd->getOsWindowHandle();
+
+ switch (eventClass)
+ {
+ case kEventClassKeyboard:
+ switch (eventKind)
+ {
+ case kEventRawKeyDown:
+ {
+ UInt32 keyCode;
+ GetEventParameter(inEvent, kEventParamKeyCode, typeUInt32,
+ NULL, sizeof(keyCode), NULL, &keyCode);
+
+ if (wasabiWnd->onKeyDown(keyCode))
+ err = noErr;
+ }
+ break;
+ case kEventRawKeyUp:
+ {
+ UInt32 keyCode;
+ GetEventParameter(inEvent, kEventParamKeyCode, typeUInt32,
+ NULL, sizeof(keyCode), NULL, &keyCode);
+
+ if (wasabiWnd->onKeyUp(keyCode))
+ err = noErr;
+ }
+ break;
+ }
+ break;
+ case kEventClassMouse:
+ switch (eventKind)
+ {
+ case kEventMouseDown:
+ {
+ HIPoint point;
+
+ GetEventParameter(inEvent, kEventParamWindowMouseLocation, typeHIPoint,
+ NULL, sizeof(point), NULL, &point);
+
+ EventMouseButton button;
+
+ GetEventParameter(inEvent, kEventParamMouseButton, typeMouseButton,
+ NULL, sizeof(button), NULL, &button);
+
+ UInt32 modifiers;
+ GetEventParameter(inEvent, kEventParamKeyModifiers, typeUInt32,
+ NULL, sizeof(modifiers), NULL, &modifiers);
+
+
+ switch (button)
+ {
+ case kEventMouseButtonPrimary:
+ if (modifiers & controlKey) // fake right click
+ wasabiWnd->onRightButtonDown(point.x, point.y);
+ else
+ wasabiWnd->onLeftButtonDown(point.x, point.y);
+ break;
+ case kEventMouseButtonSecondary:
+ wasabiWnd->onRightButtonDown(point.x, point.y);
+ break;
+ }
+ }
+ break;
+ case kEventMouseUp:
+ {
+ HIPoint point;
+ GetEventParameter(inEvent, kEventParamWindowMouseLocation, typeHIPoint,
+ NULL, sizeof(point), NULL, &point);
+
+ EventMouseButton button;
+ GetEventParameter(inEvent, kEventParamMouseButton, typeMouseButton,
+ NULL, sizeof(button), NULL, &button);
+
+ switch (button)
+ {
+ case kEventMouseButtonPrimary:
+ wasabiWnd->onLeftButtonUp(point.x, point.y);
+ break;
+ case kEventMouseButtonSecondary:
+ wasabiWnd->onRightButtonUp(point.x, point.y);
+ break;
+ }
+ }
+ break;
+ case kEventMouseMoved:
+ case kEventMouseDragged:
+ {
+ HIPoint point;
+ GetEventParameter(inEvent, kEventParamWindowMouseLocation, typeHIPoint,
+ NULL, sizeof(point), NULL, &point);
+
+ wasabiWnd->onMouseMove(point.x, point.y);
+
+ }
+ break;
+ }
+ break;
+ case kEventClassCommand:
+ if (eventKind == kEventProcessCommand)
+ {
+ err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand,
+ NULL, sizeof(HICommand), NULL, &hiCommand);
+
+ switch (hiCommand.commandID)
+ {
+ default:
+ err = eventNotHandledErr;
+ break;
+ }
+ }
+ break;
+ case kEventClassWindow:
+ switch (eventKind)
+ {
+ case kEventWindowBoundsChanging:
+ break;
+ case kEventWindowBoundsChanged:
+ {
+ HIRect bounds;
+ UInt32 attributes;
+ Rect origBounds;
+ Rect currBounds;
+ ControlRef control;
+
+ // Get the change attributes
+ err = GetEventParameter(inEvent, kEventParamAttributes, typeUInt32,
+ NULL, sizeof(UInt32), NULL, &attributes);
+
+ // If the window size changed
+ //kWindowBoundsChangeOriginChanged
+ if (attributes & kWindowBoundsChangeSizeChanged)
+ {
+ GetEventParameter(inEvent, kEventParamOriginalBounds, typeQDRectangle,
+ NULL, sizeof(Rect), NULL, &origBounds);
+
+ GetEventParameter(inEvent, kEventParamCurrentBounds, typeQDRectangle,
+ NULL, sizeof(Rect), NULL, &currBounds);
+
+ // Get the clock control
+ err = GetControlByID( window, &kWasabiID, &control );
+
+ // Hide it (to avoid remnants when downsizing)
+ //HIViewSetVisible( control, false );
+
+ // Resize it
+ HIViewGetFrame( control, &bounds );
+#define QDRECTWIDTH(R) ((R).right - (R).left)
+#define QDRECTHEIGHT(R) ((R).bottom - (R).top)
+
+ bounds.size.width += QDRECTWIDTH( currBounds ) - QDRECTWIDTH( origBounds );
+ bounds.size.height += QDRECTHEIGHT( currBounds ) - QDRECTHEIGHT( origBounds );
+ HIViewSetFrame( control, &bounds );
+
+ // Show it
+ //HIViewSetVisible( control, true );
+
+ }
+ err = noErr;
+ }
+ break;
+ case kEventWindowInit:
+ break;
+ }
+ break;
+
+ }
+
+ return err;
+}
+OSStatus MyControlEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
+{
+ HICommand hiCommand;
+ OSStatus err = eventNotHandledErr;
+ UInt32 eventClass = GetEventClass(inEvent);
+ UInt32 eventKind = GetEventKind(inEvent);
+ ifc_window *wasabiWnd = (ifc_window *)inUserData;
+ switch(eventClass)
+ {
+ case kEventClassControl:
+ switch(eventKind)
+ {
+
+ case kEventControlDraw:
+ {
+ CGContextRef context;
+ RgnHandle rgn;
+ HIShapeRef shape;
+ HIViewRef view;
+ if (GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(context), NULL, &context) == noErr
+ && GetEventParameter(inEvent, kEventParamRgnHandle, typeQDRgnHandle, NULL, sizeof(rgn), NULL, &rgn) == noErr
+ && GetEventParameter(inEvent, kEventParamDirectObject, typeControlRef, NULL, sizeof(view), NULL, &view) == noErr)
+ {
+ GetEventParameter(inEvent, kEventParamShape, typeHIShapeRef, NULL, sizeof(shape), NULL, &shape);
+
+ HIRect bounds;
+ HIViewGetBounds(view, &bounds);
+
+ Canvas canvas(context);
+// RegionI region(rgn);
+ RegionI region(shape);
+
+ //((RootWndI *)wasabiWnd)->rootwnd_paintTree(&canvas, &region);
+ wasabiWnd->paint(&canvas, &region); // TODO: should be virtualOnPaint()
+
+ err = noErr;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ return err;
+}
+#endif
diff --git a/Src/Wasabi/bfc/string/PathString.cpp b/Src/Wasabi/bfc/string/PathString.cpp
new file mode 100644
index 00000000..5bbd8756
--- /dev/null
+++ b/Src/Wasabi/bfc/string/PathString.cpp
@@ -0,0 +1,7 @@
+#include "PathString.h"
+#include <shlwapi.h>
+
+PathString::PathString(const wchar_t *directory, const wchar_t *filename)
+{
+ PathCombineW(path, directory, filename);
+} \ No newline at end of file
diff --git a/Src/Wasabi/bfc/string/PathString.h b/Src/Wasabi/bfc/string/PathString.h
new file mode 100644
index 00000000..324fc16d
--- /dev/null
+++ b/Src/Wasabi/bfc/string/PathString.h
@@ -0,0 +1,21 @@
+#ifndef NULLSOFT_BFC_PATHSTRING_H
+#define NULLSOFT_BFC_PATHSTRING_H
+
+
+#ifdef _WIN32
+#include <windows.h>
+class PathString
+{
+public:
+ PathString(const wchar_t *directory, const wchar_t *filename);
+private:
+ wchar_t path[MAX_PATH];
+};
+
+#else
+
+#error port me!
+
+#endif
+
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/bfc/string/StringW.cpp b/Src/Wasabi/bfc/string/StringW.cpp
new file mode 100644
index 00000000..54408749
--- /dev/null
+++ b/Src/Wasabi/bfc/string/StringW.cpp
@@ -0,0 +1,783 @@
+#include <bfc/wasabi_std.h>
+#include <bfc/std_mem.h>
+#include <bfc/nsguid.h>
+#include "StringW.h"
+#ifdef _WIN32
+#include <shlwapi.h>
+#endif
+
+StringW::StringW(const wchar_t *initial_val)
+ : val(NULL)
+{
+ setValue(initial_val);
+}
+
+StringW::StringW(const StringW &s)
+ : val(NULL)
+{
+ if (s == NULL) setValue(NULL);
+ else setValue(s.getValue());
+}
+
+StringW::StringW(const StringW *s)
+ : val(NULL)
+{
+ if (s == NULL) setValue(NULL);
+ else setValue(s->getValue());
+}
+
+StringW::~StringW()
+{
+ FREE(val);
+ val = NULL;
+}
+
+int StringW::replaceNumericField(int value, wchar_t fieldchar)
+{
+ if (val == NULL || *val == '\0') return 0;
+ int nrep = 0;
+ for (const wchar_t *p = val; *p; p++)
+ {
+ if (*p == fieldchar) nrep++;
+ else if (nrep) break;
+ }
+ if (nrep == 0) return 0; // no field found
+ StringW rc;
+ wchar_t fc[2] = { 0, 0 };
+ fc[0] = fieldchar;
+ for (int i = 0; i < nrep; i++) rc.cat(fc);
+ StringPrintfW fmt(L"%%0%0dd", nrep);
+ StringPrintfW replacement(fmt.getValue(), value);
+ return replace(rc, replacement);
+}
+
+// Returns index of first found, -1 if not found.
+size_t StringW::lFindChar(wchar_t findval)
+{
+ size_t length = len();
+ for (size_t i = 0; i != length; i++)
+ {
+ if (val[i] == findval)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+const wchar_t *StringW::setValue(const wchar_t *newval)
+{
+ if (newval != val)
+ {
+ if ((unsigned long long)newval == NULL || ((unsigned long long)newval <= 65535))
+ {
+ FREE(val);
+ val = NULL;
+ }
+ else
+ {
+ if (val)
+ {
+ size_t len = wcslen(newval);
+ if (val != NULL)
+#ifdef STRING_REALLOC_OPTIMS
+ {
+ size_t oldlen = wcslen(val);
+ // if smaller but greater than half previous size, don't realloc
+ if (len > oldlen || len < oldlen / 2)
+ val = (wchar_t *)REALLOC(val, sizeof(wchar_t) * (len + 1));
+ }
+#else
+ val = (wchar_t *)REALLOC(val, sizeof(wchar_t) * (len + 1));
+#endif
+ else
+ val = WMALLOC(len + 1);
+ ASSERT(newval != NULL);
+ MEMCPY_(val, newval, sizeof(wchar_t)*(len + 1));
+ }
+ else
+ val = WCSDUP(newval);
+ }
+ }
+ return getValue();
+}
+
+int StringW::isequal(const wchar_t *otherval) const
+{
+ // TODO: benski> move to WCSCMPSAFE
+ if (!otherval)
+ otherval = L"";
+ if (!getValue())
+ return !wcscmp(L"", otherval);
+ else
+ return !wcscmp(getValue(), otherval);
+}
+
+int StringW::iscaseequal(const wchar_t *otherval) const
+{
+ return !WCSICMPSAFE(getValue(), otherval);
+}
+
+int StringW::isempty() const
+{
+ return (!val || !*val);
+}
+
+void StringW::toupper()
+{
+ if (!isempty())
+ {
+#ifdef _WIN32
+ CharUpperW(val);
+#else
+ wchar_t *itr = val;
+ while (itr && *itr)
+ {
+ *itr = ::towupper(*itr);
+ itr++;
+ }
+#endif
+ }
+}
+
+void StringW::tolower()
+{
+ if (!isempty())
+ {
+#ifdef _WIN32
+ CharLowerW(val);
+#else
+ wchar_t *itr = val;
+ while (itr && *itr)
+ {
+ *itr = ::towlower(*itr);
+ itr++;
+ }
+#endif
+ }
+}
+
+const wchar_t *StringW::getValueSafe(const wchar_t *def_val) const
+{
+ if (val == NULL)
+ return def_val;
+ else
+ return val;
+}
+
+const wchar_t *StringW::cat(const wchar_t *value)
+{
+ if (value == NULL || *value == 0)
+ return getValue();
+ if (val == NULL)
+ return setValue(value);
+ return catn(value, wcslen(value));
+}
+
+const wchar_t *StringW::catn(const wchar_t *value, size_t len)
+{
+ if (len == 0) return val;
+ if (value == NULL || *value == 0) return getValue();
+ if (val == NULL) return ncpy(value, len);
+ size_t ol = wcslen(val);
+ val = (wchar_t *)REALLOC(val, sizeof(wchar_t) * (ol + len + 1));
+ val[ol + len] = 0;
+ wcsncpy(val + ol, value, len);
+ return val;
+}
+
+// replaces string with n chars of val or length of val, whichever is less.
+const wchar_t *StringW::ncpy(const wchar_t *newstr, size_t numchars)
+{
+ val = (wchar_t *)REALLOC(val, sizeof(wchar_t) * (numchars + 1));
+ val[numchars] = 0;
+ wcsncpy(val, newstr, numchars);
+ return getValue();
+}
+
+// swaps buffers with another string
+void StringW::swap(StringW *swapper)
+{
+ wchar_t *tempChar = swapper->val;
+ swapper->val = val;
+ val = tempChar;
+}
+
+void StringW::swap(StringW &swapper) // swaps buffers with another string
+{
+ wchar_t *tempChar = swapper.val;
+ swapper.val = val;
+ val = tempChar;
+}
+
+// take ownership of a buffer
+void StringW::own(wchar_t *swapper)
+{
+ if (val)
+ FREE(val);
+ val = swapper;
+}
+
+const wchar_t *StringW::catPostSeparator(const wchar_t *value, const wchar_t separator)
+{
+ if (value == NULL || *value == 0 || separator == 0) return getValue();
+ size_t oldLen = val ? wcslen(val) : 0;
+ size_t newLen = wcslen(value);
+ val = (wchar_t *)REALLOC(val, sizeof(wchar_t) * (oldLen + newLen + 1 + 1)); // +1 for separator, +1 for null character
+ wcsncpy(val + oldLen, value, newLen + 1);
+ val[oldLen + newLen] = separator; // add the separator
+ val[oldLen + newLen + 1] = 0; // null terminate
+ return val;
+}
+
+size_t StringW::va_sprintf(const wchar_t *format, va_list args)
+{
+ if (!format) return 0;
+
+ va_list saveargs = args;
+ // roughly evaluate size of dest string
+ const wchar_t *p = format;
+ size_t length = 0;
+ while (p && *p)
+ {
+ if (*(p++) != '%') length++;
+ else
+ {
+ void *arg = va_arg(args, void *);
+ for (;;)
+ {
+ const wchar_t f = *p++;
+ if (f == 'c') length++;
+ else if (f == 'i') length += 16;
+ else if (f == 'u') length += 16;
+ else if (f == 'f') length += 64;
+ else if (f == 'd' || f == 'f') length += 64;
+ else if (f == 'x') length += 32; // Hex with LC Alphas: 0x0009a64c
+ else if (f == 'X') length += 32; // Hex with UC Alphas: 0x0009A64C
+ else if (f == 's')
+ { // ::vsrintf can properly handle null.
+ if (arg == NULL)
+ {
+ length += wcslen(L"(null)"); // Just to be explicit.
+ }
+ else
+ {
+ length += wcslen((const wchar_t *)arg);
+ }
+ }
+ else if (f == 'S') // uppercase S mean narrow string
+ { // ::vsrintf can properly handle null.
+ if (arg == NULL)
+ {
+ length += STRLEN("(null)"); // Just to be explicit.
+ }
+ else
+ {
+ length += STRLEN((const char *)arg);
+ }
+ }
+ else if (ISDIGIT(f)) continue;
+ else if (f == '.') continue;
+ else if (f == '%') length++;
+ else ASSERTPR(0, "undefined format passed to stringprintf!");
+ break;
+ }
+ }
+ }
+ if (val)
+ {
+ if (len() < length)
+ val = (wchar_t *)REALLOC(val, sizeof(wchar_t) * (length + 1));
+ }
+ else
+ val = WMALLOC(length + 1);
+
+ // now write the string in val
+#ifdef _WIN32
+ size_t remain;
+ StringCchVPrintfExW(val, length+1, 0, &remain, 0, format, saveargs);
+ return length-remain;
+#elif defined(__APPLE__)
+ int real_len = ::vswprintf(val, length+1, format, saveargs);
+ ASSERTPR(real_len <= (int)length, "String.printf overflow");
+ return real_len;
+#endif
+
+}
+
+size_t StringW::len() const
+{
+ return (val == NULL) ? 0 : wcslen(val);
+}
+
+void StringW::trunc(int newlen)
+{
+ if (val)
+ {
+ int oldlen = (int)wcslen(val);
+ if (newlen < 0) newlen = MAX(oldlen + newlen, 0);
+ int trimLen = MIN(oldlen, newlen);
+ val[trimLen] = 0;
+ }
+}
+
+int StringW::lastChar()
+{
+ if (isempty()) return -1;
+ return val[len() - 1];
+}
+
+const wchar_t *StringW::prepend(const wchar_t *value)
+{
+ if (value == NULL || *value == 0) return getValue();
+ if (val == NULL) return setValue(value);
+ StringPrintfW temp(L"%s%s", value, getValue());
+ swap(&temp);
+ return getValue();
+}
+
+int StringW::replace(const wchar_t *find, const wchar_t *replace)
+{
+ if (len() == 0 || find == NULL || replace == NULL) return 0;
+
+ int find_count = 0;
+
+ wchar_t *p, *p2;
+ size_t rep_len = wcslen(replace);
+ size_t find_len = wcslen(find);
+ ptrdiff_t size_diff = rep_len - find_len;
+
+ if ( size_diff == 0 )
+ {
+ p = val;
+ while ( p = wcsstr( p, find ) )
+ {
+ wcsncpy( p, replace, rep_len );
+ p += find_len;
+ find_count++;
+ }
+ }
+ else
+ {
+ wchar_t *new_buf, *in;
+
+ p = val;
+ while ( p = wcsstr( p, find ) )
+ {
+ find_count++;
+ p += find_len;
+ }
+
+ int length = (int)( len() + find_count * size_diff + 1 );
+ new_buf = (wchar_t *)MALLOC(sizeof(wchar_t) * length);
+
+ p = val;
+ in = new_buf;
+ while ( p2 = wcsstr( p, find ) )
+ {
+ wcsncpy( in, p, p2 - p );
+ in += p2 - p;
+ wcsncpy( in, replace, rep_len );
+ in += rep_len;
+ p = p2 + find_len;
+ }
+ wcscpy( in, p );
+ new_buf[ len() + find_count * size_diff ] = 0;
+
+ // just swap buffers
+
+ FREE(val);
+ val = new_buf;
+ }
+ return find_count;
+}
+
+const wchar_t *StringW::printf(const wchar_t *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_sprintf(format, args);
+ va_end(args);
+ return getValue();
+}
+
+void StringW::AppendPath(const wchar_t *path)
+{
+ FixSlashes();
+ if (val)
+ {
+#ifdef _WIN32
+ wchar_t temp[MAX_PATH] = {0};
+ PathCombineW(temp, val, path);
+ setValue(temp);
+#else
+#warning find a better way
+ wchar_t temp[PATH_MAX] = {0};
+ swprintf(temp, PATH_MAX, L"%s%s", val, path);
+ setValue(temp);
+#endif
+ }
+ else
+ setValue(path);
+}
+
+void StringW::AppendFolder(const wchar_t *path)
+{
+#ifdef _WIN32
+ FixSlashes();
+ wchar_t temp[MAX_PATH] = {0};
+ if (val)
+ PathCombineW(temp, val, path);
+ else
+ WCSCPYN(temp, path, MAX_PATH);
+
+ PathAddBackslashW(temp);
+ setValue(temp);
+#else
+#warning find a better way
+ wchar_t temp[PATH_MAX] = {0};
+ swprintf(temp, PATH_MAX, L"%s%s/", val, path);
+ setValue(temp);
+#endif
+}
+
+void StringW::AddBackslash()
+{
+ FixSlashes();
+ if (val)
+ {
+#ifdef _WIN32
+ wchar_t temp[MAX_PATH] = {0};
+ WCSCPYN(temp, val, MAX_PATH);
+ PathAddBackslashW(temp);
+#else
+ wchar_t temp[PATH_MAX] = {0};
+ WCSCPYN(temp, val, PATH_MAX);
+ wcscat(temp, L"/");
+#warning port me
+#endif
+ setValue(temp);
+ }
+}
+
+void StringW::changeChar(wchar_t from, wchar_t to)
+{
+ if (val == NULL) return ;
+ size_t length = len();
+ for (size_t i = 0; i != length; i++)
+ if (val[i] == from) val[i] = to;
+}
+
+void StringW::RemovePath()
+{
+#ifdef _WIN32
+ // benski> the OS-level function fucks up if there are forward slashes, so we'll fix it
+ // TODO: remove eventually
+ FixSlashes();
+
+ if (val)
+ PathRemoveFileSpecW(val);
+#else
+#warning port me
+#endif
+}
+
+void StringW::purge()
+{
+ FREE(val);
+ val = NULL;
+}
+
+StringW StringW::rSplitChar(const wchar_t *findval)
+{
+ if (val == NULL) return StringW();
+ // The index of the found character
+ size_t idxval = rFindChar(findval);
+ return rSplit(idxval);
+}
+
+// Same as above, save the "findval" is a string where it searches
+// for any of the characters in the string.
+size_t StringW::rFindChar(const wchar_t *findval)
+{
+ size_t length = len();
+ size_t numchars = wcslen(findval);
+ for (size_t i = length - 1; i > 0; i--)
+ {
+ for (size_t j = 0; j != numchars; j++)
+ {
+ if (val[i] == findval[j])
+ {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+StringW StringW::lSplitChar(const wchar_t *findval)
+{
+ if (val == NULL) return StringW();
+ // The index of the found character
+ size_t idxval = lFindChar(findval);
+ return lSplit(idxval);
+}
+
+// Same as above, save the "findval" is a string where it searches
+// for any of the characters in the string.
+size_t StringW::lFindChar(const wchar_t *findval)
+{
+ size_t length = len();
+ size_t numchars = wcslen(findval);
+ for (size_t i = 0; i != length; i++)
+ {
+ for (size_t j = 0; j != numchars; j++)
+ {
+ if (val[i] == findval[j])
+ {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+StringW StringW::rSplit(size_t idxval)
+{
+ if (val == NULL) return StringW();
+ if (idxval == -1)
+ { // Not Found
+ // Copy our contents to return on the stack
+ StringW retval(val);
+ // And zero the string.
+ val[0] = 0;
+ return retval;
+ }
+ else
+ {
+ // Copy from the found index downwards to the retval
+ StringW retval(val + idxval);
+ // Terminate the found char index
+ val[idxval] = 0;
+ // That was easier, wasn't it?
+ return retval;
+ }
+}
+
+// Splits string at findval. Characters passed by search, including the
+// found character, are MOVED to the returned string. If there is no char
+// to be found, the entire string is returnef and the called instance is
+// left empty. (Makes looped splits very easy).
+StringW StringW::lSplit(size_t idxval)
+{
+ if (val == NULL) return StringW();
+ if (idxval == -1)
+ { // Not Found
+ // Copy our contents to return on the stack
+ StringW retval(val);
+ // And zero the string.
+ if (val)
+ {
+ val[0] = 0;
+ }
+ return retval;
+ }
+ else
+ {
+ StringW retval;
+ // Copy into retval the number of characters to the found char index.
+ retval.ncpy(val, idxval + 1);
+ {
+ StringW testscope;
+ // Copy into retval the number of characters to the found char index.
+ testscope.ncpy(val, idxval + 1);
+ }
+#if USE == FAST_METHODS
+ size_t len = wcslen(val + idxval + 1);
+ MEMCPY(val, val + idxval + 1, sizeof(wchar_t)*(len + 1));
+#elif USE == SAFE_METHODS
+ // Copy from the found index downwards to save for this object
+ StringW temp(val + idxval + 1);
+ // And then copy into ourselves the tempspace.
+ *this = temp;
+#endif
+ return retval;
+ }
+}
+
+// Same as split, except the find char is cut completely.
+StringW StringW::lSpliceChar(const wchar_t *findval)
+{
+ if (val == NULL) return StringW();
+ //CUT // Auto-scope reference allows us to avoid a copy.
+ //CUT String & retval = lSplitChar(findval);
+ //BU gcc doesn't agree with you and neither do I :/
+ StringW retval = lSplitChar(findval);
+ // We need to strip the findval char, which is the end char.
+ size_t end = retval.len();
+ size_t num = wcslen(findval);
+ if (end)
+ {
+ for (size_t i = 0; i != num; i++)
+ {
+ if (retval.val[end - 1] == findval[i])
+ {
+ retval.val[end - 1] = 0;
+ }
+ }
+ }
+ return retval;
+}
+
+StringW StringW::rSpliceChar(const wchar_t *findval)
+{
+ if (val == NULL) return StringW();
+ //CUT // Auto-scope reference allows us to avoid a copy.
+ //CUT String & retval = rSplitChar(findval);
+ //BU gcc doesn't agree with you and neither do I :/
+ StringW retval = rSplitChar(findval);
+ // We need to strip the findval char, which is the first char.
+ // (But we still check for empty string:)
+ size_t end = retval.len();
+ size_t num = wcslen(findval);
+ if (end)
+ {
+ for (size_t i = 0; i != num; i++)
+ {
+ if (retval.val[0] == findval[i])
+ {
+#if USE == FAST_METHODS
+ size_t len = wcslen(retval.val + 1);
+ MEMCPY(retval.val, retval.val + 1, sizeof(wchar_t)*(len + 1));
+#elif USE == SAFE_METHODS
+ StringW temp(retval.val + 1);
+ retval = temp;
+#endif
+ return retval;
+ }
+ }
+ }
+ return retval;
+}
+
+void StringW::FixSlashes()
+{
+ if (val)
+ {
+ wchar_t *itr = val;
+ while (itr && *itr)
+ {
+ if (*itr == '\\' || *itr == '/')
+ *itr = Wasabi::Std::dirChar();
+ #ifdef _WIN32
+ itr = CharNextW(itr);
+#else
+ itr++;
+#endif
+ }
+ }
+}
+
+/* ------------ */
+StringPrintfW::StringPrintfW(const wchar_t *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_sprintf(format, args);
+ va_end(args);
+}
+
+StringPrintfW::StringPrintfW(int value)
+{
+ *this += value;
+}
+
+StringPrintfW::StringPrintfW(double value)
+{
+ // TODO: review to use locale variant...
+ wchar_t* locale = _wcsdup(_wsetlocale(LC_NUMERIC, NULL));
+ _wsetlocale(LC_NUMERIC, L"C");
+ *this += StringPrintfW(L"%f", value);
+ if (locale)
+ {
+ _wsetlocale(LC_NUMERIC, locale);
+ free(locale);
+ }
+}
+
+StringPrintfW::StringPrintfW(GUID g)
+{
+ wchar_t splab[nsGUID::GUID_STRLEN + 1] = {0};
+ nsGUID::toCharW(g, splab);
+ cat(splab);
+}
+
+/* ------------ */
+int StringWComparator::compareItem(StringW *p1, StringW* p2)
+{
+ return wcscmp(p1->getValue(), p2->getValue());
+}
+
+int StringWComparator::compareAttrib(const wchar_t *attrib, StringW *item)
+{
+ return wcscmp(attrib, item->getValue());
+}
+
+/* ------------ */
+_DebugStringW::_DebugStringW(const wchar_t *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_sprintf(format, args);
+ va_end(args);
+ debugPrint();
+}
+
+void _DebugStringW::debugPrint()
+{
+#ifdef _WIN32
+ OutputDebugStringW(getValue());
+ if (lastChar() != L'\n') OutputDebugStringW(L"\n");
+#else
+#warning port me
+#endif
+}
+
+StringPathCombine::StringPathCombine(const wchar_t *path, const wchar_t *filename)
+{
+#ifdef _WIN32
+ wchar_t temp[MAX_PATH] = {0};
+ PathCombineW(temp, path, filename);
+ setValue(temp);
+#else
+ setValue(path);
+ AppendPath(filename);
+#endif
+}
+
+// StringW operators using StringPrintf
+const wchar_t *StringW::operator +=(wchar_t value)
+{
+ wchar_t add[2]={value, 0};
+ return cat(add);
+ // the "Fast" methods and the Printf be
+ // built off of that?
+}
+
+const wchar_t *StringW::operator +=(int value)
+{
+ wchar_t num[64] = {0};
+#ifdef _WIN32
+ _itow(value, num, 10);
+ #else
+ WCSNPRINTF(num, 64, L"%d", value);
+ #endif
+ return cat(num);
+}
+
+const wchar_t *StringW::operator +=(GUID guid)
+{
+ wchar_t guidstr[64] = {0};
+ nsGUID::toCharW(guid, guidstr);
+ return cat(guidstr);
+} \ No newline at end of file
diff --git a/Src/Wasabi/bfc/string/StringW.h b/Src/Wasabi/bfc/string/StringW.h
new file mode 100644
index 00000000..d78a59f1
--- /dev/null
+++ b/Src/Wasabi/bfc/string/StringW.h
@@ -0,0 +1,467 @@
+#ifndef _STRINGW_H_WASABI
+#define _STRINGW_H_WASABI
+
+#ifdef __cplusplus
+
+/**
+ This is a very basic string class. It is not trying to be a be-all end-all
+ string class. It's meant to be just enough functionality to avoid STRDUP().
+ It is available to use in client apps, but no API in Wasabi depends on its
+ use by client code, so you can ignore it if you like. ;)
+ Also note that one of the design goals is to use same storage space as
+ a char *, which means no virtual methods.
+ @short Basic string class, to replace STRDUP/FREE
+ @see StringPrintf
+ @see DebugString
+*/
+
+#include <bfc/platform/types.h>
+
+class StringW
+{
+public:
+ StringW(const wchar_t *initial_val = NULL);
+ StringW(const StringW &s);
+ StringW(const StringW *s);
+ ~StringW();
+
+ /**
+ Returns the value of the string. It is a pointer to the internal storage
+ used by the class, so you must not assume the pointer will not change,
+ because it will.
+ @see getValueSafe();
+ @ret The value of the string.
+ */
+ const wchar_t *getValue() const { return val; }
+ const wchar_t *v() const { return getValue(); } // for ease of typing
+ operator const wchar_t *() const { return getValue(); }
+ /**
+ Gets the value of the string, or a safe value if the value is NULL.
+ @param def_val The value to return if the string's value is NULL. Defaults to "".
+ @see getValue()
+ @ret The value of the string, or a safe value if the value is NULL.
+ */
+ const wchar_t *getValueSafe(const wchar_t *def_val = L"") const; // returns def_val if NULL
+
+ /**
+ Returns the value of the character at a position in the string. If the
+ position is invalid, returns -1. Note that unless bounds_check is set to
+ TRUE, the pos will only be checked for negative values.
+ @param pos The position of the character to return.
+ @param bounds_check If TRUE, pos is checked against the length of the string.
+ @see setChar()
+ @ret The value of the character at the position in the string, or -1 if the position is invalid.
+ */
+ //int getChar(int pos, int bounds_check = FALSE);
+ /**
+ Sets the value of the character at a position in the string. Not multibyte UTF-8 safe yet. No lengthwise bounds checking yet.
+ @param pos The position to set.
+ @param value The value to set.
+ @ret The value of the character set, or -1 if pos < 0.
+ */
+ //int setChar(int pos, int value);
+
+ /**
+ Sets the value of the string. The given value will be copied.
+ Can accept NULL. Note that this may cause the
+ pointer returned by getValue() et al to change.
+ @param newval The new value of the string, nul-terminated.
+ @ret The new value of the string.
+ @see getValue()
+ */
+ const wchar_t *setValue(const wchar_t *newval);
+ /**
+ Gets the value of the string in the form of a non-const wchar_t *. WARNING: you
+ don't usually need to call this. If you want to modify the string,
+ you can generally just use setChar(), or setValue().
+ @ret The value of the string, casted to a non-const wchar_t *.
+ @see getValue()
+ @see setValue();
+ @see setChar();
+ */
+ wchar_t *getNonConstVal() { return const_cast<wchar_t *>(getValue()); }
+ const wchar_t *operator =(const wchar_t *newval) { return setValue(newval); }
+ const wchar_t *operator +=(const wchar_t *addval)
+ {
+ return cat(addval);
+ }
+ const wchar_t *operator +=(wchar_t value);
+ const wchar_t *operator +=(int value);
+ const wchar_t *operator +=(GUID guid);
+
+ // copy assignment operator
+ StringW &operator =(const StringW &s)
+ {
+ if (this != &s)
+ setValue(s);
+ return *this;
+ }
+
+ // comparator operators
+ //inline int operator ==(const wchar_t *val) const
+ //{
+ // if (!val) return isempty();
+ // return isequal(val);
+ //}
+ //inline int operator <(const wchar_t *val) const
+ //{
+ // return islessthan(val);
+ //}
+ //inline int operator !=(const wchar_t *val) const
+ //{
+ // if (!val) return !isempty();
+ // return !isequal(val);
+ //}
+ //inline int operator >(const wchar_t *val) const
+ //{
+ // return (!islessthan(val)) && (!isequal(val));
+ //}
+ inline StringW operator +(const wchar_t *val)
+ {
+ StringW retval = *this;
+ return retval += val;
+ }
+ //inline int operator ==(const StringW &val) const
+ //{
+ // return isequal(val);
+ //}
+ //inline int operator <(const StringW &val) const
+ //{
+ // return islessthan(val);
+ //}
+ //inline int operator !=(const StringW &val) const
+ //{
+ // return !isequal(val);
+ //}
+ //inline int operator >(const StringW &val) const
+ //{
+ // return (!islessthan(val)) && (!isequal(val));
+ //}
+ //inline StringW operator +(const StringW &val)
+ //{
+ // StringW retval = *this;
+ // return retval += val;
+ //}
+ //inline StringW operator +(const wchar_t val)
+ //{
+ // StringW retval = *this;
+ // return retval += val;
+ //}
+
+ /**
+ Gets the length of the string's value. Note that a 0 length can result from
+ both a value of NULL and a value of "".
+ @ret The length of the string's value;
+ */
+ size_t len() const;
+ /**
+ Returns TRUE if the string's value is either NULL or "".
+ @ret TRUE if the string's value is either NULL or "", FALSE otherwise.
+ */
+ int isempty() const;
+ /**
+ Converts entire string to uppercase. Not multibyte UTF-8 safe yet.
+ @see tolower()
+ */
+ void toupper();
+ /**
+ Converts entire string to lowercase. Not multibyte UTF-8 safe yet.
+ @see tolower()
+ */
+ void tolower();
+ /**
+ Checks string value equality against a nul-terminated wchar_t *.
+ @param otherval The value to check against. If NULL, will be treated as "".
+ @ret TRUE if the string matches exactly, FALSE otherwise.
+ @see iscaseequal()
+ @see islessthan()
+ */
+ int isequal(const wchar_t *otherval) const; // basically !strcmp
+ /**
+ Checks string value equality against a nul-terminated wchar_t *, case insensitively. I.e. "Blah" is case equal to "bLaH".
+ @param otherval The value to check against. If NULL, will be treated as "".
+ @ret TRUE if the string matches case-insensitively, FALSE otherwise.
+ @see isequal()
+ @see islessthan()
+ */
+ int iscaseequal(const wchar_t *otherval) const; // basically !strcasecmp
+ //int islessthan(const wchar_t *otherval) const; // basically strcmp < 0
+
+ /**
+ Changes all instances of a character to another character throughout the
+ string. Not multibyte UTF-8 aware yet. Note you can use a 'to' of NULL,
+ but this practice is not encouraged: try to use trunc() or truncateOnChar() instead.
+ @param from The character value to modify.
+ @param to The character value to replace with.
+ @see trunc()
+ @see truncateOnChar()
+ */
+ void changeChar(wchar_t from, wchar_t to);
+ /**
+ Truncates the string value at the first given character value found. If fromright==TRUE, searches from the right, otherwise goes left-to-right. Not UTF-8 multibyte aware yet.
+ Ex:
+ StringW x("abcd");
+ x.truncateOnChar('c');
+ x now contains "ab"
+ @see changeChar()
+ */
+ //void truncateOnChar(int which, int fromright = FALSE);
+
+ /**
+ Gets the last character value (rightmost).
+ @see getChar()
+ @ret The rightmost character value, or -1 if string is empty.
+ */
+ int lastChar(); // -1 if empty
+
+ /**
+ Executes a standard printf type call and sets the string's value to it.
+ @ret The new value of the string.
+ @param format The formatting string to use.
+ */
+ const wchar_t *printf(const wchar_t *format, ...);
+ /**
+ Concatenates the given value onto the end of the string. NULL will be
+ treated as "".
+ @param value The value to concatenate.
+ @ret The new value of the string.
+ @see catn()
+ @see prepend()
+ */
+ const wchar_t *cat(const wchar_t *value);
+ /**
+ Concatenates a certain number of characters from the given value onto the end of the string. NULL will be treated as "".
+ @param value The value to concatenate.
+ @param len How many characters of value to use.
+ @ret The new value of the string.
+ @see cat()
+ @see prepend()
+ */
+ const wchar_t *catn(const wchar_t *value, size_t len);
+
+ /**
+ Useful for making directory paths and stuff
+ adds a string plus a separator character.
+ i.e.
+ StringW x = "/usr/";
+ x.catPostSeparator("bin", '/');
+ creates "/usr/bin/"
+ */
+ const wchar_t *catPostSeparator(const wchar_t *value, const wchar_t separator);
+ /**
+ similiar to above, but puts the separator first
+ i.e.
+ StringW x = "/usr";
+ x.catPostSeparator('/' "bin");
+ creates "/usr/bin"
+ */
+ //const wchar_t *catPreSeparator(const wchar_t separator, const wchar_t *value);
+ /**
+ Inserts the given string value at the beginning of the string. NULL will be
+ treated as "".
+ @param value The value to insert.
+ @ret The new value of the string.
+ @see cat()
+ @see catn()
+ */
+ const wchar_t *prepend(const wchar_t *value);
+ // replaces string with n chars of val or length of val, whichever is less.
+ const wchar_t *ncpy(const wchar_t *newstr, size_t numchars);
+
+ /**
+ Copies up to maxlen chars from the string into the destination. Differs from
+ STRNCPY in that it makes sure the destination is always nul-terminated, so
+ note that maxlen includes the terminating nul.
+ @param dest The destination to copy to.
+ @param maxlen How many bytes, at most, to copy.
+ */
+ //void strncpyTo(wchar_t *dest, int maxlen);
+
+ // -----------------------------------------
+ // Character based find-n-splice methods --
+ // "l" and "r" prefixes specify to begin at
+ // front or back of string:
+
+ // Returns index of first found, -1 if not found.
+ size_t lFindChar(wchar_t findval);
+ size_t lFindChar(const wchar_t *findval); // a list of chars to search for
+ //int rFindChar(wchar_t findval);
+ size_t rFindChar(const wchar_t *findval); // a list of chars to search for
+
+ // Splits string at findval. Characters passed by search, including the
+ // found character, are MOVED to the returned string. If there is no wchar_t
+ // to be found, the entire string is returned and the called instance is
+ // left empty. (Makes looped splits very easy).
+ StringW lSplit(size_t idxval);
+ //StringW lSplitChar(wchar_t findval);
+ StringW lSplitChar(const wchar_t *findval);
+ StringW rSplit(size_t idxval);
+ //StringW rSplitChar(wchar_t findval);
+ StringW rSplitChar(const wchar_t *findval);
+
+ // Same as split, except the find wchar_t is cut completely.
+ //StringW lSpliceChar(wchar_t findval);
+ StringW lSpliceChar(const wchar_t *findval);
+ //StringW rSpliceChar(wchar_t findval);
+ StringW rSpliceChar(const wchar_t *findval);
+
+ /**
+ Replaces all occurences of the value specified by 'find' with the value
+ specified by 'replace'.
+ @param find The value to find.
+ @param replace The value to replace with.
+ @ret The number of replacements that were executed.
+ */
+ int replace(const wchar_t *find, const wchar_t *replace);
+
+ /**
+ Replaces fields of same character with 0-padded text representation of an int.
+ Example: blah$$$$.png becomes blah0000.png
+ */
+ int replaceNumericField(int value, wchar_t fieldchar = '\x24');
+
+ // UTF8-Aware "Character Based" Methods
+ /**
+ Returns how many characters are in the string value. Same as len(), but multibyte UTF-8 aware.
+ @see len()
+ @ret Number of logical UTF-8 character in the string.
+ */
+ //int numCharacters();
+
+ /**
+ Truncates the length of the string to newlen. If newlen is negative, trims
+ -newlen characters from the end. Multibyte UTF-8 aware.
+ @param newlen The new length of the string. If the string is shorter than this, nothing happens. If this value is negative, then the absolute value of newlen is how many characters to trim from the right. I.e. -1 means trim off one character from the end.
+ @see truncateOnChar()
+ */
+ void trunc(int newlen);
+
+// void trim(const wchar_t *whitespace = " \t\r\n", int left = TRUE, int right = TRUE);
+
+ /**
+ Does a vsprintf. Used the same way as printf(), but with a va_list instead of "...".
+ @param format The format string to use.
+ @param args The argument list in va_list format.
+ @ret The number of characters in the final string.
+ */
+ size_t va_sprintf(const wchar_t *format, va_list args);
+
+ /**
+ Ensures that the string drops any memory it might have allocated.
+ */
+ void purge();
+ void swap(StringW *); // swaps buffers with another string
+ void swap(StringW &); // swaps buffers with another string
+ void own(wchar_t *); // take ownership of a buffer
+
+ void AppendPath(const wchar_t *path);
+ void AppendFolder(const wchar_t *path);
+ void AddBackslash();
+ void RemovePath();
+ void FixSlashes();
+protected:
+ wchar_t * val;
+ enum { wastage_allowed = 128 };
+};
+
+
+class StringPathCombine : public StringW
+{
+public:
+ StringPathCombine(const wchar_t *path, const wchar_t *filename);
+};
+
+
+/**
+ StringW class with a printf-style constructor. Otherwise identical to StringW.
+ Also takes some standard types, like int, double, and GUID.
+ @see GUID
+ @see StringW
+*/
+class StringPrintfW : public StringW
+{
+public:
+ StringPrintfW(const wchar_t *format = NULL, ...);
+ StringPrintfW(int value);
+ StringPrintfW(double value);
+ StringPrintfW(GUID g);
+};
+
+
+
+#if defined(NDEBUG) && defined(WASABI_NO_RELEASEMODE_DEBUGSTRINGS)
+#define DebugStringW __noop
+#else
+#define DebugStringW _DebugStringW
+#endif
+
+class _DebugStringW : public StringW
+{
+public:
+ _DebugStringW(const wchar_t *format = NULL, ...);
+ _DebugStringW(const StringW &s);
+ _DebugStringW(const StringW *s);
+
+ void debugPrint();
+};
+
+
+
+#if 0
+
+class StringToLower : public StringW
+{
+public:
+ StringToLower(const char *val = NULL) : StringW(val)
+ {
+ tolower();
+ }
+};
+class StringToUpper : public StringW
+{
+public:
+ StringToUpper(const char *val = NULL) : StringW(val)
+ {
+ toupper();
+ }
+};
+
+
+//
+// Global operator overrides to allow string to take over for
+// the use of standard operators with const char pointers as
+// left hand operands.
+inline int operator ==(const char *v1, const StringW &v2)
+{
+ return v2.isequal(v1);
+}
+inline int operator !=(const char *v1, const StringW &v2)
+{
+ return !v2.isequal(v1);
+}
+inline int operator <(const char *v1, const StringW &v2)
+{
+ return !v2.islessthan(v1);
+}
+inline int operator >(const char *v1, const StringW &v2)
+{
+ return v2.islessthan(v1);
+}
+
+#endif
+/**
+ Compares two strings. Generally used with PtrListSorted<>
+ @see PtrListSorted
+*/
+class StringWComparator
+{
+public:
+ // comparator for sorting
+ static int compareItem(StringW *p1, StringW* p2);
+ // comparator for searching
+ static int compareAttrib(const wchar_t *attrib, StringW *item);
+};
+#endif
+#endif // __cplusplus
+
+
diff --git a/Src/Wasabi/bfc/string/bfcstring.h b/Src/Wasabi/bfc/string/bfcstring.h
new file mode 100644
index 00000000..08bf0202
--- /dev/null
+++ b/Src/Wasabi/bfc/string/bfcstring.h
@@ -0,0 +1,473 @@
+#ifndef _STRING_H_WASABI
+#define _STRING_H_WASABI
+
+#ifdef __cplusplus
+
+/**
+ This is a very basic string class. It is not trying to be a be-all end-all
+ string class. It's meant to be just enough functionality to avoid STRDUP().
+ It is available to use in client apps, but no API in Wasabi depends on its
+ use by client code, so you can ignore it if you like. ;)
+ Also note that one of the design goals is to use same storage space as
+ a char *, which means no virtual methods.
+ @short Basic string class, to replace STRDUP/FREE
+ @see StringPrintf
+ @see DebugString
+*/
+
+#include <bfc/platform/types.h>
+//#include <bfc/std.h>
+#include <stdarg.h>
+
+class String
+{
+public:
+ String(const char *initial_val = NULL);
+ String(const String &s);
+ String(const String *s);
+ ~String();
+
+ /**
+ Returns the value of the string. It is a pointer to the internal storage
+ used by the class, so you must not assume the pointer will not change,
+ because it will.
+ @see getValueSafe();
+ @ret The value of the string.
+ */
+ const char *getValue() const { return val; }
+ const char *v() const { return getValue(); } // for ease of typing
+ operator const char *() const { return getValue(); }
+ /**
+ Gets the value of the string, or a safe value if the value is NULL.
+ @param def_val The value to return if the string's value is NULL. Defaults to "".
+ @see getValue()
+ @ret The value of the string, or a safe value if the value is NULL.
+ */
+ const char *getValueSafe(const char *def_val = "") const; // returns def_val if NULL
+
+ /**
+ Returns the value of the character at a position in the string. If the
+ position is invalid, returns -1. Note that unless bounds_check is set to
+ TRUE, the pos will only be checked for negative values.
+ @param pos The position of the character to return.
+ @param bounds_check If TRUE, pos is checked against the length of the string.
+ @see setChar()
+ @ret The value of the character at the position in the string, or -1 if the position is invalid.
+ */
+ int getChar(int pos, int bounds_check = false);
+ /**
+ Sets the value of the character at a position in the string. Not multibyte UTF-8 safe yet. No lengthwise bounds checking yet.
+ @param pos The position to set.
+ @param value The value to set.
+ @ret The value of the character set, or -1 if pos < 0.
+ */
+ int setChar(int pos, int value);
+
+ /**
+ Sets the value of the string. The given value will be copied.
+ Can accept NULL. Note that this may cause the
+ pointer returned by getValue() et al to change.
+ @param newval The new value of the string, nul-terminated.
+ @ret The new value of the string.
+ @see getValue()
+ */
+ const char *setValue(const char *newval);
+ /**
+ Gets the value of the string in the form of a non-const char *. WARNING: you
+ don't usually need to call this. If you want to modify the string,
+ you can generally just use setChar(), or setValue().
+ @ret The value of the string, casted to a non-const char *.
+ @see getValue()
+ @see setValue();
+ @see setChar();
+ */
+ char *getNonConstVal() { return const_cast<char *>(getValue()); }
+ const char *operator =(const char *newval) { return setValue(newval); }
+ const char *operator +=(const char *addval)
+ {
+ return cat(addval);
+ }
+ const char *operator +=(char value);
+ const char *operator +=(int value);
+ const char *operator +=(GUID guid);
+
+ // copy assignment operator
+ String &operator =(const String &s)
+ {
+ if (this != &s)
+ setValue(s);
+ return *this;
+ }
+
+ // comparator operators
+ inline int operator ==(const char *val) const
+ {
+ if (!val) return isempty();
+ return isequal(val);
+ }
+ inline int operator <(const char *val) const
+ {
+ return islessthan(val);
+ }
+ inline int operator !=(const char *val) const
+ {
+ if (!val) return !isempty();
+ return !isequal(val);
+ }
+ inline int operator >(const char *val) const
+ {
+ return (!islessthan(val)) && (!isequal(val));
+ }
+ inline String operator +(const char *val)
+ {
+ String retval = *this;
+ return retval += val;
+ }
+ inline int operator ==(const String &val) const
+ {
+ return isequal(val);
+ }
+ inline int operator <(const String &val) const
+ {
+ return islessthan(val);
+ }
+ inline int operator !=(const String &val) const
+ {
+ return !isequal(val);
+ }
+ inline int operator >(const String &val) const
+ {
+ return (!islessthan(val)) && (!isequal(val));
+ }
+ inline String operator +(const String &val)
+ {
+ String retval = *this;
+ return retval += val;
+ }
+ inline String operator +(const char val)
+ {
+ String retval = *this;
+ return retval += val;
+ }
+
+ /**
+ Gets the length of the string's value. Note that a 0 length can result from
+ both a value of NULL and a value of "".
+ @ret The length of the string's value;
+ */
+ int len() const;
+ /**
+ Returns TRUE if the string's value is either NULL or "".
+ @ret TRUE if the string's value is either NULL or "", FALSE otherwise.
+ */
+ int isempty() const;
+ /**
+ Converts entire string to uppercase. Not multibyte UTF-8 safe yet.
+ @see tolower()
+ */
+ void toupper();
+ /**
+ Converts entire string to lowercase. Not multibyte UTF-8 safe yet.
+ @see tolower()
+ */
+ void tolower();
+ /**
+ Checks string value equality against a nul-terminated char *.
+ @param otherval The value to check against. If NULL, will be treated as "".
+ @ret TRUE if the string matches exactly, FALSE otherwise.
+ @see iscaseequal()
+ @see islessthan()
+ */
+ int isequal(const char *otherval) const; // basically !strcmp
+ /**
+ Checks string value equality against a nul-terminated char *, case insensitively. I.e. "Blah" is case equal to "bLaH".
+ @param otherval The value to check against. If NULL, will be treated as "".
+ @ret TRUE if the string matches case-insensitively, FALSE otherwise.
+ @see isequal()
+ @see islessthan()
+ */
+ int iscaseequal(const char *otherval) const; // basically !strcasecmp
+ int islessthan(const char *otherval) const; // basically strcmp < 0
+
+ /**
+ Changes all instances of a character to another character throughout the
+ string. Not multibyte UTF-8 aware yet. Note you can use a 'to' of NULL,
+ but this practice is not encouraged: try to use trunc() or truncateOnChar() instead.
+ @param from The character value to modify.
+ @param to The character value to replace with.
+ @see trunc()
+ @see truncateOnChar()
+ */
+ void changeChar(int from, int to);
+ /**
+ Truncates the string value at the first given character value found. If fromright==TRUE, searches from the right, otherwise goes left-to-right. Not UTF-8 multibyte aware yet.
+ Ex:
+ String x("abcd");
+ x.truncateOnChar('c');
+ x now contains "ab"
+ @see changeChar()
+ */
+ void truncateOnChar(int which, int fromright = false);
+
+ /**
+ Gets the last character value (rightmost).
+ @see getChar()
+ @ret The rightmost character value, or -1 if string is empty.
+ */
+ int lastChar(); // -1 if empty
+
+ /**
+ Executes a standard printf type call and sets the string's value to it.
+ @ret The new value of the string.
+ @param format The formatting string to use.
+ */
+ const char *printf(const char *format, ...);
+ /**
+ Concatenates the given value onto the end of the string. NULL will be
+ treated as "".
+ @param value The value to concatenate.
+ @ret The new value of the string.
+ @see catn()
+ @see prepend()
+ */
+ const char *cat(const char *value);
+ /**
+ Concatenates a certain number of characters from the given value onto the end of the string. NULL will be treated as "".
+ @param value The value to concatenate.
+ @param len How many characters of value to use.
+ @ret The new value of the string.
+ @see cat()
+ @see prepend()
+ */
+ const char *catn(const char *value, int len);
+
+ /**
+ Useful for making directory paths and stuff
+ adds a string plus a separator character.
+ i.e.
+ String x = "/usr/";
+ x.catPostSeparator("bin", '/');
+ creates "/usr/bin/"
+ */
+ const char *catPostSeparator(const char *value, const char separator);
+ /**
+ similiar to above, but puts the separator first
+ i.e.
+ String x = "/usr";
+ x.catPostSeparator('/' "bin");
+ creates "/usr/bin"
+ */
+ const char *catPreSeparator(const char separator, const char *value);
+ /**
+ Inserts the given string value at the beginning of the string. NULL will be
+ treated as "".
+ @param value The value to insert.
+ @ret The new value of the string.
+ @see cat()
+ @see catn()
+ */
+ const char *prepend(const char *value);
+ // replaces string with n chars of val or length of val, whichever is less.
+ const char *ncpy(const char *newstr, int numchars);
+
+ /**
+ Copies up to maxlen chars from the string into the destination. Differs from
+ STRNCPY in that it makes sure the destination is always nul-terminated, so
+ note that maxlen includes the terminating nul.
+ @param dest The destination to copy to.
+ @param maxlen How many bytes, at most, to copy.
+ */
+ void strncpyTo(char *dest, int maxlen);
+
+ // -----------------------------------------
+ // Character based find-n-splice methods --
+ // "l" and "r" prefixes specify to begin at
+ // front or back of string:
+
+ // Returns index of first found, -1 if not found.
+ int lFindChar(char findval);
+ int lFindChar(const char *findval); // a list of chars to search for
+ int rFindChar(char findval);
+ int rFindChar(const char *findval); // a list of chars to search for
+
+ // Splits string at findval. Characters passed by search, including the
+ // found character, are MOVED to the returned string. If there is no char
+ // to be found, the entire string is returned and the called instance is
+ // left empty. (Makes looped splits very easy).
+ String lSplit(int idxval);
+ String lSplitChar(char findval);
+ String lSplitChar(const char *findval);
+ String rSplit(int idxval);
+ String rSplitChar(char findval);
+ String rSplitChar(const char *findval);
+
+ // Same as split, except the find char is cut completely.
+ String lSpliceChar(char findval);
+ String lSpliceChar(const char *findval);
+ String rSpliceChar(char findval);
+ String rSpliceChar(const char *findval);
+
+ /**
+ Replaces all occurences of the value specified by 'find' with the value
+ specified by 'replace'.
+ @param find The value to find.
+ @param replace The value to replace with.
+ @ret The number of replacements that were executed.
+ */
+ int replace(const char *find, const char *replace);
+
+ /**
+ Replaces fields of same character with 0-padded text representation of an int.
+ Example: blah$$$$.png becomes blah0000.png
+ */
+ int replaceNumericField(int value, int fieldchar = '\x24');
+
+ // UTF8-Aware "Character Based" Methods
+ /**
+ Returns how many characters are in the string value. Same as len(), but multibyte UTF-8 aware.
+ @see len()
+ @ret Number of logical UTF-8 character in the string.
+ */
+ int numCharacters();
+
+ /**
+ Truncates the length of the string to newlen. If newlen is negative, trims
+ -newlen characters from the end. Multibyte UTF-8 aware.
+ @param newlen The new length of the string. If the string is shorter than this, nothing happens. If this value is negative, then the absolute value of newlen is how many characters to trim from the right. I.e. -1 means trim off one character from the end.
+ @see truncateOnChar()
+ */
+ void trunc(int newlen);
+
+ void trim(const char *whitespace = " \t\r\n", int left = true, int right = true);
+
+ /**
+ Does a vsprintf. Used the same way as printf(), but with a va_list instead of "...".
+ @param format The format string to use.
+ @param args The argument list in va_list format.
+ @ret The number of characters in the final string.
+ */
+ int va_sprintf(const char *format, va_list args);
+
+ /**
+ Ensures that the string drops any memory it might have allocated.
+ */
+ void purge();
+ void swap(String *); // swaps buffers with another string
+ void swap(String &); // swaps buffers with another string
+ void own(char *); // take ownership of a buffer
+
+ void AppendPath(const char *path);
+
+protected:
+ char * val;
+ enum { wastage_allowed = 128 };
+};
+
+/**
+ String class with a printf-style constructor. Otherwise identical to String.
+ Also takes some standard types, like int, double, and GUID.
+ @see GUID
+ @see String
+*/
+class StringPrintf : public String
+{
+public:
+ StringPrintf(const char *format = NULL, ...);
+ StringPrintf(int value);
+ StringPrintf(double value);
+ StringPrintf(GUID g);
+};
+
+class StringToLower : public String
+{
+public:
+ StringToLower(const char *val = NULL) : String(val)
+ {
+ tolower();
+ }
+};
+class StringToUpper : public String
+{
+public:
+ StringToUpper(const char *val = NULL) : String(val)
+ {
+ toupper();
+ }
+};
+
+#if defined(NDEBUG) && defined(WASABI_NO_RELEASEMODE_DEBUGSTRINGS)
+#define DebugString __noop
+#else
+#define DebugString _DebugString
+#endif
+
+class _DebugString : public String
+{
+public:
+ _DebugString(const char *format = NULL, ...);
+ _DebugString(const String &s);
+ _DebugString(const String *s);
+
+ void debugPrint();
+};
+
+
+#define RecycleString String
+
+// String operators using StringPrintf
+
+inline const char *String::operator +=(char value)
+{
+ return cat(StringPrintf("%c", value)); // Uhm. Shouldn't the string be given
+ // the "Fast" methods and the Printf be
+ // built off of that?
+}
+
+inline const char *String::operator +=(int value)
+{
+ return cat(StringPrintf("%i", value));
+}
+
+inline const char *String::operator +=(GUID guid)
+{
+ return cat(StringPrintf(guid));
+}
+
+//
+// Global operator overrides to allow string to take over for
+// the use of standard operators with const char pointers as
+// left hand operands.
+inline int operator ==(const char *v1, const String &v2)
+{
+ return v2.isequal(v1);
+}
+inline int operator !=(const char *v1, const String &v2)
+{
+ return !v2.isequal(v1);
+}
+inline int operator <(const char *v1, const String &v2)
+{
+ return !v2.islessthan(v1);
+}
+inline int operator >(const char *v1, const String &v2)
+{
+ return v2.islessthan(v1);
+}
+
+
+/**
+ Compares two strings. Generally used with PtrListSorted<>
+ @see PtrListSorted
+*/
+class StringComparator
+{
+public:
+ // comparator for sorting
+ static int compareItem(String *p1, String* p2);
+ // comparator for searching
+ static int compareAttrib(const wchar_t *attrib, String *item);
+};
+
+#endif // __cplusplus
+
+#endif
diff --git a/Src/Wasabi/bfc/string/bigstring.cpp b/Src/Wasabi/bfc/string/bigstring.cpp
new file mode 100644
index 00000000..20c7c09f
--- /dev/null
+++ b/Src/Wasabi/bfc/string/bigstring.cpp
@@ -0,0 +1,95 @@
+#include "precomp_wasabi_bfc.h"
+#include "bigstring.h"
+
+BigString::BigString() {
+ mem = NULL;
+ m_linecount = 0;
+}
+
+BigString::~BigString() {
+ if (mem != NULL) {
+ FREE(mem);
+ }
+ strings.deleteAll();
+}
+
+const char *BigString::getValue() /*const*/ {
+ if (mem != NULL) return mem;
+ size_t l = 0;
+ foreach(strings)
+ l += strings.getfor()->len();
+ endfor;
+ mem = (char *)MALLOC(l+1);
+ char *p = mem;
+ String *s = NULL;
+ size_t sl = 0;
+ foreach(strings)
+ s = strings.getfor();
+ sl = s->len();
+ if (sl > 0) MEMCPY((void *)p, (void *)s->getValue(), sl);
+ p += sl;
+ endfor;
+ *p = 0;
+ return mem;
+}
+
+void BigString::setValue(const char *val) {
+ if (mem != NULL) {
+ FREE(mem);
+ mem = NULL;
+ }
+ strings.deleteAll();
+ cat(val);
+}
+
+int BigString::isempty() {
+ if (strings.getNumItems() == 0) return 1;
+ foreach(strings)
+ if (!strings.getfor()->isempty()) return 0;
+ endfor;
+ return 1;
+}
+
+void BigString::reset() {
+ if (mem != NULL) {
+ FREE(mem);
+ mem = NULL;
+ }
+ strings.deleteAll();
+ m_linecount = 0;
+}
+
+void BigString::catn(const char *s, int n) {
+ String *str = new String();
+ str->catn(s, n);
+ cat(str->getValue());
+}
+
+void BigString::cat(const char *s) {
+ if (mem != NULL) {
+ FREE(mem);
+ mem = NULL;
+ }
+ char *p = (char *)s;
+ while (p && *p) {
+ if (*p == '\r' || *p == '\n') {
+ if (*(p+1) == '\n' && *p == '\r') p++;
+ m_linecount++;
+ }
+ p++;
+ }
+ strings.addItem(new String(s));
+}
+
+char BigString::lastChar() {
+ return strings.getLast()->lastChar();
+}
+
+char BigString::firstChar() {
+ const char *s = strings.getFirst()->getValue();
+ return s ? *s : 0;
+}
+
+int BigString::getLineCount() {
+ return m_linecount;
+}
diff --git a/Src/Wasabi/bfc/string/bigstring.h b/Src/Wasabi/bfc/string/bigstring.h
new file mode 100644
index 00000000..ef2ff207
--- /dev/null
+++ b/Src/Wasabi/bfc/string/bigstring.h
@@ -0,0 +1,56 @@
+#ifndef __BIGSTRING_H
+#define __BIGSTRING_H
+
+/*
+
+A class tor concatenate chunks of texts into one big pool. This is much faster than using String if you are adding
+a lot of tiny pieces into one giant block (a typical cases of this is when writing xml). Upon request for the value,
+the class allocates one big block of memory and copies all the strings into it serially (as opposed to String
+reallocating the entire block at each concatenation). Note that because of the type of implementation BigString has
+to use, you cannot get the full block as a return value to your concatenations and assignments (+= and = return void).
+To do this, request the value explicitely (this should be kept to a strict minimum or the advantage of BigString over
+String will disapear)
+
+*/
+
+#include <bfc/string/bfcstring.h>
+#include <bfc/ptrlist.h>
+
+class BigString {
+ public:
+ BigString();
+ virtual ~BigString();
+
+ operator const char *() /*const*/ { return getValue(); }
+ const char *getValue() /*const*/;
+ char *getNonConstVal() { return (char *)getValue(); }
+ void setValue(const char *val);
+ // copy assignment operator
+ BigString& operator =(/*const*/ BigString &s) {
+ if (this != &s)
+ setValue(s);
+ return *this;
+ }
+
+ void operator =(const char *newval) { setValue(newval); }
+ void operator +=(const char *addval) {
+ cat(addval);
+ }
+
+ int isempty();
+
+ void reset();
+
+ void catn(const char *s, int n);
+ void cat(const char *s);
+ char lastChar();
+ char firstChar();
+ int getLineCount();
+
+ private:
+ PtrList<String> strings;
+ char *mem;
+ int m_linecount;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/string/encodedstr.cpp b/Src/Wasabi/bfc/string/encodedstr.cpp
new file mode 100644
index 00000000..eddba7da
--- /dev/null
+++ b/Src/Wasabi/bfc/string/encodedstr.cpp
@@ -0,0 +1,156 @@
+#include "precomp_wasabi_bfc.h"
+// someday, there will be a file here.
+#include <bfc/wasabi_std.h>
+#include "encodedstr.h"
+#include <bfc/string/bfcstring.h>
+#include <api/service/svcs/svc_stringconverter.h>
+#include <api/memmgr/api_memmgr.h>
+EncodedStr::EncodedStr(FOURCC encodingType, void *encodedBuffer, int bufferSize, int deleteIt) {
+ encoding_type = encodingType;
+ encoded_buffer = encodedBuffer;
+ buffer_size = bufferSize;
+ delete_it = deleteIt;
+}
+
+EncodedStr::~EncodedStr() {
+ if (delete_it && (encoded_buffer != NULL)) {
+#ifdef WASABI_COMPILE_MEMMGR
+ WASABI_API_MEMMGR->sysFree(encoded_buffer);
+#else
+ free(encoded_buffer);
+#endif
+ }
+}
+
+void EncodedStr::resetBuffer(FOURCC encodingType, void *encodedBuffer, int bufferSize, int deleteIt) {
+ // if there's someone already there, toss them.
+ if (delete_it && (encoded_buffer != NULL)) {
+#ifdef WASABI_COMPILE_MEMMGR
+ WASABI_API_MEMMGR->sysFree(encoded_buffer);
+#else
+ free(encoded_buffer);
+#endif
+ }
+ encoding_type = encodingType;
+ encoded_buffer = encodedBuffer;
+ buffer_size = bufferSize;
+ delete_it = deleteIt;
+}
+
+int EncodedStr::convertToUTF8(String &output_str) {
+ int retval = 0;
+ StringConverterEnum myServiceEnum(encoding_type);
+ svc_stringConverter *myConv = myServiceEnum.getFirst();
+ if (myConv != NULL) {
+
+ void *in_buffer = encoded_buffer;
+ int size_in_bytes = buffer_size;
+
+ if (encoded_buffer != NULL) {
+ // Preflight
+ int u8size = myConv->preflightToUTF8(encoding_type, in_buffer, size_in_bytes);
+ // Alloc
+#ifdef WASABI_COMPILE_MEMMGR
+ char *u8str = reinterpret_cast<char *>(WASABI_API_MEMMGR->sysMalloc(u8size));
+#else
+ char *u8str = reinterpret_cast<char *>(MALLOC(u8size));
+#endif
+ if (u8str != NULL) {
+ // Convert
+ retval = myConv->convertToUTF8(encoding_type, in_buffer, size_in_bytes, u8str, u8size);
+ if (retval < 0) {
+ // Clear on error.
+#ifdef WASABI_COMPILE_MEMMGR
+ WASABI_API_MEMMGR->sysFree(u8str);
+#else
+ free(encoded_buffer);
+#endif
+ u8str = NULL;
+ }
+ } else {
+ ASSERTPR(u8str != NULL, "Malloc failed in string converter\n");
+ }
+ // And call the method to inject the pointer into our string (cleared on error).
+ output_str.setValue(u8str);
+ }
+
+ // Once we use our service, release our locked instance of it.
+ myServiceEnum.release(myConv);
+ } else {
+ // Clear the string on error.
+ retval = SvcStrCnv::ERROR_UNAVAILABLE;
+ output_str.setValue(NULL);
+ }
+ return retval;
+}
+
+int EncodedStr::convertFromUTF8(FOURCC encodingType, const String &inputStr) {
+ int retval = 0;
+ int written = 0;
+ void *buffer = NULL;
+ StringConverterEnum myServiceEnum(encodingType);
+ svc_stringConverter *myConv = myServiceEnum.getFirst();
+
+ if (myConv != NULL) {
+ if (inputStr != NULL) {
+ const char *val = inputStr.getValue();
+ int valsize = STRLEN(val) + 1; // count the null char in your size-in-bytes!
+ // Preflight
+ int size = myConv->preflightFromUTF8(encodingType, val, valsize);
+ if (size > 0) {
+ // Alloc
+#ifdef WASABI_COMPILE_MEMMGR
+ buffer = WASABI_API_MEMMGR->sysMalloc(size);
+#else
+ buffer = MALLOC(size);
+#endif
+ if (buffer != NULL) {
+ // Convert
+ written = myConv->convertFromUTF8(encodingType, val, valsize, buffer, size);
+ if (written > 0) {
+ retval = written;
+ } else {
+ // Clear on error.
+#ifdef WASABI_COMPILE_MEMMGR
+ WASABI_API_MEMMGR->sysFree(buffer);
+#else
+ free(buffer);
+#endif
+ buffer = NULL;
+ retval = written;
+ written = 0;
+ }
+ } else {
+ ASSERTPR(buffer != NULL, "Malloc failed in string converter\n");
+ }
+ } else {
+ // Clear on error.
+ buffer = NULL;
+ retval = size;
+ written = 0;
+ }
+ }
+ // Once we use our service, release our locked instance of it.
+ myServiceEnum.release(myConv);
+ } else {
+ // On error locking down a service, all the default values are errors and called through resetBuffer.
+ retval = SvcStrCnv::ERROR_UNAVAILABLE;
+ }
+ resetBuffer(encodingType, buffer, written);
+ return retval;
+}
+
+// This is for debugging.
+int EncodedStr::operator ==(const EncodedStr &in_string) {
+ if (encoding_type == in_string.encoding_type) {
+ switch (encoding_type) {
+ case SvcStrCnv::OSNATIVE:
+ return (STRCMP(reinterpret_cast<char *>(encoded_buffer), reinterpret_cast<char *>(in_string.encoded_buffer)) == 0);
+ break;
+ default:
+ return 0;
+ break;
+ }
+ }
+ return 0;
+}
diff --git a/Src/Wasabi/bfc/string/encodedstr.h b/Src/Wasabi/bfc/string/encodedstr.h
new file mode 100644
index 00000000..ee5e49c0
--- /dev/null
+++ b/Src/Wasabi/bfc/string/encodedstr.h
@@ -0,0 +1,42 @@
+#ifndef _ENCODEDSTR_H
+#define _ENCODEDSTR_H
+
+#include <api/service/svcs/svc_stringtypes.h>
+
+class String;
+
+class EncodedStr {
+public:
+ // The EncodedStr object will automatically delete its ram, unless you
+ // specify 0 in that "delete it" parameter there, partner.
+ EncodedStr(FOURCC encodingType = 0, void *encodedBuffer = NULL, int bufferSize = 0, int deleteIt = 1);
+ ~EncodedStr();
+
+ // A "reset" will ensure any previously set buffer will be deleted
+ void resetBuffer(FOURCC encodingType, void *encodedBuffer, int bufferSize, int deleteIt = 1);
+
+ // All the calls to the service level functions are through here.
+ int convertToUTF8(String &output_str);
+ // This method will reset this object (ie: delete RAM if necessary)
+ int convertFromUTF8(FOURCC encodingType, const String &inputStr);
+
+ // Accessor inlines
+ inline FOURCC getEncodingType() { return encoding_type; }
+ inline void *getEncodedBuffer() { return encoded_buffer; }
+ inline int getBufferSize() { return buffer_size; }
+ inline int getDeleteIt() { return delete_it; }
+
+// This is for debugging.
+ int operator ==(const EncodedStr &in_string);
+
+private:
+ FOURCC encoding_type;
+ void * encoded_buffer;
+ int buffer_size;
+ int delete_it;
+};
+
+
+#endif//_ENCODEDSTR_H
+
+
diff --git a/Src/Wasabi/bfc/string/playstring.cpp b/Src/Wasabi/bfc/string/playstring.cpp
new file mode 100644
index 00000000..88583265
--- /dev/null
+++ b/Src/Wasabi/bfc/string/playstring.cpp
@@ -0,0 +1,57 @@
+#include "precomp_wasabi_bfc.h"
+
+#include "playstring.h"
+
+#define USE_TABLE
+
+Playstring::Playstring(const wchar_t *_val) {
+ val = NULL;
+ setValue(_val);
+}
+
+Playstring::Playstring(const Playstring &ps) {
+ val = NULL;
+ setValue(ps.getValue());
+}
+
+Playstring::~Playstring() {
+ setValue(NULL);
+}
+
+void Playstring::setValue(const wchar_t *newval) {
+ _setValue(newval, 0);
+}
+
+void Playstring::_setValue(const wchar_t *newval, int tablenum)
+{
+#ifdef USE_TABLE
+#ifdef WASABI_COMPILE_METADB
+ if (val != NULL) WASABI_API_METADB->metadb_releasePlaystring(val, tablenum);
+#else
+ FREE((void*)val);
+#endif
+#else
+ FREE((void*)val);
+#endif
+
+ val = NULL;
+
+ if (newval != NULL /*&& *newval != 0*/) {
+#ifdef USE_TABLE
+#ifdef WASABI_COMPILE_METADB
+ val = WASABI_API_METADB->metadb_dupPlaystring(newval, tablenum);
+#else
+ val = WCSDUP(newval);
+#endif
+#else
+ val = STRDUP(newval);
+#endif
+ }
+}
+
+Playstring& Playstring::operator =(const Playstring &ps) {
+ if (this != &ps) {
+ setValue(ps.getValue());
+ }
+ return *this;
+}
diff --git a/Src/Wasabi/bfc/string/playstring.h b/Src/Wasabi/bfc/string/playstring.h
new file mode 100644
index 00000000..2e9b183f
--- /dev/null
+++ b/Src/Wasabi/bfc/string/playstring.h
@@ -0,0 +1,49 @@
+#ifndef _PLAYSTRING_H
+#define _PLAYSTRING_H
+
+#include <bfc/common.h>
+#include <bfc/string/StringW.h>
+
+class Playstring
+{
+public:
+ Playstring(const wchar_t *val=NULL);
+ Playstring(const Playstring &ps);
+ ~Playstring();
+
+ const wchar_t *getValue() const { return val; }
+ operator const wchar_t *() const { return getValue(); }
+
+ void setValue(const wchar_t *newval);
+
+ // copy
+ Playstring& operator =(const Playstring &ps);
+
+protected:
+ void _setValue(const wchar_t *newval, int tablenum);
+
+private:
+ const wchar_t *val;
+};
+
+class PlaystringComparator {
+public:
+ // comparator for sorting
+ static int compareItem(Playstring *p1, Playstring* p2) {
+ return wcscmp(p1->getValue(), p2->getValue());
+ }
+};
+
+template <int tablenum=0>
+class PlaystringT : public Playstring {
+public:
+ PlaystringT(const wchar_t *newval) {
+ val = NULL; setValue(newval);
+ }
+ PlaystringT(const Playstring &ps) {
+ val = NULL; setValue(ps.getValue());
+ }
+ void setValue(const wchar_t *newval) { _setValue(newval, tablenum); }
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/string/string.cpp b/Src/Wasabi/bfc/string/string.cpp
new file mode 100644
index 00000000..49b7aade
--- /dev/null
+++ b/Src/Wasabi/bfc/string/string.cpp
@@ -0,0 +1,884 @@
+#include <bfc/wasabi_std.h>
+#include "string.h"
+#include <bfc/nsguid.h>
+
+String::String(const char *initial_val)
+ : val(NULL)
+{
+ setValue(initial_val);
+}
+
+String::String(const String &s)
+ : val(NULL)
+{
+ if (s == NULL) setValue(NULL);
+ else setValue(s.getValue());
+}
+
+String::String(const String *s)
+ : val(NULL)
+{
+ if (s == NULL) setValue(NULL);
+ else setValue(s->getValue());
+}
+
+String::~String()
+{
+ FREE(val);
+}
+
+const char *String::getValueSafe(const char *def_val) const
+{
+ if (val == NULL)
+ return def_val;
+ else
+ return val;
+}
+
+int String::getChar(int pos, int bounds_check)
+{
+ if (pos < 0 || val == NULL) return -1;
+ if (bounds_check && pos >= len()) return -1;
+ return val[pos];
+}
+
+int String::setChar(int pos, int value)
+{
+ if (pos < 0 || val == NULL) return -1;
+ return val[pos] = value;
+}
+
+const char *String::setValue(const char *newval)
+{
+ if (newval != val)
+ {
+ if (newval == NULL)
+ {
+ FREE(val);
+ val = NULL;
+ }
+ else
+ {
+ int len = STRLEN(newval);
+ if (val != NULL)
+#ifdef STRING_REALLOC_OPTIMS
+ {
+ int oldlen = STRLEN(val);
+ // if smaller but greater than half previous size, don't realloc
+ if (len > oldlen || len < oldlen / 2)
+ val = (char *)REALLOC(val, len + 1);
+ }
+#else
+ val = (char *)REALLOC(val, len + 1);
+#endif
+ else
+ val = (char *)MALLOC(len + 1);
+ ASSERT(newval != NULL);
+ MEMCPY_(val, newval, len + 1);
+ }
+ }
+ return getValue();
+}
+
+int String::len() const
+{
+ return (val == NULL) ? 0 : STRLEN(val);
+}
+
+int String::isempty() const
+{
+ return (!val || !*val);
+}
+
+void String::toupper()
+{
+ if (!isempty())
+ STRTOUPPER(val);
+}
+
+void String::tolower()
+{
+ if (!isempty())
+ STRTOLOWER(val);
+}
+
+int String::isequal(const char *otherval) const
+{
+ return !STRCMPSAFE(getValue(), otherval);
+}
+
+int String::iscaseequal(const char *otherval) const
+{
+ return !STRICMPSAFE(getValue(), otherval);
+}
+
+int String::islessthan(const char *otherval) const
+{
+ return STRCMPSAFE(getValue(), otherval) < 0;
+}
+
+void String::changeChar(int from, int to)
+{
+ if (val == NULL) return ;
+ int length = len();
+ for (int i = 0; i < length; i++)
+ if (val[i] == from) val[i] = to;
+}
+
+void String::truncateOnChar(int which, int fromright)
+{
+ if (fromright)
+ {
+ if (val == NULL) return ;
+ int length = len();
+ for (int i = length - 1; i >= 0; i--)
+ {
+ if (val[i] == which)
+ {
+ val[i] = '\0';
+ return ;
+ }
+ }
+ }
+ else
+ {
+ changeChar(which, '\0');
+ }
+}
+
+int String::lastChar()
+{
+ if (isempty()) return -1;
+ return val[len() - 1];
+}
+
+const char *String::printf(const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_sprintf(format, args);
+ va_end(args);
+ return getValue();
+}
+
+const char *String::cat(const char *value)
+{
+ if (value == NULL || *value == 0) return getValue();
+ if (val == NULL) return setValue(value);
+ return catn(value, STRLEN(value));
+}
+
+const char *String::catn(const char *value, int len)
+{
+ if (len == 0) return val;
+ if (value == NULL || *value == 0) return getValue();
+ if (val == NULL) return ncpy(value, len);
+ int ol = STRLEN(val);
+ val = (char *)REALLOC(val, ol + len + 1);
+ val[ol + len] = 0;
+ STRNCPY(val + ol, value, len);
+ return val;
+}
+
+const char *String::prepend(const char *value)
+{
+ if (value == NULL || *value == 0) return getValue();
+ if (val == NULL) return setValue(value);
+ StringPrintf temp("%s%s", value, getValue());
+ swap(&temp);
+ return getValue();
+}
+
+// replaces string with n chars of val or length of val, whichever is less.
+const char *String::ncpy(const char *newstr, int numchars)
+{
+ val = (char *)REALLOC(val, numchars + 1);
+ val[numchars] = 0;
+ STRNCPY(val, newstr, numchars);
+ return getValue();
+}
+
+void String::strncpyTo(char *dest, int maxlen)
+{
+ ASSERT(dest != NULL);
+ ASSERT(maxlen >= 0);
+ if (maxlen == 0) return ;
+ else if (maxlen == 1)
+ {
+ *dest = '\0';
+ return ;
+ }
+ const char *src = val;
+ if (src == NULL) src = "";
+ int copylen = MIN(STRLEN(src), maxlen);
+ if (maxlen == copylen) copylen--; // make room for 0-termination
+ MEMCPY(dest, src, copylen);
+ dest[copylen] = 0;
+}
+
+// -----------------------------------------
+// Character based find-n-splice methods --
+// "l" and "r" prefixes specify to begin at
+// front or back of string:
+
+#ifdef FAST_METHODS
+#undef FAST_METHODS
+#endif//FAST_METHODS
+#ifdef SAFE_METHODS
+#undef SAFE_METHODS
+#endif//SAFE_METHODS
+#ifdef USE
+#undef USE
+#endif//USE
+
+#define FAST_METHODS 1
+#define SAFE_METHODS 0
+
+#define USE FAST_METHODS
+
+// Returns index of first found, -1 if not found.
+int String::lFindChar(char findval)
+{
+ int length = len();
+ for (int i = 0; i < length; i++)
+ {
+ if (val[i] == findval)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+// Same as above, save the "findval" is a string where it searches
+// for any of the characters in the string.
+int String::lFindChar(const char *findval)
+{
+ int length = len();
+ int numchars = STRLEN(findval);
+ for (int i = 0; i < length; i++)
+ {
+ for (int j = 0; j < numchars; j++)
+ {
+ if (val[i] == findval[j])
+ {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+int String::rFindChar(char findval)
+{
+ int length = len();
+ for (int i = length - 1; i > 0; i--)
+ {
+ if (val[i] == findval)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+// Same as above, save the "findval" is a string where it searches
+// for any of the characters in the string.
+int String::rFindChar(const char *findval)
+{
+ int length = len();
+ int numchars = STRLEN(findval);
+ for (int i = length - 1; i > 0; i--)
+ {
+ for (int j = 0; j < numchars; j++)
+ {
+ if (val[i] == findval[j])
+ {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+// Splits string at findval. Characters passed by search, including the
+// found character, are MOVED to the returned string. If there is no char
+// to be found, the entire string is returnef and the called instance is
+// left empty. (Makes looped splits very easy).
+String String::lSplit(int idxval)
+{
+ if (val == NULL) return String();
+ if (idxval == -1)
+ { // Not Found
+ // Copy our contents to return on the stack
+ String retval(val);
+ // And zero the string.
+ if (val)
+ {
+ val[0] = 0;
+ }
+ return retval;
+ }
+ else
+ {
+ String retval;
+ // Copy into retval the number of characters to the found char index.
+ retval.ncpy(val, idxval + 1);
+ {
+ String testscope;
+ // Copy into retval the number of characters to the found char index.
+ testscope.ncpy(val, idxval + 1);
+ }
+#if USE == FAST_METHODS
+ size_t len = strlen(val + idxval + 1);
+ MEMCPY(val, val + idxval + 1, len + 1);
+#elif USE == SAFE_METHODS
+ // Copy from the found index downwards to save for this object
+ String temp(val + idxval + 1);
+ // And then copy into ourselves the tempspace.
+ *this = temp;
+#endif
+ return retval;
+ }
+ // this will never be hit. many compilers are too stupid to realize this.
+ return String();
+}
+
+String String::lSplitChar(char findval)
+{
+ if (val == NULL) return String();
+ // The index of the found character
+ int idxval = lFindChar(findval);
+ return lSplit(idxval);
+}
+
+String String::lSplitChar(const char *findval)
+{
+ if (val == NULL) return String();
+ // The index of the found character
+ int idxval = lFindChar(findval);
+ return lSplit(idxval);
+}
+
+String String::rSplit(int idxval)
+{
+ if (val == NULL) return String();
+ if (idxval == -1)
+ { // Not Found
+ // Copy our contents to return on the stack
+ String retval(val);
+ // And zero the string.
+ val[0] = 0;
+ return retval;
+ }
+ else
+ {
+ // Copy from the found index downwards to the retval
+ String retval(val + idxval);
+ // Terminate the found char index
+ val[idxval] = 0;
+ // That was easier, wasn't it?
+ return retval;
+ }
+ // this will never be hit. many compilers are too stupid to realize this.
+ return String();
+}
+
+String String::rSplitChar(char findval)
+{
+ if (val == NULL) return String();
+ // The index of the found character
+ int idxval = rFindChar(findval);
+ return rSplit(idxval);
+}
+
+String String::rSplitChar(const char *findval)
+{
+ if (val == NULL) return String();
+ // The index of the found character
+ int idxval = rFindChar(findval);
+ return rSplit(idxval);
+}
+
+// Same as split, except the find char is cut completely.
+String String::lSpliceChar(char findval)
+{
+ if (val == NULL) return String();
+ //CUT // Auto-scope reference allows us to avoid a copy.
+ //CUT String & retval = lSplitChar(findval);
+ //BU gcc doesn't agree with you and neither do I :/
+ String retval = lSplitChar(findval);
+
+ // We need to strip the findval char, which is the end char.
+ int end = retval.len();
+ if (end)
+ {
+ if (retval.val[end - 1] == findval)
+ {
+ retval.val[end - 1] = 0;
+ }
+ }
+ return retval;
+}
+
+// Same as split, except the find char is cut completely.
+String String::lSpliceChar(const char *findval)
+{
+ if (val == NULL) return String();
+ //CUT // Auto-scope reference allows us to avoid a copy.
+ //CUT String & retval = lSplitChar(findval);
+ //BU gcc doesn't agree with you and neither do I :/
+ String retval = lSplitChar(findval);
+ // We need to strip the findval char, which is the end char.
+ int end = retval.len();
+ int num = STRLEN(findval);
+ if (end)
+ {
+ for (int i = 0; i < num; i++)
+ {
+ if (retval.val[end - 1] == findval[i])
+ {
+ retval.val[end - 1] = 0;
+ }
+ }
+ }
+ return retval;
+}
+
+String String::rSpliceChar(char findval)
+{
+ if (val == NULL) return String();
+ //CUT // Auto-scope reference allows us to avoid a copy.
+ //CUT String & retval = rSplitChar(findval);
+ //BU gcc doesn't agree with you and neither do I :/
+ String retval = rSplitChar(findval);
+ // We need to strip the findval char, which is the first char.
+ // (But we still check for empty string:)
+ size_t end = retval.len();
+ if (end)
+ {
+ if (retval.val[0] == findval)
+ {
+#if USE == FAST_METHODS
+ size_t len = strlen(retval.val + 1);
+ MEMCPY(retval.val, retval.val + 1, len + 1);
+#elif USE == SAFE_METHODS
+ String temp(retval.val + 1);
+ retval = temp;
+#endif
+ return retval;
+ }
+ }
+ return retval;
+}
+
+String String::rSpliceChar(const char *findval)
+{
+ if (val == NULL) return String();
+ //CUT // Auto-scope reference allows us to avoid a copy.
+ //CUT String & retval = rSplitChar(findval);
+ //BU gcc doesn't agree with you and neither do I :/
+ String retval = rSplitChar(findval);
+ // We need to strip the findval char, which is the first char.
+ // (But we still check for empty string:)
+ size_t end = retval.len();
+ size_t num = STRLEN(findval);
+ if (end)
+ {
+ for (size_t i = 0; i < num; i++)
+ {
+ if (retval.val[0] == findval[i])
+ {
+#if USE == FAST_METHODS
+ size_t len = strlen(retval.val + 1);
+ MEMCPY(retval.val, retval.val + 1, len + 1);
+#elif USE == SAFE_METHODS
+ String temp(retval.val + 1);
+ retval = temp;
+#endif
+ return retval;
+ }
+ }
+ }
+ return retval;
+}
+
+int String::replace(const char *find, const char *replace)
+{
+ if (len() == 0 || find == NULL || replace == NULL) return 0;
+
+ int find_count = 0;
+
+ char *p, *p2;
+ int rep_len = STRLEN( replace );
+ int find_len = STRLEN( find );
+ int size_diff = rep_len - find_len;
+
+ if ( size_diff == 0 )
+ {
+ p = val;
+ while ( p = STRSTR( p, find ) )
+ {
+ STRNCPY( p, replace, rep_len );
+ p += find_len;
+ find_count++;
+ }
+ }
+ else
+ {
+ char *new_buf, *in;
+
+ p = val;
+ while ( p = STRSTR( p, find ) )
+ {
+ find_count++;
+ p += find_len;
+ }
+
+ new_buf = (char *)MALLOC( len() + find_count * size_diff + 1 );
+
+ p = val;
+ in = new_buf;
+ while ( p2 = STRSTR( p, find ) )
+ {
+ STRNCPY( in, p, (int)(p2 - p) );
+ in += p2 - p;
+ STRNCPY( in, replace, rep_len );
+ in += rep_len;
+ p = p2 + find_len;
+ }
+ STRCPY( in, p );
+ new_buf[ len() + find_count * size_diff ] = 0;
+
+ // just swap buffers
+
+ FREE(val);
+ val = new_buf;
+ }
+ return find_count;
+}
+
+int String::replaceNumericField(int value, int fieldchar)
+{
+ if (val == NULL || *val == '\0') return 0;
+ int nrep = 0;
+ for (const char *p = val; *p; p++)
+ {
+ if (*p == fieldchar) nrep++;
+ else if (nrep) break;
+ }
+ if (nrep == 0) return 0; // no field found
+ String rc;
+ char fc[2] = { 0, 0 };
+ fc[0] = fieldchar;
+ for (int i = 0; i < nrep; i++) rc.cat(fc);
+ StringPrintf fmt("%%0%0dd", nrep);
+ StringPrintf replacement(fmt.getValue(), value);
+ return replace(rc, replacement);
+}
+
+#undef USE
+#undef SAFE_METHODS
+#undef FAST_METHODS
+
+int String::numCharacters()
+{
+ // count newsize characters over how many bytes?
+ int count, bytes;
+ for (bytes = 0, count = 0; val[bytes]; count++, bytes++)
+ {
+ // If we encounter a lead byte, skip over the trail bytes.
+ switch (val[bytes] & 0xC0)
+ {
+ case 0x80: // trail bytes
+ // THIS SHOULD NEVER EVER EVER EVER HAPPEN!
+ // but we'll fall through anyhow, just in case someone
+ // sends us non-UTF8.
+ case 0xC0: // lead bytes
+ do
+ {
+ bytes++;
+ if (val[bytes] == 0)
+ {
+ // if people are giving us lame encodings, break here.
+ break;
+ }
+ }
+ while ((val[bytes + 1] & 0xC0) == 0x80);
+ break;
+ }
+ }
+ return count;
+}
+
+void String::trunc(int newlen)
+{
+ if (val == NULL) return ;
+ int oldlen = numCharacters();
+ if (newlen < 0) newlen = MAX(oldlen + newlen, 0);
+ if (newlen >= oldlen) return ;
+
+ // count newsize characters over how many bytes?
+ int count, bytes;
+ for (bytes = 0, count = 0; count < newlen; count++, bytes++)
+ {
+ // If we encounter a lead byte, skip over the trail bytes.
+ switch (val[bytes] & 0xC0)
+ {
+ case 0x80: // trail bytes
+ // THIS SHOULD NEVER EVER EVER EVER HAPPEN!
+ // but we'll fall through anyhow, just in case someone
+ // sends us non-UTF8.
+ case 0xC0: // lead bytes
+ do
+ {
+ bytes++;
+ }
+ while ((val[bytes + 1] & 0xC0) == 0x80);
+ break;
+ }
+ }
+
+ val[bytes] = 0;
+}
+
+void String::trim(const char *whitespace, int left, int right)
+{
+ if (val == NULL) return ;
+ if (left)
+ { // trim left
+ for (;;)
+ {
+ int restart = 0;
+ const char *p;
+ for (p = whitespace; *p; p++)
+ {
+ if (*p == val[0])
+ {
+ STRCPY(val, val + 1);
+ restart = 1;
+ break;
+ }
+ }
+ if (!restart) break;
+ }
+ } //left
+ if (right)
+ {
+ char *ptr = val;
+ while (ptr && *ptr) ptr++;
+ ptr--;
+ if (ptr <= val) return ;
+ for (; ptr > val; ptr--)
+ {
+ const char *p;
+ for (p = whitespace; *p; p++)
+ {
+ if (*p == *ptr)
+ {
+ *ptr = '\0';
+ break;
+ }
+ }
+ if (!*p) break;
+ }
+ } //right
+}
+
+int String::va_sprintf(const char *format, va_list args)
+{
+ if (!format) return 0;
+
+ va_list saveargs = args;
+ // roughly evaluate size of dest string
+ const char *p = format;
+ int length = 0;
+ while (p && *p)
+ {
+ if (*(p++) != '%') length++;
+ else
+ {
+ void *arg = va_arg(args, void *);
+ for (;;)
+ {
+ const char f = *p++;
+ if (f == 'c') length++;
+ else if (f == 'i') length += 16;
+ else if (f == 'u') length += 16;
+ else if (f == 'f') length += 64;
+ else if (f == 'd' || f == 'f') length += 64;
+ else if (f == 'x') length += 32; // Hex with LC Alphas: 0x0009a64c
+ else if (f == 'X') length += 32; // Hex with UC Alphas: 0x0009A64C
+ else if (f == 's')
+ { // ::vsrintf can properly handle null.
+ if (arg == NULL)
+ {
+ length += STRLEN("(null)"); // Just to be explicit.
+ }
+ else
+ {
+ length += STRLEN((const char *)arg);
+ }
+ }
+ else if (f == 'S')
+ { // ::vsrintf can properly handle null.
+ if (arg == NULL)
+ {
+ length += (int)wcslen(L"(null)"); // Just to be explicit.
+ }
+ else
+ {
+ length += (int)wcslen((const wchar_t *)arg);
+ }
+ }
+ else if (ISDIGIT(f)) continue;
+ else if (f == '.') continue;
+ else if (f == '%') length++;
+ else ASSERTPR(0, "undefined format passed to stringprintf!");
+ break;
+ }
+ }
+ }
+ if (val)
+ {
+ if (len() < length)
+ val = (char *)REALLOC(val, length + 1);
+ }
+ else val = (char *)MALLOC(length + 1);
+
+ // now write the string in val
+ int real_len = ::vsprintf_s(val, length + 1, format, saveargs);
+ ASSERTPR(real_len <= length, "String.printf overflow");
+ return real_len;
+}
+
+void String::purge()
+{
+ FREE(val);
+ val = NULL;
+}
+
+// swaps buffers with another string
+void String::swap(String *swapper)
+{
+ char *tempChar = swapper->val;
+ swapper->val = val;
+ val = tempChar;
+}
+
+void String::swap(String &swapper) // swaps buffers with another string
+{
+ char *tempChar = swapper.val;
+ swapper.val = val;
+ val = tempChar;
+}
+
+// take ownership of a buffer
+void String::own(char *swapper)
+{
+ if (val)
+ FREE(val);
+ val = swapper;
+}
+
+const char *String::catPostSeparator(const char *value, const char separator)
+{
+ if (value == NULL || *value == 0 || separator == 0) return getValue();
+ int oldLen = val ? STRLEN(val) : 0;
+ int newLen = STRLEN(value);
+ val = (char *)REALLOC(val, oldLen + newLen + 1 + 1); // +1 for separator, +1 for null character
+ STRCPY(val + oldLen, value);
+ val[oldLen + newLen] = separator; // add the separator
+ val[oldLen + newLen + 1] = 0; // null terminate
+ return val;
+}
+
+const char *String::catPreSeparator(const char separator, const char *value)
+{
+ if (value == NULL || *value == 0 || separator == 0) return getValue();
+ int oldLen = val ? STRLEN(val) : 0;
+ int newLen = STRLEN(value);
+ val = (char *)REALLOC(val, oldLen + newLen + 1 + 1); // +1 for separator, +1 for null character
+ val[oldLen] = separator; // add the separator
+ STRCPY(val + oldLen + 1, value); // +1 for separator (goes first)
+ val[oldLen + newLen + 1] = 0; // null terminate
+ return val;
+}
+
+void String::AppendPath(const char *path)
+{
+ catPreSeparator('/', path);
+}
+
+StringPrintf::StringPrintf(const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_sprintf(format, args);
+ va_end(args);
+}
+
+StringPrintf::StringPrintf(int value)
+{
+ *this += value;
+}
+
+StringPrintf::StringPrintf(double value)
+{
+ // TODO: review to use locale variant...
+ char* locale = _strdup(setlocale(LC_NUMERIC, NULL));
+ setlocale(LC_NUMERIC, "C");
+ *this += StringPrintf("%f", value);
+ if (locale)
+ {
+ setlocale(LC_NUMERIC, locale);
+ free(locale);
+ }
+}
+
+StringPrintf::StringPrintf(GUID g)
+{
+ char splab[nsGUID::GUID_STRLEN + 1] = {0};
+ nsGUID::toChar(g, splab);
+ cat(splab);
+}
+
+_DebugString::_DebugString(const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_sprintf(format, args);
+ va_end(args);
+
+ debugPrint();
+}
+
+_DebugString::_DebugString(const String &s) : String(s)
+{
+ debugPrint();
+}
+
+_DebugString::_DebugString(const String *s) : String(s)
+{
+ debugPrint();
+}
+
+void _DebugString::debugPrint()
+{
+#ifdef _WIN32
+ OutputDebugStringA(getValue());
+ if (lastChar() != '\n') OutputDebugStringA("\n");
+#else
+#warning port me
+#endif
+}
+
+int StringComparator::compareItem(String *p1, String* p2)
+{
+ return STRCMP(p1->getValue(), p2->getValue());
+}
+
+int StringComparator::compareAttrib(const wchar_t *attrib, String *item)
+{
+ return STRCMP((const char *)attrib, item->getValue());
+} \ No newline at end of file
diff --git a/Src/Wasabi/bfc/string/stringdict.h b/Src/Wasabi/bfc/string/stringdict.h
new file mode 100644
index 00000000..d88c21e7
--- /dev/null
+++ b/Src/Wasabi/bfc/string/stringdict.h
@@ -0,0 +1,96 @@
+#ifndef __STRINGDICT_H
+#define __STRINGDICT_H
+
+#include <bfc/string/StringW.h>
+#include <bfc/ptrlist.h>
+
+// a convenient class to statically declare strings and their IDs with binary search lookups
+//
+// example of use :
+//
+// BEGIN_STRINGDICTIONARY(_identifier)
+// SDI("somestring", 0);
+// SDI("someotherstring", 1);
+// SDI("andyetanotherstring", 2);
+// END_STRINGDICTIONARY(_identifier, identifier)
+
+// foo (const char *str) {
+// int a = identifier.getId(str);
+// if (a < 0) {
+// // not found!
+// }
+// return a;
+// }
+
+class StringDictionaryItem
+{
+public:
+ StringDictionaryItem(const wchar_t *string, int stringid) : str(string), id(stringid) {}
+ virtual ~StringDictionaryItem() {}
+ const wchar_t *getString()
+ {
+ return str;
+ }
+ int getId()
+ {
+ return id;
+ }
+private:
+ StringW str;
+ int id;
+};
+
+class StringDictionaryItemCompare
+{
+public:
+ static int compareItem(void *p1, void *p2)
+ {
+ return WCSICMP(((StringDictionaryItem *)p1)->getString(), ((StringDictionaryItem *)p2)->getString());
+ }
+ static int compareAttrib(const wchar_t *attrib, void *item)
+ {
+ return WCSICMP(attrib, ((StringDictionaryItem *)item)->getString());
+ }
+};
+
+class StringDictionary
+{
+public:
+ StringDictionary() {}
+ virtual ~StringDictionary()
+ {
+ items.deleteAll();
+ }
+ virtual void addItem(const wchar_t *str, int id)
+ {
+ ASSERT(id != -1);
+ items.addItem(new StringDictionaryItem(str, id));
+ }
+ virtual int getId(const wchar_t *str)
+ {
+ StringDictionaryItem *i = items.findItem(str);
+ if (i == NULL)
+ return -1;
+ return i->getId();
+ }
+private:
+ PtrListQuickSorted<StringDictionaryItem, StringDictionaryItemCompare> items;
+};
+
+#define BEGIN_STRINGDICTIONARY(class_ident) \
+ class class_ident : public StringDictionary { \
+ public: \
+ class_ident() {
+
+#define SDI(str, id) \
+ addItem(str, id);
+
+#define END_STRINGDICTIONARY(class_ident, instance_ident) \
+ }; \
+ virtual ~class_ident() { } \
+ }; \
+ \
+ class_ident instance_ident;
+
+
+#endif
diff --git a/Src/Wasabi/bfc/string/url.cpp b/Src/Wasabi/bfc/string/url.cpp
new file mode 100644
index 00000000..ea52966d
--- /dev/null
+++ b/Src/Wasabi/bfc/string/url.cpp
@@ -0,0 +1,205 @@
+#include "precomp_wasabi_bfc.h"
+#include "url.h"
+
+#include <bfc/wasabi_std.h>
+
+void Url::encode(StringW &dest, int use_plus_for_space, int encoding, int style)
+{
+ if (dest.isempty()) return;
+ StringW srcstr = dest;
+ const wchar_t *src = srcstr;
+ dest = NULL;
+/*
+ if (encoding & URLENCODE_EXCLUDEHTTPPREFIX)
+ if (!_wcsnicmp(src, L"http://", 7))
+ {
+ src += 7;
+ dest += L"http://";
+ }
+*/
+ while (src && *src)
+ {
+ int encode = 1;
+
+// if (encoding & URLENCODE_NOTHING) encode = 0;
+
+ if ((encoding & URLENCODE_EXCLUDEALPHANUM)
+ && (ISALPHA(*src) || ISDIGIT(*src)
+ || *src == '_' || *src == '-' || *src == '.' || *src == '~')
+ && *src < 128)
+ encode = 0;
+
+// if ((encoding & URLENCODE_EXCLUDE_8BIT) && (*src > 127)) encode = 0;
+ if ((encoding & URLENCODE_EXCLUDE_ABOVEEQ32) && (*src >= 32)) encode = 0;
+// if ((encoding & URLENCODE_ENCODESPACE) && *src == ' ') encode = 1;
+// if ((encoding & URLENCODE_ENCODEXML) && (*src == '<' || *src == '>' || *src == '&')) encode = 1;
+ if ((*src == '&' && (style == URLENCODE_STYLE_ANDPOUND || style == URLENCODE_STYLE_ANDPOUNDX)) ||
+ (*src == '%' && style == URLENCODE_STYLE_PERCENT)) encode = 1;
+ if ((encoding & URLENCODE_EXCLUDESLASH) && (*src == '/' || *src == ':')) encode = 0;
+ if (!encode)
+ {
+ dest += *src;
+ }
+ else if (use_plus_for_space && *src == ' ')
+ {
+ dest += '+';
+ }
+ else
+ {
+ switch (style)
+ {
+ case URLENCODE_STYLE_PERCENT:
+ dest += StringPrintfW(L"%%%02X", (int) * src);
+ break;
+ case URLENCODE_STYLE_ANDPOUND:
+ dest += StringPrintfW(L"&#%02d;", (int) * src);
+ break;
+ case URLENCODE_STYLE_ANDPOUNDX:
+ dest += StringPrintfW(L"&#x%02X;", (int) * src);
+ break;
+ }
+ }
+ src++;
+ }
+}
+
+void Url::encode(String &dest, int use_plus_for_space, int encoding, int style)
+{
+ if (dest.isempty()) return;
+ String srcstr = dest;
+ const char *src = srcstr;
+ dest = NULL;
+/*
+ if (encoding & URLENCODE_EXCLUDEHTTPPREFIX)
+ if (!_wcsnicmp(src, L"http://", 7))
+ {
+ src += 7;
+ dest += L"http://";
+ }
+*/
+ while (src && *src)
+ {
+ int encode = 1;
+
+// if (encoding & URLENCODE_NOTHING) encode = 0;
+
+ if ((encoding & URLENCODE_EXCLUDEALPHANUM)
+ && (ISALPHA(*src) || ISDIGIT(*src)
+ || *src == '_' || *src == '-' || *src == '.' || *src == '~')
+ && *(unsigned char *)src < 128)
+ encode = 0;
+
+// if ((encoding & URLENCODE_EXCLUDE_8BIT) && (*src > 127)) encode = 0;
+ if ((encoding & URLENCODE_EXCLUDE_ABOVEEQ32) && (*src >= 32)) encode = 0;
+// if ((encoding & URLENCODE_ENCODESPACE) && *src == ' ') encode = 1;
+// if ((encoding & URLENCODE_ENCODEXML) && (*src == '<' || *src == '>' || *src == '&')) encode = 1;
+ if ((*src == '&' && (style == URLENCODE_STYLE_ANDPOUND || style == URLENCODE_STYLE_ANDPOUNDX)) ||
+ (*src == '%' && style == URLENCODE_STYLE_PERCENT)) encode = 1;
+ if ((encoding & URLENCODE_EXCLUDESLASH) && (*src == '/' || *src == ':')) encode = 0;
+ if (!encode)
+ {
+ dest += *src;
+ }
+ else if (use_plus_for_space && *src == ' ')
+ {
+ dest += '+';
+ }
+ else
+ {
+ switch (style)
+ {
+ case URLENCODE_STYLE_PERCENT:
+ dest += StringPrintf("%%%02X", (unsigned char)*src);
+ break;
+ case URLENCODE_STYLE_ANDPOUND:
+ dest += StringPrintf("&#%02d;", (unsigned char)*src);
+ break;
+ case URLENCODE_STYLE_ANDPOUNDX:
+ dest += StringPrintf("&#x%02X;", (unsigned char)*src);
+ break;
+ }
+ }
+ src++;
+ }
+}
+
+void Url::decode(StringW &str, int use_plus_for_space)
+{
+ if (str.isempty()) return;
+ Url::decode(str.getNonConstVal());
+}
+
+static uint8_t quickhex(wchar_t c)
+{
+ int hexvalue = c;
+ if (hexvalue & 0x10)
+ hexvalue &= ~0x30;
+ else
+ {
+ hexvalue &= 0xF;
+ hexvalue += 9;
+ }
+ return hexvalue;
+}
+
+static uint8_t DecodeEscape(const wchar_t *&str)
+{
+ uint8_t a = quickhex(*++str);
+ uint8_t b = quickhex(*++str);
+ str++;
+ return a * 16 + b;
+}
+
+static void DecodeEscapedUTF8(wchar_t *&output, const wchar_t *&input)
+{
+ uint8_t utf8_data[1024] = {0}; // hopefully big enough!!
+ int num_utf8_words=0;
+ bool error=false;
+
+ while (input && *input && *input == '%' && num_utf8_words < sizeof(utf8_data))
+ {
+ if (iswxdigit(input[1]) && iswxdigit(input[2]))
+ {
+ utf8_data[num_utf8_words++]=DecodeEscape(input);
+ }
+ else if (input[1] == '%')
+ {
+ input+=2;
+ utf8_data[num_utf8_words++]='%';
+ }
+ else
+ {
+ error = true;
+ break;
+ }
+ }
+
+ int len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)utf8_data, num_utf8_words, 0, 0);
+ MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)utf8_data, num_utf8_words, output, len);
+ output += len;
+
+ if (error)
+ {
+ *output++ = *input++;
+ }
+}
+
+// benski> We have the luxury of knowing that decoding will ALWAYS produce smaller strings
+// so we can do it in-place
+void Url::decode(wchar_t *str)
+{
+ const wchar_t *itr = str;
+ while (itr && *itr)
+ {
+ switch (*itr)
+ {
+ case '%':
+ DecodeEscapedUTF8(str, itr);
+ break;
+ default:
+ *str++ = *itr++;
+ break;
+ }
+ }
+ *str = 0;
+} \ No newline at end of file
diff --git a/Src/Wasabi/bfc/string/url.h b/Src/Wasabi/bfc/string/url.h
new file mode 100644
index 00000000..49c72e80
--- /dev/null
+++ b/Src/Wasabi/bfc/string/url.h
@@ -0,0 +1,33 @@
+#ifndef _URL_H
+#define _URL_H
+
+#include <bfc/common.h>
+#include <bfc/string/StringW.h>
+
+//#define URLENCODE_NOTHING 1 // encode nothing (add some flags!), default is to start with everything
+#define URLENCODE_EXCLUDEALPHANUM 2 // do not encode characters that are alphanumeric (a-z,0-1) or _ - and .
+#define URLENCODE_EXCLUDESLASH 4 // don't encode '/' or ':'
+//#define URLENCODE_EXCLUDEHTTPPREFIX 8 // don't encode "http://"
+//#define URLENCODE_EXCLUDE_8BIT 16 // do not encode > 127
+#define URLENCODE_EXCLUDE_ABOVEEQ32 32 // do not encode >= 32
+//#define URLENCODE_ENCODESPACE 64 // force encoding space
+//#define URLENCODE_ENCODEXML 128 // force encoding '>' and '<'
+
+#define URLENCODE_DEFAULT URLENCODE_EXCLUDEALPHANUM
+//#define URLENCODE_FULLURL (URLENCODE_DEFAULT|URLENCODE_EXCLUDEHTTPPREFIX|URLENCODE_EXCLUDESLASH|URLENCODE_EXCLUDE_7BIT_ABOVEEQ32|URLENCODE_ENCODESPACE)
+
+class Url {
+public:
+ static void encode(StringW &dest, int use_plus_for_space = FALSE, int encoding = URLENCODE_DEFAULT, int style=URLENCODE_STYLE_PERCENT);
+ static void encode(String &dest, int use_plus_for_space = FALSE, int encoding = URLENCODE_DEFAULT, int style=URLENCODE_STYLE_PERCENT);
+ static void decode(StringW &str, int use_plus_for_space = FALSE);
+ static void decode(wchar_t *str); // in place url decode
+
+ enum {
+ URLENCODE_STYLE_PERCENT = 0, // %AB
+ URLENCODE_STYLE_ANDPOUND = 1, // &#171;
+ URLENCODE_STYLE_ANDPOUNDX = 2, // &#xAB;
+ };
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/string/utf8.cpp b/Src/Wasabi/bfc/string/utf8.cpp
new file mode 100644
index 00000000..389c231f
--- /dev/null
+++ b/Src/Wasabi/bfc/string/utf8.cpp
@@ -0,0 +1,25 @@
+#include "precomp_wasabi_bfc.h"
+
+#include "utf8.h"
+
+// this STILL doesn't work perfectly but at least it decodes what we write out
+// mostly just waiting on our wide character strategy
+
+void COMEXP UTF8_to_ASCII(const char *in, char *out) {
+ unsigned const char *src = (unsigned const char *)in;
+ unsigned char *dst = (unsigned char *)out;
+ *dst = 0;
+ for (; *src; src++) {
+ int c = *src;
+ if ((c & 0x80) == 0) {
+ *dst++ = c;
+ continue;
+ }
+ if ((c & 224) != 192) continue; // fuck you, we only check for single bytes
+ int v = (c & 0x3) << 6;
+ ++src;
+ v |= *src & 0x3f;
+ *dst++ = v;
+ }
+ *dst = 0;
+}
diff --git a/Src/Wasabi/bfc/string/utf8.h b/Src/Wasabi/bfc/string/utf8.h
new file mode 100644
index 00000000..d5847058
--- /dev/null
+++ b/Src/Wasabi/bfc/string/utf8.h
@@ -0,0 +1,8 @@
+#ifndef _UTF8_H
+#define _UTF8_H
+
+#include <bfc/common.h>
+
+void COMEXP UTF8_to_ASCII(const char *in, char *out);
+
+#endif
diff --git a/Src/Wasabi/bfc/test.cpp b/Src/Wasabi/bfc/test.cpp
new file mode 100644
index 00000000..0c2a039a
--- /dev/null
+++ b/Src/Wasabi/bfc/test.cpp
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+void prout() {
+ printf("prout\n");
+}
diff --git a/Src/Wasabi/bfc/thread.cpp b/Src/Wasabi/bfc/thread.cpp
new file mode 100644
index 00000000..3306c1bd
--- /dev/null
+++ b/Src/Wasabi/bfc/thread.cpp
@@ -0,0 +1,124 @@
+#include "precomp_wasabi_bfc.h"
+
+#include "thread.h"
+
+#if !defined(WIN32) && !defined(LINUX)
+#error port me!
+#endif
+
+#pragma warning(push)
+#pragma warning(disable : 4229)
+
+THREADCALL Thread::ThreadProc(void *param) {
+ Thread *th = static_cast<Thread*>(param);
+ th->isrunning = true;
+ int ret = th->threadProc();
+ th->isrunning = false;
+ return (THREADCALL)ret;
+}
+
+#pragma warning(pop)
+
+Thread::Thread(HANDLE _parent_handle) :
+ isrunning(false),
+ killswitch(0),
+ handle(0), parent_handle(0), nicekill(1),
+ auto_close_parent(FALSE)
+{
+ setParentHandle(_parent_handle);
+#ifdef WIN32
+ handle = CreateThread(NULL, 0, ThreadProc, (LPVOID)this, CREATE_SUSPENDED, &threadid);
+#endif
+}
+
+Thread::~Thread() {
+ if (handle != 0) {
+ if (isrunning) {
+ setKillSwitch(TRUE);
+ end();
+ // FUCKO: might need to get rough here
+ // FG> this serves no purpose, end() will not return unless the thread exits nicely
+ #ifdef WIN32
+ CloseHandle(handle);
+ #elif defined(LINUX)
+ pthread_kill(handle, SIGTERM);
+ #endif
+ }
+ }
+ setParentHandle(0);
+}
+
+int Thread::start() {
+ if (running()) return 1;
+#ifdef WIN32
+ return !(ResumeThread(handle) == 0xffffffff);
+#endif
+#ifdef LINUX
+ pthread_create(&handle, NULL, ThreadProc, (LPVOID)this);
+ return 1;
+#endif
+}
+
+bool Thread::running() {
+ return isrunning;
+}
+
+int Thread::end() {
+ while (running()) Sleep(66);
+ return 1;
+}
+
+int Thread::kill() {
+#ifdef WIN32
+ CloseHandle(handle);
+#elif defined(LINUX)
+ pthread_kill(handle, SIGTERM);
+#endif
+ handle = 0;
+ isrunning = false;
+ return 1;
+}
+
+void Thread::setKillSwitch(int k) {
+ killswitch = k;
+}
+
+int Thread::getKillSwitch() {
+ if (killswitch) return 1;
+ if (parent_handle != 0 && !parentRunning()) return 1;
+ return 0;
+}
+
+THREADID Thread::getThreadId() const {
+ return threadid;
+}
+
+void Thread::setParentHandle(HANDLE _parent_handle, int _auto_close) {
+ if (parent_handle != 0 && auto_close_parent) {
+#ifdef WIN32
+ CloseHandle(parent_handle);
+#else
+//#error port me!
+ DebugString("setParentHandle???\n");
+#endif
+ }
+ parent_handle = _parent_handle;
+ auto_close_parent = _auto_close;
+}
+
+int Thread::parentRunning() {
+ if (parent_handle == 0) return -1;
+#ifdef WIN32
+ DWORD exitcode;
+ int r = GetExitCodeThread(parent_handle, &exitcode);
+ if (r == 0 || exitcode != STILL_ACTIVE) return 0;
+ return 1;
+#else
+//#error port me!
+ DebugString("parentRunning???\n");
+#endif
+}
+
+void Thread::setPriority(int priority) {
+ Wasabi::Std::setThreadPriority(priority, handle);
+}
diff --git a/Src/Wasabi/bfc/thread.h b/Src/Wasabi/bfc/thread.h
new file mode 100644
index 00000000..01034af3
--- /dev/null
+++ b/Src/Wasabi/bfc/thread.h
@@ -0,0 +1,145 @@
+#ifndef _THREAD_H
+#define _THREAD_H
+
+#include <bfc/common.h>
+
+#if !defined(WIN32) && !defined(LINUX)
+#error port me!
+#endif
+
+#ifdef WIN32
+#define THREADCALL DWORD WINAPI
+#endif
+#ifdef LINUX
+#define THREADCALL void *
+#endif
+
+/**
+ class Thread is a portable wrapper for an operating system thread. A thread
+ is a thread of execution in a process. Ask Google if you don't know what that
+ means.
+
+ To use this class, derive from Thread and override the threadProc() method.
+ Simply return from this method and the thread will end.
+
+ Our Thread works on the kill-switch concept. You should write your thread
+ code to continually check the getKillSwitch() method to determine if you
+ should exit. When either getKillSwitch() returns TRUE or your processing is
+ done, just return from the method and the thread will end.
+
+ @short Thread object.
+ @author Nullsoft
+ @see threadProc()
+ @see getKillSwitch()
+ @see CriticalSection
+*/
+class Thread {
+public:
+/**
+ Creates a new Thread object. You can optionally pass in the handle of another
+ thread. If you do, the getKillSwitch function will check if this thread is
+ still running, and return TRUE if it has died. Usually this other thread
+ will be the main thread.
+ Threads are created in a suspended state. To start them, call start().
+
+ @see threadProc()
+ @see getKillSwitch()
+ @see ComponentAPI::main_getMainThreadHandle()
+ @see start()
+*/
+ Thread(HANDLE parent_handle=0);
+ virtual ~Thread();
+
+/**
+ Starts the thread. You must call this at some point after creating the Thread.
+
+ @ret Boolean. TRUE on success, FALSE on failure.
+*/
+ int start();
+
+/**
+ Checks whether the thread is still running.
+
+ @ret Boolean. TRUE if thread is still running, FALSE if it has ended.
+*/
+ bool running();
+
+/**
+ Waits until thread ends. Does not kill the thread, though, so you might want
+ to call setKillSwitch(TRUE) to encourage the thread to end.
+
+ @see setKillSwitch()
+*/
+ int end(); // waits for thread to end, might want to throw killswitch too
+ int kill(); // does not wait, simply kills the thread, use with care
+
+/**
+ Sets the internal kill switch to k.
+
+ @param k Boolean. TRUE to force getKillSwitch() to return TRUE.
+ @see getKillSwitch()
+*/
+ void setKillSwitch(int k);
+
+ THREADID getThreadId() const;
+
+/**
+ Sets the parent handle. If a parent handle is set, the getKillSwitch()
+ function will return TRUE when the parent thread ends.
+
+ @param parent_handle The handle of the thread to monitor.
+ @param auto_close If TRUE, the parent handle will be closed on shutdown. Normally this is the desired behavior.
+*/
+ void setParentHandle(HANDLE parent_handle, int auto_close=TRUE);
+
+/**
+ Checks if the parent thread is still running (if a handle was provided.)
+
+ @see Thread()
+ @see getKillSwitch()
+ @ret Boolean, TRUE if parent is still running, FALSE otherwise.
+*/
+ int parentRunning(); // if parent handle given, is it still running
+
+/**
+ Override this method to do your thread's work.
+*/
+ virtual int threadProc()=0;
+
+ enum { // these have to match std.cpp
+ PRIORITY_IDLE=-32767,
+ PRIORITY_LOWEST=-2,
+ PRIORITY_BELOW_NORMAL=-1,
+ PRIORITY_NORMAL=0,
+ PRIORITY_HIGH=1,
+ PRIORITY_HIGHEST=2,
+ PRIORITY_TIME_CRITICAL=32767,
+ };
+/**
+ Sets the thread's processing priority.
+
+ @param priority The new priority for the thread.
+ @see Std::setThreadPriority()
+*/
+ void setPriority(int priority);
+
+protected:
+/**
+ Your thread should call this at intervals to determine if it should exit.
+ @ret Boolean of whether the thread should exit.
+ @see threadProc()
+*/
+ int getKillSwitch(); // check this and return when it's nonzero
+
+private:
+ static THREADCALL ThreadProc(void *param);
+
+ int killswitch;
+ HANDLE handle, parent_handle;
+ int auto_close_parent;
+ THREADID threadid;
+ bool isrunning;
+ int nicekill;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/tlist.h b/Src/Wasabi/bfc/tlist.h
new file mode 100644
index 00000000..14e591bf
--- /dev/null
+++ b/Src/Wasabi/bfc/tlist.h
@@ -0,0 +1,156 @@
+//PORTABLE
+#ifndef _TLIST_H
+#define _TLIST_H
+
+#include <bfc/common.h>
+#include <bfc/wasabi_std.h>
+#include <bfc/named.h>
+
+/*
+
+A generic std::vector wannabe...
+
+NOTE: you must only use this with basic types! constructors and destructors
+will not be called.
+
+*/
+
+#include <bfc/bfc_assert.h>
+#include <bfc/std_mem.h>
+
+#define TLIST_INCREMENT 32
+
+template<class T>
+class TList {
+public:
+ TList() {
+ nitems = 0;
+ nslots = 0;
+ items = NULL;
+ }
+ virtual ~TList() {
+ FREE(items);
+ }
+
+ int getNumItems() const { return nitems; };
+
+ // CAN'T PROVIDE BOUNDS CHECKING!!! (except by ASSERT() :( )
+ T enumItem(int n) const {
+ ASSERT(items != NULL);
+ ASSERT(n >= 0 && n < nitems);
+ return items[n];
+ }
+ T operator[](int n) const { return enumItem(n); }
+
+ T getFirst() const { return enumItem(0); }
+ T getLast() const { return enumItem(getNumItems()-1); }
+
+ T *enumRef(int n) const {
+ ASSERT(items != NULL);
+ ASSERT(n >= 0 && n < nitems);
+ return items+n;
+ }
+
+ T *addItem(const T &item) {
+ ASSERT(nitems <= nslots);
+ if (items == NULL) {
+ nslots = TLIST_INCREMENT;
+ items = (T *)MALLOC(sizeof(T) * nslots);
+ nitems = 0;
+ } else if (nslots == nitems) { // time to expand
+ T *newitems;
+ nslots += TLIST_INCREMENT;
+ newitems = (T *)MALLOC(sizeof(T) * nslots);
+ MEMCPY(newitems, items, nitems * sizeof(T));
+ FREE(items);
+ items = newitems;
+ }
+ items[nitems++] = item;
+
+ return &items[nitems-1];
+ }
+
+ T *insertItem(const T &item, int pos) { // position to insert
+ ASSERT(pos >= 0 && pos <= nitems);
+ T *tmp=addItem(item);
+ int n=nitems-1;
+ while (n > pos) {
+ items[n]=items[n-1];
+ n--;
+ }
+ tmp=items+pos;
+ *tmp=item;
+ return tmp;
+ }
+
+ T *replaceItemByPos(const T &item, int pos) {
+ ASSERT(items != NULL);
+ ASSERT(nitems != 0);
+ ASSERT(pos >= 0 && pos < nitems);
+ items[pos]=item;
+ return &items[pos];
+ }
+
+ void setItem(int pos, const T &newval) {
+ if (pos < 0) return;
+ if (pos >= nitems) return;
+ items[pos] = newval;
+ }
+
+ int delItem(const T &item) {
+ int c = 0;
+
+ ASSERT(items != NULL);
+ ASSERT(nitems != 0);
+
+ T *src = items;
+ T *dst = items;
+ for (int i = 0; i < nitems; i++) {
+ if (*src != item) {
+ *dst++ = *src;
+ c++;
+ }
+ src++;
+ }
+ nitems -= c;
+
+ return c;
+ }
+
+ int delByPos(int pos) {
+ if (pos < 0 || pos >= nitems) return 0;
+ --nitems;
+ if (pos == nitems) return 1; // last one? nothing to copy over
+ MEMCPY(items+pos, items+(pos+1), sizeof(T)*(nitems-pos)); // CT:not (nitems-(pos+1)) as nitems has been decremented earlier
+ return 1;
+ }
+
+ void removeAll() {
+ FREE(items); items = NULL;
+ nitems = 0;
+ nslots = 0;
+ }
+
+ void freeAll() {
+ for (int i = 0; i < nitems; i++)
+ FREE(items[i]);
+ removeAll();
+ }
+
+ int getItemPos(const T &it) const {
+ int n = getNumItems();
+ for (int i=0;i<n;i++)
+ if(!MEMCMP(&items[i],&it,sizeof(T))) return i; // CT if (items[i] == it) return i;
+ return -1;
+ }
+ int haveItem(const T &it) const {
+ return (getItemPos(it) != -1);
+ }
+
+private:
+ int nitems, nslots;
+ T *items;
+};
+
+
+#endif
diff --git a/Src/Wasabi/bfc/util/base64.cpp b/Src/Wasabi/bfc/util/base64.cpp
new file mode 100644
index 00000000..1a67b9f1
--- /dev/null
+++ b/Src/Wasabi/bfc/util/base64.cpp
@@ -0,0 +1,315 @@
+/* Based on code from Dave Winer (http://www.scripting.com/midas/base64/) */
+#include "precomp_wasabi_bfc.h"
+#include "base64.h"
+
+char Base64::encodingTable [64] = {
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+ 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+ 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+ 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
+};
+
+int Base64::encode(MemBlock<char> &htext, MemBlock<char> &h64, int linelength) {
+ /*
+ encode the handle. some funny stuff about linelength -- it only makes
+ sense to make it a multiple of 4. if it's not a multiple of 4, we make it
+ so (by only checking it every 4 characters.
+ further, if it's 0, we don't add any line breaks at all.
+ */
+ unsigned long ixtext;
+ unsigned long lentext;
+ unsigned long origsize;
+ long ctremaining;
+ unsigned char inbuf [3] = {0}, outbuf [4] = {0};
+ short i;
+ short charsonline = 0, ctcopy;
+
+ ixtext = 0;
+
+ lentext = htext.getSize();
+
+ while (1) {
+ ctremaining = lentext - ixtext;
+
+ if (ctremaining <= 0)
+ break;
+
+ for (i = 0; i < 3; i++) {
+ unsigned long ix = ixtext + i;
+ if (ix < lentext)
+ inbuf [i] = *htext.getMemory(ix);
+ else
+ inbuf [i] = 0;
+ }
+
+ outbuf [0] = (inbuf [0] & 0xFC) >> 2;
+ outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4);
+ outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6);
+ outbuf [3] = inbuf [2] & 0x3F;
+
+ origsize = h64.getSize();
+ h64.setSize(origsize + 4);
+
+ ctcopy = 4;
+
+ switch (ctremaining) {
+ case 1:
+ ctcopy = 2;
+ break;
+ case 2:
+ ctcopy = 3;
+ break;
+ }
+
+ for (i = 0; i < ctcopy; i++)
+ *h64.getMemory(origsize + i) = encodingTable[outbuf[i]];
+
+ for (i = ctcopy; i < 4; i++)
+ *h64.getMemory(origsize + i) = '=';
+
+ ixtext += 3;
+ charsonline += 4;
+
+ if (linelength > 0) { /*DW 4/8/97 -- 0 means no line breaks*/
+ if (charsonline >= linelength) {
+ charsonline = 0;
+ origsize = h64.getSize();
+ h64.setSize(origsize + 1);
+ *h64.getMemory() = '\n';
+ }
+ }
+ }
+ return 1;
+}
+int Base64::encode(MemBlock<char> &htext, MemBlock<wchar_t> &h64, int linelength) {
+ /*
+ encode the handle. some funny stuff about linelength -- it only makes
+ sense to make it a multiple of 4. if it's not a multiple of 4, we make it
+ so (by only checking it every 4 characters.
+ further, if it's 0, we don't add any line breaks at all.
+ */
+ unsigned long ixtext;
+ unsigned long lentext;
+ unsigned long origsize;
+ long ctremaining;
+ unsigned char inbuf [3] = {0}, outbuf [4] = {0};
+ short i;
+ short charsonline = 0, ctcopy;
+
+ ixtext = 0;
+
+ lentext = htext.getSize();
+
+ while (1) {
+ ctremaining = lentext - ixtext;
+
+ if (ctremaining <= 0)
+ break;
+
+ for (i = 0; i < 3; i++) {
+ unsigned long ix = ixtext + i;
+ if (ix < lentext)
+ inbuf [i] = *htext.getMemory(ix);
+ else
+ inbuf [i] = 0;
+ }
+
+ outbuf [0] = (inbuf [0] & 0xFC) >> 2;
+ outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4);
+ outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6);
+ outbuf [3] = inbuf [2] & 0x3F;
+
+ origsize = h64.getSize();
+ h64.setSize(origsize + 4);
+
+ ctcopy = 4;
+
+ switch (ctremaining) {
+ case 1:
+ ctcopy = 2;
+ break;
+ case 2:
+ ctcopy = 3;
+ break;
+ }
+
+ for (i = 0; i < ctcopy; i++)
+ *h64.getMemory(origsize + i) = encodingTable[outbuf[i]];
+
+ for (i = ctcopy; i < 4; i++)
+ *h64.getMemory(origsize + i) = '=';
+
+ ixtext += 3;
+ charsonline += 4;
+
+ if (linelength > 0) { /*DW 4/8/97 -- 0 means no line breaks*/
+ if (charsonline >= linelength) {
+ charsonline = 0;
+ origsize = h64.getSize();
+ h64.setSize(origsize + 1);
+ *h64.getMemory() = '\n';
+ }
+ }
+ }
+ return 1;
+}
+
+
+int Base64::decode(MemBlock<char> &h64, MemBlock<char> &htext) {
+ unsigned long ixtext;
+ unsigned long lentext;
+ unsigned long origsize;
+ unsigned char ch;
+ unsigned char inbuf [4] = {0}, outbuf [4] = {0};
+ short i, ixinbuf;
+ boolean flignore;
+ boolean flendtext = false;
+
+ ixtext = 0;
+
+ lentext = h64.getSize();
+
+ ixinbuf = 0;
+
+ while (true) {
+ if (ixtext >= lentext)
+ break;
+ ch = *h64.getMemory(ixtext++);
+
+ flignore = 0;
+
+ if ((ch >= 'A') && (ch <= 'Z'))
+ ch = ch - 'A';
+ else if ((ch >= 'a') && (ch <= 'z'))
+ ch = ch - 'a' + 26;
+ else if ((ch >= '0') && (ch <= '9'))
+ ch = ch - '0' + 52;
+ else if (ch == '+')
+ ch = 62;
+ else if (ch == '=') /*no op -- can't ignore this one*/
+ flendtext = true;
+ else if (ch == '/')
+ ch = 63;
+ else
+ flignore = true;
+
+ if (!flignore) {
+ short ctcharsinbuf = 3;
+ boolean flbreak = false;
+
+ if (flendtext) {
+ if (ixinbuf == 0)
+ break;
+
+ if ((ixinbuf == 1) || (ixinbuf == 2))
+ ctcharsinbuf = 1;
+ else
+ ctcharsinbuf = 2;
+
+ ixinbuf = 3;
+ flbreak = 1;
+ }
+
+ inbuf [ixinbuf++] = ch;
+
+ if (ixinbuf == 4) {
+ ixinbuf = 0;
+
+ outbuf [0] = (inbuf [0] << 2) | ((inbuf [1] & 0x30) >> 4);
+ outbuf [1] = ((inbuf [1] & 0x0F) << 4) | ((inbuf [2] & 0x3C) >> 2);
+ outbuf [2] = ((inbuf [2] & 0x03) << 6) | (inbuf [3] & 0x3F);
+
+ origsize = htext.getSize();
+ htext.setSize(origsize + ctcharsinbuf);
+
+ for (i = 0; i < ctcharsinbuf; i++)
+ *htext.getMemory(origsize + i) = outbuf[i];
+ }
+
+ if (flbreak)
+ break;
+ }
+ }
+
+ return 1;
+}
+int Base64::decode(MemBlock<wchar_t> &h64, MemBlock<char> &htext) {
+ unsigned long ixtext;
+ unsigned long lentext;
+ unsigned long origsize;
+ unsigned char ch;
+ unsigned char inbuf [4] = {0}, outbuf [4] = {0};
+ short i, ixinbuf;
+ boolean flignore;
+ boolean flendtext = false;
+
+ ixtext = 0;
+
+ lentext = h64.getSize();
+
+ ixinbuf = 0;
+
+ while (true) {
+ if (ixtext >= lentext)
+ break;
+ ch = (unsigned char)*h64.getMemory(ixtext++);
+
+ flignore = 0;
+
+ if ((ch >= 'A') && (ch <= 'Z'))
+ ch = ch - 'A';
+ else if ((ch >= 'a') && (ch <= 'z'))
+ ch = ch - 'a' + 26;
+ else if ((ch >= '0') && (ch <= '9'))
+ ch = ch - '0' + 52;
+ else if (ch == '+')
+ ch = 62;
+ else if (ch == '=') /*no op -- can't ignore this one*/
+ flendtext = true;
+ else if (ch == '/')
+ ch = 63;
+ else
+ flignore = true;
+
+ if (!flignore) {
+ short ctcharsinbuf = 3;
+ boolean flbreak = false;
+
+ if (flendtext) {
+ if (ixinbuf == 0)
+ break;
+
+ if ((ixinbuf == 1) || (ixinbuf == 2))
+ ctcharsinbuf = 1;
+ else
+ ctcharsinbuf = 2;
+
+ ixinbuf = 3;
+ flbreak = 1;
+ }
+
+ inbuf [ixinbuf++] = ch;
+
+ if (ixinbuf == 4) {
+ ixinbuf = 0;
+
+ outbuf [0] = (inbuf [0] << 2) | ((inbuf [1] & 0x30) >> 4);
+ outbuf [1] = ((inbuf [1] & 0x0F) << 4) | ((inbuf [2] & 0x3C) >> 2);
+ outbuf [2] = ((inbuf [2] & 0x03) << 6) | (inbuf [3] & 0x3F);
+
+ origsize = htext.getSize();
+ htext.setSize(origsize + ctcharsinbuf);
+
+ for (i = 0; i < ctcharsinbuf; i++)
+ *htext.getMemory(origsize + i) = outbuf[i];
+ }
+
+ if (flbreak)
+ break;
+ }
+ }
+
+ return 1;
+}
+
+
diff --git a/Src/Wasabi/bfc/util/base64.h b/Src/Wasabi/bfc/util/base64.h
new file mode 100644
index 00000000..fc4fd658
--- /dev/null
+++ b/Src/Wasabi/bfc/util/base64.h
@@ -0,0 +1,16 @@
+#ifndef _BASE64_H
+#define _BASE64_H
+
+#include <bfc/memblock.h>
+
+class Base64 {
+public:
+ static int decode(MemBlock<wchar_t> &h64, MemBlock<char> &htext);
+ static int decode(MemBlock<char> &h64, MemBlock<char> &htext);
+ static int encode(MemBlock<char> &htext, MemBlock<char> &h64, int linelength);
+ static int encode(MemBlock<char> &htext, MemBlock<wchar_t> &h64, int linelength);
+private:
+ static char encodingTable[64];
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/util/findopenrect.cpp b/Src/Wasabi/bfc/util/findopenrect.cpp
new file mode 100644
index 00000000..537651d2
--- /dev/null
+++ b/Src/Wasabi/bfc/util/findopenrect.cpp
@@ -0,0 +1,251 @@
+#include <precomp.h>
+#include "findopenrect.h"
+
+#include <bfc/pair.h>
+
+//CUT #define MAXTRIALS 10000 // unless time runs out
+#define MOUSEPENALTY 65536
+
+FindOpenRect::FindOpenRect()
+{
+ timelimit = 100;
+ iters = 0;
+ xdiv = ydiv = 1;
+ fn = compare_overlapArea;
+ userdata = userdata2 = 0;
+ bsfval = bsfdist = 0;
+}
+
+void FindOpenRect::setCompareRectsFn(compareRectsFn _fn)
+{
+ fn = _fn;
+}
+
+RECT FindOpenRect::find(const RECT &vr, const PtrList<RECT> &list, const RECT &prev, unsigned long userdata, unsigned long userdata2)
+{
+ beginFind(vr, list, prev, userdata, userdata2);
+ return findMore();
+}
+
+void FindOpenRect::beginFind(const RECT &viewport, const PtrList<RECT> &_list,
+ const RECT &_prev, unsigned long _userdata, unsigned long _userdata2)
+{
+ vr = viewport;
+ list.copyFrom(&_list);
+ prev = _prev;
+ userdata = _userdata;
+ userdata2 = _userdata2;
+
+ // reset best rect found so far
+ //CUT bsf_nooverlap = prev;
+ //CUT found_nooverlap=0;
+ //CUT bsf_overlap = prev;
+ //CUT bsfval_nooverlap = 1e100;
+ //CUT bsfval_overlap = 1e100;
+ bsfrect = prev;
+ bsfval = 10e10;
+ bsfdist = 10e10;
+
+ //CUT POINT mousepos;
+ //CUT Std::getMousePos(&mousepos);
+}
+
+RECT FindOpenRect::findMore()
+{
+ int w = prev.right - prev.left, h = prev.bottom - prev.top;
+ int vw = vr.right - vr.left;
+ int vh = vr.bottom - vr.top;
+
+ if (vw <= w || vh <= h)
+ {
+ DebugStringW(L"findopenrect: window too big for viewport");
+ }
+
+
+ double started = Wasabi::Std::getTimeStampMS();
+
+ for (int c = 0; /*CUTc < MAXTRIALS*/; c++)
+ {
+
+ // too bad = crashy crash :P love, BU
+ if (c != 0 && (vw <= w || vh <= h))
+ break;
+
+ // set the trial rect
+ RECT tr;
+ if (iters == 0)
+ { // try prev
+ tr = prev;
+ }
+ else
+ {
+ int x = Wasabi::Std::random32(vw - w) + vr.top;
+ int y = Wasabi::Std::random32(vh - h) + vr.left;
+ if (xdiv != 1) x -= x % xdiv;
+ if (ydiv != 1) y -= y % ydiv;
+ tr = Wasabi::Std::makeRect(x, y, x + w, y + h);
+ }
+
+ // add up the coverage of trial position
+ trySingleRect(tr, TRUE);
+
+ if (timelimit > 0 && c > 0 && (int)((Wasabi::Std::getTimeStampMS() - started)*1000.f) > timelimit)
+ {
+ // DebugString("FindOpenRect::find() timeout, %d iters", c);
+ break;
+ }
+ }
+
+ return getBestRectSoFar();
+}
+
+typedef Pair<RECT, double> RectV;
+
+namespace
+{
+ class Sorter
+ {
+ public:
+ static int compareItem(RectV *p1, RectV* p2)
+ {
+ return -CMP3(p1->b, p2->b);
+ }
+ };
+};
+
+double FindOpenRect::trySingleRect(const RECT &tr, int early_out)
+{
+#if 0
+ PtrListQuickSorted<RectV, Sorter> candidates(list.getNumItems());
+ foreach(list)
+ double d = compare_overlapArea(tr, *list.getfor());
+ candidates.addItem(new RectV(*list.getfor(), d));
+ endfor
+ candidates.sort();
+#else
+ PtrList<RECT> candidates;
+ candidates.copyFrom(&list);
+#endif
+
+ double trarea = 0;
+
+ foreach(candidates)
+#if 0
+ RECT *wr = &candidates.getfor()->a;
+#else
+ RECT *wr = candidates.getfor();
+#endif
+ //CUT double bsf = MIN(found_nooverlap ? 0 : bsfval_nooverlap, bsfval_overlap);
+ trarea += (*fn)(tr, *wr, userdata, userdata2, foreach_index, bsfval);
+
+ // early quit if not breaking any records
+ if (early_out && trarea >= bsfval) break;
+
+ endfor
+
+#if 0
+ candidates.deleteAll();
+#endif
+
+ if (trarea < 0.005) trarea = 0;
+
+#if 0
+ // found one that does not overlap!
+ if (trarea == 0)
+ {
+ if (val < bsfval_nooverlap)
+ { // if it's closer than prev closest, save it
+ bsf_nooverlap = tr;
+ bsfval_nooverlap = val;
+ found_nooverlap = 1;
+ }
+ }
+ else
+ {
+ if (trarea < bsfval_overlap)
+ { // overlaps least stuff
+ bsf_overlap = tr;
+ bsfval_overlap = trarea;
+ }
+ }
+#endif
+ if (trarea == 0)
+ {
+ // find the distance from the previous
+ double val = SQRT(SQR(prev.left - tr.left) + SQR(prev.top - tr.top));
+ if (bsfdist > val)
+ {
+ bsfrect = tr;
+ bsfdist = val;
+ }
+ }
+ else
+ {
+ if (trarea < bsfval)
+ {
+ bsfrect = tr;
+ bsfval = trarea;
+ }
+ }
+ iters++;
+ return trarea;
+}
+
+double FindOpenRect::compare_overlapArea(const RECT &rect, const RECT &dest, unsigned long userdata, unsigned long userdata2, int index, double bsf)
+{
+ RECT intersection;
+ if (Wasabi::Std::rectIntersect(rect, dest, &intersection))
+ {
+ intersection.right -= intersection.left;
+ intersection.bottom -= intersection.top;
+ return intersection.right * intersection.bottom;
+ }
+ return 0;
+}
+
+void FindOpenRect::setTimeLimit(int ms)
+{
+ timelimit = ms;
+}
+
+int FindOpenRect::getNumIters()
+{
+ return iters;
+}
+
+void FindOpenRect::resetNumIters()
+{
+ iters = 0;
+}
+
+double FindOpenRect::getBestValSoFar()
+{
+ return (bsfval == 10e10) ? 0 : bsfval;
+}
+
+RECT FindOpenRect::getBestRectSoFar()
+{
+ return bsfrect;
+}
+
+void FindOpenRect::setBestSoFar(double bsf, const RECT &bestrect)
+{
+ if (bsf > 0 && bsfval > bsf)
+ {
+ bsfval = bsf;
+ bsfrect = bestrect;
+ bsfdist = SQRT(SQR(prev.left - bsfrect.left) + SQR(prev.top - bsfrect.top));
+ //CUTDebugString("*******************8 better BSF ****************");
+ }
+}
+
+RECT FindOpenRect::getOriginalRect()
+{
+ return prev;
+}
+
+void FindOpenRect::setCoordDivisor(int _xdiv, int _ydiv)
+{
+ xdiv = MAX(_xdiv, 1);
+ ydiv = MAX(_ydiv, 1);
+}
diff --git a/Src/Wasabi/bfc/util/findopenrect.h b/Src/Wasabi/bfc/util/findopenrect.h
new file mode 100644
index 00000000..97fdc5cb
--- /dev/null
+++ b/Src/Wasabi/bfc/util/findopenrect.h
@@ -0,0 +1,63 @@
+#ifndef _FINDOPENRECT_H
+#define _FINDOPENRECT_H
+
+#include <bfc/wasabi_std.h>
+#include <bfc/ptrlist.h>
+
+class FindOpenRect
+{
+public:
+ FindOpenRect();
+
+ typedef double (*compareRectsFn)(const RECT &rect, const RECT &dest, unsigned long userdata, unsigned long userdata2, int index, double bsf);
+ static double compare_overlapArea(const RECT &rect, const RECT &dest, unsigned long userdata = 0, unsigned long userdata2 = 0, int index = 0, double bsf = 0);
+
+ void setCompareRectsFn(compareRectsFn fn);
+
+ // this one does it all in one call
+ RECT find(const RECT &viewport, const PtrList<RECT> &list,
+ const RECT &prev, unsigned long userdata = 0, unsigned long userdata2 = 0);
+
+ // these let you do it over time
+ void beginFind(const RECT &viewport, const PtrList<RECT> &list,
+ const RECT &prev, unsigned long userdata = 0, unsigned long userdata2 = 0);
+ RECT findMore();
+
+ double trySingleRect(const RECT &r, int early_out = FALSE);
+
+ void setTimeLimit(int ms);
+ int getNumIters();
+ void resetNumIters();
+
+ double getBestValSoFar();
+ RECT getBestRectSoFar();
+
+ // this only sets it if it's a better value
+ void setBestSoFar(double bsf, const RECT &bestrect);
+
+ RECT getOriginalRect();
+
+ void setCoordDivisor(int xdiv, int ydiv);
+
+private:
+ RECT vr, prev;
+ PtrList<RECT> list;
+ compareRectsFn fn;
+ unsigned long userdata, userdata2;
+
+ int timelimit;
+ int iters;
+
+ int xdiv, ydiv;
+
+ RECT bsfrect;
+ double bsfval;
+ double bsfdist;
+ //CUT RECT bsf_nooverlap;
+ //CUT int found_nooverlap;
+ //CUT RECT bsf_overlap;
+ //CUT double bsfval_nooverlap;
+ //CUT double bsfval_overlap;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/util/inifile.cpp b/Src/Wasabi/bfc/util/inifile.cpp
new file mode 100644
index 00000000..dba5a9b5
--- /dev/null
+++ b/Src/Wasabi/bfc/util/inifile.cpp
@@ -0,0 +1,56 @@
+#include <precomp.h>
+
+#include "inifile.h"
+#include <bfc/nsguid.h>
+
+#ifndef WIN32
+#include "profile.h"
+#endif
+
+IniFile::IniFile(const wchar_t *_filename) : filename(_filename) { }
+
+void IniFile::setString(const wchar_t *section, const wchar_t *tagname, const wchar_t *val) {
+ WritePrivateProfileStringW(section, tagname, val, filename);
+}
+
+wchar_t *IniFile::getString(const wchar_t *section, const wchar_t *tagname, wchar_t *buf, int buflen, const wchar_t *default_val) {
+ GetPrivateProfileStringW(section, tagname, default_val, buf, buflen, filename);
+ return buf;
+}
+
+StringW IniFile::getString(const wchar_t *section, const wchar_t *tagname, const wchar_t *default_val) {
+ wchar_t buf[WA_MAX_PATH]=L"";
+ getString(section, tagname, buf, WA_MAX_PATH-1, default_val);
+ return StringW(buf);
+}
+
+void IniFile::setInt(const wchar_t *section, const wchar_t *tagname, int val) {
+ setString(section, tagname, StringPrintfW(val));
+}
+
+int IniFile::getInt(const wchar_t *section, const wchar_t *tagname, int default_val) {
+ wchar_t buf[MAX_PATH] = {0};
+ getString(section, tagname, buf, sizeof(buf), StringPrintfW(default_val));
+ return WTOI(buf);
+}
+
+int IniFile::getBool(const wchar_t *section, const wchar_t *tagname, int default_val) {
+ wchar_t buf[MAX_PATH] = {0};
+ getString(section, tagname, buf, sizeof(buf), default_val ? L"true" : L"false");
+ if (!_wcsicmp(buf, L"true")) return 1;
+ return 0;
+}
+
+void IniFile::setBool(const wchar_t *section, const wchar_t *tagname, int val) {
+ setString(section, tagname, val ? L"true" : L"false");
+}
+
+GUID IniFile::getGuid(const wchar_t *section, const wchar_t *tagname, GUID default_val) {
+ wchar_t buf[MAX_PATH] = {0};
+ getString(section, tagname, buf, sizeof(buf), StringPrintfW(default_val));
+ return nsGUID::fromCharW(buf);
+}
+
+void IniFile::setGuid(const wchar_t *section, const wchar_t *tagname, const GUID &val) {
+ setString(section, tagname, StringPrintfW(val));
+}
diff --git a/Src/Wasabi/bfc/util/inifile.h b/Src/Wasabi/bfc/util/inifile.h
new file mode 100644
index 00000000..6ce7b151
--- /dev/null
+++ b/Src/Wasabi/bfc/util/inifile.h
@@ -0,0 +1,28 @@
+#ifndef _INIFILE_H
+#define _INIFILE_H
+
+#include <bfc/string/StringW.h>
+
+class IniFile
+{
+public:
+ IniFile(const wchar_t *_filename);
+
+ void setString(const wchar_t *section, const wchar_t *tagname, const wchar_t *val);
+ wchar_t *getString(const wchar_t *section, const wchar_t *tagname, wchar_t *buf, int buflen, const wchar_t *default_val = L""); // returns buf
+ StringW getString(const wchar_t *section, const wchar_t *tagname, const wchar_t *default_val=L"");
+
+ void setInt(const wchar_t *section, const wchar_t *tagname, int val);
+ int getInt(const wchar_t *section, const wchar_t *tagname, int default_val = 0);
+
+ int getBool(const wchar_t *section, const wchar_t *tagname, int default_val = 0);
+ void setBool(const wchar_t *section, const wchar_t *tagname, int val);
+
+ GUID getGuid(const wchar_t *section, const wchar_t *tagname, GUID default_val = INVALID_GUID);
+ void setGuid(const wchar_t *section, const wchar_t *tagname, const GUID &val);
+
+private:
+ StringW filename;
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/util/profile.c b/Src/Wasabi/bfc/util/profile.c
new file mode 100644
index 00000000..3049945a
--- /dev/null
+++ b/Src/Wasabi/bfc/util/profile.c
@@ -0,0 +1,288 @@
+#pragma warn -aus
+//----------------------------------------------------------------------------
+// MS Windows Style .ini File Interface for C++
+// This is the first version.
+// Programed by xuyifeng, 1995.10, china
+//----------------------------------------------------------------------------
+// Test history:
+// Compiler OS TEST
+// ---------------------------------------------------------------
+// Watcom C++ 10.0a Rational System DOS4GW 100% tested
+// Borland C++ 3.1 DOS 100% tested
+// 10/4/97 - Bugfix: added fclose(is); at the end of getProfileString -lonerunnr/ags
+//----------------------------------------------------------------------------
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/io.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef LINUX
+#include <X11/Xos.h>
+#define _strnicmp strncasecmp
+#endif
+
+#include "profile.h"
+
+#define False 0
+#define True 1
+
+//------------------------------------------------------------------------------
+// titlePos: get a section title position & length in a string.
+//------------------------------------------------------------------------------
+static char *titlePos( char *buf, int *len )
+{
+ char *p = buf, *q;
+
+ while( *p && isspace(*p) ) p++;
+ if( *p != '[' )
+ return 0;
+
+ q = p+1;
+ while( *q && *q != ']' ) q++;
+ if( *q != ']' )
+ return 0;
+ if( len )
+ *len = (int)(q - p - 1);
+ return p+1;
+}
+
+//------------------------------------------------------------------------------
+// isTitleLine: check if a string is a section title line
+//------------------------------------------------------------------------------
+static int isTitleLine( char *bufPtr )
+{
+ return titlePos( bufPtr, 0 ) != 0;
+}
+
+//------------------------------------------------------------------------------
+// containTitle: check if a string contain a section a title
+//------------------------------------------------------------------------------
+static int containTitle( char *buf, const char *section )
+{
+ int len = 0;
+ char *p = titlePos(buf, &len);
+ if (p)
+ {
+ if( strlen( section ) == len && _strnicmp( section, p, len ) == 0 )
+ return True;
+ }
+ return False;
+}
+
+//------------------------------------------------------------------------------
+// gotoSection: move file position to start line of a section
+//------------------------------------------------------------------------------
+static int gotoSection( FILE *is, const char *section )
+{
+ char line[256] = {0};
+ while( fgets(line, 256, is) != NULL)
+ if( containTitle( line, section ) )
+ return True;
+ return False;
+}
+
+//------------------------------------------------------------------------------
+// textPos: get content's position of a entry
+//------------------------------------------------------------------------------
+static char *textPos( char *buf, const char *entry )
+{
+ if( buf[0] == ';' ) // it is comment line
+ return 0;
+
+ char *p = strchr( buf, '=' );
+ if (!p)
+ return 0;
+
+ int len = (int)(p - buf);
+ if( strlen(entry) == len && _strnicmp( buf, entry, len ) == 0 )
+ return p+1;
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// stripQuotationChar: strip a pair of quotation chars in a string
+//------------------------------------------------------------------------------
+static void stripQuotationChar( char *buf )
+{
+ char *p = buf;
+ while( *p && isspace(*p) ) p++;
+
+ if( !(*p == '\"' || *p == '\'') )
+ return;
+
+ char *q = p+strlen(p);
+ while( *q != *p && q > p ) q--;
+ if( q == p )
+ return;
+ int len = (int)(q - p - 1);
+ memmove( buf, p+1, len );
+ buf[len] = 0;
+}
+
+//------------------------------------------------------------------------------
+// readEntry: read content of entry
+//------------------------------------------------------------------------------
+static int readEntry( FILE *is, const char *entry, char *buf, int bufSize,
+ int strip )
+{
+ char lineBuf[256] = {0};
+ char *cur = buf;
+ *cur = '\0';
+ int len = -1;
+ while( fgets(lineBuf, 256, is) != NULL)
+ {
+ if (lineBuf[strlen(lineBuf)-1] == '\n')
+ lineBuf[strlen(lineBuf)-1] = 0;
+
+ if( isTitleLine( lineBuf ) ) // section is ended
+ break;
+
+ char *p = textPos( lineBuf, entry ); // not equal this entry
+ if( p == 0 )
+ continue;
+
+ if( strip )
+ stripQuotationChar( p );
+
+ len = strlen(p);
+ if( bufSize-1 < len )
+ len = bufSize-1;
+
+ strncpy( cur, p, len );
+ cur[len] = 0;
+ break;
+ }
+
+ return len;
+}
+
+//------------------------------------------------------------------------------
+// getProfileString:
+//------------------------------------------------------------------------------
+int GetPrivateProfileString( const char *section,
+ const char *entry,
+ const char *defaultString,
+ char *buffer,
+ int bufLen,
+ const char *fileName )
+{
+ FILE *is;
+ int len = -1;
+
+ is = fopen(fileName, "rt");
+
+ if( is && gotoSection( is, section ) )
+ len = readEntry(is, entry, buffer, bufLen, True);
+
+ if (len < 0) //can not read entry, use default string
+ {
+ strncpy( buffer, defaultString, bufLen-1 );
+ buffer[bufLen-1] = 0;
+ len = strlen(buffer);
+ }
+ if (is) fclose(is);
+ return len;
+}
+
+//----------------------------------------------------------------------------
+// getProfileInt:
+//----------------------------------------------------------------------------
+long GetPrivateProfileInt( const char *section,
+ const char *entry,
+ long defaultInt,
+ const char *fileName )
+{
+ char buf[256];
+ char iBuf[34]; //"34" is max space "_itoa" required under 32 bit C++
+
+ sprintf(iBuf, "%d", defaultInt);
+ GetPrivateProfileString( section, entry, iBuf, buf, 256, fileName );
+ return atol( buf );
+}
+
+static void writeEntry( FILE *os, const char *entry, const char *string )
+{
+ fprintf(os, "%s=%s\n", entry, string);
+}
+
+//------------------------------------------------------------------------------
+// writeProfileString:
+//------------------------------------------------------------------------------
+int WritePrivateProfileString( const char *section,
+ const char *entry,
+ const char *string,
+ const char *fileName )
+{
+ char path [8192] = {0};
+ char drive[256] = {0};
+ char dir [256] = {0};
+ char file [256] = {0};
+ char ext [256] = {0};
+ char buf [256] = {0};
+
+ int titleFound;
+
+ // work better on network!
+ _splitpath( path, drive, dir, file, ext );
+ _makepath( path, drive, dir, mkstemp("iniXXXXXX"), "" );
+
+ FILE *is = fopen(fileName, "rt");
+ FILE *os = fopen(path, "wt");
+
+ if(!is || !os || entry == 0) // maybe can not create file or invalid entry
+ {
+ if (is) fclose(is);
+ if (os) fclose(os);
+ return 0;
+ }
+
+ titleFound = False;
+ if (is)
+ {
+ while (fgets(buf, 256, is) != NULL)
+ {
+ fputs(buf, os);
+ if( containTitle(buf, section) )
+ {
+ titleFound = True;
+ break;
+ }
+ }
+ }
+
+ if (!titleFound) // add section
+ {
+ fprintf(os, "[%s]\n", section);
+ writeEntry( os, entry, string );
+ }
+ else
+ {
+ while (fgets(buf, 256, is) != NULL)
+ {
+ if (isTitleLine(buf)) // section ended, but still not found the entry
+ break;
+
+ if (textPos(buf, entry)) // entry found, so rewrite it
+ {
+ break;
+ }
+ fputs(buf, os);
+ }
+
+ writeEntry(os, entry, string);
+
+ if (is)
+ {
+ while(fgets(buf, 256, is) != NULL) // copy left lines
+ fputs(buf, os);
+ }
+ }
+ if (is) fclose(is);
+ if (os) fclose(os);
+ unlink(fileName);
+ rename(path, fileName);
+ return strlen(string);
+}
+
+#pragma warn .aus \ No newline at end of file
diff --git a/Src/Wasabi/bfc/util/profile.h b/Src/Wasabi/bfc/util/profile.h
new file mode 100644
index 00000000..9d0df724
--- /dev/null
+++ b/Src/Wasabi/bfc/util/profile.h
@@ -0,0 +1,26 @@
+//
+// profile.h
+// Profile support.
+// Programed by XuYiFeng 1995.4.25, All rights reserved.
+//
+
+#ifndef __PROFILE_H
+#define __PROFILE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+long GetPrivateProfileInt( const char *section, const char *entry, long defaultInt,
+ const char *fileName );
+int GetPrivateProfileString( const char *section, const char *entry,
+ const char *defaultString, char *buffer,
+ int bufLen, const char *fileName );
+int WritePrivateProfileString( const char *section, const char *entry,
+ const char *string, const char *fileName );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Src/Wasabi/bfc/util/profiler.cpp b/Src/Wasabi/bfc/util/profiler.cpp
new file mode 100644
index 00000000..3871434f
--- /dev/null
+++ b/Src/Wasabi/bfc/util/profiler.cpp
@@ -0,0 +1,6 @@
+#include <precomp.h>
+#include "profiler.h"
+
+PtrListInsertSorted<__ProfilerEntry, __ProfilerEntrySort> __profiler_entries;
+
+int __profiler_indent;
diff --git a/Src/Wasabi/bfc/util/profiler.h b/Src/Wasabi/bfc/util/profiler.h
new file mode 100644
index 00000000..e7b71e81
--- /dev/null
+++ b/Src/Wasabi/bfc/util/profiler.h
@@ -0,0 +1,128 @@
+#ifndef _PROFILER_H
+#define _PROFILER_H
+
+#include <bfc/wasabi_std.h>
+#include <bfc/string/bfcstring.h>
+#include <bfc/ptrlist.h>
+
+
+#ifdef NO_PROFILING
+#define PR_ENTER(msg)
+#define PR_LEAVE()
+#else
+
+#define _PR_ENTER(msg, line) { __Profiler __prx##line(msg)
+#define _PR_ENTER2(msg, msg2, line) { __Profiler __prx##line(msg, msg2)
+#define PR_ENTER(msg) _PR_ENTER(msg, line)
+#define PR_ENTER2(msg, msg2) _PR_ENTER2(msg, msg2, line)
+#define PR_LEAVE() }
+
+class __ProfilerEntry {
+ public:
+ __ProfilerEntry(const char *txt) { text = txt; totaltime = 0; totaln = 0; subcount = 0; lastcps = -1;}
+ virtual ~__ProfilerEntry() {}
+
+ void add(float ms) { totaltime += ms; totaln++;
+ if (subcount == 0) {
+ firstcall = Wasabi::Std::getTimeStampMS();
+ }
+ if (Wasabi::Std::getTimeStampMS() - firstcall < 1) {
+ subcount++;
+ } else {
+ lastcps = subcount;
+ subcount = 0;
+ }
+ }
+ float getAverage() { if (totaln == 0) return 0; return totaltime / (float)totaln; }
+ float getTotal() { return totaltime; }
+ const char *getText() { return text; }
+ int getLastCPS() { return lastcps; }
+
+ private:
+ float totaltime;
+ int totaln;
+ stdtimevalms firstcall;
+ int lastcps;
+ int subcount;
+ String text;
+};
+
+class __ProfilerEntrySort {
+public:
+ static int compareAttrib(const wchar_t *attrib, void *item) {
+ return STRICMP((const char *)attrib, ((__ProfilerEntry*)item)->getText());
+ }
+ static int compareItem(void *i1, void *i2) {
+ return STRICMP(((__ProfilerEntry*)i1)->getText(), ((__ProfilerEntry*)i2)->getText());
+ }
+};
+
+extern COMEXP PtrListInsertSorted<__ProfilerEntry, __ProfilerEntrySort> __profiler_entries;
+extern COMEXP int __profiler_indent;
+
+class __ProfilerManager {
+ public:
+ static void log(const char *txt, float ms, float *total, float *average, int *lastcps) {
+ int pos=-1;
+ __ProfilerEntry *e = __profiler_entries.findItem((const wchar_t *)txt, &pos);
+ if (pos < 0 || e == NULL) {
+ e = new __ProfilerEntry(txt);
+ __profiler_entries.addItem(e);
+ }
+ if (e != NULL) {
+ e->add(ms);
+ if (total != NULL) *total = e->getTotal();
+ if (average != NULL) *average = e->getAverage();
+ if (lastcps != NULL) *lastcps = e->getLastCPS();
+ }
+ }
+};
+
+#undef USE_TICK_COUNT
+
+class __Profiler {
+public:
+ __Profiler(const char *text, const char *text2="") : str(text), str2(text2) {
+ if (!str2.isempty()) str2 += " ";
+#ifdef USE_TICK_COUNT
+ ts1 = GetTickCount();
+#else
+ ts1 = Wasabi::Std::getTimeStampMS();
+#endif
+ __profiler_indent++;
+ }
+ ~__Profiler() {
+ __profiler_indent--;
+#ifdef USE_TICK_COUNT
+ stdtimevalms ts2 = GetTickCount();
+#else
+ stdtimevalms ts2 = Wasabi::Std::getTimeStampMS();
+#endif
+ float ms = (float)((ts2 - ts1)
+#ifndef USE_TICK_COUNT
+*1000.0
+#endif
+);
+ float total=0;
+ float average=0;
+ int lastcps=0;
+ __ProfilerManager::log(str, ms, &total, &average, &lastcps);
+ char buf[4096];
+ if (lastcps >= 0)
+ sprintf(buf, "%*sProfiler: %s: %s%6.4f ms (total: %6.4f ms, average: %6.4f ms, calls per second : %d)\n", __profiler_indent*4, " ", str.getValue(), str2.getValue(), ms, total, average, lastcps);
+ else
+ sprintf(buf, "%*sProfiler: %s: %s%6.4f ms (total: %6.4f ms, average: %6.4f ms)\n", __profiler_indent*4, " ", str.getValue(), str2.getValue(), ms, total, average);
+#ifdef _WIN32
+ OutputDebugStringA(buf);
+#else
+#warning port me
+#endif
+ }
+private:
+ String str, str2;
+ stdtimevalms ts1;
+};
+
+#endif//!NO_PROFILING
+
+#endif
diff --git a/Src/Wasabi/bfc/util/timefmt.cpp b/Src/Wasabi/bfc/util/timefmt.cpp
new file mode 100644
index 00000000..f0968ac6
--- /dev/null
+++ b/Src/Wasabi/bfc/util/timefmt.cpp
@@ -0,0 +1,71 @@
+#include <precomp.h>
+#include <bfc/wasabi_std.h>
+#include <time.h>
+#include "timefmt.h"
+
+void TimeFmt::printMinSec(int sec, wchar_t *buf, int buflen)
+{
+ int minutes, seconds;
+ int negative = sec < 0;
+
+ if (buf == NULL) return;
+
+ if (sec == -1)
+ {
+ *buf = 0;
+ return;
+ }
+
+ seconds = sec % 60;
+ sec /= 60;
+ minutes = sec;
+
+ StringPrintfW sp(L"%s%d:%02d", (minutes == 0 && negative) ? L"-" : L"", minutes, ABS(seconds));
+ WCSCPYN(buf, sp, buflen);
+}
+
+void TimeFmt::printHourMinSec(int sec, wchar_t *buf, int buflen, int hoursonlyifneeded)
+{
+ int hours, minutes, seconds;
+ int negative = sec < 0;
+
+ sec = ABS(sec);
+ if (buf == NULL) return;
+
+ if (sec == -1) {
+ *buf = 0;
+ return;
+ }
+
+ hours = sec / 3600;
+ sec -= hours * 3600;
+ seconds = sec % 60;
+ sec /= 60;
+ minutes = sec;
+
+ StringW sp;
+ if (hoursonlyifneeded && hours == 0)
+ sp = StringPrintfW(L"%s%d:%02d", (minutes == 0 && negative) ? L"-" : L"", minutes, seconds);
+ else
+ sp = StringPrintfW(L"%s%d:%02d:%02d", (hours == 0 && negative) ? L"-" : L"", hours, minutes, seconds);
+
+ WCSCPYN(buf, sp, buflen);
+}
+
+void TimeFmt::printTimeStamp(wchar_t *buf, int bufsize, int ts)
+{
+ if (ts == 0)
+ {
+ WCSCPYN(buf, L"Never", bufsize); // FUCKO: load from lang pack
+ return;
+ }
+
+ struct tm *tm_now;
+ tm_now = localtime((const time_t *)&ts);
+ if (tm_now == NULL)
+ {
+ *buf = 0;
+ return;
+ }
+ wcsftime(buf, bufsize, L"%a %b %Y %d %I:%M:%S %p", tm_now);
+}
diff --git a/Src/Wasabi/bfc/util/timefmt.h b/Src/Wasabi/bfc/util/timefmt.h
new file mode 100644
index 00000000..b24e0a99
--- /dev/null
+++ b/Src/Wasabi/bfc/util/timefmt.h
@@ -0,0 +1,46 @@
+//PORTABLE
+#ifndef _TIMEFMT_H
+#define _TIMEFMT_H
+
+/**
+ Simple time formatting. Can format into a minutes:seconds style
+ display based on count in seconds only.
+
+ Can also format a timestamp into human readable format.
+
+ @author Nullsoft
+ @ver 1.0
+*/
+class TimeFmt {
+public:
+ /**
+ Formats a time value in seconds to minute:seconds.
+
+ If the buffer is too small, the string will be
+ truncated.
+
+ @param seconds Time value to convert.
+ @param buf Buffer to receive formatted string.
+ @param buflen Length of the buffer.
+ */
+ static void printMinSec(int seconds, wchar_t *buf, int buflen);
+ static void printHourMinSec(int seconds, wchar_t *buf, int buflen, int hoursonlyifneeded=0);
+
+ /**
+ Formats a time value (from unix timestamp) to
+ human readable format.
+
+ If the buffer is too small, the string will be
+ truncated.
+
+ Example of formatted output:
+ Tue Sep 10 18:34:42 PDT 2002
+
+ @param buf Buffer to receive the formatted string.
+ @param bufsize Length of the buffer.
+ @param ts The timestamp to use.
+ */
+ static void printTimeStamp(wchar_t *buf, int bufsize, int ts);
+};
+
+#endif
diff --git a/Src/Wasabi/bfc/wasabi_std.cpp b/Src/Wasabi/bfc/wasabi_std.cpp
new file mode 100644
index 00000000..e608edd0
--- /dev/null
+++ b/Src/Wasabi/bfc/wasabi_std.cpp
@@ -0,0 +1,1198 @@
+#include "wasabi_std.h"
+//#include <wasabicfg.h>
+#include <bfc/parse/pathparse.h>
+#ifdef WIN32
+
+#define WIN32_LEAN_AND_MEAN
+
+#include <shlobj.h>
+#include <multimon.h>
+#if !defined(HMONITOR_DECLARED) && (WINVER < 0x500)
+DECLARE_HANDLE(HMONITOR);
+#define HMONITOR_DECLARED
+#endif
+
+#include <objbase.h>
+#include <shellapi.h> // for ShellExecute
+#include <math.h>
+#include <mbctype.h>
+
+#include <sys/stat.h>
+
+#ifndef SPI_GETWHEELSCROLLLINES
+# define SPI_GETWHEELSCROLLLINES 104
+#endif
+
+#ifndef SPI_GETLISTBOXSMOOTHSCROLLING
+# define SPI_GETLISTBOXSMOOTHSCROLLING 0x1006
+#endif
+
+#endif // WIN32
+
+#include <bfc/bfc_assert.h>
+
+#include <bfc/ptrlist.h>
+
+#include <time.h> // CUT if possible... maybe make bfc/platform/time.h
+#ifdef __APPLE__
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#include <malloc.h>
+#include <shlwapi.h>
+#endif
+
+static HANDLE wasabiHeap = NULL;
+
+void *MALLOC(size_t size)
+{
+ //ASSERT(wasabiHeap != NULL);
+ ASSERT(size > 0);
+ //return HeapAlloc(wasabiHeap, 0, size);
+ return malloc(size);
+}
+
+wchar_t *WMALLOC(size_t size)
+{
+// ASSERT(wasabiHeap != NULL);
+ ASSERT(size > 0);
+ size *= sizeof(wchar_t);
+// return (wchar_t *)HeapAlloc(wasabiHeap, 0, size);
+ return (wchar_t*)malloc(size);
+}
+
+void *CALLOC(size_t records, size_t recordsize) {
+// ASSERT(wasabiHeap != NULL);
+ ASSERT(records > 0 && recordsize > 0);
+ // return HeapAlloc(wasabiHeap, HEAP_ZERO_MEMORY, records * recordsize);
+ return calloc(records, recordsize);
+}
+
+void FREE(void *ptr) {
+ if (ptr == NULL)
+ return;
+ //HeapFree(wasabiHeap, 0, ptr);
+ free(ptr);
+ ptr = NULL;
+}
+
+// Note: MEMCPY allows dest and src to overlap
+void MEMCPY(void *dest, const void *src, size_t n) {
+ ASSERT(dest != NULL);
+ ASSERT(src != NULL);
+ ASSERT(n >= 0);
+ memmove(dest, src, n);
+}
+
+void *MEMDUP(const void *src, size_t n) {
+ void *ret;
+ ASSERT(n >= 0);
+ if (src == NULL || n == 0) return NULL;
+ ret = MALLOC(n);
+ if (ret == NULL) return NULL;
+ MEMCPY(ret, src, n);
+ return ret;
+}
+
+void *REALLOC(void *ptr, size_t size) {
+ //ASSERT(wasabiHeap != NULL);
+ ASSERT(size >= 0);
+ if (ptr == NULL) {
+ return realloc(0, size);
+ //return HeapAlloc(wasabiHeap, 0, size);
+ } else {
+ return realloc(ptr, size);
+ //return HeapReAlloc(wasabiHeap, 0, ptr, size);
+ }
+}
+
+static wchar_t TOUPPERANDSLASH(wchar_t a)
+{
+ if (a=='\\')
+ a = '/';
+ else
+ a = TOUPPERW(a);
+ return a;
+}
+
+int PATHEQL(const wchar_t *str1, const wchar_t *str2) {
+ if (str1 == NULL) {
+ if (str2 == NULL) return TRUE;
+ return FALSE;
+ }
+ while (TOUPPERANDSLASH(*str1) == TOUPPERANDSLASH(*str2) && *str1 != 0 && *str2 != 0) str1++, str2++;
+ return *str1 == *str2;
+}
+
+
+static int rand_inited;
+
+static double divider=0.;
+
+
+void Wasabi::Std::Initialize()
+{
+ //if (wasabiHeap == NULL) {
+ // wasabiHeap = HeapCreate(0, 0, 0);
+ // srandom();
+ // LARGE_INTEGER ll;
+ // QueryPerformanceFrequency(&ll);
+ // divider = (double)ll.QuadPart;
+ //}
+
+ if (0 == divider)
+ {
+ srandom();
+ LARGE_INTEGER ll;
+ QueryPerformanceFrequency(&ll);
+ divider = (double)ll.QuadPart;
+ }
+}
+
+void Wasabi::Std::getMousePos(POINT *p) {
+ ASSERT(p != NULL);
+#ifdef WIN32
+ GetCursorPos(p);
+#elif defined(__APPLE__)
+ Point pt;
+ GetMouse(&pt);
+ p->x = pt.v;
+ p->y = pt.h;
+#else
+ Window w1, w2;
+ int a, b;
+ unsigned int c;
+ int x, y;
+
+ XQueryPointer( Linux::getDisplay(), Linux::RootWin(), &w1, &w2,
+ &x, &y, &a, &b, &c );
+
+ p->x = x;
+ p->y = y;
+#endif
+}
+
+void Wasabi::Std::getMousePos(int *x, int *y) {
+ POINT p;
+ getMousePos(&p);
+ if (x != NULL) *x = p.x;
+ if (y != NULL) *y = p.y;
+}
+
+void Wasabi::Std::getMousePos(long *x, long *y) {
+ getMousePos((int *)x, (int *)y);
+}
+
+void Wasabi::Std::setMousePos(POINT *p) {
+ ASSERT(p != NULL);
+#ifdef WIN32
+ SetCursorPos(p->x, p->y);
+#elif defined(__APPLE__)
+ CGWarpMouseCursorPosition(HIPointFromPOINT(p));
+#else
+ POINT p2;
+ getMousePos( &p2 );
+
+ XWarpPointer( Linux::getDisplay(), None, None,
+ 0, 0, 1, 1, p->x - p2.x, p->y - p2.y );
+#endif
+}
+
+void Wasabi::Std::setMousePos(int x, int y) {
+ POINT p={x,y};
+ setMousePos(&p);
+}
+
+void Wasabi::Std::getViewport(RECT *r, POINT *p, int full)
+{
+#ifdef _WIN32
+ getViewport(r, p, NULL, (HWND)0, full);
+#elif defined(__APPLE__)
+ CGDirectDisplayID display;
+ CGDisplayCount count;
+ if (CGGetDisplaysWithPoint(HIPointFromPOINT(p), 1, &display, &count) == kCGErrorSuccess)
+ {
+ HIRect rect = CGDisplayBounds(display);
+ *r = RECTFromHIRect(&rect);
+ // TODO: cut out dock if full == 0 maybe GetAvailableWindowPositioningBounds if we can get the GDHandle
+ }
+#endif
+}
+
+void Wasabi::Std::getViewport(RECT *r, RECT *sr, int full)
+{
+#ifdef _WIN32
+ getViewport(r, NULL, sr, (HWND)0, full);
+#elif defined(__APPLE__)
+ CGDirectDisplayID display;
+ CGDisplayCount count;
+ if (CGGetDisplaysWithRect(HIRectFromRECT(sr), 1, &display, &count) == kCGErrorSuccess)
+ {
+ HIRect rect = CGDisplayBounds(display);
+ *r = RECTFromHIRect(&rect);
+ // TODO: cut out dock if full == 0 maybe GetAvailableWindowPositioningBounds if we can get the GDHandle
+ }
+#endif
+}
+
+void Wasabi::Std::getViewport(RECT *r, OSWINDOWHANDLE wnd, int full)
+{
+#ifdef _WIN32
+ getViewport(r, NULL, NULL, wnd, full);
+#elif defined(__APPLE__)
+ GDHandle gd;
+ Rect gdr;
+ GetWindowGreatestAreaDevice(wnd, kWindowStructureRgn, &gd, &gdr);
+
+ if (full)
+ {
+ CGDirectDisplayID display = QDGetCGDirectDisplayID(gd);
+ HIRect rect = CGDisplayBounds(display);
+ *r = RECTFromHIRect(&rect);
+ }
+ else
+ {
+ // TODO: maybe use GetAvailableWindowPositioningBounds instead
+ r->left = gdr.left;
+ r->top = gdr.top;
+ r->right = gdr.right;
+ r->bottom = gdr.bottom;
+ }
+#endif
+}
+#ifdef _WIN32
+static HINSTANCE user32_instance = 0;
+BOOL (WINAPI *Gmi)(HMONITOR mon, LPMONITORINFO lpmi) = 0;
+#endif
+void Wasabi::Std::getViewport(RECT *r, POINT *p, RECT *sr, OSWINDOWHANDLE wnd, int full) {
+ ASSERT(r != NULL);
+#ifdef WIN32
+ if (p || sr || wnd)
+ {
+ if (!user32_instance)
+ user32_instance=LoadLibraryW(L"user32.dll");
+
+ if (user32_instance)
+ {
+ HMONITOR (WINAPI *Mfp)(POINT pt, DWORD dwFlags) = (HMONITOR (WINAPI *)(POINT,DWORD)) GetProcAddress(user32_instance,"MonitorFromPoint");
+ HMONITOR (WINAPI *Mfr)(LPCRECT lpcr, DWORD dwFlags) = (HMONITOR (WINAPI *)(LPCRECT, DWORD)) GetProcAddress(user32_instance, "MonitorFromRect");
+ HMONITOR (WINAPI *Mfw)(HWND wnd, DWORD dwFlags)=(HMONITOR (WINAPI *)(HWND, DWORD)) GetProcAddress(user32_instance, "MonitorFromWindow");
+
+ if (!Gmi)
+ Gmi = (BOOL (WINAPI *)(HMONITOR,LPMONITORINFO)) GetProcAddress(user32_instance,"GetMonitorInfoW");
+
+ if (Mfp && Mfr && Mfw && Gmi)
+ {
+ HMONITOR hm;
+ if ( p )
+ hm = Mfp( *p, MONITOR_DEFAULTTONEAREST );
+ else if ( sr )
+ hm = Mfr( sr, MONITOR_DEFAULTTONEAREST );
+ else if ( wnd )
+ hm = Mfw( wnd, MONITOR_DEFAULTTONEAREST );
+
+ if (hm)
+ {
+ MONITORINFOEXW mi;
+ ZERO(mi);
+ mi.cbSize=sizeof(mi);
+
+ if (Gmi(hm,&mi))
+ {
+ if(!full)
+ *r=mi.rcWork;
+ else
+ *r=mi.rcMonitor;
+
+ return;
+ }
+ }
+ }
+ }
+ }
+ SystemParametersInfoW(SPI_GETWORKAREA,0,r,0);
+#endif
+#ifdef LINUX
+ r->left = r->top = 0;
+ r->right = Wasabi::Std::getScreenWidth();
+ r->bottom = Wasabi::Std::getScreenHeight();
+#endif
+}
+
+#ifdef WIN32
+class ViewportEnumerator {
+ public:
+ HMONITOR hm;
+#ifdef WIN32
+ int monitor_n;
+#endif
+ int counter;
+};
+
+static BOOL CALLBACK enumViewportsProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
+ ViewportEnumerator *ve = reinterpret_cast<ViewportEnumerator *>(dwData);
+ ASSERT(ve != NULL);
+ if (ve->counter == ve->monitor_n) {
+ ve->hm = hMonitor;
+ return FALSE;
+ }
+ ve->counter++;
+ return TRUE;
+}
+#endif
+
+void Wasabi::Std::srandom(unsigned int key) {
+ if (key == 0) key = (unsigned int)Std::getTimeStamp();
+ ::srand(key);
+}
+
+int Wasabi::Std::random(int max) {
+// ASSERT(max <= RAND_MAX);
+ int ret = ::rand();
+ if (max != RAND_MAX+1) ret %= max;
+ return ret;
+}
+
+unsigned int Wasabi::Std::random32(unsigned int max) {
+ if (!rand_inited++) Wasabi::Std::srandom();
+ unsigned int val=0;
+ for (int i = 0; i < sizeof(unsigned int); i++) {
+ val <<= 8;
+ val |= ((::rand()>>2) & 0xff);
+ }
+ if (max != 0xffffffff) val %= max;
+ return val;
+}
+
+#ifdef _WIN32 // PORT ME
+void Wasabi::Std::usleep(int ms) {
+ Sleep(ms);
+//INLINE
+}
+#endif
+
+__time64_t Wasabi::Std::getTimeStamp() {
+ __time64_t time64;
+ _time64(&time64);
+ return time64;
+}
+
+stdtimevalms Wasabi::Std::getTimeStampMS() {
+#ifdef WIN32
+ LARGE_INTEGER ll;
+ if (!QueryPerformanceCounter(&ll)) return getTickCount() / 1000.f;
+ stdtimevalms ret = (stdtimevalms)ll.QuadPart;
+ return ret /= divider;
+#else
+ return getTickCount() / 1000.f;
+#endif
+}
+
+uint32_t Wasabi::Std::getTickCount()
+{
+#ifdef _WIN32
+ return GetTickCount();
+#elif defined(__APPLE__)
+ struct timeval newtime;
+
+ gettimeofday(&newtime, 0);
+ return newtime.tv_sec*1000 + newtime.tv_usec/1000;
+#endif
+//INLINE
+}
+
+#ifdef _WIN32 // PORT ME
+void Wasabi::Std::ensureVisible(RECT *r) {
+ RECT sr;
+ POINT p={(r->right+r->left)/2,(r->bottom+r->top)/2};
+ Wasabi::Std::getViewport(&sr,&p);
+ int w = r->right-r->left;
+ int h = r->bottom-r->top;
+ if (r->bottom > sr.bottom) {
+ r->bottom = sr.bottom;
+ r->top = r->bottom-h;
+ }
+ if (r->right > sr.right) {
+ r->right = sr.right;
+ r->left = r->right-w;
+ }
+ if (r->left < sr.left) {
+ r->left = sr.left;
+ r->right = r->left+w;
+ }
+ if (r->top < sr.top) {
+ r->top = sr.top;
+ r->bottom = r->top+h;
+ }
+}
+#endif
+
+int Wasabi::Std::getScreenWidth()
+{
+#ifdef WIN32
+ RECT r;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
+ return r.right-r.left;
+#elif defined(__APPLE__)
+ CGDirectDisplayID mainID = CGMainDisplayID();
+ return CGDisplayPixelsWide(mainID);
+#elif defined(LINUX)
+ return DisplayWidth(Linux::getDisplay(), Linux::getScreenNum());
+#endif
+}
+
+int Wasabi::Std::getScreenHeight()
+{
+#ifdef WIN32
+ RECT r;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
+ return r.bottom-r.top;
+#elif defined(__APPLE__)
+ CGDirectDisplayID mainID = CGMainDisplayID();
+ return CGDisplayPixelsHigh(mainID);
+#else
+ return DisplayHeight( Linux::getDisplay(), Linux::getScreenNum() );
+#endif
+}
+#ifndef __APPLE__ // PORT ME
+int Wasabi::Std::messageBox(const wchar_t *txt, const wchar_t *title, int flags) {
+#ifdef WIN32
+ return MessageBoxW(NULL, txt, title, flags);
+#else
+ OutputDebugString(txt);
+#endif
+}
+#endif
+
+int Wasabi::Std::getDoubleClickDelay() {
+#ifdef WIN32
+ return GetDoubleClickTime();
+#elif defined(__APPLE__)
+ return GetDblTime();
+#endif
+}
+
+#undef GetSystemMetrics //FG> DUH!
+int Wasabi::Std::getDoubleClickX() {
+#ifdef WIN32
+ return GetSystemMetrics(SM_CYDOUBLECLK);
+#else
+ return 5;
+#endif
+}
+
+int Wasabi::Std::getDoubleClickY() {
+#ifdef WIN32
+ return GetSystemMetrics(SM_CXDOUBLECLK);
+#else
+ return 5;
+#endif
+}
+
+int Wasabi::Std::osparam_getScrollLines() {
+ int ret = 3;
+#ifdef WIN32
+ SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &ret, 0);
+#endif
+ return ret;
+}
+
+int Wasabi::Std::osparam_getSmoothScroll() {
+ int ret = 1;
+#ifdef WIN32
+ SystemParametersInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, &ret, 0);
+#endif
+ return ret;
+}
+
+
+
+const wchar_t Wasabi::Std::dirChar() {
+#ifdef WIN32
+ return '\\';
+#else
+ return '/';
+#endif
+}
+
+const char * Wasabi::Std::dirCharStr() {
+#ifdef WIN32
+ return "\\";
+#else
+ return "/";
+#endif
+};
+
+const wchar_t * Wasabi::Std::dirCharStrW()
+{
+#ifdef WIN32
+ return L"\\";
+#else
+ return L"/";
+#endif
+};
+
+int Wasabi::Std::isDirChar(int thechar, int allow_multiple_platforms) {
+ if (thechar == DIRCHAR) return 1;
+ if (allow_multiple_platforms) {
+#ifdef WIN32
+ if (thechar == '/') return 1;
+#else
+ if (thechar == '\\') return 1;
+#endif
+ }
+ return 0;
+}
+
+const wchar_t * Wasabi::Std::matchAllFiles() {
+#ifdef WIN32
+ return L"*.*";
+#else
+ return L"*";
+#endif
+}
+
+const wchar_t * Wasabi::Std::dotDir() {
+ return L".";
+}
+
+const wchar_t * Wasabi::Std::dotDotDir()
+{
+ return L"..";
+}
+#ifdef _WIN32 // PORT ME
+bool Wasabi::Std::isRootPath(const wchar_t *path)
+{
+ return PathIsRootW(path)==TRUE;
+}
+#endif
+
+int Wasabi::Std::switchChar() {
+#ifdef WIN32
+ return '/';
+#else
+ return '-';
+#endif
+}
+
+int Wasabi::Std::enumViewports( int monitor_n, RECT *r, int full )
+{
+ ASSERT( r != NULL );
+#ifdef WIN32
+ if ( !user32_instance )
+ {
+ user32_instance = LoadLibraryW( L"user32.dll" );
+ }
+ if ( user32_instance )
+ {
+ if ( !Gmi )
+ {
+ Gmi = ( BOOL( WINAPI * )( HMONITOR, LPMONITORINFO ) ) GetProcAddress( user32_instance, "GetMonitorInfoW" );
+ }
+ BOOL( WINAPI * Edm )( HDC hdc, LPCRECT clip, MONITORENUMPROC proc, LPARAM dwdata ) = ( BOOL( WINAPI * )( HDC, LPCRECT, MONITORENUMPROC, LPARAM ) ) GetProcAddress( user32_instance, "EnumDisplayMonitors" );
+ if ( Gmi && Edm )
+ {
+ ViewportEnumerator ve;
+ ve.monitor_n = monitor_n;
+ ve.hm = NULL;
+ ve.counter = 0;
+ Edm( NULL, NULL, enumViewportsProc, reinterpret_cast<LPARAM>( &ve ) );
+ HMONITOR hm = ve.hm;
+ if ( hm )
+ {
+ MONITORINFOEXW mi;
+ ZERO( mi );
+ mi.cbSize = sizeof( mi );
+ if ( Gmi( hm, &mi ) )
+ {
+ if ( !full )
+ *r = mi.rcWork;
+ else
+ *r = mi.rcMonitor;
+
+ return 1;
+ }
+ }
+ }
+ }
+ SystemParametersInfoW( SPI_GETWORKAREA, 0, r, 0 );
+ return 0;
+#elif defined(__APPLE__)
+ CGDirectDisplayID monitors[ 256 ]; // TODO: allocate dynamically
+ CGDisplayCount count;
+ if ( monitor_n >= 256 )
+ return 0;
+
+ CGGetActiveDisplayList( 256, monitors, &count );
+ if ( count <= monitor_n )
+ return 0;
+
+ HIRect rect = CGDisplayBounds( monitors[ monitor_n ] );
+ *r = RECTFromHIRect( &rect );
+ // TODO: cut out dock if full == 0 maybe GetAvailableWindowPositioningBounds if we can get the GDHandle
+#elif defined(LINUX)
+ if ( monitor_n > 0 )
+ return 0;
+ r->left = r->top = 0;
+ r->right = Wasabi::Std::getScreenWidth();
+ r->bottom = Wasabi::Std::getScreenHeight();
+ return 1;
+#endif
+}
+
+const char * Wasabi::Std::scanstr_back(const char *str, const char *toscan, const char *defval) {
+ int strl = STRLEN(str);
+ const char *s=str+strl-1;
+ if (strl < 1) return defval;
+ if (STRLEN(toscan) < 1) return defval;
+ while (1) {
+ const char *t=toscan;
+ while (t && *t) if (*t++ == *s) return s;
+#ifdef _WIN32
+ t=CharPrevA(str,s);
+#else
+ t = s-1;
+#endif
+ if (t==s) return defval;
+ s=t;
+ }
+}
+
+const wchar_t * Wasabi::Std::extension(const wchar_t *fn)
+{
+#ifdef _WIN32 // PORT ME
+ wchar_t *x = PathFindExtensionW(fn);
+ if (x && *x)
+ return CharNextW(x);
+ else
+ return x;
+#else
+#warning port me
+ return 0;
+#endif
+}
+
+const wchar_t * Wasabi::Std::filename(const wchar_t *fn)
+{
+#ifdef _WIN32
+ return PathFindFileNameW(fn);
+#else
+#warning port me
+ return 0;
+#endif
+}
+
+bool Wasabi::Std::isMatchPattern(const wchar_t *p)
+{
+ while (p && *p) {
+ switch (*p++) {
+ case '?':
+ case '*':
+ case '[':
+ case '\\':
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+bool Wasabi::Std::isValidMatchPattern(const wchar_t *p, int *error_type)
+{
+ /* init error_type */
+ *error_type = PATTERN_VALID;
+ /* loop through pattern to EOS */
+ while (p && *p) {
+ /* determine pattern type */
+ switch (*p) {
+ /* check literal escape, it cannot be at end of pattern */
+ case '\\':
+ if (!*++p) {
+ *error_type = PATTERN_ESC;
+ return FALSE;
+ }
+ p++;
+ break;
+ /* the [..] construct must be well formed */
+ case '[':
+ p++;
+ /* if the next character is ']' then bad pattern */
+ if (*p == ']') {
+ *error_type = PATTERN_EMPTY;
+ return FALSE;
+ }
+ /* if end of pattern here then bad pattern */
+ if (!*p) {
+ *error_type = PATTERN_CLOSE;
+ return FALSE;
+ }
+ /* loop to end of [..] construct */
+ while (p && *p != ']') {
+ /* check for literal escape */
+ if (*p == '\\') {
+ p++;
+ /* if end of pattern here then bad pattern */
+ if (!*p++) {
+ *error_type = PATTERN_ESC;
+ return FALSE;
+ }
+ } else p++;
+ /* if end of pattern here then bad pattern */
+ if (!*p) {
+ *error_type = PATTERN_CLOSE;
+ return FALSE;
+ }
+ /* if this a range */
+ if (*p == '-') {
+ /* we must have an end of range */
+ if (!*++p || *p == ']') {
+ *error_type = PATTERN_RANGE;
+ return FALSE;
+ } else {
+ /* check for literal escape */
+ if (*p == '\\') p++;
+ /* if end of pattern here then bad pattern */
+ if (!*p++) {
+ *error_type = PATTERN_ESC;
+ return FALSE;
+ }
+ }
+ }
+ }
+ break;
+ /* all other characters are valid pattern elements */
+ case '*':
+ case '?':
+ default:
+ p++; /* "normal" character */
+ break;
+ }
+ }
+ return TRUE;
+}
+
+#ifdef _WIN32 // PORT ME
+int Wasabi::Std::matche(register const wchar_t *p, register const wchar_t *t)
+{
+ register wchar_t range_start, range_end; /* start and end in range */
+
+ BOOLEAN invert; /* is this [..] or [!..] */
+ BOOLEAN member_match; /* have I matched the [..] construct? */
+ BOOLEAN loop; /* should I terminate? */
+
+ for ( ; *p; p++, t++)
+ {
+ /* if this is the end of the text then this is the end of the match */
+ if (!*t) {
+ return ( *p == '*' && *++p == '\0' ) ? MATCH_VALID : MATCH_ABORT;
+ }
+ /* determine and react to pattern type */
+ switch (*p) {
+ case '?': /* single any character match */
+ break;
+ case '*': /* multiple any character match */
+ return matche_after_star (p, t);
+
+ /* [..] construct, single member/exclusion character match */
+ case '[': {
+ /* move to beginning of range */
+ p++;
+ /* check if this is a member match or exclusion match */
+ invert = FALSE;
+ if (*p == '!' || *p == '^') {
+ invert = TRUE;
+ p++;
+ }
+ /* if closing bracket here or at range start then we have a malformed pattern */
+ if (*p == ']') return MATCH_PATTERN;
+
+ member_match = FALSE;
+ loop = TRUE;
+ while (loop) {
+ /* if end of construct then loop is done */
+ if (*p == ']') {
+ loop = FALSE;
+ continue;
+ }
+ /* matching a '!', '^', '-', '\' or a ']' */
+ if (*p == '\\') range_start = range_end = *++p;
+ else range_start = range_end = *p;
+ /* if end of pattern then bad pattern (Missing ']') */
+ if (!*p) return MATCH_PATTERN;
+ /* check for range bar */
+ if (*++p == '-') {
+ /* get the range end */
+ range_end = *++p;
+ /* if end of pattern or construct then bad pattern */
+ if (range_end == '\0' || range_end == ']') return MATCH_PATTERN;
+ /* special character range end */
+ if (range_end == '\\') {
+ range_end = *++p;
+ /* if end of text then we have a bad pattern */
+ if (!range_end) return MATCH_PATTERN;
+ }
+ /* move just beyond this range */
+ p++;
+ }
+ /* if the text character is in range then match found.
+ make sure the range letters have the proper
+ relationship to one another before comparison */
+ if (range_start < range_end) {
+ if (*t >= range_start && *t <= range_end) {
+ member_match = TRUE;
+ loop = FALSE;
+ }
+ } else {
+ if (*t >= range_end && *t <= range_start) {
+ member_match = TRUE;
+ loop = FALSE;
+ }
+ }
+ }
+ /* if there was a match in an exclusion set then no match */
+ /* if there was no match in a member set then no match */
+ if ((invert && member_match) || !(invert || member_match)) return MATCH_RANGE;
+ /* if this is not an exclusion then skip the rest of the [...] construct that already matched. */
+ if (member_match) {
+ while (p && *p != ']') {
+ /* bad pattern (Missing ']') */
+ if (!*p) return MATCH_PATTERN;
+ /* skip exact match */
+ if (*p == '\\') {
+ p++;
+ /* if end of text then we have a bad pattern */
+ if (!*p) return MATCH_PATTERN;
+ }
+ /* move to next pattern char */
+ p++;
+ }
+ }
+ break;
+ }
+ case '\\': /* next character is quoted and must match exactly */
+ /* move pattern pointer to quoted char and fall through */
+ p++;
+ /* if end of text then we have a bad pattern */
+ if (!*p) return MATCH_PATTERN;
+ /* must match this character exactly */
+ default:
+ if (TOUPPERW(*p) != TOUPPERW(*t)) return MATCH_LITERAL;
+ }
+ }
+ /* if end of text not reached then the pattern fails */
+ if (*t) return MATCH_END;
+ else return MATCH_VALID;
+}
+
+int Wasabi::Std::matche_after_star(register const wchar_t *p, register const wchar_t *t)
+{
+ register int match = 0;
+ register wchar_t nextp;
+ /* pass over existing ? and * in pattern */
+ while ( *p == '?' || *p == '*' )
+ {
+ /* take one char for each ? and + */
+ if (*p == '?') {
+ /* if end of text then no match */
+ if (!*t++) return MATCH_ABORT;
+ }
+ /* move to next char in pattern */
+ p++;
+ }
+ /* if end of pattern we have matched regardless of text left */
+ if (!*p) return MATCH_VALID;
+ /* get the next character to match which must be a literal or '[' */
+ nextp = *p;
+ if (nextp == '\\') {
+ nextp = p[1];
+ /* if end of text then we have a bad pattern */
+ if (!nextp) return MATCH_PATTERN;
+ }
+ /* Continue until we run out of text or definite result seen */
+ do {
+ /* a precondition for matching is that the next character
+ in the pattern match the next character in the text or that
+ the next pattern char is the beginning of a range. Increment
+ text pointer as we go here */
+ if (TOUPPERW(nextp) == TOUPPERW(*t) || nextp == '[') match = matche(p, t);
+ /* if the end of text is reached then no match */
+ if (!*t++) match = MATCH_ABORT;
+ } while ( match != MATCH_VALID && match != MATCH_ABORT && match != MATCH_PATTERN);
+ /* return result */
+ return match;
+}
+
+bool Wasabi::Std::match(const wchar_t *p, const wchar_t *t)
+{
+ int error_type;
+ error_type = matche(p,t);
+ return (error_type == MATCH_VALID ) ? TRUE : FALSE;
+}
+#endif
+#ifndef _NOSTUDIO
+int Wasabi::Std::getCurDir(wchar_t *str, int maxlen) {
+ ASSERT(str != NULL);
+#ifdef WIN32
+ int retval = 0;
+
+ retval = GetCurrentDirectoryW(maxlen, str);
+
+ return retval;
+
+#else
+#warning port me
+ return 0;
+ //return getcwd( str, maxlen ) != NULL;
+#endif
+}
+
+int Wasabi::Std::setCurDir(const wchar_t *str) {
+ ASSERT(str != NULL);
+#ifdef WIN32
+ int retval = 0;
+
+ retval = SetCurrentDirectoryW(str);
+
+ return retval;
+
+#else
+#warning port me
+ return 0;
+// return chdir( str );
+#endif
+}
+
+
+int Wasabi::Std::getNumCPUs() {
+#ifdef WIN32
+ SYSTEM_INFO si;
+ ZERO(si);
+ GetSystemInfo(&si);
+ return si.dwNumberOfProcessors;
+#else
+#ifdef PLATFORM_WARNINGS
+#warning Wasabi::Std::getNumCPUs not implemented on LINUX
+#endif
+ return 1;
+#endif
+}
+
+THREADID Wasabi::Std::getCurrentThreadId() {
+#ifdef WIN32
+ return GetCurrentThreadId();
+#else
+ return pthread_self();
+#endif
+}
+
+#ifdef WIN32
+void Wasabi::Std::setThreadPriority(int delta, HANDLE thread_handle)
+{
+ if (thread_handle == NULL) thread_handle = GetCurrentThread();
+ int v = THREAD_PRIORITY_NORMAL;
+ switch (delta) {
+ case -32767: v = THREAD_PRIORITY_IDLE; break;
+ case -2: v = THREAD_PRIORITY_LOWEST; break;
+ case -1: v = THREAD_PRIORITY_BELOW_NORMAL; break;
+ case 1: v = THREAD_PRIORITY_ABOVE_NORMAL; break;
+ case 2: v = THREAD_PRIORITY_HIGHEST; break;
+ case 32767: v = THREAD_PRIORITY_TIME_CRITICAL; break;
+ }
+ SetThreadPriority(thread_handle, v);
+}
+#else
+#ifdef PLATFORM_WARNINGS
+#warning Wasabi::Std::setThreadPriority not implemented on LINUX
+#endif
+#endif
+
+
+String Wasabi::Std::getLastErrorString(int _err) {
+ String ret;
+ if (_err == -1) {
+#ifdef WIN32
+ _err = GetLastError();
+#else
+#ifdef PLATFORM_WARNINGS
+#warning Wasabi::Std::getLastErrorString not implemented on LINUX
+#endif
+#endif
+ }
+#ifdef WIN32
+ char *sysbuf;
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, _err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char *)&sysbuf, 0, NULL);
+ ret = sysbuf;
+ LocalFree(sysbuf);
+#endif
+ return ret;
+}
+
+// gets the system font path
+void Wasabi::Std::getFontPath(int bufsize, wchar_t *dst)
+{
+ ASSERT(dst != NULL);
+#ifdef WIN32
+
+ wchar_t path[MAX_PATH]=L"";
+ SHGetSpecialFolderPathW(NULL, path, CSIDL_FONTS, FALSE);
+ WCSCPYN(dst, path, bufsize);
+
+
+#else
+#ifdef PLATFORM_WARNINGS
+#warning Wasabi::Std::getFontPath not implemented on LINUX
+#endif
+#endif
+
+}
+
+const wchar_t wasabi_default_fontnameW[] = WASABI_DEFAULT_FONTNAMEW;
+int default_font_scale = 100;
+wchar_t default_font[256] =
+#ifdef WIN32
+WASABI_DEFAULT_FONTNAMEW L".ttf";
+#elif defined(__APPLE__)
+WASABI_DEFAULT_FONTNAMEW;
+#elif defined(LINUX)
+ // even tho this isn't the way we'll port this, the style is fun.
+"-*-arial-medium-r-*--10-*-*-*-*-*-*-*";
+#endif
+
+// gets the filename of a font file guaranteed to be in the system font path.
+void Wasabi::Std::getDefaultFont(int bufsize, wchar_t *dst)
+{
+ ASSERT(dst != NULL);
+ WCSCPYN(dst, default_font, bufsize);
+}
+
+void Wasabi::Std::setDefaultFont(const wchar_t *newdefaultfont)
+{
+ WCSCPYN(default_font, newdefaultfont, 256);
+}
+
+int Wasabi::Std::getDefaultFontScale() {
+ return default_font_scale;
+}
+
+void Wasabi::Std::setDefaultFontScale(int scale) {
+ default_font_scale = scale;
+}
+
+#ifndef __APPLE__ // PORT ME
+int Wasabi::Std::createDirectory(const wchar_t *dirname)
+{
+#ifdef WIN32
+ if(!CreateDirectoryW(dirname,NULL))
+#else
+ if(mkdir(dirname, 0755))
+#endif
+ {
+ // create all the path
+ PathParserW pp(dirname);
+ int l = pp.getNumStrings();
+ for(int i=2;i<=l;i++)
+ {
+ StringW dir;
+ for(int j=0;j<i;j++)
+ dir.AppendFolder(pp.enumString(j));
+#ifdef WIN32
+ CreateDirectoryW(dir,NULL);
+#else
+ mkdir(dir, 0755);
+#endif
+ }
+ }
+ return 1;
+}
+#endif
+
+int Wasabi::Std::getFileInfos(const char *filename, fileInfoStruct *infos) {
+#ifdef WIN32
+ HANDLE h;
+ WIN32_FIND_DATAA fd = {0};
+ if((h=FindFirstFileA(filename, &fd))==INVALID_HANDLE_VALUE) return 0;
+
+ infos->fileSizeHigh=fd.nFileSizeHigh;
+ infos->fileSizeLow=fd.nFileSizeLow;
+ struct _stati64 statbuf;
+ if (_stati64(filename, &statbuf) == -1) return 0;
+ infos->lastWriteTime = statbuf.st_mtime;
+ infos->readonly = fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY;
+ FindClose(h);
+
+ return 1;
+#else
+ struct stat st;
+
+ int ret = stat( filename, &st );
+ if ( ret != 0 )
+ return 0;
+
+ infos->fileSizeHigh = 0;
+ infos->fileSizeLow = st.st_size;
+ infos->lastWriteTime = st.st_mtime;
+ return 1;
+#endif
+}
+
+void Wasabi::Std::shellExec(const wchar_t *cmd, const wchar_t *params)
+{
+#ifdef WIN32
+ ShellExecuteW(NULL, NULL, cmd, params, L".", SW_SHOWNORMAL);
+#else
+ system(StringPrintf("%S %S", cmd, params));
+#endif
+}
+
+
+#endif // nostudio
+
+void MEMFILL32(void *lptr, unsigned long val, unsigned int n) {
+ if (n == 0) return;
+#if defined(WIN32) && !defined(_WIN64)
+__asm {
+ mov eax, val
+ mov edi, lptr
+ mov ecx, n
+ rep stosd
+};
+#elif defined(GCC)
+//http://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.html ;)
+asm ("cld\n\t"
+ "rep\n\t"
+ "stosl"
+ : /* no output registers */
+ : "c" (n), "a" (val), "D" (lptr)
+ : "%ecx", "%edi" );
+#else
+ uint32_t *ptr32 = (uint32_t *)lptr;
+ for (unsigned int i=0;i!=n;i++)
+ {
+ ptr32[i] = val;
+ }
+#endif
+}
+
+void MEMFILL(unsigned short *ptr, unsigned short val, unsigned int n) {
+ if (n == 0) return;
+ unsigned long v = (unsigned long)val | ((unsigned long)val << 16);
+ int r = n & 1;
+ MEMFILL32(ptr, v, n/2);
+ if (r) ptr[n-1] = val;
+}
+
+void MEMCPY32(void *dest, const void *src, size_t words)
+{
+ // TODO: write fast asm version of this
+ memcpy(dest, src, words*4);
+}
+
+void MEMCPY_(void *dest, const void *src, size_t n)
+{
+ memcpy(dest, src, n);
+}
diff --git a/Src/Wasabi/bfc/wasabi_std.h b/Src/Wasabi/bfc/wasabi_std.h
new file mode 100644
index 00000000..96a4ed68
--- /dev/null
+++ b/Src/Wasabi/bfc/wasabi_std.h
@@ -0,0 +1,366 @@
+#ifndef _STD_H
+#define _STD_H
+
+#include <string.h>
+#include <bfc/platform/platform.h>
+#include <bfc/common.h>
+#include <bfc/bfc_assert.h>
+//#include <bfc/string/string.h>
+
+//#define WANT_UTF8_WARNINGS
+
+// to use this, do #pragma WARNING("your message") <- note the ABSENCE of ';'
+#ifndef WARNING
+ #define WARNING_TOSTR(text) #text
+ #define WARNING_TOSTR1(text) WARNING_TOSTR(text)
+ #define WARNING(text) message(__FILE__ "(" WARNING_TOSTR1(__LINE__) ") : " text)
+#endif
+// and for this one, do #pragma COMPILATION_CHAT("your_nick", "nick_you're_talking_to", "your message")
+#define CHAT(from, to, text) message(__FILE__ "(" WARNING_TOSTR1(__LINE__) ") : <" from "> " to ": " text)
+#define SELF(from, text) message(__FILE__ "(" WARNING_TOSTR1(__LINE__) ") : * " from"/#wasabi " text)
+
+//#ifndef WASABIDLLEXPORT
+//#error go define WASABIDLLEXPORT in your platform .h
+//#endif
+
+#ifndef NOVTABLE
+#define NOVTABLE
+#endif
+
+#ifndef NOVTABLE
+#error go define NOVTABLE in your platform .h
+#endif
+
+#include "std_mem.h"
+#include "std_math.h"
+#include "std_string.h"
+#include "std_file.h"
+#include "wasabi_std_rect.h"
+#include "std_keyboard.h"
+#include <stdlib.h>
+#include <locale.h>
+#define WASABI_DEFAULT_FONTNAME "Arial"
+#define WASABI_DEFAULT_FONTNAMEW L"Arial"
+extern const wchar_t wasabi_default_fontnameW[];
+static _locale_t C_locale;
+
+#include <wchar.h>
+static __inline char TOUPPER(char c)
+{
+#ifdef _WIN32
+ char tmp = c;
+ CharUpperBuffA(&tmp, 1);
+ return tmp;
+#else
+ return toupper(c);
+#endif
+}
+
+static __inline wchar_t TOUPPERW(wchar_t c)
+{
+ return towupper(c);
+}
+
+static __inline wchar_t TOLOWERW(wchar_t c)
+{
+ return towlower(c);
+}
+
+__inline bool WTOB(const wchar_t *str) {
+#ifdef WIN64
+ if (!str || (unsigned long long)str < WCHAR_MAX) return 0;
+#else
+ if (!str || (unsigned long)str < WCHAR_MAX) return 0;
+#endif
+
+ if(!C_locale) C_locale = _create_locale(LC_NUMERIC,"C");
+ return !!_wtoi_l(str,C_locale);
+}
+
+ __inline int WTOI(const wchar_t *str) {
+#ifdef WIN64
+ if (!str || (unsigned long long)str < WCHAR_MAX) return 0;
+#else
+ if (!str || (unsigned long)str < WCHAR_MAX) return 0;
+#endif
+ if(!C_locale) C_locale = _create_locale(LC_NUMERIC,"C");
+ return _wtoi_l(str,C_locale);
+ }
+
+ //__inline int ATOI(const char *str) { if (!str) return 0; return atoi(str); }
+ //__inline double ATOF(const char *str) { if (!str) return 0.0; return atof(str); }
+
+ __inline double WTOF(const wchar_t *str) {
+#ifdef WIN64
+ if (!str || (unsigned long long)str < WCHAR_MAX) return 0.0;
+#else
+ if (!str || (unsigned long)str < WCHAR_MAX) return 0.0;
+#endif
+
+ if(!C_locale) C_locale = _create_locale(LC_NUMERIC,"C");
+ return _wtof_l(str,C_locale);
+ }
+
+__inline int STRTOL(const char *str, char **stopstr, int base)
+{
+ if(!C_locale) C_locale = _create_locale(LC_NUMERIC,"C");
+ return _strtol_l(str, stopstr, base, C_locale);
+}
+
+wchar_t *WCSDUP(const wchar_t *ptr);
+COMEXP int STRLEN(const char *str);
+COMEXP int STRCMP(const char *str1, const char *str2);
+COMEXP int STRICMP(const char *str1, const char *str2);
+
+int WCSICMP(const wchar_t *str1, const wchar_t *str2);
+int WCSNICMP(const wchar_t *str1, const wchar_t *str2, size_t len);
+int WCSCOLL(const wchar_t *str1, const wchar_t *str2);
+int WCSICOLL(const wchar_t *str1, const wchar_t *str2);
+bool WCSIPREFIX(const wchar_t *str1, const wchar_t *prefix);
+wchar_t *WCSTOK(wchar_t *str, const wchar_t *sep, wchar_t **last);
+
+COMEXP int STREQL(const char *str1, const char *str2);
+COMEXP int STRCASEEQL(const char *str1, const char *str2);
+wchar_t *WCSCASESTR(const wchar_t *str1, const wchar_t *str2);
+COMEXP char *STRSTR(const char *str1, const char *str2);
+COMEXP void STRCPY(char *dest, const char *src);
+COMEXP void STRNCPY(char *dest, const char *src, int maxchar);
+COMEXP void WCSCPYN(wchar_t *dest, const wchar_t *src, size_t maxchar);
+COMEXP char *STRCHR(const char *str, int c);
+COMEXP void STRCAT(char *dest, const char *append);
+COMEXP unsigned long STRTOUL(const char *str, char **p, int radix);
+
+#ifdef __cplusplus
+COMEXP int STRCMPSAFE(const char *str1, const char *str2, const char *defval1 = "", const char *defval2 = "");
+COMEXP int STRICMPSAFE(const char *str1, const char *str2, const char *defval1 = "", const char *defval2 = "");
+COMEXP int WCSICMPSAFE(const wchar_t *str1, const wchar_t *str2, const wchar_t *defval1 = L"", const wchar_t *defval2 = L"");
+COMEXP int WCSEQLSAFE(const wchar_t *str1, const wchar_t *str2, const wchar_t *defval1 = L"", const wchar_t *defval2 = L"");
+COMEXP int STRCASEEQLSAFE(const char *str1, const char *str2, const char *defval1 = "", const char *defval2 = "");
+COMEXP int WCSCASEEQLSAFE(const wchar_t *str1, const wchar_t *str2, const wchar_t *defval1 = L"", const wchar_t *defval2 = L"");
+#endif
+
+COMEXP int PATHEQL(const wchar_t *str1, const wchar_t *str2);
+COMEXP void STRTOUPPER(char *str);
+COMEXP void STRTOLOWER(char *str);
+COMEXP void WCSTOUPPER(wchar_t *str);
+COMEXP void KEYWORDUPPER(wchar_t *p);
+COMEXP void WCSTOLOWER(wchar_t *str);
+
+#ifdef _WIN32
+#define STRSAFE_NO_DEPRECATE
+//#include <tchar.h>
+#include <strsafe.h>
+#undef STRSAFE_NO_DEPRECATE
+#define WCSNPRINTF StringCchPrintfW
+#elif defined(__APPLE__)
+#define WCSNPRINTF swprintf
+#endif
+
+#ifdef WIN32
+#define SPRINTF wsprintfA
+#else
+#define SPRINTF sprintf
+#endif
+
+#define SSCANF sscanf
+
+#define WA_MAX_PATH (8*1024)
+
+// seconds since 1970
+typedef unsigned int stdtimeval;
+// milliseconds since...??
+typedef double stdtimevalms;
+
+#ifdef _WIN32
+typedef unsigned long THREADID;
+#else
+typedef pthread_t THREADID;
+#endif
+
+#ifdef __cplusplus
+
+#include <bfc/string/bfcstring.h>
+
+namespace Wasabi
+{
+ namespace Std
+ {
+ void Initialize();
+ void getMousePos(POINT* p);
+ void getMousePos(int* x, int* y);
+ void getMousePos(long* x, long* y);
+ void setMousePos(POINT* p);
+ void setMousePos(int x, int y);
+
+ void srandom(unsigned int key = 0); //if key==0, uses time()
+ int random(int max = RAND_MAX + 1); // from 0 to max-1 (RAND_MAX = 0x7fff)
+ unsigned int random32(unsigned int max = 0xffffffff); // full 32-bits of randomness
+
+ // time functions
+ void usleep(int ms);
+ // get time in seconds since 1970
+ time_t getTimeStamp();
+ // get time in seconds as double, but not since any specific time
+ // useful for relative timestamps only
+ stdtimevalms getTimeStampMS();
+ // get milliseconds since system started. usefull for relative only
+ uint32_t getTickCount();
+
+ void tolowerString(char* str);
+ void ensureVisible(RECT* r);
+ int getScreenWidth();
+ int getScreenHeight();
+ // THREADS/PROCESSES/CPUs
+ int getNumCPUs();
+ // a unique # returned by the OS
+ THREADID getCurrentThreadId();
+ // attempts to adjust thread priority compared to main thread
+ // normal range is from -2 .. +2, and -32767 for idle, 32767 for time critical
+ // use the constants from bfc/thread.h
+#ifdef _WIN32
+ void setThreadPriority(int delta, HANDLE thread_handle = NULL);
+#endif
+
+ String getLastErrorString(int force_errno = -1);
+
+
+ int messageBox(const wchar_t* txt, const wchar_t* title, int flags);
+
+ int getDoubleClickDelay();
+ int getDoubleClickX();
+ int getDoubleClickY();
+
+ // returns how many lines to scroll for wheelie mice (from the OS)
+ int osparam_getScrollLines();
+ int osparam_getSmoothScroll();
+
+
+ const wchar_t dirChar(); // \ for win32, / for all else
+#define DIRCHAR (Wasabi::Std::dirChar())
+ const char* dirCharStr(); // "\\" for win32, "/" for all else
+#define DIRCHARSTR (Wasabi::Std::dirCharStr())
+ const wchar_t* dirCharStrW(); // "\\" for win32, "/" for all else
+#define DIRCHARSTRW (Wasabi::Std::dirCharStrW())
+ int isDirChar(int thechar, int allow_multiple_platforms = TRUE);
+ const wchar_t* matchAllFiles(); // "*.*" on win32, "*" on else
+#define MATCHALLFILES (Wasabi::Std::matchAllFiles())
+ const wchar_t* dotDir(); // usually "."
+#define DOTDIR (Wasabi::Std::dotDir())
+ const wchar_t* dotDotDir(); // usually ".."
+#define DOTDOTDIR (Wasabi::Std::dotDotDir())
+
+ bool isRootPath(const wchar_t* path); // "c:\" or "\" on win32, "/" on linux
+
+ int switchChar(); // '/' on win32, '-' for all else
+#define SWITCHCHAR (Wasabi::Std::switchChar())
+
+
+ void getViewport(RECT* r, POINT* p, int full = 0);
+ void getViewport(RECT* r, RECT* sr, int full = 0);
+ void getViewport(RECT* r, OSWINDOWHANDLE wnd, int full = 0);
+ void getViewport(RECT* r, POINT* p, RECT* sr, OSWINDOWHANDLE wnd, int full = 0);
+ int enumViewports(int monitor_n, RECT* r, int full = 0);
+
+ // returns the address of the last occurence of any of the characters of toscan in str string
+ const char* scanstr_back(const char* str, const char* toscan, const char* defval);
+
+ // retrieves extension of a given filename
+ const wchar_t* extension(const wchar_t* fn);
+
+ // retrieves filename from a given path+filename
+ const wchar_t* filename(const wchar_t* fn);
+
+ int getCurDir(wchar_t* str, int maxlen);
+ int setCurDir(const wchar_t* str);
+
+ // regexp match functions
+
+ // A match means the entire string TEXT is used up in matching.
+ // In the pattern string:
+ // `*' matches any sequence of characters (zero or more)
+ // `?' matches any character
+ // [SET] matches any character in the specified set,
+ // [!SET] or [^SET] matches any character not in the specified set.
+
+ // A set is composed of characters or ranges; a range looks like
+ // character hyphen character (as in 0-9 or A-Z). [0-9a-zA-Z_] is the
+ // minimal set of characters allowed in the [..] pattern construct.
+ // Other characters are allowed (ie. 8 bit characters) if your system
+ // will support them.
+
+ // To suppress the special syntactic significance of any of `[]*?!^-\',
+ // and match the character exactly, precede it with a `\'.
+
+ enum {
+ MATCH_VALID = 1, /* valid match */
+ MATCH_END, /* premature end of pattern string */
+ MATCH_ABORT, /* premature end of text string */
+ MATCH_RANGE, /* match failure on [..] construct */
+ MATCH_LITERAL, /* match failure on literal match */
+ MATCH_PATTERN, /* bad pattern */
+ };
+
+ enum {
+ PATTERN_VALID = 0, /* valid pattern */
+ PATTERN_ESC = -1, /* literal escape at end of pattern */
+ PATTERN_RANGE = -2, /* malformed range in [..] construct */
+ PATTERN_CLOSE = -3, /* no end bracket in [..] construct */
+ PATTERN_EMPTY = -4, /* [..] contstruct is empty */
+ };
+
+ // return TRUE if PATTERN has any special wildcard characters
+ bool isMatchPattern(const wchar_t* p);
+
+ // return TRUE if PATTERN has is a well formed regular expression
+ bool isValidMatchPattern(const wchar_t* p, int* error_type);
+
+ // return MATCH_VALID if pattern matches, or an errorcode otherwise
+ int matche(register const wchar_t* p, register const wchar_t* t);
+ int matche_after_star(register const wchar_t* p, register const wchar_t* t);
+
+ // return TRUE if pattern matches, FALSE otherwise.
+ bool match(const wchar_t* p, const wchar_t* t);
+
+ // gets the system font path.
+ void getFontPath(int bufsize, wchar_t* dst);
+
+ // gets the filename of a font file guaranteed to be in the system font path.
+ void getDefaultFont(int bufsize, wchar_t* dst);
+
+ // sets a new default font, ie "blah.ttf"
+ void setDefaultFont(const wchar_t* newdefaultfont);
+
+ // gets the default font scale
+ int getDefaultFontScale();
+
+ // sets the new default font scale
+ void setDefaultFontScale(int scale);
+
+ // creates a directory. returns 0 on error, nonzero on success
+ int createDirectory(const wchar_t* dirname);
+
+ // gets informations about a given filename. returns 0 if file not found
+ typedef struct
+ {
+ unsigned int fileSizeHigh;
+ unsigned int fileSizeLow;
+ time_t lastWriteTime;
+ int readonly;
+ }
+ fileInfoStruct;
+
+ int getFileInfos(const char* filename, fileInfoStruct* infos);
+
+ // removes a directory
+ void removeDirectory(const char* buf, int recurse);
+
+
+ void shellExec(const wchar_t* cmd, const wchar_t* params = NULL);
+
+ int isLittleEndian();
+
+ }
+}
+#endif
+
+#endif
diff --git a/Src/Wasabi/bfc/wasabi_std_rect.cpp b/Src/Wasabi/bfc/wasabi_std_rect.cpp
new file mode 100644
index 00000000..a5040da0
--- /dev/null
+++ b/Src/Wasabi/bfc/wasabi_std_rect.cpp
@@ -0,0 +1,77 @@
+#include "wasabi_std_rect.h"
+#include <bfc/platform/minmax.h>
+#include <bfc/std_mem.h>
+
+bool Wasabi::Std::rectIntersect(const RECT &i1, const RECT &i2, RECT *intersection)
+{
+ RECT out;
+ out.left = MAX(i1.left, i2.left);
+ out.right = MIN(i1.right, i2.right);
+ out.top = MAX(i1.top, i2.top);
+ out.bottom = MIN(i1.bottom, i2.bottom);
+
+ if (intersection != NULL) *intersection = out;
+ return (out.left < out.right && out.top < out.bottom);
+}
+
+bool Wasabi::Std::pointInRect(const RECT &r, const POINT &p)
+{
+ if (p.x < r.left ||
+ p.x >= r.right ||
+ p.y < r.top ||
+ p.y >= r.bottom) return 0;
+ return true;
+}
+
+void Wasabi::Std::setRect(RECT *r, int left, int top, int right, int bottom)
+{
+ r->left = left;
+ r->top = top;
+ r->right = right;
+ r->bottom = bottom;
+
+}
+
+RECT Wasabi::Std::makeRect(int left, int top, int right, int bottom)
+{
+ RECT r;
+ r.left = left;
+ r.top = top;
+ r.right = right;
+ r.bottom = bottom;
+ return r;
+
+}
+
+POINT Wasabi::Std::makePoint(int x, int y)
+{
+ POINT p = { x, y };
+ return p;
+}
+
+void Wasabi::Std::offsetRect(RECT *r, int x, int y)
+{
+ r->left += x;
+ r->right += x;
+ r->top += y;
+ r->bottom += y;
+}
+
+bool Wasabi::Std::rectEqual(const RECT &a, const RECT &b)
+{
+ return !MEMCMP(&a, &b, sizeof(RECT));
+}
+
+bool Wasabi::Std::rectEqual(const RECT *a, const RECT *b)
+{
+ return !MEMCMP(a, b, sizeof(RECT));
+}
+
+void Wasabi::Std::scaleRect(RECT *r, double scale)
+{
+ r->left =(long)(r->left * scale + 0.5);
+ r->right = (long)(r->right * scale + 0.5);
+ r->bottom = (long)(r->bottom * scale + 0.5);
+ r->top = (long)(r->top * scale + 0.5);
+}
+
diff --git a/Src/Wasabi/bfc/wasabi_std_rect.h b/Src/Wasabi/bfc/wasabi_std_rect.h
new file mode 100644
index 00000000..d99d319a
--- /dev/null
+++ b/Src/Wasabi/bfc/wasabi_std_rect.h
@@ -0,0 +1,22 @@
+#ifndef NULLSOFT_BFC_STD_RECT_H
+#define NULLSOFT_BFC_STD_RECT_H
+
+#include <bfc/platform/platform.h>
+namespace Wasabi
+{
+ namespace Std
+ {
+ bool rectIntersect(const RECT& a, const RECT& b, RECT* intersection = NULL);
+ bool pointInRect(const RECT& r, const POINT& p);
+ void setRect(RECT* r, int left, int top, int right, int bottom);
+ RECT makeRect(int left, int top, int right, int bottom);
+ POINT makePoint(int x, int y);
+ void setPoint(POINT* p, int x, int y);
+ void offsetRect(RECT* r, int x, int y);
+ bool rectEqual(const RECT& a, const RECT& b);
+ bool rectEqual(const RECT* a, const RECT* b);
+ void scaleRect(RECT* r, double scale);
+
+ }
+}
+#endif \ No newline at end of file
diff --git a/Src/Wasabi/bfc/wasabi_std_wnd.h b/Src/Wasabi/bfc/wasabi_std_wnd.h
new file mode 100644
index 00000000..b4a45274
--- /dev/null
+++ b/Src/Wasabi/bfc/wasabi_std_wnd.h
@@ -0,0 +1,86 @@
+#ifndef _STD_WIN_H
+#define _STD_WIN_H
+
+#include <bfc/platform/platform.h>
+#include <bfc/wasabi_std.h>
+
+#define ROOTSTRING L"RootWnd"
+#define BASEWNDCLASSNAME L"BaseWindow_" ROOTSTRING
+
+#ifdef __cplusplus
+
+class ifc_window;
+namespace Wasabi
+{
+ namespace Std
+ {
+ namespace Wnd {
+ OSWINDOWHANDLE createWnd(RECT* r, int nochild, int acceptdrops, OSWINDOWHANDLE parent, OSMODULEHANDLE module, ifc_window* rw);
+ void destroyWnd(OSWINDOWHANDLE wnd);
+
+ int isValidWnd(OSWINDOWHANDLE wnd);
+
+ void setWndPos(OSWINDOWHANDLE wnd, OSWINDOWHANDLE zorder, int x, int y, int w, int h,
+ int nozorder, int noactive, int nocopybits, int nomove, int noresize);
+ void bringToFront(OSWINDOWHANDLE wnd);
+ void sendToBack(OSWINDOWHANDLE wnd);
+ int isWndVisible(OSWINDOWHANDLE wnd);
+ void showWnd(OSWINDOWHANDLE wnd, int noactivate = FALSE);
+ void hideWnd(OSWINDOWHANDLE wnd);
+ int isPopup(OSWINDOWHANDLE wnd);
+ void setEnabled(OSWINDOWHANDLE wnd, int enabled);
+ void setFocus(OSWINDOWHANDLE wnd);
+ OSWINDOWHANDLE getFocus();
+ void setTopmost(OSWINDOWHANDLE, int topmost);
+
+ void invalidateRect(OSWINDOWHANDLE wnd, RECT* r = NULL);
+ void invalidateRegion(OSWINDOWHANDLE wnd, OSREGIONHANDLE region);
+ void validateRect(OSWINDOWHANDLE wnd, RECT* r = NULL);
+ void validateRegion(OSWINDOWHANDLE wnd, OSREGIONHANDLE region);
+ void update(OSWINDOWHANDLE wnd);
+ int getUpdateRect(OSWINDOWHANDLE wnd, RECT* r);
+ void getUpdateRegion(OSWINDOWHANDLE wnd, OSREGIONHANDLE region);
+ int haveGetRandomRegion();
+ void getRandomRegion(HDC hdc, OSREGIONHANDLE region); // sorry, HDC
+
+ void setWndRegion(OSWINDOWHANDLE wnd, OSREGIONHANDLE region, int redraw = FALSE);
+
+ int isDesktopAlphaAvailable();
+ int isTransparencyAvailable();
+ void setLayeredWnd(OSWINDOWHANDLE wnd, int layered);
+ int isLayeredWnd(OSWINDOWHANDLE wnd);
+ void setLayeredAlpha(OSWINDOWHANDLE wnd, int amount);
+ void updateLayeredWnd(OSWINDOWHANDLE wnd, int x, int y, int w, int h, HDC surfdc, int alpha);
+ void moveLayeredWnd(OSWINDOWHANDLE wnd, int x, int y);
+
+ void getClientRect(OSWINDOWHANDLE wnd, RECT* r);
+ void getWindowRect(OSWINDOWHANDLE wnd, RECT* r);
+ void clientToScreen(OSWINDOWHANDLE wnd, int* x, int* y);
+ void screenToClient(OSWINDOWHANDLE wnd, int* x, int* y);
+
+ void setParent(OSWINDOWHANDLE child, OSWINDOWHANDLE newparent);
+ OSWINDOWHANDLE getParent(OSWINDOWHANDLE wnd);
+ // void reparent(OSWINDOWHANDLE child, OSWINDOWHANDLE newparent);
+ OSWINDOWHANDLE getTopmostChild(OSWINDOWHANDLE wnd);
+
+ void setCapture(OSWINDOWHANDLE wnd);
+ void releaseCapture();
+ OSWINDOWHANDLE getCapture();
+
+ void revokeDragNDrop(OSWINDOWHANDLE wnd);
+
+ void setWndName(OSWINDOWHANDLE wnd, const wchar_t* name);
+ void getWndName(OSWINDOWHANDLE wnd, wchar_t* name, int maxlen);
+ void setIcon(OSWINDOWHANDLE wnd, OSICONHANDLE icon, int large = FALSE);
+
+ OSWINDOWHANDLE getActiveWindow();
+ void setActiveWindow(OSWINDOWHANDLE wnd);
+ void clipOSChildren(OSWINDOWHANDLE wnd, OSREGIONHANDLE reg);
+ int alphaStretchBlit(HDC destHDC, int dstx, int dsty, int dstw, int dsth, HDC sourceHDC, int srcx, int srcy, int srcw, int srch);
+ OSWINDOWHANDLE getWindowFromPoint(POINT pt);
+
+ };
+ }
+}
+#endif
+#endif